diff --git a/DEPS b/DEPS
index 942ac3d..ffce7ef 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '95105938da29f8a43cd76199769ed6ec6710a446',
+  'skia_revision': 'd7b25c734e6835152451fbe2ff3b809c5006ad51',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '32d14df37820a52fc0aa3217025b9180d66a7259',
+  'v8_revision': 'ecd588b881f43afa11b7f57029b1d8af69c54c3a',
   # 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.
@@ -193,7 +193,7 @@
    Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'b1b22ffc6a5c809c41cc27910e3e8b479c15d3a2',
 
   'src/third_party/libjingle/source/talk':
-    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + 'f213f6d46a0132c77b1eedc714b9ee71a91e782b', # commit position 10609
+    Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '54a2705b0cb5978dc4c6054bea2f02130a21d328', # commit position 10622
 
   'src/third_party/usrsctp/usrsctplib':
     Var('chromium_git') + '/external/usrsctplib.git' + '@' + '36444a999739e9e408f8f587cb4c3ffeef2e50ac', # from svn revision 9215
@@ -217,7 +217,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' + '@' + 'b671e854b2721cb982ce7d0c05f406e0e244fbc6', # commit position 10614
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'e22c7db3011093af98a9d698087f145a9471ad18', # commit position 10619
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/base/i18n/icu_util.cc b/base/i18n/icu_util.cc
index 1dd54cd6..e3afc04 100644
--- a/base/i18n/icu_util.cc
+++ b/base/i18n/icu_util.cc
@@ -143,6 +143,7 @@
     return true;
   }
   if (data_fd == kInvalidPlatformFile) {
+    LOG(ERROR) << "Invalid file descriptor to ICU data received.";
     return false;
   }
 
@@ -164,6 +165,7 @@
 
 #if !defined(OS_NACL)
 #if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#if defined(OS_ANDROID)
 bool InitializeICUWithFileDescriptor(
     PlatformFile data_fd,
     const MemoryMappedFile::Region& data_region) {
@@ -179,6 +181,28 @@
   *out_region = g_icudtl_region;
   return g_icudtl_pf;
 }
+#endif
+
+const uint8* GetRawIcuMemory() {
+  CHECK(g_icudtl_mapped_file);
+  return g_icudtl_mapped_file->data();
+}
+
+bool InitializeICUFromRawMemory(const uint8* raw_memory) {
+#if !defined(COMPONENT_BUILD)
+#if !defined(NDEBUG)
+  DCHECK(!g_check_called_once || !g_called_once);
+  g_called_once = true;
+#endif
+
+  UErrorCode err = U_ZERO_ERROR;
+  udata_setCommonData(const_cast<uint8*>(raw_memory), &err);
+  return err == U_ZERO_ERROR;
+#else
+  return true;
+#endif
+}
+
 #endif  // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
 
 bool InitializeICU() {
diff --git a/base/i18n/icu_util.h b/base/i18n/icu_util.h
index d62f8bac..ec244267 100644
--- a/base/i18n/icu_util.h
+++ b/base/i18n/icu_util.h
@@ -18,16 +18,37 @@
 BASE_I18N_EXPORT bool InitializeICU();
 
 #if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
+#if defined(OS_ANDROID)
 // Returns the PlatformFile and Region that was initialized by InitializeICU().
 // Use with InitializeICUWithFileDescriptor().
 BASE_I18N_EXPORT PlatformFile GetIcuDataFileHandle(
     MemoryMappedFile::Region* out_region);
 
-// Android and html_viewer use a file descriptor passed by browser process to
-// initialize ICU in render processes.
+// Android uses a file descriptor passed by browser process to initialize ICU
+// in render processes.
 BASE_I18N_EXPORT bool InitializeICUWithFileDescriptor(
     PlatformFile data_fd,
     const MemoryMappedFile::Region& data_region);
+#endif
+
+// Returns a void pointer to the memory mapped ICU data file.
+//
+// There are cases on Android where we would be unsafely reusing a file
+// descriptor within the same process when initializing two copies of ICU from
+// different binaries in the same address space. This returns an unowned
+// pointer to the memory mapped icu data file; consumers copies of base must
+// not outlive the copy of base that owns the memory mapped file.
+BASE_I18N_EXPORT const uint8* GetRawIcuMemory();
+
+// Initializes ICU memory
+//
+// This does nothing in component builds; this initialization should only be
+// done in cases where there could be two copies of base in a single process in
+// non-component builds. (The big example is mojo: the shell will have a copy
+// of base linked in, and the majority of mojo applications will have base
+// linked in but in non-component builds, these will be separate copies of
+// base.)
+BASE_I18N_EXPORT bool InitializeICUFromRawMemory(const uint8* raw_memory);
 #endif  // ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
 #endif  // !defined(OS_NACL)
 
diff --git a/build/android/gyp/apk_obfuscate.py b/build/android/gyp/apk_obfuscate.py
index 286555d..a227945 100755
--- a/build/android/gyp/apk_obfuscate.py
+++ b/build/android/gyp/apk_obfuscate.py
@@ -85,7 +85,6 @@
   proguard = proguard_util.ProguardCmdBuilder(options.proguard_jar_path)
   proguard.outjar(options.obfuscated_jar_path)
 
-  library_classpath = [options.android_sdk_jar]
   input_jars = build_utils.ParseGypList(options.input_jars_paths)
 
   exclude_paths = []
@@ -94,30 +93,15 @@
     # configs should only contain the process_resources.py generated config.
     assert len(configs) == 1, (
         'test apks should not have custom proguard configs: ' + str(configs))
-    tested_jar_info = build_utils.ReadJson(
-        options.tested_apk_obfuscated_jar_path + '.info')
-    exclude_paths = tested_jar_info['inputs']
-    configs = tested_jar_info['configs']
+    proguard.tested_apk_info(options.tested_apk_obfuscated_jar_path + '.info')
 
-    proguard.is_test(True)
-    proguard.mapping(options.tested_apk_obfuscated_jar_path + '.mapping')
-    library_classpath.append(options.tested_apk_obfuscated_jar_path)
-
-  proguard.libraryjars(library_classpath)
+  proguard.libraryjars([options.android_sdk_jar])
   proguard_injars = [p for p in input_jars if p not in exclude_paths]
   proguard.injars(proguard_injars)
   proguard.configs(configs)
 
   proguard.CheckOutput()
 
-  this_info = {
-    'inputs': proguard_injars,
-    'configs': configs
-  }
-
-  build_utils.WriteJson(
-      this_info, options.obfuscated_jar_path + '.info')
-
 
 def main(argv):
   options, _ = ParseArgs(argv)
diff --git a/build/android/gyp/proguard.py b/build/android/gyp/proguard.py
index 5997f61..2484354 100755
--- a/build/android/gyp/proguard.py
+++ b/build/android/gyp/proguard.py
@@ -26,6 +26,8 @@
   parser.add_option('--is-test', action='store_true',
       help='If true, extra proguard options for instrumentation tests will be '
       'added.')
+  parser.add_option('--tested-apk-info', help='Path to the proguard .info file '
+      'for the tested apk')
   parser.add_option('--classpath', action='append',
                     help='Classpath for proguard.')
   parser.add_option('--stamp', help='Path to touch on success.')
@@ -52,8 +54,8 @@
   if options.mapping:
     proguard.mapping(options.mapping)
 
-  if options.is_test:
-    proguard.is_test(True)
+  if options.tested_apk_info:
+    proguard.tested_apk_info(options.tested_apk_info)
 
   classpath = list(set(options.classpath))
   proguard.libraryjars(classpath)
diff --git a/build/android/gyp/util/proguard_util.py b/build/android/gyp/util/proguard_util.py
index 901cd9f..8ca8646 100644
--- a/build/android/gyp/util/proguard_util.py
+++ b/build/android/gyp/util/proguard_util.py
@@ -32,45 +32,55 @@
   def __init__(self, proguard_jar):
     assert os.path.exists(proguard_jar)
     self._proguard_jar_path = proguard_jar
-    self._test = None
+    self._tested_apk_info_path = None
+    self._tested_apk_info = None
     self._mapping = None
     self._libraries = None
     self._injars = None
     self._configs = None
     self._outjar = None
+    self._cmd = None
 
   def outjar(self, path):
+    assert self._cmd is None
     assert self._outjar is None
     self._outjar = path
 
-  def is_test(self, enable):
-    assert self._test is None
-    self._test = enable
+  def tested_apk_info(self, tested_apk_info_path):
+    assert self._cmd is None
+    assert self._tested_apk_info is None
+    self._tested_apk_info_path = tested_apk_info_path
 
   def mapping(self, path):
+    assert self._cmd is None
     assert self._mapping is None
     assert os.path.exists(path), path
     self._mapping = path
 
   def libraryjars(self, paths):
+    assert self._cmd is None
     assert self._libraries is None
     for p in paths:
       assert os.path.exists(p), p
     self._libraries = paths
 
   def injars(self, paths):
+    assert self._cmd is None
     assert self._injars is None
     for p in paths:
       assert os.path.exists(p), p
     self._injars = paths
 
   def configs(self, paths):
+    assert self._cmd is None
     assert self._configs is None
     for p in paths:
       assert os.path.exists(p), p
     self._configs = paths
 
   def build(self):
+    if self._cmd:
+      return self._cmd
     assert self._injars is not None
     assert self._outjar is not None
     assert self._configs is not None
@@ -78,7 +88,16 @@
       'java', '-jar', self._proguard_jar_path,
       '-forceprocessing',
     ]
-    if self._test:
+    if self._tested_apk_info_path:
+      assert len(self._configs) == 1
+      tested_apk_info = build_utils.ReadJson(self._tested_apk_info_path)
+      self._configs += tested_apk_info['configs']
+      self._injars = [
+          p for p in self._injars if not p in tested_apk_info['inputs']]
+      if not self._libraries:
+        self._libraries = []
+      self._libraries += tested_apk_info['inputs']
+      self._mapping = tested_apk_info['mapping']
       cmd += [
         '-dontobfuscate',
         '-dontoptimize',
@@ -111,18 +130,38 @@
       '-printusage', self._outjar + '.usage',
       '-printmapping', self._outjar + '.mapping',
     ]
-    return cmd
+    self._cmd = cmd
+    return self._cmd
 
   def GetInputs(self):
+    self.build()
     inputs = [self._proguard_jar_path] + self._configs + self._injars
     if self._mapping:
       inputs.append(self._mapping)
     if self._libraries:
       inputs += self._libraries
+    if self._tested_apk_info_path:
+      inputs += [self._tested_apk_info_path]
     return inputs
 
 
   def CheckOutput(self):
-    build_utils.CheckOutput(self.build(), print_stdout=True,
+    self.build()
+    # Proguard will skip writing these files if they would be empty. Create
+    # empty versions of them all now so that they are updated as the build
+    # expects.
+    open(self._outjar + '.dump', 'w').close()
+    open(self._outjar + '.seeds', 'w').close()
+    open(self._outjar + '.usage', 'w').close()
+    open(self._outjar + '.mapping', 'w').close()
+    build_utils.CheckOutput(self._cmd, print_stdout=True,
                             stdout_filter=FilterProguardOutput)
 
+    this_info = {
+      'inputs': self._injars,
+      'configs': self._configs,
+      'mapping': self._outjar + '.mapping',
+    }
+
+    build_utils.WriteJson(this_info, self._outjar + '.info')
+
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 3b85cf5..541efda 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -192,6 +192,10 @@
   parser.add_option('--tested-apk-config',
       help='Path to the build config of the tested apk (for an instrumentation '
       'test apk).')
+  parser.add_option('--proguard-enabled', action='store_true',
+      help='Whether proguard is enabled for this apk.')
+  parser.add_option('--proguard-info',
+      help='Path to the proguard .info output for this apk.')
 
   options, args = parser.parse_args(argv)
 
@@ -351,6 +355,17 @@
   if options.type in ['android_apk', 'deps_dex']:
     deps_dex_files = [c['dex_path'] for c in all_library_deps]
 
+  proguard_enabled = options.proguard_enabled
+  if options.type == 'android_apk':
+    deps_info['proguard_enabled'] = proguard_enabled
+
+  if proguard_enabled:
+    deps_info['proguard_info'] = options.proguard_info
+    config['proguard'] = {}
+    proguard_config = config['proguard']
+    proguard_config['input_paths'] = [options.jar_path] + java_full_classpath
+    proguard_config['tested_apk_info'] = ''
+
   # An instrumentation test apk should exclude the dex files that are in the apk
   # under test.
   if options.type == 'android_apk' and options.tested_apk_config:
@@ -364,12 +379,19 @@
     expected_tested_package = tested_apk_config['package_name']
     AndroidManifest(options.android_manifest).CheckInstrumentation(
         expected_tested_package)
+    if tested_apk_config['proguard_enabled']:
+      assert proguard_enabled, ('proguard must be enabled for instrumentation'
+          ' apks if it\'s enabled for the tested apk')
+      proguard_config['tested_apk_info'] = tested_apk_config['proguard_info']
 
   # Dependencies for the final dex file of an apk or a 'deps_dex'.
   if options.type in ['android_apk', 'deps_dex']:
     config['final_dex'] = {}
     dex_config = config['final_dex']
-    # TODO(cjhopman): proguard version
+    if proguard_enabled:
+      # When proguard is enabled, the proguarded jar contains the code for all
+      # of the dependencies.
+      deps_dex_files = []
     dex_config['dependency_dex_files'] = deps_dex_files
 
   if options.type == 'android_apk':
diff --git a/build/common.gypi b/build/common.gypi
index b80d0f2..f44a972 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -1535,7 +1535,7 @@
     'ozone_platform_egltest%': 0,
     'ozone_platform_gbm%': 0,
     'ozone_platform_ozonex%': 0,
-    'ozone_platform_test%': 0,
+    'ozone_platform_headless%': 0,
 
     # Experiment: http://crbug.com/426914
     'envoy%': 0,
@@ -2363,13 +2363,13 @@
       }],
 
       ['use_ozone==1 and ozone_auto_platforms==1', {
-        # Use test as the default platform.
-        'ozone_platform%': 'test',
+        # Use headless as the default platform.
+        'ozone_platform%': 'headless',
 
         # Build all platforms whose deps are in install-build-deps.sh.
         # Only these platforms will be compile tested by buildbots.
         'ozone_platform_gbm%': 1,
-        'ozone_platform_test%': 1,
+        'ozone_platform_headless%': 1,
         'ozone_platform_egltest%': 1,
       }],
 
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index 0866aa4..9895c46 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -74,6 +74,51 @@
   }
 }
 
+template("proguard") {
+  action(target_name) {
+    set_sources_assignment_filter([])
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "data_deps",
+                             "public_deps",
+                             "testonly",
+                           ])
+    script = "//build/android/gyp/proguard.py"
+    _proguard_jar_path = "//third_party/proguard/lib/proguard.jar"
+    _output_jar_path = invoker.output_jar_path
+    inputs = [
+      android_sdk_jar,
+      _proguard_jar_path,
+    ]
+    if (defined(invoker.inputs)) {
+      inputs += invoker.inputs
+    }
+    depfile = "${target_gen_dir}/${target_name}.d"
+    outputs = [
+      depfile,
+      _output_jar_path,
+      "$_output_jar_path.dump",
+      "$_output_jar_path.seeds",
+      "$_output_jar_path.mapping",
+      "$_output_jar_path.usage",
+    ]
+    args = [
+      "--depfile",
+      rebase_path(depfile, root_build_dir),
+      "--proguard-path",
+      rebase_path(_proguard_jar_path, root_build_dir),
+      "--output-path",
+      rebase_path(_output_jar_path, root_build_dir),
+      "--classpath",
+      rebased_android_sdk_jar,
+    ]
+    if (defined(invoker.args)) {
+      args += invoker.args
+    }
+  }
+}
+
 template("findbugs") {
   jar_path = invoker.jar_path
 
@@ -233,19 +278,15 @@
 # See build/android/gyp/write_build_config.py and
 # build/android/gyp/util/build_utils.py:ExpandFileArgs
 template("write_build_config") {
-  set_sources_assignment_filter([])
-
-  assert(defined(invoker.type))
-  assert(defined(invoker.build_config))
-
-  type = invoker.type
-  build_config = invoker.build_config
-
-  assert(type == "android_apk" || type == "java_library" ||
-         type == "android_resources" || type == "deps_dex" ||
-         type == "android_assets" || type == "resource_rewriter")
-
   action(target_name) {
+    set_sources_assignment_filter([])
+    type = invoker.type
+    build_config = invoker.build_config
+
+    assert(type == "android_apk" || type == "java_library" ||
+           type == "android_resources" || type == "deps_dex" ||
+           type == "android_assets" || type == "resource_rewriter")
+
     deps = []
     forward_variables_from(invoker,
                            [
@@ -403,6 +444,14 @@
           "--readelf-path=$rebased_android_readelf",
         ]
       }
+
+      if (defined(invoker.proguard_enabled) && invoker.proguard_enabled) {
+        args += [
+          "--proguard-enabled",
+          "--proguard-info",
+          rebase_path(invoker.proguard_info, root_build_dir),
+        ]
+      }
     }
 
     if (defined(invoker.srcjar)) {
@@ -426,44 +475,29 @@
   assert(invoker.build_config != "")
 
   if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
-    _proguard_jar_path = "//third_party/proguard/lib/proguard.jar"
-    _proguard_config_path = invoker.proguard_config
     _build_config = invoker.build_config
     _rebased_build_config = rebase_path(_build_config, root_build_dir)
+    _proguard_config_path = invoker.proguard_config
     _output_jar_target = "${target_name}__proguard_process"
-    action(_output_jar_target) {
+    proguard(_output_jar_target) {
       forward_variables_from(invoker,
                              [
                                "data_deps",
                                "deps",
                                "public_deps",
                              ])
-      script = "//build/android/gyp/proguard.py"
       inputs = [
-        android_sdk_jar,
-        _proguard_jar_path,
         _build_config,
         _input_jar_path,
         _proguard_config_path,
       ]
-      depfile = "${target_gen_dir}/${target_name}.d"
-      outputs = [
-        depfile,
-        _output_jar_path,
-      ]
+      output_jar_path = _output_jar_path
+      _rebased_input_paths = [ rebase_path(_input_jar_path, root_build_dir) ]
+      _rebased_proguard_configs =
+          [ rebase_path(_proguard_config_path, root_build_dir) ]
       args = [
-        "--depfile",
-        rebase_path(depfile, root_build_dir),
-        "--proguard-path",
-        rebase_path(_proguard_jar_path, root_build_dir),
-        "--input-path",
-        rebase_path(_input_jar_path, root_build_dir),
-        "--output-path",
-        rebase_path(_output_jar_path, root_build_dir),
-        "--proguard-config",
-        rebase_path(_proguard_config_path, root_build_dir),
-        "--classpath",
-        rebased_android_sdk_jar,
+        "--input-paths=$_rebased_input_paths",
+        "--proguard-configs=$_rebased_proguard_configs",
         "--classpath=@FileArg($_rebased_build_config:javac:classpath)",
       ]
     }
@@ -1540,6 +1574,14 @@
       ]
     }
 
+    if (defined(invoker.proguard_file)) {
+      outputs += [ invoker.proguard_file ]
+      args += [
+        "--proguard-file",
+        rebase_path(invoker.proguard_file, root_build_dir),
+      ]
+    }
+
     if (defined(invoker.args)) {
       args += invoker.args
     }
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index d28d5a7..090f557 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -1351,6 +1351,12 @@
   # Help GN understand that _create_abi_split is not unused (bug in GN).
   assert(_create_abi_split || true)
 
+  _proguard_enabled =
+      defined(invoker.proguard_enabled) && invoker.proguard_enabled
+  if (_proguard_enabled) {
+    _proguard_jar_path = "$base_path.proguard.jar"
+  }
+
   build_config_target = "${_template_name}__build_config"
   write_build_config(build_config_target) {
     forward_variables_from(invoker, [ "apk_under_test" ])
@@ -1366,11 +1372,17 @@
       deps += invoker.deps
     }
 
+    proguard_enabled = _proguard_enabled
+    if (_proguard_enabled) {
+      proguard_info = "$_proguard_jar_path.info"
+    }
+
     native_libs = _native_libs
   }
 
   _final_deps = []
 
+  _generated_proguard_config = "$base_path.resources.proguard.txt"
   process_resources_target = "${_template_name}__process_resources"
   process_resources(process_resources_target) {
     forward_variables_from(invoker, [ "include_all_resources" ])
@@ -1381,6 +1393,7 @@
     zip_path = resources_zip_path
     all_resources_zip_path = _all_resources_zip_path
     generate_constant_ids = true
+    proguard_file = _generated_proguard_config
 
     build_config = _build_config
     deps = _android_manifest_deps + [ ":$build_config_target" ]
@@ -1493,20 +1506,47 @@
     }
   }
 
+  if (_proguard_enabled) {
+    _proguard_configs = [ _generated_proguard_config ]
+    if (defined(invoker.proguard_configs)) {
+      _proguard_configs += invoker.proguard_configs
+    }
+    _proguard_target = "${_template_name}__proguard"
+    proguard(_proguard_target) {
+      deps = [
+        ":$build_config_target",
+        ":$process_resources_target",
+        ":$java_target",
+      ]
+      inputs = [
+                 _build_config,
+                 _jar_path,
+               ] + _proguard_configs
+
+      output_jar_path = _proguard_jar_path
+      rebased_proguard_configs = rebase_path(_proguard_configs, root_build_dir)
+      args = [
+        "--proguard-configs=$rebased_proguard_configs",
+        "--tested-apk-info=@FileArg($_rebased_build_config:proguard:tested_apk_info)",
+        "--input-paths=@FileArg($_rebased_build_config:proguard:input_paths)",
+      ]
+    }
+    _dex_sources = [ _proguard_jar_path ]
+    _dex_deps = [ ":$_proguard_target" ]
+  } else {
+    _dex_sources = [ _lib_dex_path ]
+    _dex_deps = [ ":$java_target" ]
+  }
+
   dex("$final_dex_target_name") {
-    deps = [
-      ":$build_config_target",
-      ":$java_target",
-    ]
+    deps = _dex_deps + [ ":$build_config_target" ]
     inputs = [
       _build_config,
     ]
+    sources = _dex_sources
     output = final_dex_path
     _dex_arg_key = "${_rebased_build_config}:final_dex:dependency_dex_files"
-    args = [
-      "--inputs=@FileArg($_dex_arg_key)",
-      _rebased_lib_dex_path,
-    ]
+    args = [ "--inputs=@FileArg($_dex_arg_key)" ]
   }
 
   if (_native_libs != []) {
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 0a66eea2..43e19c3 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -242,6 +242,25 @@
     overlay_processor_->ProcessForOverlays(
         resource_provider_, render_passes_in_draw_order, &frame.overlay_list,
         &frame.root_damage_rect);
+
+    // No need to render in case the damage rect is completely composited using
+    // overlays and dont have any copy requests.
+    if (frame.root_damage_rect.IsEmpty()) {
+      bool handle_copy_requests = false;
+      for (auto* pass : *render_passes_in_draw_order) {
+        if (!pass->copy_requests.empty()) {
+          handle_copy_requests = true;
+          break;
+        }
+      }
+
+      if (!handle_copy_requests) {
+        BindFramebufferToOutputSurface(&frame);
+        FinishDrawingFrame(&frame);
+        render_passes_in_draw_order->clear();
+        return;
+      }
+    }
   }
 
   for (size_t i = 0; i < render_passes_in_draw_order->size(); ++i) {
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 8c9efc7..dd325bd 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -1613,6 +1613,35 @@
   Mock::VerifyAndClearExpectations(&scheduler_);
 }
 
+TEST_F(GLRendererWithOverlaysTest, OccludedQuadNotDrawn) {
+  bool use_validator = true;
+  Init(use_validator);
+  renderer_->set_expect_overlays(true);
+  gfx::Rect viewport_rect(16, 16);
+
+  scoped_ptr<RenderPass> pass = CreateRenderPass();
+
+  CreateFullscreenCandidateQuad(resource_provider_.get(),
+                                pass->shared_quad_state_list.back(),
+                                pass.get());
+
+  CreateFullscreenOpaqueQuad(resource_provider_.get(),
+                             pass->shared_quad_state_list.back(), pass.get());
+  CreateFullscreenOpaqueQuad(resource_provider_.get(),
+                             pass->shared_quad_state_list.back(), pass.get());
+
+  RenderPassList pass_list;
+  pass_list.push_back(pass.Pass());
+
+  output_surface_->set_is_displayed_as_overlay_plane(true);
+  EXPECT_CALL(*renderer_, DoDrawQuad(_, _, _)).Times(0);
+  EXPECT_CALL(scheduler_, Schedule(_, _, _, _, _)).Times(2);
+  renderer_->DrawFrame(&pass_list, 1.f, viewport_rect, viewport_rect, false);
+  SwapBuffers();
+  Mock::VerifyAndClearExpectations(renderer_.get());
+  Mock::VerifyAndClearExpectations(&scheduler_);
+}
+
 TEST_F(GLRendererWithOverlaysTest, ResourcesExportedAndReturnedWithDelay) {
   bool use_validator = true;
   Init(use_validator);
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index f763781..7f15c9d8 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -446,7 +446,6 @@
 
 # GYP: //chrome/android/chrome_apk.gyp:chrome_public_test_apk
 instrumentation_test_apk("chrome_public_test_apk") {
-  # TODO(GYP,cjhopman): Does this need version code/name?
   apk_name = "ChromePublicTest"
   apk_under_test = ":chrome_public_apk"
   android_manifest = chrome_public_test_apk_manifest
@@ -455,4 +454,5 @@
     "//chrome/android:chrome_shared_test_java",
   ]
   isolate_file = "../chrome_public_test_apk.isolate"
+  proguard_enabled = !is_debug
 }
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 2fa5557..5a6296c8 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -17,18 +17,22 @@
 
 # GYP: //chrome/android/chrome_apk.gypi
 template("chrome_public_apk_tmpl") {
-  forward_variables_from(invoker, "*")
-
   android_apk(target_name) {
+    forward_variables_from(invoker, "*")
     _native_lib_file =
         rebase_path("$root_gen_dir/CHROME_VERSION.json", root_out_dir)
     native_lib_version_arg = "@FileArg($_native_lib_file:full-quoted)"
 
-    # TODO(GYP):
-    #'proguard_enabled': 'true',
-    #'proguard_flags_paths': [
-    #  'chrome/android/java/proguard.flags',
-    #]
+    if (!is_debug) {
+      proguard_enabled = true
+      _prev_proguard_configs = []
+      if (defined(proguard_configs)) {
+        _prev_proguard_configs = proguard_configs
+      }
+      proguard_configs = []
+      proguard_configs =
+          [ "//chrome/android/java/proguard.flags" ] + _prev_proguard_configs
+    }
 
     if (chromium_linker_supported) {
       use_chromium_linker = chrome_public_apk_use_chromium_linker
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
index f0e68cf..80d68e3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
@@ -24,6 +24,11 @@
         implements OverlayPanelContentFactory {
 
     /**
+     * The extra dp added around the close button touch target.
+     */
+    private static final int CLOSE_BUTTON_TOUCH_SLOP_DP = 5;
+
+    /**
      * State of the Overlay Panel.
      */
     public static enum PanelState {
@@ -472,6 +477,19 @@
     }
 
     /**
+     * @param x The x coordinate in dp.
+     * @param y The y coordinate in dp.
+     * @return Whether the given |x| |y| coordinate is inside the close button.
+     */
+    protected boolean isCoordinateInsideCloseButton(float x, float y) {
+        boolean isInY = y >= (getCloseIconY() - CLOSE_BUTTON_TOUCH_SLOP_DP)
+                && y <= (getCloseIconY() + getCloseIconDimension() + CLOSE_BUTTON_TOUCH_SLOP_DP);
+        boolean isInX = x >= (getCloseIconX() - CLOSE_BUTTON_TOUCH_SLOP_DP)
+                && x <= (getCloseIconX() + getCloseIconDimension() + CLOSE_BUTTON_TOUCH_SLOP_DP);
+        return isInY && isInX;
+    }
+
+    /**
      * Handles the click gesture.
      *
      * @param time The timestamp of the gesture.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
index 961c20e..ff7e45b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
@@ -28,11 +28,6 @@
 public class ContextualSearchPanel extends OverlayPanel {
 
     /**
-     * The extra dp added around the close button touch target.
-     */
-    private static final int CLOSE_BUTTON_TOUCH_SLOP_DP = 5;
-
-    /**
      * The delay after which the hide progress will be hidden.
      */
     private static final long HIDE_PROGRESS_BAR_DELAY = 1000 / 60 * 4;
@@ -282,19 +277,6 @@
         }
     }
 
-    /**
-     * @param x The x coordinate in dp.
-     * @param y The y coordinate in dp.
-     * @return Whether the given |x| |y| coordinate is inside the close button.
-     */
-    private boolean isCoordinateInsideCloseButton(float x, float y) {
-        boolean isInY = y >= (getCloseIconY() - CLOSE_BUTTON_TOUCH_SLOP_DP)
-                && y <= (getCloseIconY() + getCloseIconDimension() + CLOSE_BUTTON_TOUCH_SLOP_DP);
-        boolean isInX = x >= (getCloseIconX() - CLOSE_BUTTON_TOUCH_SLOP_DP)
-                && x <= (getCloseIconX() + getCloseIconDimension() + CLOSE_BUTTON_TOUCH_SLOP_DP);
-        return isInY && isInX;
-    }
-
     @Override
     public boolean onInterceptBarClick() {
         return onInterceptOpeningPanel();
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 5e838bf..4f42e63 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
@@ -1259,7 +1259,7 @@
      * Updates the target offset of the Base Page in order to keep the selection in view
      * after expanding the Panel.
      */
-    private void updateBasePageTargetY() {
+    protected void updateBasePageTargetY() {
         mBasePageTargetY = calculateBasePageTargetY(PanelState.EXPANDED);
     }
 
@@ -1270,7 +1270,7 @@
      * @param expandedState
      * @return The target offset Y.
      */
-    private float calculateBasePageTargetY(PanelState expandedState) {
+    protected float calculateBasePageTargetY(PanelState expandedState) {
         // Only a fullscreen wide Panel should offset the base page. A small panel should
         // always return zero to ensure the Base Page remains in the same position.
         if (!isFullscreenSizePanel()) return 0.f;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModeBarControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModeBarControl.java
index 4d61e4b..9fe8fec 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModeBarControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModeBarControl.java
@@ -24,6 +24,11 @@
     private TextView mReaderText;
 
     /**
+     * Track the last string that was displayed in the bar to avoid unnecessary re-draw.
+     */
+    private int mLastDisplayedStringId;
+
+    /**
      * @param panel             The panel.
      * @param context           The Android Context used to inflate the View.
      * @param container         The container View used to inflate the View.
@@ -43,6 +48,9 @@
      * @param stringId The resource ID of the string to set the text to.
      */
     public void setBarText(int stringId) {
+        if (stringId == mLastDisplayedStringId) return;
+        mLastDisplayedStringId = stringId;
+
         inflate();
         mReaderText.setText(stringId);
         invalidate();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java
new file mode 100644
index 0000000..0500439e3
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java
@@ -0,0 +1,277 @@
+// Copyright 2015 The Chromium 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.compositor.bottombar.readermode;
+
+import android.content.Context;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.compositor.bottombar.OverlayContentDelegate;
+import org.chromium.chrome.browser.compositor.bottombar.OverlayContentProgressObserver;
+import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel;
+import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
+import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelContent;
+import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelContentViewDelegate;
+import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager;
+import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager.PanelPriority;
+import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
+import org.chromium.chrome.browser.compositor.scene_layer.ContextualSearchSceneLayer;
+import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer;
+import org.chromium.chrome.browser.dom_distiller.ReaderModeManagerDelegate;
+import org.chromium.content.browser.ContentViewCore;
+import org.chromium.ui.resources.ResourceManager;
+
+/**
+ * The panel containing reader mode.
+ */
+public class ReaderModePanel extends OverlayPanel {
+
+    /**
+     * The compositor layer used for drawing the panel.
+     */
+    private ContextualSearchSceneLayer mSceneLayer;
+
+    /**
+     * Delegate for calling functions on the ReaderModeManager.
+     */
+    private ReaderModeManagerDelegate mManagerDelegate;
+
+    /**
+     * Delegate for passing the current ContentViewCore to the layout manager.
+     */
+    private OverlayPanelContentViewDelegate mContentViewDelegate;
+
+    /**
+     * The opacity of the panel bar text.
+     */
+    private float mReaderBarTextOpacity;
+
+    // ============================================================================================
+    // Constructor
+    // ============================================================================================
+
+    /**
+     * @param context The current Android {@link Context}.
+     * @param updateHost The {@link LayoutUpdateHost} used to request updates in the Layout.
+     */
+    public ReaderModePanel(Context context, LayoutUpdateHost updateHost,
+                OverlayPanelManager panelManager,
+                OverlayPanelContentViewDelegate contentViewDelegate) {
+        super(context, updateHost, panelManager);
+        mSceneLayer = createNewReaderModeSceneLayer();
+        mContentViewDelegate = contentViewDelegate;
+    }
+
+    /**
+     * Destroy the panel's components.
+     */
+    public void destroy() {
+        super.destroy();
+        destroyReaderModeBarControl();
+    }
+
+    @Override
+    public OverlayPanelContent createNewOverlayPanelContent() {
+        OverlayContentDelegate delegate = new OverlayContentDelegate() {
+            @Override
+            public void onContentViewCreated(ContentViewCore contentView) {
+                mContentViewDelegate.setOverlayPanelContentViewCore(contentView);
+            }
+
+            @Override
+            public void onContentViewDestroyed() {
+                mContentViewDelegate.releaseOverlayPanelContentViewCore();
+            }
+
+            @Override
+            public void onMainFrameNavigation(String url, boolean isExternalUrl,
+                    boolean isFailure) {
+                if (isExternalUrl) {
+                    mManagerDelegate.createNewTab(url);
+                }
+            }
+        };
+
+        return new OverlayPanelContent(delegate, new OverlayContentProgressObserver(), mActivity);
+    }
+
+    // ============================================================================================
+    // Scene layer
+    // ============================================================================================
+
+    @Override
+    public SceneLayer getSceneLayer() {
+        return mSceneLayer;
+    }
+
+    @Override
+    public void updateSceneLayer(ResourceManager resourceManager) {
+        if (mSceneLayer == null) return;
+
+        // This will cause the ContentViewCore to size itself appropriately for the panel (includes
+        // top controls height).
+        updateTopControlsState();
+
+        // TODO(mdjones): Uncomment this when other changes have merged!
+        //mSceneLayer.update(resourceManager, this,
+        //    0, getBarTextViewId(), null, 0, mReaderBarTextOpacity, null);
+    }
+
+    /**
+     * Create a new scene layer for this panel. This should be overridden by tests as necessary.
+     */
+    protected ContextualSearchSceneLayer createNewReaderModeSceneLayer() {
+        return new ContextualSearchSceneLayer(mContext.getResources().getDisplayMetrics().density);
+    }
+
+    // ============================================================================================
+    // Manager Integration
+    // ============================================================================================
+
+    /**
+     * Sets the {@code ReaderModeManagerDelegate} associated with this panel.
+     * @param delegate The {@code ReaderModeManagerDelegate}.
+     */
+    public void setManagerDelegate(ReaderModeManagerDelegate delegate) {
+        // TODO(mdjones): This looks similar to setManagementDelegate in ContextualSearchPanel,
+        // consider moving this to OverlayPanel.
+        if (mManagerDelegate != delegate) {
+            mManagerDelegate = delegate;
+            if (mManagerDelegate != null) {
+                setChromeActivity(mManagerDelegate.getChromeActivity());
+                initializeUiState();
+                updateBasePageTargetY();
+            }
+        }
+    }
+
+    // ============================================================================================
+    // Generic Event Handling
+    // ============================================================================================
+
+    @Override
+    public void handleBarClick(long time, float x, float y) {
+        super.handleBarClick(time, x, y);
+        if (isCoordinateInsideCloseButton(x, y)) {
+            closePanel(StateChangeReason.CLOSE_BUTTON, true);
+            mManagerDelegate.onCloseButtonPressed();
+        } else {
+            maximizePanel(StateChangeReason.SEARCH_BAR_TAP);
+        }
+    }
+
+    @Override
+    public boolean onInterceptBarClick() {
+        // TODO(mdjones): Handle compatibility mode here (promote to tab on tap).
+        return false;
+    }
+
+    // ============================================================================================
+    // Panel base methods
+    // ============================================================================================
+
+    @Override
+    public PanelPriority getPriority() {
+        return PanelPriority.MEDIUM;
+    }
+
+    @Override
+    public boolean canBeSuppressed() {
+        return true;
+    }
+
+    @Override
+    public void peekPanel(StateChangeReason reason) {
+        super.peekPanel(reason);
+        mManagerDelegate.onPanelPeek();
+    }
+
+    @Override
+    protected void updatePanelForCloseOrPeek(float percent) {
+        super.updatePanelForCloseOrPeek(percent);
+        getReaderModeBarControl().setBarText(R.string.reader_view_text);
+        mReaderBarTextOpacity = 1.0f;
+    }
+
+    @Override
+    protected void updatePanelForExpansion(float percent) {
+        super.updatePanelForExpansion(percent);
+        if (percent < 0.5f) {
+            mReaderBarTextOpacity = 1.0f - 2.0f * percent;
+            getReaderModeBarControl().setBarText(R.string.reader_view_text);
+        } else {
+            mReaderBarTextOpacity = 2.0f * (percent - 0.5f);
+            getReaderModeBarControl().setBarText(R.string.reader_mode_expanded_title);
+        }
+    }
+
+    @Override
+    protected void updatePanelForMaximization(float percent) {
+        super.updatePanelForMaximization(percent);
+        getReaderModeBarControl().setBarText(R.string.reader_mode_expanded_title);
+        mReaderBarTextOpacity = 1.0f;
+    }
+
+    @Override
+    public float getArrowIconOpacity() {
+        // TODO(mdjones): This will not be needed once Reader Mode has its own scene layer.
+        // Never show the arrow icon.
+        return 0.0f;
+    }
+
+    @Override
+    public float getCloseIconOpacity() {
+        // TODO(mdjones): Make close button controlled by overlay panel as a toggle.
+        // TODO(mdjones): This will not be needed once Reader Mode has its own scene layer.
+        // Always show the close icon.
+        return 1.0f;
+    }
+
+    @Override
+    protected float calculateBasePageTargetY(PanelState state) {
+        // TODO(mdjones): Remove this method when this panel behaves like the toolbar. In the case
+        // of reader mode the base page will always need to move the same amount.
+        return -getToolbarHeight();
+    }
+
+    // ============================================================================================
+    // ReaderModeBarControl
+    // ============================================================================================
+
+    private ReaderModeBarControl mReaderModeBarControl;
+
+    /**
+     * @return The Id of the Search Term View.
+     */
+    public int getBarTextViewId() {
+        return getReaderModeBarControl().getViewId();
+    }
+
+    /**
+     * Creates the ReaderModeBarControl, if needed. The Views are set to INVISIBLE, because
+     * they won't actually be displayed on the screen (their snapshots will be displayed instead).
+     */
+    protected ReaderModeBarControl getReaderModeBarControl() {
+        assert mContainerView != null;
+        assert mResourceLoader != null;
+
+        if (mReaderModeBarControl == null) {
+            mReaderModeBarControl =
+                    new ReaderModeBarControl(this, mContext, mContainerView, mResourceLoader);
+        }
+
+        assert mReaderModeBarControl != null;
+        return mReaderModeBarControl;
+    }
+
+    /**
+     * Destroys the ReaderModeBarControl.
+     */
+    protected void destroyReaderModeBarControl() {
+        if (mReaderModeBarControl != null) {
+            mReaderModeBarControl.destroy();
+            mReaderModeBarControl = null;
+        }
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerDelegate.java
new file mode 100644
index 0000000..2fb87d2
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManagerDelegate.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.chrome.browser.dom_distiller;
+
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.compositor.bottombar.readermode.ReaderModePanel;
+
+/**
+ * Delegate for the panel to call into the manager.
+ */
+public interface ReaderModeManagerDelegate {
+    /**
+     * @return Reader mode header background color.
+     */
+    int getReaderModeHeaderBackgroundColor();
+
+    /**
+     * @return One of ReaderModeManager.POSSIBLE, NOT_POSSIBLE, STARTED constants.
+     */
+    int getReaderModeStatus();
+
+    /**
+     * @param panel The panel to be managed.
+     */
+    void setReaderModePanel(ReaderModePanel panel);
+
+    /**
+     * Load a URL in a new tab.
+     * @param url The URL to load in the tab.
+     */
+    void createNewTab(String url);
+
+    /**
+     * Notify the manager that the panel was closed using the "x" icon.
+     */
+    void onCloseButtonPressed();
+
+    /**
+     * Notify the manager that the panel is starting to peek.
+     */
+    void onPanelPeek();
+
+    /**
+     * @return The ChromeActivity that owns the manager.
+     */
+    ChromeActivity getChromeActivity();
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/DocumentModeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/DocumentModeManager.java
index 58914a3..eb153585 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/DocumentModeManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/DocumentModeManager.java
@@ -145,27 +145,19 @@
             "SM-N7505", // Galaxy Note3 Neo
             "SM-N7505L", // Galaxy Note3 Neo
             "SM-N7507", // Galaxy Note3 Neo
-            "HTC One dual sim", // HTC ONE
-            "HTC 801e", // HTC One
-            "HTC One", // HTC One
-            "HTC One 801e", // HTC One
-            "HTC_PN071", // HTC One
-            "HTC 802t", // HTC One
-            "HTC 802t 16GB", // HTC One
-            "HTC 802w", // HTC One
-            "HTC One dual sim", // HTC One
-            "HTC 802d", // HTC One
-            "HTC One dual 802d", // HTC One
-            "HTC One dual sim", // HTC One
-            "HTC One", // HTC One
-            "HTCONE", // HTC One
+            "HTC ONE DUAL SIM", // HTC ONE
+            "HTC 801E", // HTC One
             "HTC ONE", // HTC One
-            "HTC One", // HTC One
-            "HTC One 801e", // HTC One 801e
-            "HTC One 801s", // HTC One 801e
-            "HTC One dual 802d", //HTC One Dual 802d
-            "HTC One dual sim", // HTC One Dual Sim
-            "HTC One", // HTC One Google Play edition
+            "HTC ONE 801E", // HTC One
+            "HTC_PN071", // HTC One
+            "HTC 802T", // HTC One
+            "HTC 802T 16GB", // HTC One
+            "HTC 802W", // HTC One
+            "HTC 802D", // HTC One
+            "HTC ONE DUAL 802D", // HTC One
+            "HTCONE", // HTC One
+            "HTC ONE 801E", // HTC One 801e
+            "HTC ONE 801S", // HTC One 801e
     };
 
     private static DocumentModeManager sManager;
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 3b70c45..2484006 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -2055,9 +2055,12 @@
       <message name="IDS_MENU_OPEN_IN_PRODUCT" desc="App menu item for opening link in Chrome. [CHAR-LIMIT=30]">
         Open in <ph name="PRODUCT_NAME">%1$s<ex>Chrome</ex></ph>
       </message>
-      <message name="IDS_READER_VIEW_TEXT" desc="Message shown on the reader mode button bar, to invite the user to tap to open a reader mode.">
+      <message name="IDS_READER_VIEW_TEXT" desc="Message shown on the reader mode button bar, to invite the user to tap to open a reader mode. Reader mode extracts content and removes clutter from a web page and puts the result in a panel making it easier to read.">
         Make page mobile-friendly
       </message>
+      <message name="IDS_READER_MODE_EXPANDED_TITLE" desc="Message shown on the reader mode button bar when it is opened to show reader mode. Reader mode extracts content and removes clutter from a web page and puts the result in a panel making it easier to read.">
+        Mobile-friendly view
+      </message>
       <message name="IDS_UPDATE_AVAILABLE_INFOBAR" desc="Text to display when a new update is detected.">
         Chrome is out of date. Important security improvements and new features are available in the latest version.
       </message>
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 cd9d821c..6b4df95 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -263,8 +263,9 @@
      * renderer. https://crbug.com/434477.
      * @throws InterruptedException
      * @throws TimeoutException
+     * @SmallTest
      */
-    @SmallTest
+    @FlakyTest
     public void testNewTabSetsContentViewSize() throws InterruptedException, TimeoutException {
         ChromeTabUtils.newTabFromMenu(getInstrumentation(), getActivity());
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java
index 4624f86..d8f16f5f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenIconTest.java
@@ -7,6 +7,7 @@
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
+import android.test.FlakyTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.ViewGroup;
 import android.widget.ImageView;
@@ -38,7 +39,11 @@
         startWebappActivity();
     }
 
-    @SmallTest
+    /**
+     * Marked as flaky on http://crbug.com/554929
+     * @SmallTest
+     */
+    @FlakyTest
     @Feature({"Webapps"})
     public void testShowSplashIcon() {
         ViewGroup splashScreen = getActivity().getSplashScreenForTests();
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp
index f22ad9a..e5c40fc 100644
--- a/chrome/app/settings_chromium_strings.grdp
+++ b/chrome/app/settings_chromium_strings.grdp
@@ -29,6 +29,9 @@
   </message>
 
   <!-- Sync Page -->
+  <message name="IDS_SETTINGS_SYNC_SIGNIN" desc="The label that appears on the sync button in the options dialog when sync has not been set up by the user.">
+    Sign in to Chromium
+  </message>
   <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.
   </message>
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp
index e8178d9..19a0626 100644
--- a/chrome/app/settings_google_chrome_strings.grdp
+++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -29,6 +29,9 @@
   </message>
 
   <!-- Sync Page -->
+  <message name="IDS_SETTINGS_SYNC_SIGNIN" desc="The label that appears on the sync button in the options dialog when sync has not been set up by the user.">
+    Sign in to Chrome
+  </message>
   <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.
   </message>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index dae7ea8..5c97da9 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -539,12 +539,13 @@
     Delete
   </message>
 
-  <!-- Sign-in Page -->
-  <message name="IDS_SETTINGS_SIGNIN" desc="Name of the settings page which manages Chrome's signed-in Google profile.">
-    Sign in
+  <!-- Sync / People Page -->
+  <message name="IDS_SETTINGS_SYNC_PEOPLE" desc="Name of the settings page which manages Chrome's signed-in Google profile.">
+    People
   </message>
-
-  <!-- Sync Page -->
+  <message name="IDS_SETTINGS_SYNC_OVERVIEW" desc="The message that appears in the options dialog when sync has not been set up by the user.">
+    Sign in to get your bookmarks, history, passwords and other settings on all your devices. You'll also automatically be signed in to your Google services.
+  </message>
   <message name="IDS_SETTINGS_SYNC_DISCONNECT" desc="The text to display on the button to indicate stop syncing functionality.">
     Sign Out
   </message>
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 059a6ad..58be71c 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -661,13 +661,6 @@
                   << " list specified.";
   }
 
-#if defined(FIELDTRIAL_TESTING_ENABLED)
-  if (!command_line->HasSwitch(switches::kDisableFieldTrialTestingConfig) &&
-      !command_line->HasSwitch(switches::kForceFieldTrials) &&
-      !command_line->HasSwitch(variations::switches::kVariationsServerURL))
-    chrome_variations::AssociateDefaultFieldTrialConfig();
-#endif  // defined(FIELDTRIAL_TESTING_ENABLED)
-
   if (command_line->HasSwitch(switches::kForceVariationIds)) {
     // Create default variation ids which will always be included in the
     // X-Client-Data request header.
@@ -685,6 +678,14 @@
       command_line->GetSwitchValueASCII(switches::kEnableFeatures),
       command_line->GetSwitchValueASCII(switches::kDisableFeatures));
 
+#if defined(FIELDTRIAL_TESTING_ENABLED)
+  if (!command_line->HasSwitch(switches::kDisableFieldTrialTestingConfig) &&
+      !command_line->HasSwitch(switches::kForceFieldTrials) &&
+      !command_line->HasSwitch(variations::switches::kVariationsServerURL)) {
+    chrome_variations::AssociateDefaultFieldTrialConfig(feature_list.get());
+  }
+#endif  // defined(FIELDTRIAL_TESTING_ENABLED)
+
   variations::VariationsService* variations_service =
       browser_process_->variations_service();
   if (variations_service)
diff --git a/chrome/browser/chromeos/file_manager/video_player_browsertest.cc b/chrome/browser/chromeos/file_manager/video_player_browsertest.cc
index 34b0c1d..e7ffefe 100644
--- a/chrome/browser/chromeos/file_manager/video_player_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/video_player_browsertest.cc
@@ -76,4 +76,15 @@
   StartTest();
 }
 
+// http://crbug.com/508949
+#if defined(MEMORY_SANITIZER)
+#define MAYBE_ClickControlButtons DISABLED_ClickControlButtons
+#else
+#define MAYBE_ClickControlButtons ClickControlButtons
+#endif
+IN_PROC_BROWSER_TEST_F(VideoPlayerBrowserTest, MAYBE_ClickControlButtons) {
+  set_test_case_name("clickControlButtons");
+  StartTest();
+}
+
 }  // namespace file_manager
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index fcf2787..36d155c 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/prefs/pref_member.h"
 #include "base/prefs/pref_service.h"
 #include "base/run_loop.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/test/test_file_util.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/download/chrome_download_manager_delegate.h"
@@ -43,6 +44,7 @@
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
+#include "net/base/filename_util.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/url_request/url_request_mock_http_job.h"
@@ -308,8 +310,12 @@
   // Returns full paths of destination file and directory.
   void GetDestinationPaths(const std::string& prefix,
                            base::FilePath* full_file_name,
-                           base::FilePath* dir) {
-    *full_file_name = save_dir_.path().AppendASCII(prefix + ".htm");
+                           base::FilePath* dir,
+                           content::SavePageType save_page_type =
+                               content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML) {
+    std::string extension =
+        (save_page_type == content::SAVE_PAGE_TYPE_AS_MHTML) ? ".mht" : ".htm";
+    *full_file_name = save_dir_.path().AppendASCII(prefix + extension);
     *dir = save_dir_.path().AppendASCII(prefix + "_files");
   }
 
@@ -350,7 +356,8 @@
                       int expected_number_of_files,
                       base::FilePath* output_dir,
                       base::FilePath* main_file_name) {
-    GetDestinationPaths(prefix_for_output_files, main_file_name, output_dir);
+    GetDestinationPaths(prefix_for_output_files, main_file_name, output_dir,
+                        save_page_type);
     DownloadPersistedObserver persisted(
         browser()->profile(),
         base::Bind(&DownloadStoredProperly, url, *main_file_name,
@@ -784,12 +791,13 @@
 
 // Test for crbug.com/526786.
 IN_PROC_BROWSER_TEST_F(SavePageSitePerProcessBrowserTest, SaveAsCompleteHtml) {
-  GURL url(embedded_test_server()->GetURL("a.com", "/save_page/iframes.htm"));
+  GURL url(
+      embedded_test_server()->GetURL("a.com", "/save_page/frames-xsite.htm"));
   ui_test_utils::NavigateToURL(browser(), url);
 
   base::FilePath full_file_name, dir;
-  SaveCurrentTab(url, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML, "iframes", 5,
-                 &dir, &full_file_name);
+  SaveCurrentTab(url, content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML,
+                 "frames-xsite-complete-html", 5, &dir, &full_file_name);
   ASSERT_FALSE(HasFailure());
 
   EXPECT_TRUE(base::DirectoryExists(dir));
@@ -814,24 +822,30 @@
   // by this particular test).
   std::string main_contents;
   ASSERT_TRUE(base::ReadFileToString(full_file_name, &main_contents));
-  EXPECT_THAT(main_contents,
-              HasSubstr("<iframe src=\"./iframes_files/a.html\"></iframe>"));
-  EXPECT_THAT(main_contents,
-              HasSubstr("<iframe src=\"./iframes_files/b.html\"></iframe>"));
-  EXPECT_THAT(main_contents,
-              HasSubstr("<img src=\"./iframes_files/1.png\">"));
+  EXPECT_THAT(
+      main_contents,
+      HasSubstr("<iframe "
+                "src=\"./frames-xsite-complete-html_files/a.html\"></iframe>"));
+  EXPECT_THAT(
+      main_contents,
+      HasSubstr("<iframe "
+                "src=\"./frames-xsite-complete-html_files/b.html\"></iframe>"));
+  EXPECT_THAT(
+      main_contents,
+      HasSubstr("<img src=\"./frames-xsite-complete-html_files/1.png\">"));
 
   // Verification of html contents.
-  EXPECT_THAT(main_contents, HasSubstr("896fd88d-a77a-4f46-afd8-24db7d5af9c2"))
-      << "Verifing if content from iframes.htm is present";
+  EXPECT_THAT(
+      main_contents,
+      HasSubstr("frames-xsite.htm: 896fd88d-a77a-4f46-afd8-24db7d5af9c2"));
   std::string a_contents;
   ASSERT_TRUE(base::ReadFileToString(dir.AppendASCII("a.html"), &a_contents));
-  EXPECT_THAT(a_contents, HasSubstr("1b8aae2b-e164-462f-bd5b-98aa366205f2"))
-      << "Verifing if content from a.htm is present";
+  EXPECT_THAT(a_contents,
+              HasSubstr("a.htm: 1b8aae2b-e164-462f-bd5b-98aa366205f2"));
   std::string b_contents;
   ASSERT_TRUE(base::ReadFileToString(dir.AppendASCII("b.html"), &b_contents));
-  EXPECT_THAT(b_contents, HasSubstr("3a35f7fa-96a9-4487-9f18-4470263907fa"))
-      << "Verifing if content from b.htm is present";
+  EXPECT_THAT(b_contents,
+              HasSubstr("b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa"));
 }
 
 // Test for crbug.com/538766.
@@ -839,38 +853,39 @@
 // (but note that the test only fails with --site-per-process flag).
 IN_PROC_BROWSER_TEST_F(SavePageSitePerProcessBrowserTest,
                        DISABLED_SaveAsMHTML) {
-  GURL url(embedded_test_server()->GetURL("a.com", "/save_page/iframes.htm"));
+  GURL url(
+      embedded_test_server()->GetURL("a.com", "/save_page/frames-xsite.htm"));
   ui_test_utils::NavigateToURL(browser(), url);
 
   base::FilePath full_file_name, dir;
-  SaveCurrentTab(url, content::SAVE_PAGE_TYPE_AS_MHTML, "iframes", -1, &dir,
-                 &full_file_name);
+  SaveCurrentTab(url, content::SAVE_PAGE_TYPE_AS_MHTML, "frames-xsite-mhtml",
+                 -1, &dir, &full_file_name);
   ASSERT_FALSE(HasFailure());
 
   std::string mhtml;
   ASSERT_TRUE(base::ReadFileToString(full_file_name, &mhtml));
 
   // Verify content of main frame, subframes and some savable resources.
-  EXPECT_THAT(mhtml, HasSubstr("896fd88d-a77a-4f46-afd8-24db7d5af9c2"))
-      << "Verifing if content from iframes.htm is present";
-  EXPECT_THAT(mhtml, HasSubstr("1b8aae2b-e164-462f-bd5b-98aa366205f2"))
-      << "Verifing if content from a.htm is present";
-  EXPECT_THAT(mhtml, HasSubstr("3a35f7fa-96a9-4487-9f18-4470263907fa"))
-      << "Verifing if content from b.htm is present";
+  EXPECT_THAT(
+      mhtml,
+      HasSubstr("frames-xsite.htm: 896fd88d-a77a-4f46-afd8-24db7d5af9c2"));
+  EXPECT_THAT(mhtml, HasSubstr("a.htm: 1b8aae2b-e164-462f-bd5b-98aa366205f2"));
+  EXPECT_THAT(mhtml, HasSubstr("b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa"));
   EXPECT_THAT(mhtml, HasSubstr("font-size: 20px;"))
-      << "Verifing if content from 1.css is present";
+      << "Verifying if content from 1.css is present";
 
   // Verify presence of URLs associated with main frame, subframes and some
   // savable resources.
   // (note that these are single-line regexes).
-  EXPECT_THAT(mhtml, ContainsRegex("Content-Location.*/save_page/iframes.htm"));
+  EXPECT_THAT(mhtml,
+              ContainsRegex("Content-Location.*/save_page/frames-xsite.htm"));
   EXPECT_THAT(mhtml, ContainsRegex("Content-Location.*/save_page/a.htm"));
   EXPECT_THAT(mhtml, ContainsRegex("Content-Location.*/save_page/b.htm"));
   EXPECT_THAT(mhtml, ContainsRegex("Content-Location.*/save_page/1.css"));
   EXPECT_THAT(mhtml, ContainsRegex("Content-Location.*/save_page/1.png"));
 
-  // Verify that 1.png appear in the output only once (despite being referred to
-  // twice - from iframes.htm and from b.htm).
+  // Verify that 1.png appears in the output only once (despite being referred
+  // to twice - from iframes.htm and from b.htm).
   int count = 0;
   size_t pos = 0;
   for (;;) {
@@ -883,4 +898,174 @@
   EXPECT_EQ(1, count) << "Verify number of image/png parts in the mhtml output";
 }
 
+// Test suite that verifies that the frame tree "looks" the same before
+// and after a save-page-as.
+class SavePageMultiFrameBrowserTest : public SavePageSitePerProcessBrowserTest {
+ protected:
+  void TestMultiFramePage(content::SavePageType save_page_type,
+                          const GURL& url,
+                          int expected_number_of_frames,
+                          const std::vector<std::string>& expected_substrings) {
+    // Navigate to the test page and verify if test expectations
+    // are met (this is mostly a sanity check - a failure to meet
+    // expectations would probably mean that there is a test bug
+    // (i.e. that we got called with wrong expected_foo argument).
+    ui_test_utils::NavigateToURL(browser(), url);
+    DLOG(INFO) << "Verifying test expectations for original page... : "
+               << GetCurrentTab(browser())->GetLastCommittedURL();
+    // TODO(lukasza/paulmeyer): crbug.com/457440: Can uncomment
+    // the assertion below once find-in-page works for oop frames.
+    // AssertExpectationsAboutCurrentTab(expected_number_of_frames,
+    //                                   expected_substrings);
+
+    // Save the page.
+    base::FilePath full_file_name, dir;
+    SaveCurrentTab(url, save_page_type, "save_result", -1, &dir,
+                   &full_file_name);
+    ASSERT_FALSE(HasFailure());
+
+    // Stop the test server (to make sure the locally saved page
+    // is self-contained / won't try to open original resources).
+    ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
+
+    // Open the saved page and verify if test expectations are
+    // met (i.e. if the same expectations are met for "after"
+    // [saved version of the page] as for the "before"
+    // [the original version of the page].
+    ui_test_utils::NavigateToURL(browser(),
+                                 GURL(net::FilePathToFileURL(full_file_name)));
+    DLOG(INFO) << "Verifying test expectations for saved page... : "
+               << GetCurrentTab(browser())->GetLastCommittedURL();
+    AssertExpectationsAboutCurrentTab(expected_number_of_frames,
+                                      expected_substrings);
+  }
+
+ private:
+  void AssertExpectationsAboutCurrentTab(
+      int expected_number_of_frames,
+      const std::vector<std::string>& expected_substrings) {
+    int actual_number_of_frames = 0;
+    GetCurrentTab(browser())->ForEachFrame(base::Bind(
+        &IncrementInteger, base::Unretained(&actual_number_of_frames)));
+    EXPECT_EQ(expected_number_of_frames, actual_number_of_frames);
+
+    for (const auto& expected_substring : expected_substrings) {
+      int actual_number_of_matches = ui_test_utils::FindInPage(
+          GetCurrentTab(browser()), base::UTF8ToUTF16(expected_substring),
+          true,  // |forward|
+          true,  // |case_sensitive|
+          nullptr, nullptr);
+
+      EXPECT_EQ(1, actual_number_of_matches)
+          << "Verifying if \"" << expected_substring << "\" appears "
+          << "exactly once in the web-contents text";
+    }
+
+    int actual_number_of_errors = ui_test_utils::FindInPage(
+        GetCurrentTab(browser()), base::UTF8ToUTF16("err"),
+        true,   // |forward|
+        false,  // |case_sensitive|
+        nullptr, nullptr);
+    EXPECT_EQ(0, actual_number_of_errors);
+  }
+
+  static void IncrementInteger(int* i, content::RenderFrameHost* /* unused */) {
+    (*i)++;
+  }
+};
+
+// TODO(lukasza): Pivot on mhtml-vs-complete-html using test params
+// (once all SavePageMultiFrameBrowserTest are enabled).
+
+IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest,
+                       CrossSiteFrames_CompleteHtml) {
+  std::vector<std::string> expected_substrings{
+      "frames-xsite.htm: 896fd88d-a77a-4f46-afd8-24db7d5af9c2",
+      "a.htm: 1b8aae2b-e164-462f-bd5b-98aa366205f2",
+      "b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa",
+  };
+  GURL url(
+      embedded_test_server()->GetURL("a.com", "/save_page/frames-xsite.htm"));
+  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML, url, 3,
+                     expected_substrings);
+}
+
+// Test for crbug.com/538766 and crbug.com/539936.
+// Disabled because both bugs are not yet fixed.
+IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest,
+                       DISABLED_CrossSiteFrames_MHTML) {
+  std::vector<std::string> expected_substrings{
+      "frames-xsite.htm: 896fd88d-a77a-4f46-afd8-24db7d5af9c2",
+      "a.htm: 1b8aae2b-e164-462f-bd5b-98aa366205f2",
+      "b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa",
+  };
+  GURL url(
+      embedded_test_server()->GetURL("a.com", "/save_page/frames-xsite.htm"));
+  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_MHTML, url, 3,
+                     expected_substrings);
+}
+
+// Test for crbug.com/553478 (complete html part).
+IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest,
+                       DISABLED_ObjectElements_CompleteHtml) {
+  // 4 = main frame + iframe + object w/ html doc + object w/ pdf doc
+  // (svg and png objects do not get a separate frame)
+  int expected_number_of_frames = 4;
+
+  std::vector<std::string> expected_substrings{
+      "frames-objects.htm: 8da13db4-a512-4d9b-b1c5-dc1c134234b9",
+      "a.htm: 1b8aae2b-e164-462f-bd5b-98aa366205f2",
+      "b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa",
+  };
+  GURL url(
+      embedded_test_server()->GetURL("a.com", "/save_page/frames-objects.htm"));
+  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML, url,
+                     expected_number_of_frames, expected_substrings);
+}
+
+// Test for crbug.com/553478 (mhtml part).
+// See crbug.com/553478#c3 for some MHTML-specific notes.
+IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest,
+                       DISABLED_ObjectElements_MHTML) {
+  // 4 = main frame + iframe + object w/ html doc + object w/ pdf doc
+  // (svg and png objects do not get a separate frame)
+  int expected_number_of_frames = 4;
+
+  std::vector<std::string> expected_substrings{
+      "frames-objects.htm: 8da13db4-a512-4d9b-b1c5-dc1c134234b9",
+      "a.htm: 1b8aae2b-e164-462f-bd5b-98aa366205f2",
+      "b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa",
+  };
+  GURL url(
+      embedded_test_server()->GetURL("a.com", "/save_page/frames-objects.htm"));
+  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_MHTML, url,
+                     expected_number_of_frames, expected_substrings);
+}
+
+IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest, AboutBlank_CompleteHtml) {
+  std::vector<std::string> expected_substrings{
+      "main: acb0609d-eb10-4c26-83e2-ad8afb7b0ff3",
+      "sub1: b124df3a-d39f-47a1-ae04-5bb5d0bf549e",
+      "sub2: 07014068-604d-45ae-884f-a068cfe7bc0a",
+      "sub3: 06cc8fcc-c692-4a1a-a10f-1645b746e8f4",
+  };
+  GURL url(embedded_test_server()->GetURL("a.com",
+                                          "/save_page/frames-about-blank.htm"));
+  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML, url, 4,
+                     expected_substrings);
+}
+
+IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest, AboutBlank_MHTML) {
+  std::vector<std::string> expected_substrings{
+      "main: acb0609d-eb10-4c26-83e2-ad8afb7b0ff3",
+      "sub1: b124df3a-d39f-47a1-ae04-5bb5d0bf549e",
+      "sub2: 07014068-604d-45ae-884f-a068cfe7bc0a",
+      "sub3: 06cc8fcc-c692-4a1a-a10f-1645b746e8f4",
+  };
+  GURL url(embedded_test_server()->GetURL("a.com",
+                                          "/save_page/frames-about-blank.htm"));
+  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_MHTML, url, 4,
+                     expected_substrings);
+}
+
 }  // namespace
diff --git a/chrome/browser/memory/tab_manager_browsertest.cc b/chrome/browser/memory/tab_manager_browsertest.cc
index 71e5938..9436da2 100644
--- a/chrome/browser/memory/tab_manager_browsertest.cc
+++ b/chrome/browser/memory/tab_manager_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/base_switches.h"
 #include "base/command_line.h"
 #include "base/memory/memory_pressure_listener.h"
 #include "chrome/browser/browser_process.h"
@@ -25,7 +26,18 @@
 
 namespace memory {
 
-using TabManagerTest = InProcessBrowserTest;
+class TabManagerTest : public InProcessBrowserTest {
+ public:
+  // Tab discarding is enabled by default on CrOS. On other platforms, force it
+  // by turning on the corresponding experiment as some tests assume this
+  // behavior it turned on.
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+#if !defined(OS_CHROMEOS)
+    command_line->AppendSwitchASCII(switches::kForceFieldTrials,
+                                    "AutomaticTabDiscarding/Enabled/");
+#endif
+  }
+};
 
 IN_PROC_BROWSER_TEST_F(TabManagerTest, TabManagerBasics) {
   using content::WindowedNotificationObserver;
diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js
index 6df0cff..36a1a66 100644
--- a/chrome/browser/resources/options/browser_options.js
+++ b/chrome/browser/resources/options/browser_options.js
@@ -2197,7 +2197,6 @@
     'showTouchpadControls',
     'toggleExtensionIndicators',
     'updateAccountPicture',
-    'updateAutoLaunchState',
     'updateDefaultBrowserState',
     'updateEasyUnlock',
     'updateManagesSupervisedUsers',
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html
index 0775dc56..ca8e3d9 100644
--- a/chrome/browser/resources/settings/basic_page/basic_page.html
+++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -18,8 +18,8 @@
   <link rel="import" type="css" href="basic_page.css">
   <template>
 <if expr="not chromeos">
-    <settings-section i18n-values="page-title:signinPageTitle"
-        current-route="[[currentRoute]]" section="signin">
+    <settings-section i18n-values="page-title:peoplePageTitle"
+        current-route="[[currentRoute]]" section="people">
       <settings-signin-page current-route="{{currentRoute}}">
       </settings-signin-page>
     </settings-section>
diff --git a/chrome/browser/resources/settings/compiled_resources.gyp b/chrome/browser/resources/settings/compiled_resources.gyp
index 4ec217f..252f283 100644
--- a/chrome/browser/resources/settings/compiled_resources.gyp
+++ b/chrome/browser/resources/settings/compiled_resources.gyp
@@ -14,6 +14,7 @@
         'on_startup_page/compiled_resources.gyp:*',
         'prefs/compiled_resources.gyp:*',
         'site_settings/compiled_resources.gyp:*',
+        'sync_page/compiled_resources.gyp:*',
         'controls/compiled_resources.gyp:*',
       ],
     },
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index 7becb81..26ab4a6c 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -29,7 +29,7 @@
 <if expr="not chromeos">
           <paper-icon-item>
             <iron-icon icon="social:person" item-icon></iron-icon>
-            <span i18n-content="signinPageTitle"></span>
+            <span i18n-content="peoplePageTitle"></span>
           </paper-icon-item>
 </if>
           <paper-icon-item>
diff --git a/chrome/browser/resources/settings/settings_page/settings_router.js b/chrome/browser/resources/settings/settings_page/settings_router.js
index 3a78d36..6caa660d 100644
--- a/chrome/browser/resources/settings/settings_page/settings_router.js
+++ b/chrome/browser/resources/settings/settings_page/settings_router.js
@@ -121,7 +121,7 @@
     {
       url: '/syncSetup',
       page: 'basic',
-      section: 'signin',
+      section: 'people',
       subpage: ['sync'],
       subpageTitles: ['syncPageTitle'],
     },
diff --git a/chrome/browser/resources/settings/signin_page/signin_page.html b/chrome/browser/resources/settings/signin_page/signin_page.html
index c9ca9d1..06be1b7 100644
--- a/chrome/browser/resources/settings/signin_page/signin_page.html
+++ b/chrome/browser/resources/settings/signin_page/signin_page.html
@@ -14,21 +14,36 @@
       href="chrome://md-settings/settings_page/settings_page.css">
   <template>
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
-        section="signin">
+        section="people">
       <neon-animatable id="main">
-        <div id="syncStatusText"></div>
-
-        <paper-button on-tap="onDisconnectTap_" raised
-            hidden="[[!syncStatus.signedIn]]"
-            disabled="[[syncStatus.setupInProgress]]"
-            i18n-content="syncDisconnect">
-        </paper-button>
-
-        <template is="dom-if"
-            if="[[isAdvancedSyncSettingsVisible_(syncStatus)]]">
-          <paper-button on-tap="onSyncTap_" raised>
-            [[i18n('syncPageTitle')]]
+        <div class="settings-row" hidden="[[!isStatusTextSet_(syncStatus)]]">
+          <span id="syncStatusText"></span>
+          <paper-button on-tap="onActionLinkTap_">
+            [[syncStatus.actionLinkText]]
           </paper-button>
+        </div>
+
+        <template is="dom-if" if="[[!syncStatus.signedIn]]">
+          <div class="settings-row">[[i18n('syncOverview')]]</div>
+          <div class="settings-row button-strip">
+            <paper-button on-tap="onSigninTap_" raised
+                disabled="[[syncStatus.setupInProgress]]">
+                [[i18n('syncSignin')]]
+            </paper-button>
+          </div>
+        </template>
+        <template is="dom-if" if="[[syncStatus.signedIn]]">
+          <paper-button on-tap="onDisconnectTap_" raised
+              disabled="[[syncStatus.setupInProgress]]">
+              [[i18n('syncDisconnect')]]
+          </paper-button>
+
+          <template is="dom-if"
+              if="[[isAdvancedSyncSettingsVisible_(syncStatus)]]">
+            <paper-button on-tap="onSyncTap_" raised>
+              [[i18n('syncPageTitle')]]
+            </paper-button>
+          </template>
         </template>
       </neon-animatable>
       <neon-animatable id="sync">
@@ -43,14 +58,14 @@
       <h2 i18n-content="syncDisconnectTitle"></h2>
       <div i18n-values=".innerHTML:syncDisconnectExplanation"></div>
 <if expr="(not chromeos and is_posix) or is_win or is_macosx">
-      <paper-checkbox id="syncSetupDeleteProfile"
+      <paper-checkbox id="deleteProfile"
           i18n-content="syncDisconnectDeleteProfile">
       </paper-checkbox>
 </if>
       <div class="button-strip">
         <paper-button dialog-dismiss i18n-content="cancel">
         </paper-button>
-        <paper-button dialog-confirm raised
+        <paper-button dialog-confirm raised on-tap="onDisconnectConfirm_"
             i18n-content="syncDisconnectConfirm">
         </paper-button>
       </div>
diff --git a/chrome/browser/resources/settings/signin_page/signin_page.js b/chrome/browser/resources/settings/signin_page/signin_page.js
index ea86ede3..c4ea9f7 100644
--- a/chrome/browser/resources/settings/signin_page/signin_page.js
+++ b/chrome/browser/resources/settings/signin_page/signin_page.js
@@ -40,7 +40,7 @@
   },
 
   created: function() {
-    settings.SyncPrivateApi.setSyncStatusCallback(
+    settings.SyncPrivateApi.getSyncStatus(
         this.handleSyncStatusFetched_.bind(this));
   },
 
@@ -57,11 +57,29 @@
   },
 
   /** @private */
+  onActionLinkTap_: function() {
+    settings.SyncPrivateApi.showSetupUI();
+  },
+
+  /** @private */
+  onSigninTap_: function() {
+    settings.SyncPrivateApi.startSignIn();
+  },
+
+  /** @private */
   onDisconnectTap_: function() {
     this.$.disconnectDialog.open();
   },
 
   /** @private */
+  onDisconnectConfirm_: function() {
+    var deleteProfile = this.$.deleteProfile && this.$.deleteProfile.checked;
+    settings.SyncPrivateApi.disconnect(deleteProfile);
+
+    // Dialog automatically closed because button has dialog-confirm attribute.
+  },
+
+  /** @private */
   onSyncTap_: function() {
     this.$.pages.setSubpageChain(['sync']);
   },
@@ -70,6 +88,14 @@
    * @private
    * @return {boolean}
    */
+  isStatusTextSet_: function() {
+    return this.syncStatus && this.syncStatus.statusText.length > 0;
+  },
+
+  /**
+   * @private
+   * @return {boolean}
+   */
   isAdvancedSyncSettingsVisible_: function() {
     var status = this.syncStatus;
     return status && status.signedIn && !status.managed &&
diff --git a/chrome/browser/resources/settings/sync_page/compiled_resources.gyp b/chrome/browser/resources/settings/sync_page/compiled_resources.gyp
new file mode 100644
index 0000000..6167188
--- /dev/null
+++ b/chrome/browser/resources/settings/sync_page/compiled_resources.gyp
@@ -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.
+{
+  'targets': [
+    {
+      'target_name': 'sync_page',
+      'variables': {
+        'depends': [
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
+          '../../../../../ui/webui/resources/js/i18n_behavior.js',
+          '../settings_page/settings_animated_pages.js',
+          'sync_private_api.js',
+        ],
+      },
+      'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
+    },
+    {
+      'target_name': 'sync_private_api',
+      'variables': {
+        'depends': [
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
+          '../../../../../ui/webui/resources/js/compiled_resources.gyp:cr',
+          '../../../../../ui/webui/resources/js/cr.js',
+        ],
+      },
+      'includes': ['../../../../../third_party/closure_compiler/compile_js.gypi'],
+    },
+  ],
+}
diff --git a/chrome/browser/resources/settings/sync_page/sync_page.html b/chrome/browser/resources/settings/sync_page/sync_page.html
index 679c259..e01921a 100644
--- a/chrome/browser/resources/settings/sync_page/sync_page.html
+++ b/chrome/browser/resources/settings/sync_page/sync_page.html
@@ -15,7 +15,7 @@
       href="chrome://md-settings/settings_page/settings_page.css">
   <link rel="import" type="css" href="sync_page.css">
   <template>
-    <iron-pages id="pages" selected="spinner" attr-for-selected="id">
+    <iron-pages id="pages" selected="loading" attr-for-selected="id">
       <div id="loading" i18n-content="syncLoading"></div>
       <div id="timeout" i18n-content="syncTimeout"></div>
       <div id="main">
diff --git a/chrome/browser/resources/settings/sync_page/sync_page.js b/chrome/browser/resources/settings/sync_page/sync_page.js
index bd22258..c50064e 100644
--- a/chrome/browser/resources/settings/sync_page/sync_page.js
+++ b/chrome/browser/resources/settings/sync_page/sync_page.js
@@ -55,7 +55,7 @@
 
     /**
      * The current sync preferences, supplied by settings.SyncPrivateApi.
-     * @type {?settings.SyncPrivateApi.SyncPrefs}
+     * @type {?settings.SyncPrefs}
      */
     syncPrefs: {
       type: Object,
@@ -99,7 +99,7 @@
 
   /** @private */
   currentRouteChanged_: function() {
-    if (this.currentRoute.section == 'signin' &&
+    if (this.currentRoute.section == 'people' &&
         this.currentRoute.subpage.length == 1 &&
         this.currentRoute.subpage[0] == 'sync') {
       // Display loading page until the settings have been retrieved.
@@ -179,16 +179,16 @@
 
   /**
    * Callback invoked from calling settings.SyncPrivateApi.setSyncPrefs().
-   * @param {!SyncPrivatApi.SetSyncCallbackState} callbackState
+   * @param {!settings.PageStatus} callbackState
    * @private
    */
   setPageStatusCallback_: function(callbackState) {
-    if (callbackState == settings.SyncPrivateApi.PageStatus.DONE) {
+    if (callbackState == settings.PageStatus.DONE) {
       this.onCancelTap_();
-    } else if (callbackState == settings.SyncPrivateApi.PageStatus.TIMEOUT) {
+    } else if (callbackState == settings.PageStatus.TIMEOUT) {
       this.$.pages.selected = 'timeout';
     } else if (callbackState ==
-               settings.SyncPrivateApi.PageStatus.PASSPHRASE_ERROR) {
+               settings.PageStatus.PASSPHRASE_ERROR) {
       this.$$('#incorrectPassphraseError').hidden = false;
     }
   },
diff --git a/chrome/browser/resources/settings/sync_page/sync_private_api.js b/chrome/browser/resources/settings/sync_page/sync_private_api.js
index 2324de0..e9e9433 100644
--- a/chrome/browser/resources/settings/sync_page/sync_private_api.js
+++ b/chrome/browser/resources/settings/sync_page/sync_private_api.js
@@ -2,6 +2,87 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+cr.exportPath('settings');
+
+/**
+ * The state of sync. This is the data structure sent back and forth between
+ * C++ and JS. Its naming and structure is not optimal, but changing it would
+ * require changes to the C++ handler, which is already functional.
+ * @typedef {{
+ *   appsEnforced: boolean,
+ *   appsRegistered: boolean,
+ *   appsSynced: boolean,
+ *   autofillEnforced: boolean,
+ *   autofillRegistered: boolean,
+ *   autofillSynced: boolean,
+ *   bookmarksEnforced: boolean,
+ *   bookmarksRegistered: boolean,
+ *   bookmarksSynced: boolean,
+ *   encryptAllData: boolean,
+ *   encryptAllDataAllowed: boolean,
+ *   enterGooglePassphraseBody: (string|undefined),
+ *   enterPassphraseBody: (string|undefined),
+ *   extensionsEnforced: boolean,
+ *   extensionsRegistered: boolean,
+ *   extensionsSynced: boolean,
+ *   fullEncryptionBody: string,
+ *   isGooglePassphrase: (boolean|undefined),
+ *   passphrase: (string|undefined),
+ *   passphraseFailed: boolean,
+ *   passwordsEnforced: boolean,
+ *   passwordsRegistered: boolean,
+ *   passwordsSynced: boolean,
+ *   preferencesEnforced: boolean,
+ *   preferencesRegistered: boolean,
+ *   preferencesSynced: boolean,
+ *   showPassphrase: boolean,
+ *   syncAllDataTypes: boolean,
+ *   syncNothing: boolean,
+ *   tabsEnforced: boolean,
+ *   tabsRegistered: boolean,
+ *   tabsSynced: boolean,
+ *   themesEnforced: boolean,
+ *   themesRegistered: boolean,
+ *   themesSynced: boolean,
+ *   typedUrlsEnforced: boolean,
+ *   typedUrlsRegistered: boolean,
+ *   typedUrlsSynced: boolean,
+ *   usePassphrase: boolean,
+ *   wifiCredentialsEnforced: (boolean|undefined),
+ *   wifiCredentialsSynced: (boolean|undefined)
+ * }}
+ */
+settings.SyncPrefs;
+
+/**
+ * @typedef {{actionLinkText: (string|undefined),
+ *            childUser: (boolean|undefined),
+ *            hasError: (boolean|undefined),
+ *            hasUnrecoverableError: (boolean|undefined),
+ *            managed: (boolean|undefined),
+ *            setupCompleted: (boolean|undefined),
+ *            setupInProgress: (boolean|undefined),
+ *            signedIn: (boolean|undefined),
+ *            signinAllowed: (boolean|undefined),
+ *            signoutAllowed: (boolean|undefined),
+ *            statusText: (string|undefined),
+ *            supervisedUser: (boolean|undefined),
+ *            syncSystemEnabled: (boolean|undefined)}}
+ * @see chrome/browser/ui/webui/settings/sync_handler.cc
+ */
+settings.SyncStatus;
+
+/**
+ * @enum {string}
+ */
+settings.PageStatus = {
+  SPINNER: 'spinner',                   // Before the page has loaded.
+  CONFIGURE: 'configure',               // Preferences ready to be configured.
+  TIMEOUT: 'timeout',                   // Preferences loading has timed out.
+  DONE: 'done',                         // Sync subpage can be closed now.
+  PASSPHRASE_ERROR: 'passphraseError',  // Error in the passphrase.
+};
+
 cr.define('settings', function() {
   /**
    * API which encapsulates messaging between JS and C++ for the sync page.
@@ -9,92 +90,41 @@
    */
   function SyncPrivateApi() {}
 
-  /**
-   * The state of sync. This is the data structure sent back and forth between
-   * C++ and JS. Its naming and structure is not optimal, but changing it would
-   * require changes to the C++ handler, which is already functional.
-   * @typedef {{
-   *   appsEnforced: boolean,
-   *   appsRegistered: boolean,
-   *   appsSynced: boolean,
-   *   autofillEnforced: boolean,
-   *   autofillRegistered: boolean,
-   *   autofillSynced: boolean,
-   *   bookmarksEnforced: boolean,
-   *   bookmarksRegistered: boolean,
-   *   bookmarksSynced: boolean,
-   *   encryptAllData: boolean,
-   *   encryptAllDataAllowed: boolean,
-   *   enterGooglePassphraseBody: (string|undefined),
-   *   enterPassphraseBody: (string|undefined),
-   *   extensionsEnforced: boolean,
-   *   extensionsRegistered: boolean,
-   *   extensionsSynced: boolean,
-   *   fullEncryptionBody: string,
-   *   isGooglePassphrase: (boolean|undefined),
-   *   passphrase: (string|undefined),
-   *   passphraseFailed: boolean,
-   *   passwordsEnforced: boolean,
-   *   passwordsRegistered: boolean,
-   *   passwordsSynced: boolean,
-   *   preferencesEnforced: boolean,
-   *   preferencesRegistered: boolean,
-   *   preferencesSynced: boolean,
-   *   showPassphrase: boolean,
-   *   syncAllDataTypes: boolean,
-   *   syncNothing: boolean,
-   *   tabsEnforced: boolean,
-   *   tabsRegistered: boolean,
-   *   tabsSynced: boolean,
-   *   themesEnforced: boolean,
-   *   themesRegistered: boolean,
-   *   themesSynced: boolean,
-   *   typedUrlsEnforced: boolean,
-   *   typedUrlsRegistered: boolean,
-   *   typedUrlsSynced: boolean,
-   *   usePassphrase: boolean,
-   *   wifiCredentialsEnforced: (boolean|undefined),
-   *   wifiCredentialsSynced: (boolean|undefined)
-   * }}
-   */
-  SyncPrivateApi.SyncPrefs;
-
-  /**
-   * @typedef {{actionLinkText: (string|undefined),
-   *            childUser: (boolean|undefined),
-   *            hasError: (boolean|undefined),
-   *            hasUnrecoverableError: (boolean|undefined),
-   *            managed: (boolean|undefined),
-   *            setupCompleted: (boolean|undefined),
-   *            setupInProgress: (boolean|undefined),
-   *            signedIn: (boolean|undefined),
-   *            signinAllowed: (boolean|undefined),
-   *            signoutAllowed: (boolean|undefined),
-   *            statusText: (string|undefined),
-   *            supervisedUser: (boolean|undefined),
-   *            syncSystemEnabled: (boolean|undefined)}}
-   * @see chrome/browser/ui/webui/settings/sync_handler.cc
-   */
-  SyncPrivateApi.SyncStatus;
-
-  /**
-   * @enum {string}
-   */
-  SyncPrivateApi.PageStatus = {
-    SPINNER: 'spinner',                   // Before the page has loaded.
-    CONFIGURE: 'configure',               // Preferences ready to be configured.
-    TIMEOUT: 'timeout',                   // Preferences loading has timed out.
-    DONE: 'done',                         // Sync subpage can be closed now.
-    PASSPHRASE_ERROR: 'passphraseError',  // Error in the passphrase.
-  };
-
-  /** @private {?function(SyncPrivateApi.SyncPrefs)} */
+  /** @private {?function(settings.SyncPrefs)} */
   SyncPrivateApi.syncPrefsCallback_ = null;
 
-  /** @private {?function(SyncPrivateApi.PageStatus)} */
+  /** @private {?function(settings.PageStatus)} */
   SyncPrivateApi.setPageStatusCallback_ = null;
 
   /**
+   * Starts the signin process for the user. Does nothing if the user is
+   * already signed in.
+   * @private
+   */
+  SyncPrivateApi.startSignIn = function() {
+    chrome.send('SyncSetupStartSignIn');
+  };
+
+  /**
+   * Disconnects the signed in user.
+   * @param {!boolean} deleteProfile
+   * @private
+   */
+  SyncPrivateApi.disconnect = function(deleteProfile) {
+    chrome.send('SyncSetupStopSyncing', [deleteProfile]);
+  };
+
+  /**
+   * Determines the appropriate page to show in the Sync Setup UI based on
+   * the state of the Sync backend. Does nothing if the user is not signed in.
+   * @private
+   */
+  SyncPrivateApi.showSetupUI = function() {
+    chrome.send('SyncSetupShowSetupUI');
+    chrome.send('coreOptionsUserMetricsAction', ['Options_ShowSyncAdvanced']);
+  };
+
+  /**
    * Function to invoke when the sync page has been navigated to. This registers
    * the UI as the "active" sync UI so that if the user tries to open another
    * sync UI, this one will be shown instead.
@@ -114,7 +144,7 @@
 
   /**
    * Sets the callback to be invoked when sync data has been fetched.
-   * @param {!function(SyncPrivateApi.SyncPrefs)} callback
+   * @param {!function(settings.SyncPrefs)} callback
    */
   SyncPrivateApi.setSyncPrefsCallback = function(callback) {
     SyncPrivateApi.syncPrefsCallback_ = callback;
@@ -122,7 +152,7 @@
 
   /**
    * Handler for when state has been fetched from C++.
-   * @param {!SyncPrivateApi.SyncPrefs} syncPrefsFromCpp
+   * @param {!settings.SyncPrefs} syncPrefsFromCpp
    * @private
    */
   SyncPrivateApi.sendSyncPrefs_ = function(syncPrefsFromCpp) {
@@ -132,8 +162,8 @@
 
   /**
    * Sets the sync state by sending it to the C++ layer.
-   * @param {!SyncPrivateApi.SyncPrefs} syncPrefs
-   * @param {!function(SyncPrivateApi.PageStatus)} callback
+   * @param {!settings.SyncPrefs} syncPrefs
+   * @param {!function(settings.PageStatus)} callback
    */
   SyncPrivateApi.setSyncPrefs = function(syncPrefs, callback) {
     SyncPrivateApi.setPageStatusCallback_ = callback;
@@ -142,29 +172,28 @@
 
   /**
    * Handler for when setSyncPrefs() has either succeeded or failed.
-   * @param {!SyncPrivateApi.SyncPrefs} state
+   * @param {!settings.PageStatus} status
    * @private
    */
-  SyncPrivateApi.setPageStatus_ = function(state) {
+  SyncPrivateApi.setPageStatus_ = function(status) {
     if (SyncPrivateApi.setPageStatusCallback_)
-      SyncPrivateApi.setPageStatusCallback_(state);
+      SyncPrivateApi.setPageStatusCallback_(status);
 
     SyncPrivateApi.setPageStatusCallback_ = null;
   };
 
   /**
-   * Sets the callback to be invoked when sync status has been fetched.
-   * Also requests an initial sync status update.
-   * @param {!function(SyncPrivateApi.SyncStatus)} callback
+   * Sends a request from JS to C++ for the current sync status.
+   * @param {!function(settings.SyncStatus)} callback
    */
-  SyncPrivateApi.setSyncStatusCallback = function(callback) {
+  SyncPrivateApi.getSyncStatus = function(callback) {
     SyncPrivateApi.syncStatusCallback_ = callback;
     chrome.send('SyncSetupGetSyncStatus');
   };
 
   /**
    * Handler for when sync status has been fetched from C++.
-   * @param {!SyncPrivateApi.SyncStatus} syncStatusFromCpp
+   * @param {!settings.SyncStatus} syncStatusFromCpp
    * @private
    */
   SyncPrivateApi.sendSyncStatus = function(syncStatusFromCpp) {
@@ -175,19 +204,19 @@
   /**
    * This function encapsulates the logic that maps from the legacy
    * SyncSettingsHandler to an API natural to the new Polymer implementation.
-   * @param {!SyncPrivateApi.PageStatus} status
-   * @param {!SyncPrivateApi.SyncPrefs} prefs
+   * @param {!settings.PageStatus} status
+   * @param {!settings.SyncPrefs} prefs
    */
   SyncPrivateApi.showSyncSetupPage = function(status, prefs) {
     switch (status) {
-      case SyncPrivateApi.PageStatus.TIMEOUT:
-      case SyncPrivateApi.PageStatus.DONE:
+      case settings.PageStatus.TIMEOUT:
+      case settings.PageStatus.DONE:
         SyncPrivateApi.setPageStatus_(status);
         break;
-      case SyncPrivateApi.PageStatus.CONFIGURE:
+      case settings.PageStatus.CONFIGURE:
         if (prefs.passphraseFailed) {
           SyncPrivateApi.setPageStatus_(
-              SyncPrivateApi.PageStatus.PASSPHRASE_ERROR);
+              settings.PageStatus.PASSPHRASE_ERROR);
           return;
         }
 
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index b26a1c2..b6e6eab 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -629,21 +629,35 @@
     base::DIR_START_MENU,
   };
   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-  base::string16 shortcut_name(
-      dist->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME));
+  const base::string16 shortcut_name(
+      dist->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME) +
+      installer::kLnkExt);
+  base::FilePath programs_folder;
   base::FilePath shortcut;
 
   // Check both the common and the per-user Start Menu folders for system-level
   // installs.
   size_t folder = InstallUtil::IsPerUserInstall(chrome_exe) ? 1 : 0;
   for (; folder < arraysize(kFolderIds); ++folder) {
-    if (!PathService::Get(kFolderIds[folder], &shortcut)) {
+    if (!PathService::Get(kFolderIds[folder], &programs_folder)) {
       NOTREACHED();
       continue;
     }
 
-    shortcut = shortcut.Append(shortcut_name).Append(shortcut_name +
-                                                     installer::kLnkExt);
+    shortcut = programs_folder.Append(shortcut_name);
+    if (base::PathExists(shortcut))
+      return shortcut;
+
+    // Check in "Start Menu\Programs\<BROWSER>" if the shortcut was not found in
+    // "Start Menu\Programs". This fallback check is here to handle running
+    // instances that are updated past the change that migrates Chrome's start
+    // menu shortcut from the "Google Chrome" folder up into the main "Programs"
+    // folder. This code will become obsolete when the migration change lands,
+    // and is to be removed in that change.
+    shortcut =
+        programs_folder.Append(dist->GetStartMenuShortcutSubfolder(
+                                   BrowserDistribution::SUBFOLDER_CHROME))
+            .Append(shortcut_name);
     if (base::PathExists(shortcut))
       return shortcut;
   }
diff --git a/chrome/browser/signin/account_reconcilor_unittest.cc b/chrome/browser/signin/account_reconcilor_unittest.cc
index 21e3c8e..8e600ab 100644
--- a/chrome/browser/signin/account_reconcilor_unittest.cc
+++ b/chrome/browser/signin/account_reconcilor_unittest.cc
@@ -564,8 +564,53 @@
       "Signin.Reconciler.AddedToCookieJar.FirstRun", 1, 1);
   histogram_tester()->ExpectUniqueSample(
       "Signin.Reconciler.RemovedFromCookieJar.FirstRun", 0, 1);
+
+  base::HistogramTester::CountsMap expected_counts;
+  expected_counts["Signin.Reconciler.Duration.Success"] = 1;
+  EXPECT_THAT(histogram_tester()->GetTotalCountsForPrefix(
+      "Signin.Reconciler.Duration.Success"),
+      testing::ContainerEq(expected_counts));
 }
 
+#if !defined(OS_CHROMEOS)
+// This test does not run on ChromeOS because it calls
+// FakeSigninManagerForTesting::SignOut() which doesn't exist for ChromeOS.
+
+TEST_F(AccountReconcilorTest, SignoutAfterErrorDoesNotRecordUma) {
+  const std::string account_id =
+      ConnectProfileToAccount("12345", "user@gmail.com");
+  token_service()->UpdateCredentials(account_id, "refresh_token");
+  cookie_manager_service()->SetListAccountsResponseOneAccount(
+      "user@gmail.com", "12345");
+
+  const std::string account_id2 =
+      PickAccountIdForAccount("67890", "other@gmail.com");
+  token_service()->UpdateCredentials(account_id2, "refresh_token");
+
+  EXPECT_CALL(*GetMockReconcilor(), PerformMergeAction(account_id2));
+
+  AccountReconcilor* reconcilor = GetMockReconcilor();
+  reconcilor->StartReconcile();
+
+  base::RunLoop().RunUntilIdle();
+  ASSERT_TRUE(reconcilor->is_reconcile_started_);
+  GoogleServiceAuthError
+    error(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
+  SimulateAddAccountToCookieCompleted(reconcilor, account_id2, error);
+  ASSERT_FALSE(reconcilor->is_reconcile_started_);
+
+  EXPECT_CALL(*GetMockReconcilor(), PerformLogoutAllAccountsAction());
+  signin_manager()->SignOut(signin_metrics::SIGNOUT_TEST);
+
+  base::HistogramTester::CountsMap expected_counts;
+  expected_counts["Signin.Reconciler.Duration.Failure"] = 1;
+  EXPECT_THAT(histogram_tester()->GetTotalCountsForPrefix(
+      "Signin.Reconciler.Duration.Failure"),
+      testing::ContainerEq(expected_counts));
+}
+
+#endif  // !defined(OS_CHROMEOS)
+
 TEST_P(AccountReconcilorTest, StartReconcileRemoveFromCookie) {
   const std::string account_id =
       ConnectProfileToAccount("12345", "user@gmail.com");
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 47b8387..1f5b503 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
@@ -496,12 +496,6 @@
                                   IDS_SETTINGS_SEARCH_ENGINES_ADD_BUTTON_LABEL);
 }
 
-#if !defined(OS_CHROMEOS)
-void AddSigninSettingsStrings(content::WebUIDataSource* html_source) {
-  html_source->AddLocalizedString("signinPageTitle", IDS_SETTINGS_SIGNIN);
-}
-#endif
-
 void AddSiteSettingsStrings(content::WebUIDataSource* html_source) {
   html_source->AddLocalizedString("siteSettingsPageTitle",
                                   IDS_SETTINGS_SITE_SETTINGS);
@@ -579,6 +573,9 @@
 }
 
 void AddSyncStrings(content::WebUIDataSource* html_source) {
+  html_source->AddLocalizedString("peoplePageTitle", IDS_SETTINGS_SYNC_PEOPLE);
+  html_source->AddLocalizedString("syncOverview", IDS_SETTINGS_SYNC_OVERVIEW);
+  html_source->AddLocalizedString("syncSignin", IDS_SETTINGS_SYNC_SIGNIN);
   html_source->AddLocalizedString("syncDisconnect",
                                   IDS_SETTINGS_SYNC_DISCONNECT);
   html_source->AddLocalizedString("syncDisconnectTitle",
@@ -590,7 +587,7 @@
           .spec();
   html_source->AddString(
       "syncDisconnectExplanation",
-      l10n_util::GetStringFUTF16(IDS_SYNC_STOP_SYNCING_EXPLANATION_LABEL,
+      l10n_util::GetStringFUTF16(IDS_SETTINGS_SYNC_DISCONNECT_EXPLANATION,
                                  base::ASCIIToUTF16(disconnect_help_url)));
   html_source->AddLocalizedString("syncDisconnectDeleteProfile",
                                   IDS_SETTINGS_SYNC_DISCONNECT_DELETE_PROFILE);
@@ -746,9 +743,6 @@
   AddResetStrings(html_source);
   AddSearchEnginesStrings(html_source);
   AddSearchStrings(html_source);
-#if !defined(OS_CHROMEOS)
-  AddSigninSettingsStrings(html_source);
-#endif
   AddSiteSettingsStrings(html_source);
   AddSyncStrings(html_source);
   AddUsersStrings(html_source);
diff --git a/chrome/common/variations/fieldtrial_testing_config_schema.json b/chrome/common/variations/fieldtrial_testing_config_schema.json
index 840f5fd..3f16573 100644
--- a/chrome/common/variations/fieldtrial_testing_config_schema.json
+++ b/chrome/common/variations/fieldtrial_testing_config_schema.json
@@ -24,6 +24,16 @@
               {"field": "value", "type": "string"}
             ]
           }
+        },
+        {
+          "field": "enable_features",
+          "type": "array",
+          "contents": { "type": "string"}
+        },
+        {
+          "field": "disable_features",
+          "type": "array",
+          "contents": { "type": "string"}
         }
       ]
     }
diff --git a/chrome/common/variations/variations_util.cc b/chrome/common/variations/variations_util.cc
index 767d1f26..87da726 100644
--- a/chrome/common/variations/variations_util.cc
+++ b/chrome/common/variations/variations_util.cc
@@ -7,6 +7,7 @@
 #include <string>
 #include <vector>
 
+#include "base/feature_list.h"
 #include "base/metrics/field_trial.h"
 #include "base/strings/string_split.h"
 #include "chrome/common/variations/fieldtrial_testing_config.h"
@@ -62,8 +63,8 @@
   return true;
 }
 
-void AssociateParamsFromFieldTrialConfig(
-    const FieldTrialTestingConfig& config) {
+void AssociateParamsFromFieldTrialConfig(const FieldTrialTestingConfig& config,
+                                         base::FeatureList* feature_list) {
   for (size_t i = 0; i < config.groups_size; ++i) {
     const FieldTrialTestingGroup& group = config.groups[i];
     if (group.params_size != 0) {
@@ -75,12 +76,24 @@
       variations::AssociateVariationParams(group.study, group.group_name,
                                            params);
     }
-    base::FieldTrialList::CreateFieldTrial(group.study, group.group_name);
+    base::FieldTrial* trial =
+        base::FieldTrialList::CreateFieldTrial(group.study, group.group_name);
+
+    for (size_t j = 0; j < group.enable_features_size; ++j) {
+      feature_list->RegisterFieldTrialOverride(
+          group.enable_features[j], base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+          trial);
+    }
+    for (size_t j = 0; j < group.disable_features_size; ++j) {
+      feature_list->RegisterFieldTrialOverride(
+          group.disable_features[j],
+          base::FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
+    }
   }
 }
 
-void AssociateDefaultFieldTrialConfig() {
-  AssociateParamsFromFieldTrialConfig(kFieldTrialConfig);
+void AssociateDefaultFieldTrialConfig(base::FeatureList* feature_list) {
+  AssociateParamsFromFieldTrialConfig(kFieldTrialConfig, feature_list);
 }
 
 }  // namespace chrome_variations
diff --git a/chrome/common/variations/variations_util.h b/chrome/common/variations/variations_util.h
index 7112aff..fe84dc8 100644
--- a/chrome/common/variations/variations_util.h
+++ b/chrome/common/variations/variations_util.h
@@ -7,6 +7,10 @@
 
 #include <string>
 
+namespace base {
+class FeatureList;
+}
+
 namespace chrome_variations {
 
 struct FieldTrialTestingConfig;
@@ -17,14 +21,17 @@
 // on the formatting.
 bool AssociateParamsFromString(const std::string& variations_string);
 
-// Provides a mechanism to associate multiple set of params to multiple groups
-// with the |config| struct. This will also force the selection of FieldTrial
-// groups specified in the |config|.
-void AssociateParamsFromFieldTrialConfig(const FieldTrialTestingConfig& config);
+// Provides a mechanism to associate multiple set of params and features to
+// multiple groups with the |config| struct. This will also force the selection
+// of FieldTrial groups specified in the |config|. Registers features associated
+// with default field trials with |feature_list|.
+void AssociateParamsFromFieldTrialConfig(const FieldTrialTestingConfig& config,
+                                         base::FeatureList* feature_list);
 
-// Associates params to FieldTrial groups and forces the selection of groups
-// specified in testing/variations/fieldtrial_testing_config_*.json.
-void AssociateDefaultFieldTrialConfig();
+// Associates params and features to FieldTrial groups and forces the selection
+// of groups specified in testing/variations/fieldtrial_testing_config_*.json.
+// Registers features associated with default field trials with |feature_list|.
+void AssociateDefaultFieldTrialConfig(base::FeatureList* feature_list);
 
 }  // namespace chrome_variations
 
diff --git a/chrome/common/variations/variations_util_unittest.cc b/chrome/common/variations/variations_util_unittest.cc
index 40d93f0..7b1fb9b 100644
--- a/chrome/common/variations/variations_util_unittest.cc
+++ b/chrome/common/variations/variations_util_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/common/variations/variations_util.h"
 
+#include "base/feature_list.h"
 #include "base/metrics/field_trial.h"
 #include "chrome/common/variations/fieldtrial_testing_config.h"
 #include "components/variations/variations_associated_data.h"
@@ -50,13 +51,16 @@
                                                                   {"y", "2"}};
 
   const FieldTrialTestingGroup array_kFieldTrialConfig_groups[] = {
-      {"TestStudy1", "TestGroup1", array_kFieldTrialConfig_params, 2},
-      {"TestStudy2", "TestGroup2", NULL, 0}};
+      {"TestStudy1", "TestGroup1", array_kFieldTrialConfig_params, 2, NULL, 0,
+       NULL, 0},
+      {"TestStudy2", "TestGroup2", NULL, 0, NULL, 0, NULL, 0}};
 
   const FieldTrialTestingConfig kConfig = {
       array_kFieldTrialConfig_groups, 2,
   };
-  AssociateParamsFromFieldTrialConfig(kConfig);
+
+  base::FeatureList feature_list;
+  AssociateParamsFromFieldTrialConfig(kConfig, &feature_list);
 
   EXPECT_EQ("1", variations::GetVariationParamValue("TestStudy1", "x"));
   EXPECT_EQ("2", variations::GetVariationParamValue("TestStudy1", "y"));
@@ -71,4 +75,39 @@
   EXPECT_EQ("TestGroup2", base::FieldTrialList::FindFullName("TestStudy2"));
 }
 
+TEST_F(VariationsUtilTest, AssociateFeaturesFromFieldTrialConfig) {
+  const base::Feature kFeatureA{"A", base::FEATURE_DISABLED_BY_DEFAULT};
+  const base::Feature kFeatureB{"B", base::FEATURE_ENABLED_BY_DEFAULT};
+  const base::Feature kFeatureC{"C", base::FEATURE_DISABLED_BY_DEFAULT};
+  const base::Feature kFeatureD{"D", base::FEATURE_ENABLED_BY_DEFAULT};
+
+  const char* enable_features[] = {"A", "B"};
+  const char* disable_features[] = {"C", "D"};
+
+  const FieldTrialTestingGroup array_kFieldTrialConfig_groups[] = {
+      {"TestStudy1", "TestGroup1", NULL, 0, enable_features, 2, NULL, 0},
+      {"TestStudy2", "TestGroup2", NULL, 0, NULL, 0, disable_features, 2}};
+
+  const FieldTrialTestingConfig kConfig = {
+      array_kFieldTrialConfig_groups, 2,
+  };
+
+  base::FeatureList::ClearInstanceForTesting();
+  scoped_ptr<base::FeatureList> feature_list(new base::FeatureList);
+  AssociateParamsFromFieldTrialConfig(kConfig, feature_list.get());
+  base::FeatureList::SetInstance(feature_list.Pass());
+
+  // Check the resulting feature and field trial states. Trials should not be
+  // active until their associated features are queried.
+  EXPECT_FALSE(base::FieldTrialList::IsTrialActive("TestStudy1"));
+  EXPECT_TRUE(base::FeatureList::IsEnabled(kFeatureA));
+  EXPECT_TRUE(base::FeatureList::IsEnabled(kFeatureB));
+  EXPECT_TRUE(base::FieldTrialList::IsTrialActive("TestStudy1"));
+
+  EXPECT_FALSE(base::FieldTrialList::IsTrialActive("TestStudy2"));
+  EXPECT_FALSE(base::FeatureList::IsEnabled(kFeatureC));
+  EXPECT_FALSE(base::FeatureList::IsEnabled(kFeatureD));
+  EXPECT_TRUE(base::FieldTrialList::IsTrialActive("TestStudy2"));
+}
+
 }  // namespace chrome_variations
diff --git a/chrome/installer/mini_installer/chrome.release b/chrome/installer/mini_installer/chrome.release
index 98453be..34fd53e 100644
--- a/chrome/installer/mini_installer/chrome.release
+++ b/chrome/installer/mini_installer/chrome.release
@@ -74,4 +74,3 @@
 # packaged in this directory.
 Logo.png: %(VersionDir)s\VisualElements\
 SmallLogo.png: %(VersionDir)s\VisualElements\
-splash-620x300.png: %(VersionDir)s\VisualElements\
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index 978646f..9584b01 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -278,17 +278,15 @@
     //   - Localized display name for the product.
     //   - Relative path to the VisualElements directory, three times.
     static const char kManifestTemplate[] =
-        "<Application>\r\n"
+        "<Application "
+            "xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>\r\n"
         "  <VisualElements\r\n"
-        "      DisplayName='%ls'\r\n"
-        "      Logo='%ls\\Logo.png'\r\n"
-        "      SmallLogo='%ls\\SmallLogo.png'\r\n"
-        "      ForegroundText='light'\r\n"
-        "      BackgroundColor='#323232'>\r\n"
-        "    <DefaultTile ShowName='allLogos'/>\r\n"
-        "    <SplashScreen Image='%ls\\splash-620x300.png'/>\r\n"
-        "  </VisualElements>\r\n"
-        "</Application>";
+        "      ShowNameOnSquare150x150Logo='on'\r\n"
+        "      Square150x150Logo='%ls\\Logo.png'\r\n"
+        "      Square70x70Logo='%ls\\SmallLogo.png'\r\n"
+        "      ForegroundText='light'>\r\n"
+        "      BackgroundColor='#323232'/>\r\n"
+        "</Application>\r\n";
 
     const base::string16 manifest_template(
         base::ASCIIToUTF16(kManifestTemplate));
@@ -302,8 +300,7 @@
 
     // Fill the manifest with the desired values.
     base::string16 manifest16(base::StringPrintf(
-        manifest_template.c_str(), display_name.c_str(), elements_dir.c_str(),
-        elements_dir.c_str(), elements_dir.c_str()));
+        manifest_template.c_str(), elements_dir.c_str(), elements_dir.c_str()));
 
     // Write the manifest to |src_path|.
     const std::string manifest(base::UTF16ToUTF8(manifest16));
diff --git a/chrome/installer/setup/install_unittest.cc b/chrome/installer/setup/install_unittest.cc
index 6f8b9c0..da0e4cc 100644
--- a/chrome/installer/setup/install_unittest.cc
+++ b/chrome/installer/setup/install_unittest.cc
@@ -227,35 +227,15 @@
   std::string read_manifest;
   ASSERT_TRUE(base::ReadFileToString(manifest_path_, &read_manifest));
 
-#if defined(GOOGLE_CHROME_BUILD)
   static const char kExpectedManifest[] =
-      "<Application>\r\n"
+      "<Application xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>\r\n"
       "  <VisualElements\r\n"
-      "      DisplayName='Google Chrome'\r\n"
-      "      Logo='0.0.0.0\\VisualElements\\Logo.png'\r\n"
-      "      SmallLogo='0.0.0.0\\VisualElements\\SmallLogo.png'\r\n"
-      "      ForegroundText='light'\r\n"
-      "      BackgroundColor='#323232'>\r\n"
-      "    <DefaultTile ShowName='allLogos'/>\r\n"
-      "    <SplashScreen Image='0.0.0.0\\VisualElements\\splash-620x300.png'/>"
-      "\r\n"
-      "  </VisualElements>\r\n"
-      "</Application>";
-#else
-  static const char kExpectedManifest[] =
-      "<Application>\r\n"
-      "  <VisualElements\r\n"
-      "      DisplayName='Chromium'\r\n"
-      "      Logo='0.0.0.0\\VisualElements\\Logo.png'\r\n"
-      "      SmallLogo='0.0.0.0\\VisualElements\\SmallLogo.png'\r\n"
-      "      ForegroundText='light'\r\n"
-      "      BackgroundColor='#323232'>\r\n"
-      "    <DefaultTile ShowName='allLogos'/>\r\n"
-      "    <SplashScreen Image='0.0.0.0\\VisualElements\\splash-620x300.png'/>"
-      "\r\n"
-      "  </VisualElements>\r\n"
-      "</Application>";
-#endif
+      "      ShowNameOnSquare150x150Logo='on'\r\n"
+      "      Square150x150Logo='0.0.0.0\\VisualElements\\Logo.png'\r\n"
+      "      Square70x70Logo='0.0.0.0\\VisualElements\\SmallLogo.png'\r\n"
+      "      ForegroundText='light'>\r\n"
+      "      BackgroundColor='#323232'/>\r\n"
+      "</Application>\r\n";
 
   ASSERT_STREQ(kExpectedManifest, read_manifest.c_str());
 }
diff --git a/chrome/installer/setup/setup_constants.cc b/chrome/installer/setup/setup_constants.cc
index c626746..8d705fa 100644
--- a/chrome/installer/setup/setup_constants.cc
+++ b/chrome/installer/setup/setup_constants.cc
@@ -10,7 +10,7 @@
 const wchar_t kChromeArchive[] = L"chrome.7z";
 const wchar_t kChromeCompressedArchive[] = L"chrome.packed.7z";
 const wchar_t kVisualElements[] = L"VisualElements";
-const wchar_t kVisualElementsManifest[] = L"VisualElementsManifest.xml";
+const wchar_t kVisualElementsManifest[] = L"chrome.VisualElementsManifest.xml";
 const wchar_t kWowHelperExe[] = L"wow_helper.exe";
 
 // Sub directory of install source package under install temporary directory.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 541a044..b90283a 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -667,6 +667,7 @@
 
       # Field trial config
       "//tools/variations/",
+      "//testing/variations/",
 
       # For isolate contract.
       "//testing/scripts/common.py",
diff --git a/chrome/test/data/save_page/a.htm b/chrome/test/data/save_page/a.htm
index 3731f86..7de4493 100644
--- a/chrome/test/data/save_page/a.htm
+++ b/chrome/test/data/save_page/a.htm
@@ -5,7 +5,9 @@
     </title>
   </head>
   <body>
-    Content verification marker: 1b8aae2b-e164-462f-bd5b-98aa366205f2
+    Content verification marker:
+    a.htm: 1b8aae2b-e164-462f-bd5b-98aa366205f2
+
     Can you see this sentence?
   </body>
 </html>
diff --git a/chrome/test/data/save_page/b.htm b/chrome/test/data/save_page/b.htm
index a218477..3e912054 100644
--- a/chrome/test/data/save_page/b.htm
+++ b/chrome/test/data/save_page/b.htm
@@ -6,7 +6,8 @@
     <link type="text/css" href="1.css" rel="stylesheet">
   </head>
   <body>
-    Content verification marker: 3a35f7fa-96a9-4487-9f18-4470263907fa
+    Content verification marker:
+    b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa
 
     The picture below is the back button.<br>
     <img src="1.png"> </img>
diff --git a/chrome/test/data/save_page/b.saved1.htm b/chrome/test/data/save_page/b.saved1.htm
index 1289d498..c296a2b33 100644
--- a/chrome/test/data/save_page/b.saved1.htm
+++ b/chrome/test/data/save_page/b.saved1.htm
@@ -7,7 +7,8 @@
     <link type="text/css" href="./b_files/1.css" rel="stylesheet">
   </head>
   <body>
-    Content verification marker: 3a35f7fa-96a9-4487-9f18-4470263907fa
+    Content verification marker:
+    b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa
 
     The picture below is the back button.<br>
     <img src="./b_files/1.png"> 
diff --git a/chrome/test/data/save_page/b.saved2.htm b/chrome/test/data/save_page/b.saved2.htm
index 9239e5f..0d189bd 100644
--- a/chrome/test/data/save_page/b.saved2.htm
+++ b/chrome/test/data/save_page/b.saved2.htm
@@ -7,7 +7,8 @@
     <link type="text/css" href="./Test page for saving page feature_files/1.css" rel="stylesheet">
   </head>
   <body>
-    Content verification marker: 3a35f7fa-96a9-4487-9f18-4470263907fa
+    Content verification marker:
+    b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa
 
     The picture below is the back button.<br>
     <img src="./Test page for saving page feature_files/1.png"> 
diff --git a/content/test/data/download/local-about-blank-subframes.html b/chrome/test/data/save_page/frames-about-blank.htm
similarity index 100%
rename from content/test/data/download/local-about-blank-subframes.html
rename to chrome/test/data/save_page/frames-about-blank.htm
diff --git a/chrome/test/data/save_page/frames-objects.htm b/chrome/test/data/save_page/frames-objects.htm
new file mode 100644
index 0000000..0f521f2
--- /dev/null
+++ b/chrome/test/data/save_page/frames-objects.htm
@@ -0,0 +1,41 @@
+<!doctype html>
+<html>
+  <head><title>Object elements test</title></head>
+  <body>
+    Content verification marker:
+    frames-objects.htm: 8da13db4-a512-4d9b-b1c5-dc1c134234b9
+    <br>
+    <br>
+
+    Html object:
+    <br>
+    <object data="b.htm" border="1">err_no_object_data</object>
+    <br>
+    <br>
+
+    Regular iframe:
+    <br>
+    <iframe src="a.htm" border="1"></iframe>
+    <br>
+    <br>
+
+    Png object:
+    <br>
+    <object data="png.png" border="1">err_no_object_data</object>
+    <br>
+    <br>
+
+    Pdf object:
+    <br>
+    <object data="pdf.pdf" border="1">err_no_object_data</object>
+    <br>
+    <br>
+
+    Svg object:
+    <br>
+    <object data="svg.svg" border="1">err_no_object_data</object>
+    <br>
+    <br>
+
+  </body>
+</html>
diff --git a/chrome/test/data/save_page/iframes.htm b/chrome/test/data/save_page/frames-xsite.htm
similarity index 89%
rename from chrome/test/data/save_page/iframes.htm
rename to chrome/test/data/save_page/frames-xsite.htm
index 20837e2..0f4e006 100644
--- a/chrome/test/data/save_page/iframes.htm
+++ b/chrome/test/data/save_page/frames-xsite.htm
@@ -17,7 +17,8 @@
 
   <h1>Test content</h1>
 
-  Content verification marker: 896fd88d-a77a-4f46-afd8-24db7d5af9c2
+  Content verification marker:
+  frames-xsite.htm: 896fd88d-a77a-4f46-afd8-24db7d5af9c2
 
   <iframe src="/cross-site/bar.com/save_page/a.htm"></iframe>
   <iframe src="b.htm"></iframe>
diff --git a/chrome/test/data/save_page/pdf.pdf b/chrome/test/data/save_page/pdf.pdf
new file mode 100644
index 0000000..e30b299
--- /dev/null
+++ b/chrome/test/data/save_page/pdf.pdf
Binary files differ
diff --git a/chrome/test/data/save_page/png.png b/chrome/test/data/save_page/png.png
new file mode 100644
index 0000000..7f2d63e
--- /dev/null
+++ b/chrome/test/data/save_page/png.png
Binary files differ
diff --git a/chrome/test/data/save_page/svg.svg b/chrome/test/data/save_page/svg.svg
new file mode 100644
index 0000000..c64428e
--- /dev/null
+++ b/chrome/test/data/save_page/svg.svg
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="64px"
+   height="64px"
+   id="svg2985"
+   version="1.1"
+   inkscape:version="0.48.4 r9939"
+   sodipodi:docname="New document 2">
+  <defs
+     id="defs2987" />
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="5.5"
+     inkscape:cx="32"
+     inkscape:cy="37.492543"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:document-units="px"
+     inkscape:grid-bbox="true"
+     inkscape:window-width="729"
+     inkscape:window-height="633"
+     inkscape:window-x="2304"
+     inkscape:window-y="141"
+     inkscape:window-maximized="0" />
+  <metadata
+     id="metadata2990">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     id="layer1"
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer">
+    <path
+       sodipodi:type="spiral"
+       style="fill:#ffff00;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+       id="path2993"
+       sodipodi:cx="13.272727"
+       sodipodi:cy="16.363636"
+       sodipodi:expansion="1"
+       sodipodi:revolution="3"
+       sodipodi:radius="21.993988"
+       sodipodi:argument="-18.034925"
+       sodipodi:t0="0"
+       d="m 13.272727,16.363636 c 0.756633,0.802215 -0.708074,1.415711 -1.333334,1.257575 -1.694418,-0.428542 -1.90471,-2.621079 -1.181815,-3.924244 1.293088,-2.331056 4.479349,-2.5154 6.515152,-1.106055 2.987623,2.068271 3.145056,6.363141 1.030295,9.106062 -2.818644,3.655881 -8.256033,3.782844 -11.6969699,0.954535 C 2.2759878,19.092371 2.1812057,12.498235 5.7272796,8.3636298 10.02205,3.3560686 17.780244,3.2943313 22.606068,7.560614 28.293134,12.588281 28.32135,21.514797 23.333324,27.030311 17.57445,33.39819 7.4769016,33.392601 1.2727176,27.681807 -5.7768706,21.19284 -5.7372958,9.9224301 0.69698126,3.0302922 7.9152677,-4.7016449 20.359836,-4.6279644 27.939405,2.5303157 36.354164,10.477363 36.246294,24.097041 28.363622,32.363649"
+       transform="matrix(1.5307376,0,0,1.5940705,9.1703267,8.8563054)" />
+    <text
+       xml:space="preserve"
+       style="font-size:24px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ff0000;fill-opacity:1;stroke:none;font-family:Sans"
+       x="-17.957426"
+       y="51.259815"
+       id="text2995"
+       sodipodi:linespacing="125%"
+       transform="matrix(0.79593293,-0.60538482,0.60538482,0.79593293,0,0)"><tspan
+         sodipodi:role="line"
+         id="tspan2997"
+         x="-17.957426"
+         y="51.259815">SVG</tspan></text>
+  </g>
+</svg>
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index 306af8a..6ac1963 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -137,7 +137,7 @@
 
   run_list_path = "$root_out_dir/tests/run_test_list.txt"
 
-  additional_options = [ "--ozone-platform=test" ]
+  additional_options = [ "--ozone-platform=headless" ]
 
   build_tests = true
 
diff --git a/chromecast/chromecast_tests.gypi b/chromecast/chromecast_tests.gypi
index 53316ba..4eaea74 100644
--- a/chromecast/chromecast_tests.gypi
+++ b/chromecast/chromecast_tests.gypi
@@ -396,7 +396,7 @@
           'variables': {
             'test_generator_py': '<(DEPTH)/chromecast/tools/build/generate_test_lists.py',
             'test_inputs_dir': '<(SHARED_INTERMEDIATE_DIR)/chromecast/tests',
-            'test_additional_options': '--ozone-platform=test'
+            'test_additional_options': '--ozone-platform=headless'
           },
           'actions': [
             {
diff --git a/components/html_viewer/BUILD.gn b/components/html_viewer/BUILD.gn
index dc5b228..876a79d 100644
--- a/components/html_viewer/BUILD.gn
+++ b/components/html_viewer/BUILD.gn
@@ -298,12 +298,10 @@
     deps = [
       ":pak",
       "//gin",
-      "//third_party/icu:icudata",
     ]
     dest = html_viewer_unittests_assets
     sources = [
       "$root_build_dir/html_viewer.pak",
-      "$root_build_dir/icudtl.dat",
     ]
     renaming_sources = v8_external_startup_data_renaming_sources
     renaming_destinations = v8_external_startup_data_renaming_destinations
diff --git a/components/html_viewer/global_state.cc b/components/html_viewer/global_state.cc
index a0bb8be..9d7f46b 100644
--- a/components/html_viewer/global_state.cc
+++ b/components/html_viewer/global_state.cc
@@ -8,7 +8,6 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
-#include "base/i18n/icu_util.h"
 #include "base/logging.h"
 #include "components/html_viewer/blink_platform_impl.h"
 #include "components/html_viewer/blink_settings_impl.h"
@@ -146,15 +145,12 @@
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   base::File pak_file = resource_loader_.ReleaseFile(kResourceResourcesPak);
 
-  bool initialize_icu_and_ui = true;
+  bool initialize_ui = true;
 #if defined(COMPONENT_BUILD)
   if (command_line->HasSwitch("single-process"))
-    initialize_icu_and_ui = false;
+    initialize_ui = false;
 #endif
-  if (initialize_icu_and_ui) {
-    base::i18n::InitializeICUWithFileDescriptor(
-        resource_loader_.GetICUFile().TakePlatformFile(),
-        base::MemoryMappedFile::Region::kWholeFile);
+  if (initialize_ui) {
     ui::RegisterPathProvider();
     base::File pak_file_2 = pak_file.Duplicate();
     ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(
diff --git a/components/html_viewer/html_viewer_main.cc b/components/html_viewer/html_viewer_main.cc
index 79349639..9afd58d 100644
--- a/components/html_viewer/html_viewer_main.cc
+++ b/components/html_viewer/html_viewer_main.cc
@@ -6,32 +6,6 @@
 #include "mojo/application/public/cpp/application_runner.h"
 #include "third_party/mojo/src/mojo/public/c/system/main.h"
 
-// TODO(erg): Much of this will be the same between mojo applications. Maybe we
-// could centralize this code?
-#if defined(OS_LINUX) && !defined(OS_ANDROID)
-#include "base/rand_util.h"
-#include "base/sys_info.h"
-#include "third_party/icu/source/i18n/unicode/timezone.h"
-
-// TODO(erg): Much of this was coppied from zygote_main_linux.cc
-extern "C" {
-void __attribute__((visibility("default"))) MojoSandboxWarm() {
-  base::RandUint64();
-  base::SysInfo::AmountOfPhysicalMemory();
-  base::SysInfo::MaxSharedMemorySize();
-  base::SysInfo::NumberOfProcessors();
-
-  // ICU DateFormat class (used in base/time_format.cc) needs to get the
-  // Olson timezone ID by accessing the zoneinfo files on disk. After
-  // TimeZone::createDefault is called once here, the timezone ID is
-  // cached and there's no more need to access the file system.
-  scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
-
-  // TODO(erg): Perform OpenSSL warmup; it wants access to /dev/urandom.
-}
-}
-#endif  // defined(OS_LINUX) && !defined(OS_ANDROID)
-
 MojoResult MojoMain(MojoHandle shell_handle) {
   mojo::ApplicationRunner runner(new html_viewer::HTMLViewer);
   return runner.Run(shell_handle);
diff --git a/components/mus/ws/connection_manager.cc b/components/mus/ws/connection_manager.cc
index 5f320d9..5b103d8 100644
--- a/components/mus/ws/connection_manager.cc
+++ b/components/mus/ws/connection_manager.cc
@@ -370,6 +370,15 @@
   return host ? host->root_window() : nullptr;
 }
 
+void ConnectionManager::ScheduleSurfaceDestruction(ServerWindow* window) {
+  for (auto& pair : host_connection_map_) {
+    if (pair.first->root_window()->Contains(window)) {
+      pair.first->ScheduleSurfaceDestruction(window);
+      break;
+    }
+  }
+}
+
 void ConnectionManager::OnWindowDestroyed(ServerWindow* window) {
   if (!in_destructor_)
     ProcessWindowDeleted(window->id());
diff --git a/components/mus/ws/connection_manager.h b/components/mus/ws/connection_manager.h
index 3236568..0b522e9 100644
--- a/components/mus/ws/connection_manager.h
+++ b/components/mus/ws/connection_manager.h
@@ -194,6 +194,7 @@
   mus::SurfacesState* GetSurfacesState() override;
   void OnScheduleWindowPaint(const ServerWindow* window) override;
   const ServerWindow* GetRootWindow(const ServerWindow* window) const override;
+  void ScheduleSurfaceDestruction(ServerWindow* window) override;
 
   // Overridden from ServerWindowObserver:
   void OnWindowDestroyed(ServerWindow* window) override;
diff --git a/components/mus/ws/display_manager.cc b/components/mus/ws/display_manager.cc
index d40e78f..03eb620 100644
--- a/components/mus/ws/display_manager.cc
+++ b/components/mus/ws/display_manager.cc
@@ -14,6 +14,7 @@
 #include "components/mus/public/interfaces/gpu.mojom.h"
 #include "components/mus/public/interfaces/quads.mojom.h"
 #include "components/mus/surfaces/surfaces_state.h"
+#include "components/mus/surfaces/top_level_display_client.h"
 #include "components/mus/ws/display_manager_factory.h"
 #include "components/mus/ws/server_window.h"
 #include "components/mus/ws/server_window_surface.h"
@@ -245,10 +246,15 @@
 
 void DefaultDisplayManager::DidDraw() {
   frame_pending_ = false;
+  delegate_->OnCompositorFrameDrawn();
   if (!dirty_rect_.IsEmpty())
     WantToDraw();
 }
 
+bool DefaultDisplayManager::IsFramePending() const {
+  return frame_pending_;
+}
+
 void DefaultDisplayManager::WantToDraw() {
   if (draw_timer_.IsRunning() || frame_pending_)
     return;
diff --git a/components/mus/ws/display_manager.h b/components/mus/ws/display_manager.h
index ab66f02..fd3217b 100644
--- a/components/mus/ws/display_manager.h
+++ b/components/mus/ws/display_manager.h
@@ -12,13 +12,13 @@
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
-#include "components/mus/surfaces/top_level_display_client.h"
 #include "components/mus/ws/display_manager_delegate.h"
 #include "third_party/mojo/src/mojo/public/cpp/bindings/callback.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/platform_window/platform_window_delegate.h"
 
 namespace cc {
+class CompositorFrame;
 class SurfaceIdAllocator;
 class SurfaceManager;
 }  // namespace cc
@@ -38,7 +38,9 @@
 
 namespace mus {
 
+class GpuState;
 class SurfacesState;
+class TopLevelDisplayClient;
 
 namespace ws {
 
@@ -71,6 +73,9 @@
   virtual void UpdateTextInputState(const ui::TextInputState& state) = 0;
   virtual void SetImeVisibility(bool visible) = 0;
 
+  // Returns true if a compositor frame has been submitted but not drawn yet.
+  virtual bool IsFramePending() const = 0;
+
   // Overrides factory for testing. Default (NULL) value indicates regular
   // (non-test) environment.
   static void set_factory_for_testing(DisplayManagerFactory* factory) {
@@ -101,6 +106,7 @@
   const mojom::ViewportMetrics& GetViewportMetrics() override;
   void UpdateTextInputState(const ui::TextInputState& state) override;
   void SetImeVisibility(bool visible) override;
+  bool IsFramePending() const override;
 
  private:
   void WantToDraw();
diff --git a/components/mus/ws/display_manager_delegate.h b/components/mus/ws/display_manager_delegate.h
index 00fab3e..ba4652c 100644
--- a/components/mus/ws/display_manager_delegate.h
+++ b/components/mus/ws/display_manager_delegate.h
@@ -39,6 +39,9 @@
 
   virtual void OnTopLevelSurfaceChanged(cc::SurfaceId surface_id) = 0;
 
+  // Called when a compositor frame is finished drawing.
+  virtual void OnCompositorFrameDrawn() = 0;
+
  protected:
   virtual ~DisplayManagerDelegate() {}
 };
diff --git a/components/mus/ws/server_window.cc b/components/mus/ws/server_window.cc
index c88da20..c33e4cb 100644
--- a/components/mus/ws/server_window.cc
+++ b/components/mus/ws/server_window.cc
@@ -306,6 +306,18 @@
   return root == window;
 }
 
+void ServerWindow::DestroySurfacesScheduledForDestruction() {
+  if (!surface_manager_)
+    return;
+  ServerWindowSurface* surface = surface_manager_->GetDefaultSurface();
+  if (surface)
+    surface->DestroySurfacesScheduledForDestruction();
+
+  surface = surface_manager_->GetUnderlaySurface();
+  if (surface)
+    surface->DestroySurfacesScheduledForDestruction();
+}
+
 ServerWindowSurfaceManager* ServerWindow::GetOrCreateSurfaceManager() {
   if (!surface_manager_.get())
     surface_manager_.reset(new ServerWindowSurfaceManager(this));
diff --git a/components/mus/ws/server_window.h b/components/mus/ws/server_window.h
index cc5d6d9..d99c7b8 100644
--- a/components/mus/ws/server_window.h
+++ b/components/mus/ws/server_window.h
@@ -123,6 +123,9 @@
   // visible.
   bool IsDrawn() const;
 
+  // Called when its appropriate to destroy surfaces scheduled for destruction.
+  void DestroySurfacesScheduledForDestruction();
+
   ServerWindowSurfaceManager* GetOrCreateSurfaceManager();
   ServerWindowSurfaceManager* surface_manager() {
     return surface_manager_.get();
diff --git a/components/mus/ws/server_window_delegate.h b/components/mus/ws/server_window_delegate.h
index 8ea28d6..549cdf3 100644
--- a/components/mus/ws/server_window_delegate.h
+++ b/components/mus/ws/server_window_delegate.h
@@ -28,6 +28,10 @@
   virtual const ServerWindow* GetRootWindow(
       const ServerWindow* window) const = 0;
 
+  // Schedules a callback to DestroySurfacesScheduledForDestruction() at the
+  // appropriate time, which may be synchronously.
+  virtual void ScheduleSurfaceDestruction(ServerWindow* window) = 0;
+
  protected:
   virtual ~ServerWindowDelegate() {}
 };
diff --git a/components/mus/ws/server_window_surface.cc b/components/mus/ws/server_window_surface.cc
index 8d70cded..f06b052 100644
--- a/components/mus/ws/server_window_surface.cc
+++ b/components/mus/ws/server_window_surface.cc
@@ -15,9 +15,7 @@
 #include "mojo/converters/surfaces/surfaces_type_converters.h"
 
 namespace mus {
-
 namespace ws {
-
 namespace {
 
 void CallCallback(const mojo::Closure& callback, cc::SurfaceDrawStatus status) {
@@ -59,7 +57,15 @@
     // If the size of the CompostiorFrame has changed then destroy the existing
     // Surface and create a new one of the appropriate size.
     if (frame_size != last_submitted_frame_size_) {
-      surface_factory_.Destroy(surface_id_);
+      // Rendering of the topmost frame happens in two phases. First the frame
+      // is generated and submitted, and a later date it is actually drawn.
+      // During the time the frame is generated and drawn we can't destroy the
+      // surface, otherwise when drawn you get an empty surface. To deal with
+      // this we schedule destruction via the delegate. The delegate will call
+      // us back when we're not waiting on a frame to be drawn (which may be
+      // synchronously).
+      surfaces_scheduled_for_destruction_.insert(surface_id_);
+      window()->delegate()->ScheduleSurfaceDestruction(window());
       surface_id_ = manager_->GenerateId();
       surface_factory_.Create(surface_id_);
     }
@@ -72,6 +78,13 @@
   last_submitted_frame_size_ = frame_size;
 }
 
+void ServerWindowSurface::DestroySurfacesScheduledForDestruction() {
+  std::set<cc::SurfaceId> surfaces;
+  surfaces.swap(surfaces_scheduled_for_destruction_);
+  for (auto& id : surfaces)
+    surface_factory_.Destroy(id);
+}
+
 ServerWindow* ServerWindowSurface::window() {
   return manager_->window();
 }
@@ -138,5 +151,4 @@
 }
 
 }  // namespace ws
-
 }  // namespace mus
diff --git a/components/mus/ws/server_window_surface.h b/components/mus/ws/server_window_surface.h
index a9be778..712dba0 100644
--- a/components/mus/ws/server_window_surface.h
+++ b/components/mus/ws/server_window_surface.h
@@ -52,6 +52,9 @@
 
   const cc::SurfaceId& id() const { return surface_id_; }
 
+  // Destroys old surfaces that have been outdated by a new surface.
+  void DestroySurfacesScheduledForDestruction();
+
  private:
   ServerWindow* window();
 
@@ -88,6 +91,9 @@
   mojom::SurfaceClientPtr client_;
   mojo::Binding<Surface> binding_;
 
+  // Set of surface ids that need to be destroyed.
+  std::set<cc::SurfaceId> surfaces_scheduled_for_destruction_;
+
   DISALLOW_COPY_AND_ASSIGN(ServerWindowSurface);
 };
 
diff --git a/components/mus/ws/test_server_window_delegate.cc b/components/mus/ws/test_server_window_delegate.cc
index 3d24a7b7..b2e7a1e 100644
--- a/components/mus/ws/test_server_window_delegate.cc
+++ b/components/mus/ws/test_server_window_delegate.cc
@@ -25,6 +25,9 @@
   return root_window_;
 }
 
+void TestServerWindowDelegate::ScheduleSurfaceDestruction(
+    ServerWindow* window) {}
+
 }  // namespace ws
 
 }  // namespace mus
diff --git a/components/mus/ws/test_server_window_delegate.h b/components/mus/ws/test_server_window_delegate.h
index 2d1b2f7..5e019db 100644
--- a/components/mus/ws/test_server_window_delegate.h
+++ b/components/mus/ws/test_server_window_delegate.h
@@ -26,6 +26,7 @@
   mus::SurfacesState* GetSurfacesState() override;
   void OnScheduleWindowPaint(const ServerWindow* window) override;
   const ServerWindow* GetRootWindow(const ServerWindow* window) const override;
+  void ScheduleSurfaceDestruction(ServerWindow* window) override;
 
   const ServerWindow* root_window_;
 
diff --git a/components/mus/ws/window_tree_host_impl.cc b/components/mus/ws/window_tree_host_impl.cc
index eee39c7..c6e8a17 100644
--- a/components/mus/ws/window_tree_host_impl.cc
+++ b/components/mus/ws/window_tree_host_impl.cc
@@ -39,7 +39,10 @@
   }
 }
 
-WindowTreeHostImpl::~WindowTreeHostImpl() {}
+WindowTreeHostImpl::~WindowTreeHostImpl() {
+  for (ServerWindow* window : windows_needing_frame_destruction_)
+    window->RemoveObserver(this);
+}
 
 void WindowTreeHostImpl::Init(WindowTreeHostDelegate* delegate) {
   delegate_ = delegate;
@@ -65,6 +68,17 @@
   return false;
 }
 
+void WindowTreeHostImpl::ScheduleSurfaceDestruction(ServerWindow* window) {
+  if (!display_manager_->IsFramePending()) {
+    window->DestroySurfacesScheduledForDestruction();
+    return;
+  }
+  if (windows_needing_frame_destruction_.count(window))
+    return;
+  windows_needing_frame_destruction_.insert(window);
+  window->AddObserver(this);
+}
+
 const mojom::ViewportMetrics& WindowTreeHostImpl::GetViewportMetrics() const {
   return display_manager_->GetViewportMetrics();
 }
@@ -162,6 +176,15 @@
   event_dispatcher_.set_surface_id(surface_id);
 }
 
+void WindowTreeHostImpl::OnCompositorFrameDrawn() {
+  std::set<ServerWindow*> windows;
+  windows.swap(windows_needing_frame_destruction_);
+  for (ServerWindow* window : windows) {
+    window->RemoveObserver(this);
+    window->DestroySurfacesScheduledForDestruction();
+  }
+}
+
 void WindowTreeHostImpl::OnFocusChanged(ServerWindow* old_focused_window,
                                         ServerWindow* new_focused_window) {
   // There are up to four connections that need to be notified:
@@ -257,5 +280,10 @@
                                            base::Bind(&base::DoNothing));
 }
 
+void WindowTreeHostImpl::OnWindowDestroyed(ServerWindow* window) {
+  windows_needing_frame_destruction_.erase(window);
+  window->RemoveObserver(this);
+}
+
 }  // namespace ws
 }  // namespace mus
diff --git a/components/mus/ws/window_tree_host_impl.h b/components/mus/ws/window_tree_host_impl.h
index f41f476c..c3c5f1d 100644
--- a/components/mus/ws/window_tree_host_impl.h
+++ b/components/mus/ws/window_tree_host_impl.h
@@ -14,6 +14,7 @@
 #include "components/mus/ws/event_dispatcher_delegate.h"
 #include "components/mus/ws/focus_controller_delegate.h"
 #include "components/mus/ws/server_window.h"
+#include "components/mus/ws/server_window_observer.h"
 
 namespace mus {
 namespace ws {
@@ -31,7 +32,8 @@
 class WindowTreeHostImpl : public DisplayManagerDelegate,
                            public mojom::WindowTreeHost,
                            public FocusControllerDelegate,
-                           public EventDispatcherDelegate {
+                           public EventDispatcherDelegate,
+                           public ServerWindowObserver {
  public:
   // TODO(fsamuel): All these parameters are just plumbing for creating
   // DisplayManagers. We should probably just store these common parameters
@@ -62,6 +64,11 @@
   bool SchedulePaintIfInViewport(const ServerWindow* window,
                                  const gfx::Rect& bounds);
 
+  // Schedules destruction of surfaces in |window|. If a frame has been
+  // scheduled but not drawn surface destruction is delayed until the frame is
+  // drawn, otherwise destruction is immediate.
+  void ScheduleSurfaceDestruction(ServerWindow* window);
+
   // Returns the metrics for this viewport.
   const mojom::ViewportMetrics& GetViewportMetrics() const;
 
@@ -99,6 +106,7 @@
       const mojom::ViewportMetrics& old_metrics,
       const mojom::ViewportMetrics& new_metrics) override;
   void OnTopLevelSurfaceChanged(cc::SurfaceId surface_id) override;
+  void OnCompositorFrameDrawn() override;
 
   // FocusControllerDelegate:
   void OnFocusChanged(ServerWindow* old_focused_window,
@@ -112,6 +120,9 @@
                                   bool in_nonclient_area,
                                   mojom::EventPtr event) override;
 
+  // ServerWindowObserver:
+  void OnWindowDestroyed(ServerWindow* window) override;
+
   WindowTreeHostDelegate* delegate_;
   ConnectionManager* const connection_manager_;
   mojom::WindowTreeHostClientPtr client_;
@@ -121,6 +132,10 @@
   scoped_ptr<FocusController> focus_controller_;
   mojom::WindowManagerPtr window_manager_;
 
+  // Set of windows with surfaces that need to be destroyed once the frame
+  // draws.
+  std::set<ServerWindow*> windows_needing_frame_destruction_;
+
   DISALLOW_COPY_AND_ASSIGN(WindowTreeHostImpl);
 };
 
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc
index bf3fccd0..d2145c9 100644
--- a/components/mus/ws/window_tree_unittest.cc
+++ b/components/mus/ws/window_tree_unittest.cc
@@ -237,6 +237,7 @@
   }
   void UpdateTextInputState(const ui::TextInputState& state) override {}
   void SetImeVisibility(bool visible) override {}
+  bool IsFramePending() const override { return false; }
 
  private:
   mojom::ViewportMetrics display_metrices_;
diff --git a/components/resource_provider/BUILD.gn b/components/resource_provider/BUILD.gn
index 5d26584..9a9ecb0 100644
--- a/components/resource_provider/BUILD.gn
+++ b/components/resource_provider/BUILD.gn
@@ -17,10 +17,7 @@
     deps = [
       ":java_library",
       ":resource_provider_lib",
-      "//third_party/icu:icudata",
     ]
-
-    resources = [ "$root_out_dir/icudtl.dat" ]
   }
 
   shared_library("resource_provider_lib") {
@@ -75,11 +72,8 @@
       "//base",
       "//components/resource_provider/public/interfaces",
       "//mojo/environment:chromium",
-      "//third_party/icu:icudata",
       "//url",
     ]
-
-    resources = [ "$root_out_dir/icudtl.dat" ]
   }
 }
 
diff --git a/components/resource_provider/public/cpp/resource_loader.cc b/components/resource_provider/public/cpp/resource_loader.cc
index 8b1c116..5dd763f 100644
--- a/components/resource_provider/public/cpp/resource_loader.cc
+++ b/components/resource_provider/public/cpp/resource_loader.cc
@@ -56,15 +56,6 @@
   return file_wrapper->Pass();
 }
 
-base::File ResourceLoader::GetICUFile() {
-  base::File rv;
-  resource_provider_->GetICUHandle(
-      base::Bind(&ResourceLoader::OnGotICU, base::Unretained(this), &rv));
-  resource_provider_.WaitForIncomingResponse();
-  CHECK(rv.IsValid());
-  return rv.Pass();
-}
-
 void ResourceLoader::OnGotResources(const std::vector<std::string>& paths,
                                     mojo::Array<mojo::ScopedHandle> resources) {
 
@@ -77,8 +68,4 @@
   loaded_ = true;
 }
 
-void ResourceLoader::OnGotICU(base::File* file, mojo::ScopedHandle handle) {
-  *file = GetFileFromHandle(handle.Pass());
-}
-
 }  // namespace resource_provider
diff --git a/components/resource_provider/public/cpp/resource_loader.h b/components/resource_provider/public/cpp/resource_loader.h
index 2b055aa..69b5094 100644
--- a/components/resource_provider/public/cpp/resource_loader.h
+++ b/components/resource_provider/public/cpp/resource_loader.h
@@ -46,8 +46,6 @@
   // Releases and returns the file wrapping the handle.
   base::File ReleaseFile(const std::string& path);
 
-  base::File GetICUFile();
-
   bool loaded() const { return loaded_; }
 
  private:
@@ -56,7 +54,6 @@
   // Callback when resources have loaded.
   void OnGotResources(const std::vector<std::string>& paths,
                       mojo::Array<mojo::ScopedHandle> resources);
-  void OnGotICU(base::File* file, mojo::ScopedHandle handle);
 
   ResourceProviderPtr resource_provider_;
 
diff --git a/components/resource_provider/public/interfaces/resource_provider.mojom b/components/resource_provider/public/interfaces/resource_provider.mojom
index 01c6b99..15af0d1 100644
--- a/components/resource_provider/public/interfaces/resource_provider.mojom
+++ b/components/resource_provider/public/interfaces/resource_provider.mojom
@@ -15,7 +15,4 @@
   // The result is an array of platform handles for each of the requested paths.
   // TODO(sky): this should really be map<string,handle>, but that doesn't work.
   GetResources(array<string> paths) => (array<handle> resource_handles);
-
-  // Fetch a handle to the shared version of ICU table.
-  GetICUHandle() => (handle resource_handle);
 };
diff --git a/components/resource_provider/resource_provider_impl.cc b/components/resource_provider/resource_provider_impl.cc
index 3f14e76..628c16a 100644
--- a/components/resource_provider/resource_provider_impl.cc
+++ b/components/resource_provider/resource_provider_impl.cc
@@ -17,8 +17,6 @@
 namespace resource_provider {
 namespace {
 
-const char kResourceIcudtl[] = "icudtl.dat";
-
 ScopedHandle GetHandleForPath(const base::FilePath& path) {
   if (path.empty())
     return ScopedHandle();
@@ -68,12 +66,4 @@
   callback.Run(handles.Pass());
 }
 
-void ResourceProviderImpl::GetICUHandle(const GetICUHandleCallback& callback) {
-  const base::FilePath resource_app_path(
-      GetPathForApplicationUrl(resource_provider_app_url_));
-  mojo::ScopedHandle handle = GetHandleForPath(
-      GetPathForResourceNamed(resource_app_path, kResourceIcudtl));
-  callback.Run(handle.Pass());
-}
-
 }  // namespace resource_provider
diff --git a/components/resource_provider/resource_provider_impl.h b/components/resource_provider/resource_provider_impl.h
index b805cf7..8884a5b 100644
--- a/components/resource_provider/resource_provider_impl.h
+++ b/components/resource_provider/resource_provider_impl.h
@@ -21,7 +21,6 @@
   // ResourceProvider:
   void GetResources(mojo::Array<mojo::String> paths,
                     const GetResourcesCallback& callback) override;
-  void GetICUHandle(const GetICUHandleCallback& callback) override;
 
   const base::FilePath application_path_;
   const std::string resource_provider_app_url_;
diff --git a/components/signin/core/browser/account_reconcilor.cc b/components/signin/core/browser/account_reconcilor.cc
index 51bcd3b..3e140cc 100644
--- a/components/signin/core/browser/account_reconcilor.cc
+++ b/components/signin/core/browser/account_reconcilor.cc
@@ -13,6 +13,7 @@
 #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 "components/signin/core/browser/profile_oauth2_token_service.h"
 #include "components/signin/core/browser/signin_client.h"
 #include "components/signin/core/browser/signin_metrics.h"
@@ -250,6 +251,8 @@
 }
 
 void AccountReconcilor::StartReconcile() {
+  reconcile_start_time_ = base::Time::Now();
+
   if (!IsProfileConnected() || !client_->AreSigninCookiesAllowed()) {
     VLOG(1) << "AccountReconcilor::StartReconcile: !connected or no cookies";
     return;
@@ -440,6 +443,13 @@
 }
 
 void AccountReconcilor::CalculateIfReconcileIsDone() {
+  base::TimeDelta duration = base::Time::Now() - reconcile_start_time_;
+  // Record the duration if reconciliation was underway and now it is over.
+  if (is_reconcile_started_ && add_to_cookie_.empty()) {
+    signin_metrics::LogSigninAccountReconciliationDuration(duration,
+        !error_during_last_reconcile_);
+  }
+
   is_reconcile_started_ = !add_to_cookie_.empty();
   if (!is_reconcile_started_)
     VLOG(1) << "AccountReconcilor::CalculateIfReconcileIsDone: done";
diff --git a/components/signin/core/browser/account_reconcilor.h b/components/signin/core/browser/account_reconcilor.h
index 6008c543..ba6ec7c 100644
--- a/components/signin/core/browser/account_reconcilor.h
+++ b/components/signin/core/browser/account_reconcilor.h
@@ -92,6 +92,8 @@
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileNoopMultiple);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, StartReconcileAddToCookie);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
+                           SignoutAfterErrorDoesNotRecordUma);
+  FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
                            StartReconcileRemoveFromCookie);
   FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest,
                            StartReconcileAddToCookieTwice);
@@ -176,7 +178,7 @@
   // True while the reconcilor is busy checking or managing the accounts in
   // this profile.
   bool is_reconcile_started_;
-  base::Time m_reconcile_start_time_;
+  base::Time reconcile_start_time_;
 
   // True iff this is the first time the reconcilor is executing.
   bool first_execution_;
diff --git a/components/signin/core/browser/signin_metrics.cc b/components/signin/core/browser/signin_metrics.cc
index 9cc6773..a154d11 100644
--- a/components/signin/core/browser/signin_metrics.cc
+++ b/components/signin/core/browser/signin_metrics.cc
@@ -53,6 +53,15 @@
   }
 }
 
+void LogSigninAccountReconciliationDuration(base::TimeDelta duration,
+                                            bool successful) {
+  if (successful) {
+    UMA_HISTOGRAM_TIMES("Signin.Reconciler.Duration.Success", duration);
+  } else {
+    UMA_HISTOGRAM_TIMES("Signin.Reconciler.Duration.Failure", duration);
+  }
+}
+
 void LogSigninProfile(bool is_first_run, base::Time install_date) {
   // Track whether or not the user signed in during the first run of Chrome.
   UMA_HISTOGRAM_BOOLEAN("Signin.DuringFirstRun", is_first_run);
diff --git a/components/signin/core/browser/signin_metrics.h b/components/signin/core/browser/signin_metrics.h
index 9c6ecda..fa7242b 100644
--- a/components/signin/core/browser/signin_metrics.h
+++ b/components/signin/core/browser/signin_metrics.h
@@ -198,6 +198,12 @@
                                     bool is_first_reconcile,
                                     int pre_count_gaia_cookies);
 
+// Logs duration of a single execution of AccountReconciler to UMA histograms.
+// |duration| - How long execution of AccountReconciler took.
+// |successful| - True if AccountReconciler was successful.
+void LogSigninAccountReconciliationDuration(base::TimeDelta duration,
+                                            bool successful);
+
 // Track a successful signin.
 void LogSigninAddAccount();
 
diff --git a/content/browser/devtools/protocol/emulation_handler.cc b/content/browser/devtools/protocol/emulation_handler.cc
index 9659991..cae9f00 100644
--- a/content/browser/devtools/protocol/emulation_handler.cc
+++ b/content/browser/devtools/protocol/emulation_handler.cc
@@ -35,19 +35,11 @@
   return result;
 }
 
-// When continuously applying device emulation, we wait for compositor frame
-// before applying new values. If the frame does not arrive during this
-// timeout, we proceed anyway.
-const int kFrameTimeoutMs = 67;
-
 }  // namespace
 
 EmulationHandler::EmulationHandler(page::PageHandler* page_handler)
     : touch_emulation_enabled_(false),
       device_emulation_enabled_(false),
-      device_emulation_needs_update_(false),
-      device_emulation_waiting_for_frame_(false),
-      frame_timer_(new base::Timer(false, false)),
       page_handler_(page_handler),
       host_(nullptr)
 {
@@ -67,14 +59,14 @@
 
   host_ = host;
   UpdateTouchEventEmulationState();
-  ApplyDeviceEmulationState();
+  UpdateDeviceEmulationState();
 }
 
 void EmulationHandler::Detached() {
   touch_emulation_enabled_ = false;
   device_emulation_enabled_ = false;
   UpdateTouchEventEmulationState();
-  ApplyDeviceEmulationState();
+  UpdateDeviceEmulationState();
 }
 
 Response EmulationHandler::SetGeolocationOverride(
@@ -200,7 +192,7 @@
 
   device_emulation_enabled_ = true;
   device_emulation_params_ = params;
-  DeviceEmulationNeedsUpdate();
+  UpdateDeviceEmulationState();
   return Response::OK();
 }
 
@@ -209,7 +201,7 @@
     return Response::OK();
 
   device_emulation_enabled_ = false;
-  DeviceEmulationNeedsUpdate();
+  UpdateDeviceEmulationState();
   return Response::OK();
 }
 
@@ -233,31 +225,11 @@
     GetWebContents()->SetForceDisableOverscrollContent(enabled);
 }
 
-void EmulationHandler::DeviceEmulationNeedsUpdate() {
-  device_emulation_needs_update_ = true;
-  if (!device_emulation_waiting_for_frame_)
-    ApplyDeviceEmulationState();
-}
-
-void EmulationHandler::OnSwapCompositorFrame() {
-  frame_timer_->Stop();
-  device_emulation_waiting_for_frame_ = false;
-  if (device_emulation_needs_update_)
-    ApplyDeviceEmulationState();
-}
-
-void EmulationHandler::ApplyDeviceEmulationState() {
-  device_emulation_needs_update_ = false;
+void EmulationHandler::UpdateDeviceEmulationState() {
   RenderWidgetHostImpl* widget_host =
       host_ ? host_->GetRenderWidgetHost() : nullptr;
   if (!widget_host)
     return;
-  device_emulation_waiting_for_frame_ = true;
-  frame_timer_->Start(
-      FROM_HERE,
-      base::TimeDelta::FromMilliseconds(kFrameTimeoutMs),
-      base::Bind(&EmulationHandler::OnSwapCompositorFrame,
-                 base::Unretained(this)));
   if (device_emulation_enabled_) {
     widget_host->Send(new ViewMsg_EnableDeviceEmulation(
         widget_host->GetRoutingID(), device_emulation_params_));
diff --git a/content/browser/devtools/protocol/emulation_handler.h b/content/browser/devtools/protocol/emulation_handler.h
index 4f1e26f..c2a4bd3 100644
--- a/content/browser/devtools/protocol/emulation_handler.h
+++ b/content/browser/devtools/protocol/emulation_handler.h
@@ -5,7 +5,6 @@
 #ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_EMULATION_HANDLER_H_
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_EMULATION_HANDLER_H_
 
-#include "base/timer/timer.h"
 #include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h"
 #include "content/browser/devtools/protocol/page_handler.h"
 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
@@ -33,7 +32,6 @@
 
   void SetRenderFrameHost(RenderFrameHostImpl* host);
   void Detached();
-  void OnSwapCompositorFrame();
 
   Response SetGeolocationOverride(double* latitude,
                                   double* longitude,
@@ -61,18 +59,13 @@
  private:
   WebContentsImpl* GetWebContents();
   void UpdateTouchEventEmulationState();
-
-  void DeviceEmulationNeedsUpdate();
-  void ApplyDeviceEmulationState();
+  void UpdateDeviceEmulationState();
 
   bool touch_emulation_enabled_;
   std::string touch_emulation_configuration_;
 
   bool device_emulation_enabled_;
   blink::WebDeviceEmulationParams device_emulation_params_;
-  bool device_emulation_needs_update_;
-  bool device_emulation_waiting_for_frame_;
-  scoped_ptr<base::Timer> frame_timer_;
 
   page::PageHandler* page_handler_;
   RenderFrameHostImpl* host_;
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index 4c5b369..fb191fb 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -716,8 +716,6 @@
     page_handler_->OnSwapCompositorFrame(base::get<1>(param).metadata);
   if (input_handler_)
     input_handler_->OnSwapCompositorFrame(base::get<1>(param).metadata);
-  if (emulation_handler_)
-    emulation_handler_->OnSwapCompositorFrame();
   if (frame_trace_recorder_ && tracing_handler_->did_initiate_recording()) {
     frame_trace_recorder_->OnSwapCompositorFrame(
         current_ ? current_->host() : nullptr,
@@ -731,8 +729,6 @@
     page_handler_->OnSynchronousSwapCompositorFrame(frame_metadata);
   if (input_handler_)
     input_handler_->OnSwapCompositorFrame(frame_metadata);
-  if (emulation_handler_)
-    emulation_handler_->OnSwapCompositorFrame();
   if (frame_trace_recorder_ && tracing_handler_->did_initiate_recording()) {
     frame_trace_recorder_->OnSynchronousSwapCompositorFrame(
         current_ ? current_->host() : nullptr,
diff --git a/content/browser/download/mhtml_generation_browsertest.cc b/content/browser/download/mhtml_generation_browsertest.cc
index 8bffabb..6ade20f 100644
--- a/content/browser/download/mhtml_generation_browsertest.cc
+++ b/content/browser/download/mhtml_generation_browsertest.cc
@@ -83,40 +83,6 @@
   EXPECT_GT(file_size, 100);  // Verify the actual file size.
 }
 
-// This test verifies how MHTML serialization handles frames that have
-// the same URI (especially about:blank URI) but different content.
-// It should preserve contents of all the frames.
-IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, LocalAboutBlankSubframes) {
-  base::FilePath path(temp_dir_.path());
-  path = path.Append(FILE_PATH_LITERAL("test-local-about-blank-subframes.mht"));
-
-  GenerateMHTML(path, embedded_test_server()->GetURL(
-                          "/download/local-about-blank-subframes.html"));
-  ASSERT_FALSE(HasFailure());
-
-  std::string mhtml;
-  ASSERT_TRUE(base::ReadFileToString(path, &mhtml));
-
-  // Make sure the contents of all frames are present.
-  // 1. Check for contents (this is insufficient as it can also hit the contents
-  //    in the iframe.srcdoc attribute).
-  EXPECT_THAT(mhtml, HasSubstr("main: acb0609d-eb10-4c26-83e2-ad8afb7b0ff3"));
-  EXPECT_THAT(mhtml, HasSubstr("sub1: b124df3a-d39f-47a1-ae04-5bb5d0bf549e"));
-  EXPECT_THAT(mhtml, HasSubstr("sub2: 07014068-604d-45ae-884f-a068cfe7bc0a"));
-  EXPECT_THAT(mhtml, HasSubstr("sub3: 06cc8fcc-c692-4a1a-a10f-1645b746e8f4"));
-  // 2. Count the number of text/html mhtml parts.
-  int count = 0;
-  size_t pos = 0;
-  for (;;) {
-    pos = mhtml.find("Content-Type: text/html", pos);
-    if (pos == std::string::npos)
-      break;
-    count++;
-    pos++;
-  }
-  EXPECT_EQ(4, count) << "Verify number of text/html parts in the mhtml output";
-}
-
 IN_PROC_BROWSER_TEST_F(MHTMLGenerationTest, InvalidPath) {
   base::FilePath path(FILE_PATH_LITERAL("/invalid/file/path"));
 
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index 6dfe0d9f..193ab945 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -796,8 +796,10 @@
     blink::WebRTCPeerConnectionHandlerClient* client,
     PeerConnectionDependencyFactory* dependency_factory)
     : client_(client),
+      is_closed_(false),
       dependency_factory_(dependency_factory),
       weak_factory_(this) {
+  CHECK(client_),
   g_peer_connection_handlers.Get().insert(this);
 }
 
@@ -817,13 +819,13 @@
 
 // static
 void RTCPeerConnectionHandler::DestructAllHandlers() {
+  // Copy g_peer_connection_handlers since releasePeerConnectionHandler will
+  // remove an item.
   std::set<RTCPeerConnectionHandler*> handlers(
       g_peer_connection_handlers.Get().begin(),
       g_peer_connection_handlers.Get().end());
-  for (auto handler : handlers) {
-    if (handler->client_)
-      handler->client_->releasePeerConnectionHandler();
-  }
+  for (auto* handler : handlers)
+    handler->client_->releasePeerConnectionHandler();
 }
 
 // static
@@ -1309,7 +1311,7 @@
 
 void RTCPeerConnectionHandler::CloseClientPeerConnection() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (client_)
+  if (!is_closed_)
     client_->closePeerConnection();
 }
 
@@ -1380,7 +1382,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   DVLOG(1) << "RTCPeerConnectionHandler::stop";
 
-  if (!client_ || !native_peer_connection_.get())
+  if (!is_closed_ || !native_peer_connection_.get())
     return;  // Already stopped.
 
   if (peer_connection_tracker_)
@@ -1388,9 +1390,8 @@
 
   native_peer_connection_->Close();
 
-  // The client_ pointer is not considered valid after this point and no further
-  // callbacks must be made.
-  client_ = nullptr;
+  // This object may no longer forward call backs to blink.
+  is_closed_ = true;
 }
 
 void RTCPeerConnectionHandler::OnSignalingChange(
@@ -1402,7 +1403,7 @@
       GetWebKitSignalingState(new_state);
   if (peer_connection_tracker_)
     peer_connection_tracker_->TrackSignalingStateChange(this, state);
-  if (client_)
+  if (!is_closed_)
     client_->didChangeSignalingState(state);
 }
 
@@ -1438,7 +1439,7 @@
       GetWebKitIceConnectionState(new_state);
   if (peer_connection_tracker_)
     peer_connection_tracker_->TrackIceConnectionStateChange(this, state);
-  if(client_)
+  if (!is_closed_)
     client_->didChangeICEConnectionState(state);
 }
 
@@ -1451,7 +1452,7 @@
   if (new_state == webrtc::PeerConnectionInterface::kIceGatheringComplete) {
     // If ICE gathering is completed, generate a NULL ICE candidate,
     // to signal end of candidates.
-    if (client_) {
+    if (!is_closed_) {
       blink::WebRTCICECandidate null_candidate;
       client_->didGenerateICECandidate(null_candidate);
     }
@@ -1508,7 +1509,7 @@
 
   track_metrics_.AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM,
                            s->webrtc_stream().get());
-  if (client_)
+  if (!is_closed_)
     client_->didAddRemoteStream(s->webkit_stream());
 }
 
@@ -1536,7 +1537,7 @@
         this, webkit_stream, PeerConnectionTracker::SOURCE_REMOTE);
   }
 
-  if (client_)
+  if (!is_closed_)
     client_->didRemoveRemoteStream(webkit_stream);
 }
 
@@ -1550,7 +1551,7 @@
         this, handler->channel().get(), PeerConnectionTracker::SOURCE_REMOTE);
   }
 
-  if (client_)
+  if (!is_closed_)
     client_->didAddRemoteDataChannel(handler.release());
 }
 
@@ -1579,7 +1580,7 @@
       NOTREACHED();
     }
   }
-  if (client_)
+  if (!is_closed_)
     client_->didGenerateICECandidate(web_candidate);
 }
 
diff --git a/content/renderer/media/rtc_peer_connection_handler.h b/content/renderer/media/rtc_peer_connection_handler.h
index 8e8af25..fa45d6a 100644
--- a/content/renderer/media/rtc_peer_connection_handler.h
+++ b/content/renderer/media/rtc_peer_connection_handler.h
@@ -225,8 +225,14 @@
 
   base::ThreadChecker thread_checker_;
 
-  // |client_| is a weak pointer, and is valid until stop() has returned.
-  blink::WebRTCPeerConnectionHandlerClient* client_;
+  // |client_| is a weak pointer to the blink object (blink::RTCPeerConnection)
+  // that owns this object.
+  // It is valid for the lifetime of this object.
+  blink::WebRTCPeerConnectionHandlerClient* const client_;
+  // True if this PeerConnection has been closed.
+  // After the PeerConnection has been closed, this object may no longer
+  // forward callbacks to blink.
+  bool is_closed_;
 
   // |dependency_factory_| is a raw pointer, and is valid for the lifetime of
   // RenderThreadImpl.
diff --git a/content/renderer/media/rtc_peer_connection_handler_unittest.cc b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
index 6cbdd1db..88fad70 100644
--- a/content/renderer/media/rtc_peer_connection_handler_unittest.cc
+++ b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
@@ -334,6 +334,11 @@
   pc_handler_.reset(NULL);
 }
 
+TEST_F(RTCPeerConnectionHandlerTest, DestructAllHandlers) {
+  EXPECT_CALL(*mock_client_.get(), releasePeerConnectionHandler())
+      .Times(1);
+  RTCPeerConnectionHandler::DestructAllHandlers();
+}
 TEST_F(RTCPeerConnectionHandlerTest, CreateOffer) {
   blink::WebRTCSessionDescriptionRequest request;
   blink::WebMediaConstraints options;
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc
index 0e8b8b7..b50eb09 100644
--- a/content/shell/browser/shell.cc
+++ b/content/shell/browser/shell.cc
@@ -68,7 +68,9 @@
       devtools_frontend_(NULL),
       is_fullscreen_(false),
       window_(NULL),
+#if defined(OS_MACOSX)
       url_edit_view_(NULL),
+#endif
       headless_(false) {
   const base::CommandLine& command_line =
       *base::CommandLine::ForCurrentProcess();
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h
index 05ec79e..9ef5be2 100644
--- a/content/shell/browser/shell.h
+++ b/content/shell/browser/shell.h
@@ -225,7 +225,9 @@
   bool is_fullscreen_;
 
   gfx::NativeWindow window_;
-  gfx::NativeEditView url_edit_view_;
+#if defined(OS_MACOSX)
+  NSTextField* url_edit_view_;
+#endif
 
   gfx::Size content_size_;
 
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index b74816c..5136dac 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -186,6 +186,31 @@
       <message name="IDS_IOS_VERSION_COPIED" desc="The message displayed when the version label is tapped (in About settings) [Length: 10em] [iOS only]">
         Copied
       </message>
+
+      <!-- Password Manager -->
+      <message name="IDS_IOS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT" desc="Info bar message to save a password. [Length: 60em]">
+        Do you want <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> to save your password for this site?
+      </message>
+      <message name="IDS_IOS_PASSWORD_MANAGER_SAVE_BUTTON" desc="Save button text for password manager [Length: 10em]">
+        Save
+      </message>
+      <message name="IDS_IOS_PASSWORD_MANAGER_BLACKLIST_BUTTON" desc="Button text for the 'Save Password' infobar's 'Never remember for this site' option [Length: 10em]">
+        Never
+      </message>
+
+      <!-- Password Generation -->
+      <message name="IDS_IOS_GENERATED_PASSWORD_ACCEPT" desc="The text of the button that accepts the generated password. [Length: 20em] [iOS only]">
+        Use Password
+      </message>
+      <message name="IDS_IOS_GENERATE_PASSWORD_LABEL" desc="Input accessory view label to generate a password. [Length: 20em] [iOS only]">
+        Generate Password
+      </message>
+      <message name="IDS_IOS_GENERATED_PASSWORD_PROMPT_DESCRIPTION" desc="The explanation text for the generated password prompt. [iOS only]">
+        Chrome will store this in your <ph name="BEGIN_LINK">BEGIN_LINK</ph>Google saved passwords<ph name="END_LINK">END_LINK</ph> and autofill it for you so you don't have to remember it yourself.
+      </message>
+      <message name="IDS_IOS_GENERATED_PASSWORD_PROMPT_TITLE" desc="The text of the button that accepts the generated password. [Length: 20em] [iOS only]">
+        Password Generated by Chrome
+      </message>
     </messages>
   </release>
 </grit>
diff --git a/ios/web/net/cookie_notification_bridge.mm b/ios/web/net/cookie_notification_bridge.mm
index 8ebb9a7..a610f00 100644
--- a/ios/web/net/cookie_notification_bridge.mm
+++ b/ios/web/net/cookie_notification_bridge.mm
@@ -14,13 +14,14 @@
 namespace web {
 
 CookieNotificationBridge::CookieNotificationBridge() {
-  observer_.reset([[NSNotificationCenter defaultCenter]
+  id<NSObject> observer = [[NSNotificationCenter defaultCenter]
       addObserverForName:NSHTTPCookieManagerCookiesChangedNotification
                   object:[NSHTTPCookieStorage sharedHTTPCookieStorage]
                    queue:nil
               usingBlock:^(NSNotification* notification) {
-                  OnNotificationReceived(notification);
-              }]);
+                OnNotificationReceived(notification);
+              }];
+  observer_.reset([observer retain]);
 }
 
 CookieNotificationBridge::~CookieNotificationBridge() {
diff --git a/mandoline/app/desktop/launcher_process.cc b/mandoline/app/desktop/launcher_process.cc
index 5a94a32..60f5e32 100644
--- a/mandoline/app/desktop/launcher_process.cc
+++ b/mandoline/app/desktop/launcher_process.cc
@@ -32,8 +32,6 @@
   if (!command_line->HasSwitch(switches::kMojoSingleProcess))
     command_line->AppendSwitch(switches::kEnableMultiprocess);
   command_line->AppendSwitch("use-new-edk");
-  // http://crbug.com/546644
-  command_line->AppendSwitch(switches::kMojoNoSandbox);
 
   bool trace_startup = command_line->HasSwitch(switches::kTraceStartup);
   if (trace_startup) {
diff --git a/mandoline/services/core_services/BUILD.gn b/mandoline/services/core_services/BUILD.gn
index f3b6ed7..8e093f8 100644
--- a/mandoline/services/core_services/BUILD.gn
+++ b/mandoline/services/core_services/BUILD.gn
@@ -27,11 +27,6 @@
     }
     deps += [ ":copy_files" ]
   }
-
-  if (!is_android) {
-    deps += [ "//third_party/icu:icudata" ]
-    resources = [ "$root_out_dir/icudtl.dat" ]
-  }
 }
 
 source_set("sources") {
diff --git a/mandoline/services/core_services/main.cc b/mandoline/services/core_services/main.cc
index e9d36ba..ef8c847 100644
--- a/mandoline/services/core_services/main.cc
+++ b/mandoline/services/core_services/main.cc
@@ -6,32 +6,6 @@
 #include "mojo/application/public/cpp/application_runner.h"
 #include "third_party/mojo/src/mojo/public/c/system/main.h"
 
-// TODO(erg): Much of this will be the same between mojo applications. Maybe we
-// could centralize this code?
-#if defined(OS_LINUX) && !defined(OS_ANDROID)
-#include "base/rand_util.h"
-#include "base/sys_info.h"
-#include "third_party/icu/source/i18n/unicode/timezone.h"
-
-// TODO(erg): Much of this was coppied from zygote_main_linux.cc
-extern "C" {
-void __attribute__((visibility("default"))) MojoSandboxWarm() {
-  base::RandUint64();
-  base::SysInfo::AmountOfPhysicalMemory();
-  base::SysInfo::MaxSharedMemorySize();
-  base::SysInfo::NumberOfProcessors();
-
-  // ICU DateFormat class (used in base/time_format.cc) needs to get the
-  // Olson timezone ID by accessing the zoneinfo files on disk. After
-  // TimeZone::createDefault is called once here, the timezone ID is
-  // cached and there's no more need to access the file system.
-  scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
-
-  // TODO(erg): Perform OpenSSL warmup; it wants access to /dev/urandom.
-}
-}
-#endif  // defined(OS_LINUX) && !defined(OS_ANDROID)
-
 MojoResult MojoMain(MojoHandle shell_handle) {
   mojo::ApplicationRunner runner(
       new core_services::CoreServicesApplicationDelegate);
diff --git a/mandoline/ui/desktop_ui/browser_window.cc b/mandoline/ui/desktop_ui/browser_window.cc
index a78e60ec..c049cf2 100644
--- a/mandoline/ui/desktop_ui/browser_window.cc
+++ b/mandoline/ui/desktop_ui/browser_window.cc
@@ -25,6 +25,7 @@
 #include "ui/mojo/init/ui_init.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/button/label_button.h"
+#include "ui/views/layout/layout_manager.h"
 #include "ui/views/mus/aura_init.h"
 #include "ui/views/mus/display_converter.h"
 #include "ui/views/mus/native_widget_mus.h"
@@ -69,6 +70,25 @@
   DISALLOW_COPY_AND_ASSIGN(ProgressView);
 };
 
+class BrowserWindow::LayoutManagerImpl : public views::LayoutManager {
+ public:
+  explicit LayoutManagerImpl(BrowserWindow* window) : window_(window) {}
+  ~LayoutManagerImpl() override {}
+
+ private:
+  // views::LayoutManager:
+  gfx::Size GetPreferredSize(const views::View* view) const override {
+    return gfx::Size();
+  }
+  void Layout(views::View* host) override {
+    window_->Layout(host);
+  }
+
+  BrowserWindow* window_;
+
+  DISALLOW_COPY_AND_ASSIGN(LayoutManagerImpl);
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 // BrowserWindow, public:
 
@@ -339,42 +359,6 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// BrowserWindow, views::LayoutManager implementation:
-
-gfx::Size BrowserWindow::GetPreferredSize(const views::View* view) const {
-  return gfx::Size();
-}
-
-void BrowserWindow::Layout(views::View* host) {
-  // TODO(fsamuel): All bounds should be in physical pixels.
-  gfx::Rect bounds_in_physical_pixels(host->bounds());
-  float inverse_device_pixel_ratio =
-      1.0f / root_->viewport_metrics().device_pixel_ratio;
-
-  gfx::Rect toolbar_bounds = gfx::ScaleToEnclosingRect(
-      bounds_in_physical_pixels, inverse_device_pixel_ratio);
-  toolbar_bounds.Inset(10, 10, 10, toolbar_bounds.height() - 40);
-  toolbar_view_->SetBoundsRect(toolbar_bounds);
-
-  find_bar_view_->SetBoundsRect(toolbar_bounds);
-
-  gfx::Rect progress_bar_bounds(toolbar_bounds.x(), toolbar_bounds.bottom() + 2,
-                                toolbar_bounds.width(), 5);
-
-  // The content view bounds are in physical pixels.
-  gfx::Rect content_bounds(DIPSToPixels(progress_bar_bounds.x()),
-                           DIPSToPixels(progress_bar_bounds.bottom() + 10), 0,
-                           0);
-  content_bounds.set_width(DIPSToPixels(progress_bar_bounds.width()));
-  content_bounds.set_height(host->bounds().height() - content_bounds.y() -
-                            DIPSToPixels(10));
-  content_->SetBounds(content_bounds);
-
-  // The omnibox view bounds are in physical pixels.
-  omnibox_view_->SetBounds(bounds_in_physical_pixels);
-}
-
-////////////////////////////////////////////////////////////////////////////////
 // BrowserWindow, FindBarDelegate implementation:
 
 void BrowserWindow::OnDoFind(const std::string& find, bool forward) {
@@ -408,7 +392,8 @@
   progress_bar_ = new ProgressView;
   widget_delegate->GetContentsView()->AddChildView(toolbar_view_);
   widget_delegate->GetContentsView()->AddChildView(progress_bar_);
-  widget_delegate->GetContentsView()->SetLayoutManager(this);
+  widget_delegate->GetContentsView()->SetLayoutManager(
+      new LayoutManagerImpl(this));
 
   find_bar_view_ = new FindBarView(this);
   widget_delegate->GetContentsView()->AddChildView(find_bar_view_);
@@ -437,4 +422,33 @@
   omnibox_view_->MoveToFront();
 }
 
+void BrowserWindow::Layout(views::View* host) {
+  // TODO(fsamuel): All bounds should be in physical pixels.
+  gfx::Rect bounds_in_physical_pixels(host->bounds());
+  float inverse_device_pixel_ratio =
+      1.0f / root_->viewport_metrics().device_pixel_ratio;
+
+  gfx::Rect toolbar_bounds = gfx::ScaleToEnclosingRect(
+      bounds_in_physical_pixels, inverse_device_pixel_ratio);
+  toolbar_bounds.Inset(10, 10, 10, toolbar_bounds.height() - 40);
+  toolbar_view_->SetBoundsRect(toolbar_bounds);
+
+  find_bar_view_->SetBoundsRect(toolbar_bounds);
+
+  gfx::Rect progress_bar_bounds(toolbar_bounds.x(), toolbar_bounds.bottom() + 2,
+                                toolbar_bounds.width(), 5);
+
+  // The content view bounds are in physical pixels.
+  gfx::Rect content_bounds(DIPSToPixels(progress_bar_bounds.x()),
+                           DIPSToPixels(progress_bar_bounds.bottom() + 10), 0,
+                           0);
+  content_bounds.set_width(DIPSToPixels(progress_bar_bounds.width()));
+  content_bounds.set_height(host->bounds().height() - content_bounds.y() -
+                            DIPSToPixels(10));
+  content_->SetBounds(content_bounds);
+
+  // The omnibox view bounds are in physical pixels.
+  omnibox_view_->SetBounds(bounds_in_physical_pixels);
+}
+
 }  // namespace mandoline
diff --git a/mandoline/ui/desktop_ui/browser_window.h b/mandoline/ui/desktop_ui/browser_window.h
index 5852f0e..04c5c38 100644
--- a/mandoline/ui/desktop_ui/browser_window.h
+++ b/mandoline/ui/desktop_ui/browser_window.h
@@ -15,7 +15,6 @@
 #include "mandoline/ui/desktop_ui/public/interfaces/view_embedder.mojom.h"
 #include "mojo/application/public/cpp/interface_factory.h"
 #include "mojo/common/weak_binding_set.h"
-#include "ui/views/layout/layout_manager.h"
 #include "url/gurl.h"
 
 namespace mojo {
@@ -31,6 +30,7 @@
 
 namespace views {
 class AuraInit;
+class View;
 }
 
 namespace mandoline {
@@ -45,7 +45,6 @@
                       public web_view::mojom::WebViewClient,
                       public ViewEmbedder,
                       public mojo::InterfaceFactory<ViewEmbedder>,
-                      public views::LayoutManager,
                       public FindBarDelegate {
  public:
   BrowserWindow(mojo::ApplicationImpl* app,
@@ -61,6 +60,8 @@
   void GoForward();
 
  private:
+  class LayoutManagerImpl;
+
   ~BrowserWindow() override;
 
   float DIPSToPixels(float value) const;
@@ -93,10 +94,6 @@
               mojo::InterfaceRequest<ViewEmbedder> request) override;
 
 
-  // Overridden from views::LayoutManager:
-  gfx::Size GetPreferredSize(const views::View* view) const override;
-  void Layout(views::View* host) override;
-
   // Overridden from FindBarDelegate:
   void OnDoFind(const std::string& find, bool forward) override;
   void OnHideFindBar() override;
@@ -104,6 +101,8 @@
   void Init(mus::Window* root);
   void EmbedOmnibox();
 
+  void Layout(views::View* host);
+
   mojo::ApplicationImpl* app_;
   scoped_ptr<ui::mojo::UIInit> ui_init_;
   scoped_ptr<views::AuraInit> aura_init_;
diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc
index 4ef4f65..a50acf9 100644
--- a/media/audio/mac/audio_low_latency_input_mac.cc
+++ b/media/audio/mac/audio_low_latency_input_mac.cc
@@ -199,6 +199,8 @@
   if (!manager_->MaybeChangeBufferSize(input_device_id_, audio_unit_, 1,
                                        number_of_frames_,
                                        &buffer_size_was_changed_)) {
+    result = kAudioUnitErr_FormatNotSupported;
+    HandleError(result);
     return false;
   }
   DLOG_IF(WARNING, buffer_size_was_changed_) << "IO buffer size was changed to "
diff --git a/media/ozone/media_ozone_platform.cc b/media/ozone/media_ozone_platform.cc
index cda1396..15d52c6 100644
--- a/media/ozone/media_ozone_platform.cc
+++ b/media/ozone/media_ozone_platform.cc
@@ -52,7 +52,7 @@
   return new MediaOzonePlatformStub;
 }
 
-MediaOzonePlatform* CreateMediaOzonePlatformTest() {
+MediaOzonePlatform* CreateMediaOzonePlatformHeadless() {
   return new MediaOzonePlatformStub;
 }
 
diff --git a/mojo/application/public/cpp/BUILD.gn b/mojo/application/public/cpp/BUILD.gn
index 12b0e51..578463f 100644
--- a/mojo/application/public/cpp/BUILD.gn
+++ b/mojo/application/public/cpp/BUILD.gn
@@ -26,6 +26,7 @@
     "application_impl.h",
     "application_runner.h",
     "connect.h",
+    "initialize_base_and_icu.cc",
     "interface_factory.h",
     "interface_factory_impl.h",
     "lib/app_lifetime_helper.cc",
@@ -44,6 +45,7 @@
 
   deps = [
     "//base",
+    "//base:i18n",
     "//mojo/application/public/interfaces",
     "//mojo/common",
     "//mojo/environment:chromium",
diff --git a/mojo/application/public/cpp/initialize_base_and_icu.cc b/mojo/application/public/cpp/initialize_base_and_icu.cc
new file mode 100644
index 0000000..4635d49
--- /dev/null
+++ b/mojo/application/public/cpp/initialize_base_and_icu.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.
+
+// This file declares a raw symbol and should be included only once in a
+// certain binary target. This needs to be run before we raise the sandbox,
+// which means that it can't use mojo. Our runners will dig around in the
+// symbol table and run this before the mojo system is initialized.
+
+#include "base/files/file.h"
+#include "base/i18n/icu_util.h"
+#include "base/rand_util.h"
+#include "base/sys_info.h"
+#include "third_party/icu/source/i18n/unicode/timezone.h"
+#include "third_party/mojo/src/mojo/public/c/system/types.h"
+
+extern "C" {
+#if defined(WIN32)
+__declspec(dllexport) void __cdecl
+#else
+void __attribute__((visibility("default")))
+#endif
+InitializeBase(const uint8* icu_data) {
+  base::RandUint64();
+  base::SysInfo::AmountOfPhysicalMemory();
+  base::SysInfo::NumberOfProcessors();
+#if defined(OS_POSIX) && !defined(OS_MACOSX)
+  base::SysInfo::MaxSharedMemorySize();
+#endif
+
+  // Initialize core ICU. We must perform the full initialization before we
+  // initialize icu::TimeZone subsystem because otherwise ICU gets in a state
+  // where the timezone data is disconnected from the locale data which can
+  // cause crashes.
+  CHECK(base::i18n::InitializeICUFromRawMemory(icu_data));
+
+  // ICU DateFormat class (used in base/time_format.cc) needs to get the
+  // Olson timezone ID by accessing the zoneinfo files on disk. After
+  // TimeZone::createDefault is called once here, the timezone ID is
+  // cached and there's no more need to access the file system.
+  scoped_ptr<icu::TimeZone> zone(icu::TimeZone::createDefault());
+}
+}
diff --git a/mojo/runner/BUILD.gn b/mojo/runner/BUILD.gn
index 803b4ff..84bc12b 100644
--- a/mojo/runner/BUILD.gn
+++ b/mojo/runner/BUILD.gn
@@ -52,7 +52,7 @@
     ]
     deps += [
       "//components/tracing:startup_tracing",
-      "//mojo/shell",
+      "//third_party/icu:icudata",
     ]
   } else {
     sources += [
@@ -106,6 +106,7 @@
   deps = [
     "//mojo/runner/host:switches",
     "//base",
+    "//base:i18n",
   ]
 }
 
@@ -147,6 +148,7 @@
   public_deps = [
     ":init",
     ":switches",
+    "//mojo/shell",
   ]
 
   if (!is_component_build) {
@@ -327,10 +329,12 @@
     deps = [
       "//mojo/services/test_service:test_app",
       "//mojo/services/test_service:test_request_tracker_app",
+      "//third_party/icu:icudata",
     ]
 
     # Directories can't be specified as sources so pass manually to the script.
     args = [
+      "--files=" + rebase_path("$root_out_dir/icudtl.dat", root_build_dir),
       "--files=" + rebase_path("$root_out_dir/test_app", root_build_dir),
       "--files=" +
           rebase_path("$root_out_dir/test_request_tracker_app", root_build_dir),
diff --git a/mojo/runner/android/main.cc b/mojo/runner/android/main.cc
index fdce835..3980c22 100644
--- a/mojo/runner/android/main.cc
+++ b/mojo/runner/android/main.cc
@@ -40,9 +40,6 @@
 
 namespace {
 
-// Tag for logging.
-const char kLogTag[] = "chromium";
-
 // Command line argument for the communication fifo.
 const char kFifoPath[] = "fifo-path";
 
diff --git a/mojo/runner/context.cc b/mojo/runner/context.cc
index 014a66a..850cb5a 100644
--- a/mojo/runner/context.cc
+++ b/mojo/runner/context.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/i18n/icu_util.h"
 #include "base/lazy_instance.h"
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
@@ -70,7 +71,7 @@
   manager->RegisterContentHandler("application/pdf", GURL("mojo:pdf_viewer"));
   manager->RegisterContentHandler("image/gif", GURL("mojo:html_viewer"));
   manager->RegisterContentHandler("image/jpeg", GURL("mojo:html_viewer"));
-  manager->RegisterContentHandler("image/png", GURL("mojo:png_viewer"));
+  manager->RegisterContentHandler("image/png", GURL("mojo:html_viewer"));
   manager->RegisterContentHandler("text/css", GURL("mojo:html_viewer"));
   manager->RegisterContentHandler("text/html", GURL("mojo:html_viewer"));
   manager->RegisterContentHandler("text/plain", GURL("mojo:html_viewer"));
@@ -198,6 +199,10 @@
         "mojo_runner.trace");
   }
 
+  // ICU data is a thing every part of the system needs. This here warms
+  // up the copy of ICU in the mojo runner.
+  CHECK(base::i18n::InitializeICU());
+
   EnsureEmbedderIsInitialized();
   task_runners_.reset(
       new TaskRunners(base::MessageLoop::current()->task_runner()));
diff --git a/mojo/runner/host/BUILD.gn b/mojo/runner/host/BUILD.gn
index b534287..4227baa 100644
--- a/mojo/runner/host/BUILD.gn
+++ b/mojo/runner/host/BUILD.gn
@@ -62,6 +62,7 @@
     ":switches",
     "//base",
     "//base:base_static",
+    "//base:i18n",
     "//mojo/gles2",
     "//mojo/message_pump",
     "//mojo/platform_handle:platform_handle_impl",
diff --git a/mojo/runner/host/child_process.cc b/mojo/runner/host/child_process.cc
index d90358f..fac23ec 100644
--- a/mojo/runner/host/child_process.cc
+++ b/mojo/runner/host/child_process.cc
@@ -9,6 +9,7 @@
 #include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/files/file_path.h"
+#include "base/i18n/icu_util.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -24,6 +25,7 @@
 #include "mojo/runner/child/child_controller.mojom.h"
 #include "mojo/runner/host/native_application_support.h"
 #include "mojo/runner/host/switches.h"
+#include "mojo/runner/init.h"
 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 #include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
 #include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h"
@@ -293,22 +295,17 @@
     app_library = mojo::runner::LoadNativeApplication(
         command_line.GetSwitchValuePath(switches::kChildProcess));
 
+    base::i18n::InitializeICU();
+    CallLibraryEarlyInitialization(app_library);
+
 #if defined(OS_LINUX) && !defined(OS_ANDROID)
     if (command_line.HasSwitch(switches::kEnableSandbox)) {
-      // Warm parts of base.
+      // Warm parts of base in the copy of base in the mojo runner.
       base::RandUint64();
       base::SysInfo::AmountOfPhysicalMemory();
       base::SysInfo::MaxSharedMemorySize();
       base::SysInfo::NumberOfProcessors();
 
-      // Do whatever warming that the mojo application wants.
-      typedef void (*SandboxWarmFunction)();
-      SandboxWarmFunction sandbox_warm = reinterpret_cast<SandboxWarmFunction>(
-          base::GetFunctionPointerFromNativeLibrary(app_library,
-                                                    "MojoSandboxWarm"));
-      if (sandbox_warm)
-        sandbox_warm();
-
       // TODO(erg,jln): Allowing access to all of /dev/shm/ makes it easy to
       // spy on other shared memory using processes. This is a temporary hack
       // so that we have some sandbox until we have proper shared memory
diff --git a/mojo/runner/host/in_process_native_runner.cc b/mojo/runner/host/in_process_native_runner.cc
index 19cc88c..ee5e9e3 100644
--- a/mojo/runner/host/in_process_native_runner.cc
+++ b/mojo/runner/host/in_process_native_runner.cc
@@ -12,6 +12,7 @@
 #include "base/threading/platform_thread.h"
 #include "mojo/runner/host/native_application_support.h"
 #include "mojo/runner/host/out_of_process_native_runner.h"
+#include "mojo/runner/init.h"
 
 namespace mojo {
 namespace runner {
@@ -57,6 +58,7 @@
   // TODO(vtl): ScopedNativeLibrary doesn't have a .get() method!
   base::NativeLibrary app_library = LoadNativeApplication(app_path_);
   app_library_.Reset(app_library);
+  CallLibraryEarlyInitialization(app_library);
   RunNativeApplication(app_library, application_request_.Pass());
   app_completed_callback_runner_.Run();
   app_completed_callback_runner_.Reset();
diff --git a/mojo/runner/init.cc b/mojo/runner/init.cc
index a5cc9e1..b76dfc6 100644
--- a/mojo/runner/init.cc
+++ b/mojo/runner/init.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "base/debug/debugger.h"
 #include "base/files/file_path.h"
+#include "base/i18n/icu_util.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/strings/string_split.h"
@@ -60,5 +61,23 @@
   }
 }
 
+void CallLibraryEarlyInitialization(base::NativeLibrary app_library) {
+  // Do whatever warming that the mojo application wants.
+  typedef void (*LibraryEarlyInitFunction)(const uint8*);
+  LibraryEarlyInitFunction init_function =
+      reinterpret_cast<LibraryEarlyInitFunction>(
+          base::GetFunctionPointerFromNativeLibrary(app_library,
+                                                    "InitializeBase"));
+  if (init_function) {
+    // Get the ICU data that we prewarmed in the runner and then pass it to
+    // the copy of icu in the mojo binary that we're running.
+    const uint8* icu_data = base::i18n::GetRawIcuMemory();
+    init_function(icu_data);
+  }
+
+  // TODO(erg): All chromium binaries load base. We might want to make a
+  // general system for other people.
+}
+
 }  // namespace runner
 }  // namespace mojo
diff --git a/mojo/runner/init.h b/mojo/runner/init.h
index c4e8abd..879886c 100644
--- a/mojo/runner/init.h
+++ b/mojo/runner/init.h
@@ -5,6 +5,8 @@
 #ifndef MOJO_RUNNER_INIT_H_
 #define MOJO_RUNNER_INIT_H_
 
+#include "base/native_library.h"
+
 namespace mojo {
 namespace runner {
 
@@ -13,6 +15,10 @@
 
 void WaitForDebuggerIfNecessary();
 
+// Calls "LibraryEarlyInitialization" in |app_library| if it exists. We do
+// common initialization there now.
+void CallLibraryEarlyInitialization(base::NativeLibrary app_library);
+
 }  // namespace runner
 }  // namespace mojo
 
diff --git a/styleguide/c++/c++11.html b/styleguide/c++/c++11.html
index 61f7c8e..ee12414 100644
--- a/styleguide/c++/c++11.html
+++ b/styleguide/c++/c++11.html
@@ -80,7 +80,7 @@
 <td><a href="http://en.cppreference.com/w/cpp/language/auto">
 auto specifier</a></td>
 <td>Use according to the <a
-href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#auto">Google
+href="https://google.github.io/styleguide/cppguide.html#auto">Google
 Style Guide on <code>auto</code></a>. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/OQyYSfH9m2M">Discussion thread</a>. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/5-Bt3BJzAo0">Another discussion thread</a>.</td>
 </tr>
 
@@ -155,7 +155,7 @@
 <code>base::Callback</code> instead, because they offer protection against a
 large class of object lifetime mistakes. Don't use default captures
 (<code>[=]</code>, <code>[&amp;]</code> &ndash; <a
-  href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Lambda_expressions">Google Style Guide</a>).
+  href="https://google.github.io/styleguide/cppguide.html#Lambda_expressions">Google Style Guide</a>).
 Lambdas are typically useful as a parameter to methods or
 functions that will use them immediately, such as those in
 <code>&lt;algorithm&gt;</code>. <a
@@ -183,8 +183,7 @@
 <td>Allows non-static class members to be initialized at their definitions (outside constructors)</td>
 <td><a href="http://en.cppreference.com/w/cpp/language/data_members">
 Non-static data members</a></td>
-<td><a href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Initialization">Google
-Style Guide</a>.
+<td>
 <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/zqB-DySA4V0">Discussion thread</a>
 </td>
 </tr>
@@ -197,7 +196,7 @@
 nullptr</a></td>
 <td>Recommended for new code.
 <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/4mijeJHzxLg">Discussion thread</a>.
-<a href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#0_and_nullptr/NULL">Google Style Guide</a>.
+<a href="https://google.github.io/styleguide/cppguide.html#0_and_nullptr/NULL">Google Style Guide</a>.
 <code>std::nullptr_t</code> can be used too.
 </td>
 </tr>
@@ -312,7 +311,7 @@
 <td><a href="http://en.cppreference.com/w/cpp/language/constexpr">
 constexpr specifier</a></td>
 <td>Doesn't work in MSVS2013. Reevalute once it does. <a
-href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Use_of_constexpr">Google
+href="https://google.github.io/styleguide/cppguide.html#Use_of_constexpr">Google
 Style Guide on <code>constexpr</code></a></td>
 </tr>
 
@@ -394,7 +393,7 @@
 Fundamental types</a></td>
 <td>Doesn't work in MSVS2013. Reevaluate once it does.  Non-UTF-8 text is
 banned by the
-<a href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Non-ASCII_Characters">
+<a href="https://google.github.io/styleguide/cppguide.html#Non-ASCII_Characters">
 C++ Style Guide</a>. However, may be useful for
 consuming non-ASCII data. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/ME2kL7_Kvyk">Discussion thread</a></td>
 </tr>
@@ -512,7 +511,7 @@
 <td><a href="http://en.cppreference.com/w/cpp/error/exception">
 std::exception</a></td>
 <td>Exceptions are banned by the
-<a href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Exceptions"> C++ Style Guide</a>. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/8i4tMqNpHhg">Discussion thread</a></td>
+<a href="https://google.github.io/styleguide/cppguide.html#Exceptions"> C++ Style Guide</a>. <a href="https://groups.google.com/a/chromium.org/forum/#!topic/chromium-dev/8i4tMqNpHhg">Discussion thread</a></td>
 </tr>
 
 <tr>
@@ -574,7 +573,7 @@
 <td>Obtains the address of an object even with overloaded <code>operator&amp;</code></td>
 <td><a href="http://en.cppreference.com/w/cpp/memory/addressof">std::addressof</a></td>
 <td>Usage should be rare as
-<a href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Operator_Overloading">
+<a href="https://google.github.io/styleguide/cppguide.html#Operator_Overloading">
 Operator Overloading</a> is rare and <code>&amps;</code>
 should suffice in most cases. May be preferable
 over <code>&amps;</code> for performing object
@@ -856,7 +855,7 @@
 <td><code>std::shared_ptr</code></td>
 <td>Allows shared ownership of a pointer through reference counts</td>
 <td><a href="http://en.cppreference.com/w/cpp/memory/shared_ptr">std::shared_ptr</a></td>
-<td><a href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Ownership_and_Smart_Pointers">
+<td><a href="https://google.github.io/styleguide/cppguide.html#Ownership_and_Smart_Pointers">
 Ownership and Smart Pointers</a></td>
 </tr>
 
@@ -971,7 +970,7 @@
 <td><code>std::unique_ptr&lt;<i>type</i>&gt;</code></td>
 <td>Defines a pointer with clear and unambiguous ownership</td>
 <td>TODO: documentation link</td>
-<td><a href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Ownership_and_Smart_Pointers">
+<td><a href="https://google.github.io/styleguide/cppguide.html#Ownership_and_Smart_Pointers">
 Ownership and Smart Pointers</a></td>
 </tr>
 
@@ -1000,7 +999,7 @@
 <td>Allows a weak reference to a <code>std::shared_ptr</code></td>
 <td><a href="http://en.cppreference.com/w/cpp/memory/weak_ptr">
 std::weak_ptr</a></td>
-<td><a href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Ownership_and_Smart_Pointers">
+<td><a href="https://google.github.io/styleguide/cppguide.html#Ownership_and_Smart_Pointers">
 Ownership and Smart Pointers</a></td>
 </tr>
 
@@ -1023,7 +1022,7 @@
 std::codecvt_utf8_utf16</a>
 </td>
 <td>Non-UTF-8 text is banned by the
-<a href="https://google-styleguide.googlecode.com/svn/trunk/cppguide.html#Non-ASCII_Characters">
+<a href="https://google.github.io/styleguide/cppguide.html#Non-ASCII_Characters">
 C++ Style Guide</a>. However, may be useful for
 consuming non-ASCII data.</td>
 </tr>
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 406bb09..ad9e912 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -1,11 +1,7 @@
 {
   "Android GN": {
     "additional_compile_targets": [
-      "chrome_public_apk",
-      "chrome_public_test_apk",
-      "content_shell_apk",
-      "mandoline:all",
-      "system_webview_apk"
+      "gn_all"
     ],
     "gtest_tests": [
       {
@@ -129,13 +125,7 @@
   },
   "Android GN (dbg)": {
     "additional_compile_targets": [
-      "blimp_tests",
-      "chrome_public_apk",
-      "chrome_public_test_apk",
-      "content_shell_apk",
-      "content_shell_test_apk",
-      "mandoline:all",
-      "system_webview_apk"
+      "gn_all"
     ]
   },
   "Android Tests": {
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 4733b71..a48f66a 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -332,8 +332,6 @@
 
 crbug.com/548904 [ Linux Win7 ] fast/writing-mode/Kusa-Makura-background-canvas.html [ Failure Pass ]
 
-crbug.com/552643 compositing/perpendicular-layer-sorting.html [ Pass Failure ]
-
 crbug.com/552433 svg/W3C-SVG-1.1/coords-units-02-b.svg [ Pass Failure ]
 crbug.com/552433 [ Linux Mac Win10 Win7 ] svg/dom/length-list-parser.html [ Failure Pass ]
 crbug.com/552433 [ Linux Mac Win10 Win7 ] svg/transforms/text-with-pattern-with-svg-transform.svg [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/http/tests/push_messaging/push-subscription-stringification.html b/third_party/WebKit/LayoutTests/http/tests/push_messaging/push-subscription-stringification.html
index 80df533..c901557 100644
--- a/third_party/WebKit/LayoutTests/http/tests/push_messaging/push-subscription-stringification.html
+++ b/third_party/WebKit/LayoutTests/http/tests/push_messaging/push-subscription-stringification.html
@@ -27,13 +27,19 @@
         })
         .then(function(pushSubscription) {
             var reflectedObject = JSON.parse(JSON.stringify(pushSubscription));
-            var expectedProperties = ['endpoint'];
 
-            assert_equals(expectedProperties.length,
-                          Object.getOwnPropertyNames(reflectedObject).length);
+            assert_own_property(reflectedObject, 'endpoint');
+            assert_equals(reflectedObject.endpoint, pushSubscription.endpoint);
 
-            for (var key of expectedProperties)
-                assert_equals(reflectedObject[key], pushSubscription[key]);
+            assert_own_property(reflectedObject, 'keys');
+            assert_own_property(reflectedObject.keys, 'p256dh');
+
+            var key = btoa(String.fromCharCode.apply(null, new Uint8Array(pushSubscription.getKey('p256dh'))));
+
+            // Convert |key| to the base64url alphabet by replacing non-URL safe characters.
+            key = key.replace(/\//g, '_').replace(/\+/g, '-');
+
+            assert_equals(reflectedObject.keys.p256dh, key);
 
             return service_worker_unregister_and_done(test, workerScope);
         })
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/category-filter.html b/third_party/WebKit/LayoutTests/inspector/tracing/category-filter.html
index f3eebd9..2855323 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/category-filter.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/category-filter.html
@@ -52,18 +52,19 @@
     for (var i = 0; i < rootRecord.presentationChildren().length; ++i)
         rootRecord.presentationChildren()[i].setCollapsed(false);
 
+    var categoryFilter = WebInspector.panels.timeline._filters._categoryFilter;
     InspectorTest.addResult("Original records");
-    WebInspector.panels.timeline._categoryFilter.notifyFilterChanged();
+    categoryFilter.notifyFilterChanged();
     InspectorTest.dumpVisibleRecords();
 
     InspectorTest.addResult("Visible records when 'loading' is disabled");
     WebInspector.TimelineUIUtils.categories().loading.hidden = true;
-    WebInspector.panels.timeline._categoryFilter.notifyFilterChanged();
+    categoryFilter.notifyFilterChanged();
     InspectorTest.dumpVisibleRecords();
 
     InspectorTest.addResult("Visible records when 'scripting' is disabled");
     WebInspector.TimelineUIUtils.categories().scripting.hidden = true;
-    WebInspector.panels.timeline._categoryFilter.notifyFilterChanged();
+    categoryFilter.notifyFilterChanged();
     InspectorTest.dumpVisibleRecords();
 
     InspectorTest.completeTest();
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-filtering.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-filtering.html
index 681608b..2d1ca2c 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-filtering.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-filtering.html
@@ -79,7 +79,8 @@
     dumpRecords();
 
     InspectorTest.addResult("Filtered by 'bar':");
-    panel._filters._textFilterUI.setValue("bar");
+    var textFilterUI = panel._filters._textFilterUI;
+    textFilterUI.setValue("bar");
     dumpRecords();
 
     InspectorTest.addResult("Collapsed 'bar04' and 'foo13':");
@@ -94,7 +95,7 @@
     dumpRecords();
 
     InspectorTest.addResult("Filtered by 'foo':");
-    panel._filters._textFilterUI.setValue("foo");
+    textFilterUI.setValue("foo");
     dumpRecords();
 
     InspectorTest.completeTest();
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/perpendicular-layer-sorting-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/perpendicular-layer-sorting-expected.png
new file mode 100644
index 0000000..3e75710
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/compositing/perpendicular-layer-sorting-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/perpendicular-layer-sorting-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/perpendicular-layer-sorting-expected.png
index 3e75710..bf790f1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/perpendicular-layer-sorting-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/perpendicular-layer-sorting-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/perpendicular-layer-sorting-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/perpendicular-layer-sorting-expected.png
index 3e75710..bf790f1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/perpendicular-layer-sorting-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/perpendicular-layer-sorting-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/perpendicular-layer-sorting-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/perpendicular-layer-sorting-expected.png
index e35cf11..2f7a463 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/perpendicular-layer-sorting-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/perpendicular-layer-sorting-expected.png
Binary files differ
diff --git a/third_party/WebKit/Source/bindings/core/v8/NPV8Object.h b/third_party/WebKit/Source/bindings/core/v8/NPV8Object.h
index 543af66..89f8513 100644
--- a/third_party/WebKit/Source/bindings/core/v8/NPV8Object.h
+++ b/third_party/WebKit/Source/bindings/core/v8/NPV8Object.h
@@ -34,6 +34,8 @@
 #include "bindings/core/v8/V8DOMWrapper.h"
 #include "core/CoreExport.h"
 
+#include "platform/heap/Handle.h"
+
 // Chromium uses npruntime.h from the Chromium source repository under
 // third_party/npapi/bindings.
 #include <bindings/npruntime.h>
@@ -56,7 +58,7 @@
 public:
     NPObject object;
     v8::Persistent<v8::Object> v8Object;
-    LocalDOMWindow* rootObject;
+    RawPtrWillBeUntracedMember<LocalDOMWindow> rootObject;
 };
 
 struct PrivateIdentifier {
diff --git a/third_party/WebKit/Source/core/css/StyleRuleImport.cpp b/third_party/WebKit/Source/core/css/StyleRuleImport.cpp
index 0fcd5af..90eddf9 100644
--- a/third_party/WebKit/Source/core/css/StyleRuleImport.cpp
+++ b/third_party/WebKit/Source/core/css/StyleRuleImport.cpp
@@ -61,6 +61,7 @@
 
 DEFINE_TRACE_AFTER_DISPATCH(StyleRuleImport)
 {
+    visitor->trace(m_styleSheetClient);
     visitor->trace(m_parentStyleSheet);
     visitor->trace(m_mediaQueries);
     visitor->trace(m_styleSheet);
diff --git a/third_party/WebKit/Source/core/css/StyleRuleImport.h b/third_party/WebKit/Source/core/css/StyleRuleImport.h
index bcea473..2c795e1 100644
--- a/third_party/WebKit/Source/core/css/StyleRuleImport.h
+++ b/third_party/WebKit/Source/core/css/StyleRuleImport.h
@@ -68,8 +68,14 @@
             m_ownerRule->setCSSStyleSheet(href, baseURL, charset, sheet);
         }
         String debugName() const override { return "ImportedStyleSheetClient"; }
+
+        DEFINE_INLINE_TRACE()
+        {
+            visitor->trace(m_ownerRule);
+        }
+
     private:
-        StyleRuleImport* m_ownerRule;
+        RawPtrWillBeMember<StyleRuleImport> m_ownerRule;
     };
 
     void setCSSStyleSheet(const String& href, const KURL& baseURL, const String& charset, const CSSStyleSheetResource*);
diff --git a/third_party/WebKit/Source/core/html/forms/DateTimeChooser.h b/third_party/WebKit/Source/core/html/forms/DateTimeChooser.h
index 7f46aa6..8a14fe3 100644
--- a/third_party/WebKit/Source/core/html/forms/DateTimeChooser.h
+++ b/third_party/WebKit/Source/core/html/forms/DateTimeChooser.h
@@ -33,6 +33,7 @@
 
 #include "core/CoreExport.h"
 #include "platform/geometry/IntRect.h"
+#include "platform/heap/Handle.h"
 #include "wtf/Allocator.h"
 #include "wtf/RefCounted.h"
 #include "wtf/text/WTFString.h"
@@ -70,13 +71,15 @@
 };
 
 // For pickers like color pickers and date pickers.
-class CORE_EXPORT DateTimeChooser : public RefCounted<DateTimeChooser> {
+class CORE_EXPORT DateTimeChooser : public RefCountedWillBeGarbageCollectedFinalized<DateTimeChooser> {
 public:
     virtual ~DateTimeChooser();
 
     virtual void endChooser() = 0;
     // Returns a root AXObject in the DateTimeChooser if it's available.
     virtual AXObject* rootAXObject() = 0;
+
+    DEFINE_INLINE_VIRTUAL_TRACE() { }
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp
index 16fa618..9d60f71 100644
--- a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp
@@ -185,6 +185,7 @@
 DEFINE_TRACE(PickerIndicatorElement)
 {
     visitor->trace(m_pickerIndicatorOwner);
+    visitor->trace(m_chooser);
     HTMLDivElement::trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h
index f24f1f40..fe14ee6 100644
--- a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h
+++ b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h
@@ -83,7 +83,7 @@
     HTMLInputElement* hostInput();
 
     RawPtrWillBeMember<PickerIndicatorOwner> m_pickerIndicatorOwner;
-    RefPtr<DateTimeChooser> m_chooser;
+    RefPtrWillBeMember<DateTimeChooser> m_chooser;
 };
 
 DEFINE_TYPE_CASTS(PickerIndicatorElement, Element, element, element->isPickerIndicatorElement(), element.isPickerIndicatorElement());
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.cpp b/third_party/WebKit/Source/core/loader/EmptyClients.cpp
index c9ba86a..1759fdc 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.cpp
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.cpp
@@ -98,9 +98,9 @@
     return nullptr;
 }
 
-PassRefPtr<DateTimeChooser> EmptyChromeClient::openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&)
+PassRefPtrWillBeRawPtr<DateTimeChooser> EmptyChromeClient::openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&)
 {
-    return PassRefPtr<DateTimeChooser>();
+    return nullptr;
 }
 
 void EmptyChromeClient::openTextDataListChooser(HTMLInputElement&)
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h
index fde63d5..4e4967bc8 100644
--- a/third_party/WebKit/Source/core/loader/EmptyClients.h
+++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -144,7 +144,7 @@
     void enumerateChosenDirectory(FileChooser*) override {}
 
     PassOwnPtrWillBeRawPtr<ColorChooser> openColorChooser(LocalFrame*, ColorChooserClient*, const Color&) override;
-    PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) override;
+    PassRefPtrWillBeRawPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) override;
     void openTextDataListChooser(HTMLInputElement&) override;
 
     void openFileChooser(LocalFrame*, PassRefPtr<FileChooser>) override;
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h
index 3a28d45..431a1f0b 100644
--- a/third_party/WebKit/Source/core/page/ChromeClient.h
+++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -168,7 +168,7 @@
     //    returns true, if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
     //  - <datalist> UI for date/time input types regardless of
     //    ENABLE(INPUT_MULTIPLE_FIELDS_UI)
-    virtual PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) = 0;
+    virtual PassRefPtrWillBeRawPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) = 0;
 
     virtual void openTextDataListChooser(HTMLInputElement&)= 0;
 
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp
index d0fe9f2..6fde3ad 100644
--- a/third_party/WebKit/Source/core/page/Page.cpp
+++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -561,6 +561,7 @@
 #if ENABLE(OILPAN)
     visitor->trace(m_animator);
     visitor->trace(m_autoscrollController);
+    visitor->trace(m_chromeClient);
     visitor->trace(m_dragCaretController);
     visitor->trace(m_dragController);
     visitor->trace(m_focusController);
diff --git a/third_party/WebKit/Source/core/page/Page.h b/third_party/WebKit/Source/core/page/Page.h
index 0f8a3c4..70e7ade 100644
--- a/third_party/WebKit/Source/core/page/Page.h
+++ b/third_party/WebKit/Source/core/page/Page.h
@@ -222,7 +222,7 @@
 
     RefPtrWillBeMember<PageAnimator> m_animator;
     const OwnPtrWillBeMember<AutoscrollController> m_autoscrollController;
-    ChromeClient* m_chromeClient;
+    RawPtrWillBeMember<ChromeClient> m_chromeClient;
     const OwnPtrWillBeMember<DragCaretController> m_dragCaretController;
     const OwnPtrWillBeMember<DragController> m_dragController;
     const OwnPtrWillBeMember<FocusController> m_focusController;
diff --git a/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp b/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp
index 577acb3..fd7c8a4 100644
--- a/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp
+++ b/third_party/WebKit/Source/core/svg/animation/SVGSMILElement.cpp
@@ -39,6 +39,7 @@
 #include "core/svg/SVGURIReference.h"
 #include "core/svg/animation/SMILTimeContainer.h"
 #include "platform/FloatConversion.h"
+#include "platform/heap/Handle.h"
 #include "wtf/MathExtras.h"
 #include "wtf/StdLibExtras.h"
 #include "wtf/Vector.h"
@@ -129,6 +130,7 @@
     DEFINE_INLINE_VIRTUAL_TRACE()
     {
         visitor->trace(m_animation);
+        visitor->trace(m_condition);
         EventListener::trace(visitor);
     }
 
@@ -143,7 +145,7 @@
     void handleEvent(ExecutionContext*, Event*) override;
 
     RawPtrWillBeMember<SVGSMILElement> m_animation;
-    SVGSMILElement::Condition* m_condition;
+    RawPtrWillBeMember<SVGSMILElement::Condition> m_condition;
 };
 
 bool ConditionEventListener::operator==(const EventListener& listener) const
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
index a567915..2b7db80 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -62,12 +62,9 @@
     this._model.addEventListener(WebInspector.TimelineModel.Events.BufferUsage, this._onTracingBufferUsage, this);
     this._model.addEventListener(WebInspector.TimelineModel.Events.RetrieveEventsProgress, this._onRetrieveEventsProgress, this);
 
-    this._categoryFilter = new WebInspector.TimelineCategoryFilter();
-    this._durationFilter = new WebInspector.TimelineIsLongFilter();
-    this._textFilter = new WebInspector.TimelineTextFilter();
-    this._model.addFilter(this._categoryFilter);
-    this._model.addFilter(this._durationFilter);
-    this._model.addFilter(this._textFilter);
+    this._filters = new WebInspector.TimelineFilters();
+    for (var filter of this._filters.filters())
+        this._model.addFilter(filter);
     this._model.addFilter(new WebInspector.TimelineStaticFilter());
 
     /** @type {!Array.<!WebInspector.TimelineModeView>} */
@@ -163,8 +160,6 @@
 WebInspector.TimelinePanel.rowHeight = 18;
 WebInspector.TimelinePanel.headerHeight = 20;
 
-WebInspector.TimelinePanel.durationFilterPresetsMs = [0, 1, 15];
-
 WebInspector.TimelinePanel.prototype = {
     /**
      * @override
@@ -297,7 +292,7 @@
     _addModeView: function(modeView)
     {
         modeView.setWindowTimes(this.windowStartTime(), this.windowEndTime());
-        modeView.refreshRecords(this._textFilter._regex);
+        modeView.refreshRecords(this._filters.searchRegExp());
         this._stackView.appendView(modeView.view(), "timelinePanelTimelineStackSplitViewState", undefined, 112);
         modeView.view().addEventListener(WebInspector.SplitWidget.Events.SidebarSizeChanged, this._sidebarResized, this);
         this._currentViews.push(modeView);
@@ -350,8 +345,7 @@
         this._panelToolbar.appendToolbarItem(clearButton);
         this._panelToolbar.appendSeparator();
 
-        this._filterBar = this._createFilterBar();
-        this._panelToolbar.appendToolbarItem(this._filterBar.filterButton());
+        this._panelToolbar.appendToolbarItem(this._filters.filterButton());
 
         var garbageCollectButton = new WebInspector.ToolbarButton(WebInspector.UIString("Collect garbage"), "garbage-collect-toolbar-item");
         garbageCollectButton.addEventListener("click", this._garbageCollectButtonClicked, this);
@@ -402,75 +396,7 @@
         this._progressToolbarItem.setVisible(false);
         this._panelToolbar.appendToolbarItem(this._progressToolbarItem);
 
-        this.element.appendChild(this._filterBar.filtersElement());
-    },
-
-    /**
-     * @return {!WebInspector.FilterBar}
-     */
-    _createFilterBar: function()
-    {
-        this._filterBar = new WebInspector.FilterBar("timelinePanel");
-        this._filters = {};
-        this._filters._textFilterUI = new WebInspector.TextFilterUI();
-        this._filters._textFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._textFilterChanged, this);
-        this._filterBar.addFilter(this._filters._textFilterUI);
-
-        var durationOptions = [];
-        for (var presetIndex = 0; presetIndex < WebInspector.TimelinePanel.durationFilterPresetsMs.length; ++presetIndex) {
-            var durationMs = WebInspector.TimelinePanel.durationFilterPresetsMs[presetIndex];
-            var durationOption = {};
-            if (!durationMs) {
-                durationOption.label = WebInspector.UIString("All");
-                durationOption.title = WebInspector.UIString("Show all records");
-            } else {
-                durationOption.label = WebInspector.UIString("\u2265 %dms", durationMs);
-                durationOption.title = WebInspector.UIString("Hide records shorter than %dms", durationMs);
-            }
-            durationOption.value = durationMs;
-            durationOptions.push(durationOption);
-        }
-        this._filters._durationFilterUI = new WebInspector.ComboBoxFilterUI(durationOptions);
-        this._filters._durationFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._durationFilterChanged, this);
-        this._filterBar.addFilter(this._filters._durationFilterUI);
-
-        this._filters._categoryFiltersUI = {};
-        var categories = WebInspector.TimelineUIUtils.categories();
-        for (var categoryName in categories) {
-            var category = categories[categoryName];
-            if (!category.visible)
-                continue;
-            var filter = new WebInspector.CheckboxFilterUI(category.name, category.title);
-            filter.setColor(category.fillColorStop0, category.borderColor);
-            this._filters._categoryFiltersUI[category.name] = filter;
-            filter.addEventListener(WebInspector.FilterUI.Events.FilterChanged, this._categoriesFilterChanged.bind(this, categoryName), this);
-            this._filterBar.addFilter(filter);
-        }
-        return this._filterBar;
-    },
-
-    _textFilterChanged: function(event)
-    {
-        var searchQuery = this._filters._textFilterUI.value();
-        this.searchCanceled();
-        this._textFilter.setRegex(searchQuery ? createPlainTextSearchRegex(searchQuery, "i") : null);
-    },
-
-    _durationFilterChanged: function()
-    {
-        var duration = this._filters._durationFilterUI.value();
-        var minimumRecordDuration = parseInt(duration, 10);
-        this._durationFilter.setMinimumRecordDuration(minimumRecordDuration);
-    },
-
-    /**
-     * @param {string} name
-     */
-    _categoriesFilterChanged: function(name)
-    {
-        var categories = WebInspector.TimelineUIUtils.categories();
-        categories[name].hidden = !this._filters._categoryFiltersUI[name].checked();
-        this._categoryFilter.notifyFilterChanged();
+        this.element.appendChild(this._filters.filtersElement());
     },
 
     /**
@@ -577,7 +503,7 @@
     {
         for (var i = 0; i < this._currentViews.length; ++i) {
             var view = this._currentViews[i];
-            view.refreshRecords(this._textFilter._regex);
+            view.refreshRecords(this._filters.searchRegExp());
         }
         this._updateSelectionDetails();
     },
@@ -610,20 +536,17 @@
         }
         this._flameChart = null;
         if (viewMode === WebInspector.TimelinePanel.ViewMode.FlameChart) {
-            this._filterBar.filterButton().setEnabled(false);
-            this._filterBar.filtersElement().classList.toggle("hidden", true);
+            this._filters.setEnabled(false);
             this._flameChart = new WebInspector.TimelineFlameChartView(this, this._model, this._frameModel);
             this._flameChart.enableNetworkPane(this._captureNetworkSetting.get());
             this._addModeView(this._flameChart);
         } else if (viewMode === WebInspector.TimelinePanel.ViewMode.Waterfall) {
-            this._filterBar.filterButton().setEnabled(true);
-            this._filterBar.filtersElement().classList.toggle("hidden", !this._filterBar.filtersToggled());
+            this._filters.setEnabled(true);
             var timelineView = new WebInspector.TimelineView(this, this._model);
             this._addModeView(timelineView);
             timelineView.setFrameModel(this._frameModel);
         } else if (viewMode === WebInspector.TimelinePanel.ViewMode.CallTree || viewMode === WebInspector.TimelinePanel.ViewMode.BottomUp) {
-            this._filterBar.filterButton().setEnabled(false);
-            this._filterBar.filtersElement().classList.toggle("hidden", true);
+            this._filters.setEnabled(false);
             var innerView = viewMode === WebInspector.TimelinePanel.ViewMode.BottomUp ? new WebInspector.BottomUpTimelineTreeView(this._model) : new WebInspector.CallTreeTimelineTreeView(this._model);
             var treeView = new WebInspector.TimelineTreeModeView(this, innerView);
             this._addModeView(treeView);
@@ -958,7 +881,7 @@
      */
     _updateSearchHighlight: function(revealRecord, shouldJump, jumpBackwards)
     {
-        if (!this._textFilter.isEmpty() || !this._searchRegex) {
+        if (this._filters.searchRegExp() || !this._searchRegex) {
             this._clearHighlight();
             return;
         }
@@ -1702,19 +1625,11 @@
 
 WebInspector.TimelineTextFilter.prototype = {
     /**
-     * @return {boolean}
+     * @param {?RegExp} regExp
      */
-    isEmpty: function()
+    _setRegExp: function(regExp)
     {
-        return !this._regex;
-    },
-
-    /**
-     * @param {?RegExp} regex
-     */
-    setRegex: function(regex)
-    {
-        this._regex = regex;
+        this._regExp = regExp;
         this.notifyFilterChanged();
     },
 
@@ -1725,7 +1640,7 @@
      */
     accept: function(event)
     {
-        return !this._regex || WebInspector.TimelineUIUtils.testContentMatching(event, this._regex);
+        return !this._regExp || WebInspector.TimelineUIUtils.testContentMatching(event, this._regExp);
     },
 
     __proto__: WebInspector.TimelineModel.Filter.prototype
@@ -1946,3 +1861,131 @@
         return false;
     }
 }
+
+/**
+ * @constructor
+ */
+WebInspector.TimelineFilters = function()
+{
+    this._categoryFilter = new WebInspector.TimelineCategoryFilter();
+    this._durationFilter = new WebInspector.TimelineIsLongFilter();
+    this._textFilter = new WebInspector.TimelineTextFilter();
+    this._filters = [this._categoryFilter, this._durationFilter, this._textFilter];
+
+    this._createFilterBar();
+}
+
+WebInspector.TimelineFilters._durationFilterPresetsMs = [0, 1, 15];
+
+WebInspector.TimelineFilters.prototype = {
+    /**
+     * @return {!Array<!WebInspector.TimelineModel.Filter>}
+     */
+    filters: function()
+    {
+        return this._filters;
+    },
+
+    /**
+     * @param {boolean} enabled
+     */
+    setEnabled: function(enabled)
+    {
+        this.filterButton().setEnabled(enabled);
+        this.filtersElement().classList.toggle("hidden", !enabled || !this._filterBar.filtersToggled());
+    },
+
+    /**
+     * @return {?RegExp}
+     */
+    searchRegExp: function()
+    {
+        return this._textFilter._regExp;
+    },
+
+    /**
+     * @return {!WebInspector.ToolbarItem}
+     */
+    filterButton: function()
+    {
+        return this._filterBar.filterButton();
+    },
+
+    /**
+     * @return {!Element}
+     */
+    filtersElement: function()
+    {
+        return this._filterBar.filtersElement();
+    },
+
+    _createFilterBar: function()
+    {
+        this._filterBar = new WebInspector.FilterBar("timelinePanel");
+
+        this._textFilterUI = new WebInspector.TextFilterUI();
+        this._textFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, textFilterChanged, this);
+        this._filterBar.addFilter(this._textFilterUI);
+
+        var durationOptions = [];
+        for (var durationMs of WebInspector.TimelineFilters._durationFilterPresetsMs) {
+            var durationOption = {};
+            if (!durationMs) {
+                durationOption.label = WebInspector.UIString("All");
+                durationOption.title = WebInspector.UIString("Show all records");
+            } else {
+                durationOption.label = WebInspector.UIString("\u2265 %dms", durationMs);
+                durationOption.title = WebInspector.UIString("Hide records shorter than %dms", durationMs);
+            }
+            durationOption.value = durationMs;
+            durationOptions.push(durationOption);
+        }
+        var durationFilterUI = new WebInspector.ComboBoxFilterUI(durationOptions);
+        durationFilterUI.addEventListener(WebInspector.FilterUI.Events.FilterChanged, durationFilterChanged, this);
+        this._filterBar.addFilter(durationFilterUI);
+
+        var categoryFiltersUI = {};
+        var categories = WebInspector.TimelineUIUtils.categories();
+        for (var categoryName in categories) {
+            var category = categories[categoryName];
+            if (!category.visible)
+                continue;
+            var filter = new WebInspector.CheckboxFilterUI(category.name, category.title);
+            filter.setColor(category.fillColorStop0, category.borderColor);
+            categoryFiltersUI[category.name] = filter;
+            filter.addEventListener(WebInspector.FilterUI.Events.FilterChanged, categoriesFilterChanged.bind(this, categoryName));
+            this._filterBar.addFilter(filter);
+        }
+        return this._filterBar;
+
+        /**
+         * @this {WebInspector.TimelineFilters}
+         */
+        function textFilterChanged()
+        {
+            var searchQuery = this._textFilterUI.value();
+            this._textFilter._setRegExp(searchQuery ? createPlainTextSearchRegex(searchQuery, "i") : null);
+        }
+
+        /**
+         * @this {WebInspector.TimelineFilters}
+         */
+        function durationFilterChanged()
+        {
+            var duration = durationFilterUI.value();
+            var minimumRecordDuration = parseInt(duration, 10);
+            this._durationFilter.setMinimumRecordDuration(minimumRecordDuration);
+        }
+
+        /**
+         * @param {string} name
+         * @this {WebInspector.TimelineFilters}
+         */
+        function categoriesFilterChanged(name)
+        {
+            var categories = WebInspector.TimelineUIUtils.categories();
+            categories[name].hidden = !categoryFiltersUI[name].checked();
+            this._categoryFilter.notifyFilterChanged();
+        }
+    }
+};
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js b/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js
index 856b8e3..fd0c7e5 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/FilterBar.js
@@ -629,10 +629,9 @@
     },
 
     /**
-     * @param {string} typeName
      * @return {*}
      */
-    value: function(typeName)
+    value: function()
     {
         var option = this._options[this._filterComboBox.selectedIndex()];
         return option.value;
diff --git a/third_party/WebKit/Source/modules/push_messaging/PushSubscription.cpp b/third_party/WebKit/Source/modules/push_messaging/PushSubscription.cpp
index a114ff4..007b19b 100644
--- a/third_party/WebKit/Source/modules/push_messaging/PushSubscription.cpp
+++ b/third_party/WebKit/Source/modules/push_messaging/PushSubscription.cpp
@@ -10,10 +10,12 @@
 #include "bindings/core/v8/V8ObjectBuilder.h"
 #include "modules/push_messaging/PushError.h"
 #include "modules/serviceworkers/ServiceWorkerRegistration.h"
+#include "platform/RuntimeEnabledFeatures.h"
 #include "public/platform/Platform.h"
 #include "public/platform/modules/push_messaging/WebPushProvider.h"
 #include "public/platform/modules/push_messaging/WebPushSubscription.h"
 #include "wtf/OwnPtr.h"
+#include "wtf/text/Base64.h"
 
 namespace blink {
 
@@ -71,8 +73,14 @@
     V8ObjectBuilder result(scriptState);
     result.addString("endpoint", endpoint());
 
-    // TODO(peter): Include |p256dh| in the serialized JSON blob if the intended
-    // serialization behavior gets defined in the spec.
+    if (RuntimeEnabledFeatures::pushMessagingDataEnabled()) {
+        ASSERT(m_p256dh);
+
+        V8ObjectBuilder keys(scriptState);
+        keys.add("p256dh", WTF::base64URLEncode(static_cast<const char*>(m_p256dh->data()), m_p256dh->byteLength()));
+
+        result.add("keys", keys);
+    }
 
     return result.scriptValue();
 }
diff --git a/third_party/WebKit/Source/modules/push_messaging/PushSubscription.idl b/third_party/WebKit/Source/modules/push_messaging/PushSubscription.idl
index 775d63b..7a59bc5 100644
--- a/third_party/WebKit/Source/modules/push_messaging/PushSubscription.idl
+++ b/third_party/WebKit/Source/modules/push_messaging/PushSubscription.idl
@@ -18,5 +18,5 @@
     [RuntimeEnabled=PushMessagingData] ArrayBuffer? getKey(PushEncryptionKeyName name);
     [CallWith=ScriptState] Promise<boolean> unsubscribe();
 
-    serializer = { attribute };
+    serializer;
 };
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
index 11feeba..cb3e93d 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -603,7 +603,7 @@
     return controller.release();
 }
 
-PassRefPtr<DateTimeChooser> ChromeClientImpl::openDateTimeChooser(DateTimeChooserClient* pickerClient, const DateTimeChooserParameters& parameters)
+PassRefPtrWillBeRawPtr<DateTimeChooser> ChromeClientImpl::openDateTimeChooser(DateTimeChooserClient* pickerClient, const DateTimeChooserParameters& parameters)
 {
     notifyPopupOpeningObservers();
 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.h b/third_party/WebKit/Source/web/ChromeClientImpl.h
index f687f87..9324144 100644
--- a/third_party/WebKit/Source/web/ChromeClientImpl.h
+++ b/third_party/WebKit/Source/web/ChromeClientImpl.h
@@ -107,7 +107,7 @@
     void printDelegate(LocalFrame*) override;
     void annotatedRegionsChanged() override;
     PassOwnPtrWillBeRawPtr<ColorChooser> openColorChooser(LocalFrame*, ColorChooserClient*, const Color&) override;
-    PassRefPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) override;
+    PassRefPtrWillBeRawPtr<DateTimeChooser> openDateTimeChooser(DateTimeChooserClient*, const DateTimeChooserParameters&) override;
     void openFileChooser(LocalFrame*, PassRefPtr<FileChooser>) override;
     void enumerateChosenDirectory(FileChooser*) override;
     void setCursor(const Cursor&, LocalFrame* localRoot) override;
diff --git a/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp b/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp
index 670f97a..789345d 100644
--- a/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp
+++ b/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp
@@ -58,15 +58,21 @@
     m_popup = m_chromeClient->openPagePopup(this);
 }
 
-PassRefPtr<DateTimeChooserImpl> DateTimeChooserImpl::create(ChromeClientImpl* chromeClient, DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
+PassRefPtrWillBeRawPtr<DateTimeChooserImpl> DateTimeChooserImpl::create(ChromeClientImpl* chromeClient, DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
 {
-    return adoptRef(new DateTimeChooserImpl(chromeClient, client, parameters));
+    return adoptRefWillBeNoop(new DateTimeChooserImpl(chromeClient, client, parameters));
 }
 
 DateTimeChooserImpl::~DateTimeChooserImpl()
 {
 }
 
+DEFINE_TRACE(DateTimeChooserImpl)
+{
+    visitor->trace(m_chromeClient);
+    DateTimeChooser::trace(visitor);
+}
+
 void DateTimeChooserImpl::endChooser()
 {
     if (!m_popup)
@@ -184,7 +190,7 @@
 
 void DateTimeChooserImpl::setValueAndClosePopup(int numValue, const String& stringValue)
 {
-    RefPtr<DateTimeChooserImpl> protector(this);
+    RefPtrWillBeRawPtr<DateTimeChooserImpl> protector(this);
     if (numValue >= 0)
         setValue(stringValue);
     endChooser();
diff --git a/third_party/WebKit/Source/web/DateTimeChooserImpl.h b/third_party/WebKit/Source/web/DateTimeChooserImpl.h
index 07cce09..ab0db16 100644
--- a/third_party/WebKit/Source/web/DateTimeChooserImpl.h
+++ b/third_party/WebKit/Source/web/DateTimeChooserImpl.h
@@ -43,13 +43,15 @@
 
 class DateTimeChooserImpl final : public DateTimeChooser, public PagePopupClient {
 public:
-    static PassRefPtr<DateTimeChooserImpl> create(ChromeClientImpl*, DateTimeChooserClient*, const DateTimeChooserParameters&);
+    static PassRefPtrWillBeRawPtr<DateTimeChooserImpl> create(ChromeClientImpl*, DateTimeChooserClient*, const DateTimeChooserParameters&);
     ~DateTimeChooserImpl() override;
 
     // DateTimeChooser functions:
     void endChooser() override;
     AXObject* rootAXObject() override;
 
+    DECLARE_VIRTUAL_TRACE();
+
 private:
     DateTimeChooserImpl(ChromeClientImpl*, DateTimeChooserClient*, const DateTimeChooserParameters&);
     // PagePopupClient functions:
@@ -63,7 +65,7 @@
     Element& ownerElement() override;
     void didClosePopup() override;
 
-    ChromeClientImpl* m_chromeClient;
+    RawPtrWillBeMember<ChromeClientImpl> m_chromeClient;
     DateTimeChooserClient* m_client;
     PagePopup* m_popup;
     DateTimeChooserParameters m_parameters;
diff --git a/third_party/WebKit/Source/web/ExternalDateTimeChooser.h b/third_party/WebKit/Source/web/ExternalDateTimeChooser.h
index 19ef587..faa89f73 100644
--- a/third_party/WebKit/Source/web/ExternalDateTimeChooser.h
+++ b/third_party/WebKit/Source/web/ExternalDateTimeChooser.h
@@ -38,7 +38,7 @@
 
 class ExternalDateTimeChooser final : public DateTimeChooser {
 public:
-    static PassRefPtr<ExternalDateTimeChooser> create(ChromeClientImpl*, WebViewClient*, DateTimeChooserClient*, const DateTimeChooserParameters&);
+    static PassRefPtrWillBeRawPtr<ExternalDateTimeChooser> create(ChromeClientImpl*, WebViewClient*, DateTimeChooserClient*, const DateTimeChooserParameters&);
     ~ExternalDateTimeChooser() override;
 
     // The following functions are for DateTimeChooserCompletion.
diff --git a/third_party/WebKit/Source/web/InspectorEmulationAgent.cpp b/third_party/WebKit/Source/web/InspectorEmulationAgent.cpp
index 1d1c071..b879e21 100644
--- a/third_party/WebKit/Source/web/InspectorEmulationAgent.cpp
+++ b/third_party/WebKit/Source/web/InspectorEmulationAgent.cpp
@@ -125,6 +125,7 @@
 
 DEFINE_TRACE(InspectorEmulationAgent)
 {
+    visitor->trace(m_webLocalFrameImpl);
     InspectorBaseAgent::trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/web/InspectorEmulationAgent.h b/third_party/WebKit/Source/web/InspectorEmulationAgent.h
index 2a7950c..4e87a7d 100644
--- a/third_party/WebKit/Source/web/InspectorEmulationAgent.h
+++ b/third_party/WebKit/Source/web/InspectorEmulationAgent.h
@@ -42,7 +42,7 @@
     explicit InspectorEmulationAgent(WebLocalFrameImpl*);
     WebViewImpl* webViewImpl();
 
-    WebLocalFrameImpl* m_webLocalFrameImpl;
+    RawPtrWillBeMember<WebLocalFrameImpl> m_webLocalFrameImpl;
 };
 
 
diff --git a/third_party/WebKit/Source/web/InspectorRenderingAgent.cpp b/third_party/WebKit/Source/web/InspectorRenderingAgent.cpp
index ded8466..b3674a1 100644
--- a/third_party/WebKit/Source/web/InspectorRenderingAgent.cpp
+++ b/third_party/WebKit/Source/web/InspectorRenderingAgent.cpp
@@ -99,6 +99,7 @@
 
 DEFINE_TRACE(InspectorRenderingAgent)
 {
+    visitor->trace(m_webLocalFrameImpl);
     InspectorBaseAgent::trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/web/InspectorRenderingAgent.h b/third_party/WebKit/Source/web/InspectorRenderingAgent.h
index 76f3c5a..2c447e3 100644
--- a/third_party/WebKit/Source/web/InspectorRenderingAgent.h
+++ b/third_party/WebKit/Source/web/InspectorRenderingAgent.h
@@ -37,7 +37,7 @@
     bool compositingEnabled(ErrorString*);
     WebViewImpl* webViewImpl();
 
-    WebLocalFrameImpl* m_webLocalFrameImpl;
+    RawPtrWillBeMember<WebLocalFrameImpl> m_webLocalFrameImpl;
 };
 
 
diff --git a/third_party/WebKit/Source/web/PopupMenuImpl.cpp b/third_party/WebKit/Source/web/PopupMenuImpl.cpp
index 7aff969..44ce540 100644
--- a/third_party/WebKit/Source/web/PopupMenuImpl.cpp
+++ b/third_party/WebKit/Source/web/PopupMenuImpl.cpp
@@ -254,6 +254,7 @@
 
 DEFINE_TRACE(PopupMenuImpl)
 {
+    visitor->trace(m_chromeClient);
     visitor->trace(m_ownerElement);
     PopupMenu::trace(visitor);
 }
diff --git a/third_party/WebKit/Source/web/PopupMenuImpl.h b/third_party/WebKit/Source/web/PopupMenuImpl.h
index b428f77..9313d03 100644
--- a/third_party/WebKit/Source/web/PopupMenuImpl.h
+++ b/third_party/WebKit/Source/web/PopupMenuImpl.h
@@ -54,7 +54,7 @@
     Locale& locale() override;
     void didClosePopup() override;
 
-    ChromeClientImpl* m_chromeClient;
+    RawPtrWillBeMember<ChromeClientImpl> m_chromeClient;
     RawPtrWillBeMember<HTMLSelectElement> m_ownerElement;
     PagePopup* m_popup;
     bool m_needsUpdate;
diff --git a/third_party/libjingle/README.chromium b/third_party/libjingle/README.chromium
index e0a9c11..459566d 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: 10609
+Revision: 10622
 License: BSD
 License File: source/talk/COPYING
 Security Critical: yes
diff --git a/tools/battor_agent/OWNERS b/tools/battor_agent/OWNERS
new file mode 100644
index 0000000..a90dd82
--- /dev/null
+++ b/tools/battor_agent/OWNERS
@@ -0,0 +1,3 @@
+charliea@chromium.org
+nednguyen@google.com
+zhenw@chromium.org
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index f71a853..77d9f9f 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -42957,6 +42957,11 @@
   </summary>
 </histogram>
 
+<histogram name="Signin.Reconciler.Duration">
+  <owner>rogerta@chromium.org</owner>
+  <summary>Records the execution time of the account reconciler.</summary>
+</histogram>
+
 <histogram name="Signin.Reconciler.ExternalCcResultTime.Completed">
   <owner>mlerman@chromium.org</owner>
   <summary>
@@ -81593,6 +81598,12 @@
   <affected-histogram name="Signin.Reconciler.RemovedFromCookieJar"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="Signin.Reconciler.Duration" separator=".">
+  <suffix name="Success" label="Successful execution of reconciler"/>
+  <suffix name="Failure" label="Failed execution of reconciler"/>
+  <affected-histogram name="Signin.Reconciler.Duration"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="SimpleCacheWithOrWithoutIndex">
   <affected-histogram name="SimpleCache.SyncCreatePlatformFileError"/>
   <affected-histogram name="SimpleCache.SyncCreateResult"/>
diff --git a/tools/perf/perf.isolate b/tools/perf/perf.isolate
index 49f22c82..20cb796 100644
--- a/tools/perf/perf.isolate
+++ b/tools/perf/perf.isolate
@@ -12,6 +12,7 @@
          './',
           # Field trial configs
           '../variations/',
+          '../../testing/variations/',
         ],
       },
     }],
diff --git a/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder.py b/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder.py
index 3bcbb70..bb484281 100644
--- a/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder.py
+++ b/tools/telemetry/telemetry/internal/backends/chrome/android_browser_finder.py
@@ -123,14 +123,12 @@
     except Exception:
       logging.exception('Failure while creating Android browser.')
       original_exception = sys.exc_info()
-
       try:
         browser_backend.Close()
       except Exception:
         logging.exception('Secondary failure while closing browser backend.')
 
-      raise original_exception
-
+      raise original_exception[0], original_exception[1], original_exception[2]
 
   def SupportsOptions(self, finder_options):
     if len(finder_options.extensions_to_load) != 0:
diff --git a/tools/telemetry/telemetry/internal/backends/mandoline/mandoline_browser_backend.py b/tools/telemetry/telemetry/internal/backends/mandoline/mandoline_browser_backend.py
index 99971ad..5f1fa76 100644
--- a/tools/telemetry/telemetry/internal/backends/mandoline/mandoline_browser_backend.py
+++ b/tools/telemetry/telemetry/internal/backends/mandoline/mandoline_browser_backend.py
@@ -50,6 +50,10 @@
     args = []
     args.extend(self.browser_options.extra_browser_args)
     args.extend(self.GetReplayBrowserStartupArgs())
+    # Currently the bots that run mojo perf tests use such an old kernel that
+    # it doesn't support the namespace sandboxing primitives. Disable it until
+    # infra fixes it.
+    args.extend('--no-sandbox')
     return args
 
   def _UseHostResolverRules(self):
diff --git a/tools/variations/fieldtrial_to_struct.py b/tools/variations/fieldtrial_to_struct.py
index b19dc55..dcaed3a 100755
--- a/tools/variations/fieldtrial_to_struct.py
+++ b/tools/variations/fieldtrial_to_struct.py
@@ -48,6 +48,12 @@
       for param in sorted(params_data.keys()):
         params.append({'key': param, 'value': params_data[param]})
       group['params'] = params
+    enable_features_data = group_data.get('enable_features')
+    if enable_features_data:
+      group['enable_features'] = enable_features_data
+    disable_features_data = group_data.get('disable_features')
+    if disable_features_data:
+      group['disable_features'] = disable_features_data
     element['groups'].append(group)
   return {'elements': {'kFieldTrialConfig': element}}
 
diff --git a/tools/variations/fieldtrial_to_struct_unittest.py b/tools/variations/fieldtrial_to_struct_unittest.py
index f1980ac..7575e83 100644
--- a/tools/variations/fieldtrial_to_struct_unittest.py
+++ b/tools/variations/fieldtrial_to_struct_unittest.py
@@ -18,7 +18,9 @@
           'params': {
             'x': '1',
             'y': '2'
-          }
+          },
+          'enable_features': ['A', 'B'],
+          'disable_features': ['C']
         }
       ],
       'Study2': [{'group_name': 'OtherGroup'}]
@@ -34,7 +36,10 @@
               'params': [
                 {'key': 'x', 'value': '1'},
                 {'key': 'y', 'value': '2'}
-              ]
+              ],
+             'enable_features': ['A',
+                                 'B'],
+             'disable_features': ['C']
             },
             {
               'study': 'Study2',
@@ -44,6 +49,7 @@
         }
       }
     }
+    self.maxDiff = None
     self.assertEqual(expected, result)
 
   def test_FieldTrialToStructMain(self):
diff --git a/tools/variations/unittest_data/expected_output.cc b/tools/variations/unittest_data/expected_output.cc
index b4b08d3..d2f5cac 100644
--- a/tools/variations/unittest_data/expected_output.cc
+++ b/tools/variations/unittest_data/expected_output.cc
@@ -10,6 +10,16 @@
 #include "test_ouput.h"
 
 
+const char* const array_kFieldTrialConfig_enable_features_0[] = {
+    "X",
+};
+const char* const array_kFieldTrialConfig_disable_features[] = {
+    "C",
+};
+const char* const array_kFieldTrialConfig_enable_features[] = {
+    "A",
+    "B",
+};
 const FieldTrialGroupParams array_kFieldTrialConfig_params[] = {
     {
       "x",
@@ -26,15 +36,33 @@
     "TestGroup1",
     NULL,
     0,
+    NULL,
+    0,
+    NULL,
+    0,
   },
   {
     "TestStudy2",
     "TestGroup2",
     array_kFieldTrialConfig_params,
     2,
+    array_kFieldTrialConfig_enable_features,
+    2,
+    array_kFieldTrialConfig_disable_features,
+    1,
+  },
+  {
+    "TestStudy3",
+    "TestGroup3",
+    NULL,
+    0,
+    array_kFieldTrialConfig_enable_features_0,
+    1,
+    NULL,
+    0,
   },
 };
 const FieldTrialTestingConfig kFieldTrialConfig = {
   array_kFieldTrialConfig_groups,
-  2,
+  3,
 };
diff --git a/tools/variations/unittest_data/expected_output.h b/tools/variations/unittest_data/expected_output.h
index f5591a9..3ecaddc 100644
--- a/tools/variations/unittest_data/expected_output.h
+++ b/tools/variations/unittest_data/expected_output.h
@@ -23,6 +23,10 @@
   const char* const group_name;
   const FieldTrialGroupParams * params;
   const size_t params_size;
+  const char* const * enable_features;
+  const size_t enable_features_size;
+  const char* const * disable_features;
+  const size_t disable_features_size;
 };
 
 struct FieldTrialTestingConfig {
diff --git a/tools/variations/unittest_data/test_config.json b/tools/variations/unittest_data/test_config.json
index 7c60cb5..fca6883c 100644
--- a/tools/variations/unittest_data/test_config.json
+++ b/tools/variations/unittest_data/test_config.json
@@ -8,7 +8,12 @@
       "params": {
         "x": "1",
         "y": "2"
-      }
+      },
+      "enable_features": ["A", "B"],
+      "disable_features": ["C"]
     }
+  ],
+  "TestStudy3": [
+    {"group_name": "TestGroup3", "enable_features": ["X"]}
   ]
 }
\ No newline at end of file
diff --git a/ui/file_manager/file_manager/foreground/js/mouse_inactivity_watcher.js b/ui/file_manager/file_manager/foreground/js/mouse_inactivity_watcher.js
index ab7f333..ceac19d 100644
--- a/ui/file_manager/file_manager/foreground/js/mouse_inactivity_watcher.js
+++ b/ui/file_manager/file_manager/foreground/js/mouse_inactivity_watcher.js
@@ -58,6 +58,11 @@
     this.activityStarted_();
     this.activityStopped_();
   }.bind(this));
+  // If pointer goes outside the app window, tools should be hidden immediately.
+  document.addEventListener('mouseout', function(event) {
+    if (event.relatedTarget === null)
+      this.forceTimeout_();
+  }.bind(this));
 }
 
 /**
@@ -179,3 +184,14 @@
   if (!this.disabled_ && !this.toolsActive_())
     this.showTools(false);
 };
+
+/**
+ * Force the timer to be timed out immediately.
+ * @private
+ */
+MouseInactivityWatcher.prototype.forceTimeout_ = function() {
+  if (this.timeoutID_) {
+    clearTimeout(this.timeoutID_);
+    this.onTimeout_();
+  }
+};
diff --git a/ui/file_manager/integration_tests/video_player/click_control_buttons.js b/ui/file_manager/integration_tests/video_player/click_control_buttons.js
new file mode 100644
index 0000000..44d5e07
--- /dev/null
+++ b/ui/file_manager/integration_tests/video_player/click_control_buttons.js
@@ -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.
+
+'use strict';
+
+/**
+ * Waits that calling callRemoteTestUtil for |funcName| function with |filename|
+ * returns |expectedResult|.
+ * @param {string} funcName Function name for callRemoteTestUtil.
+ * @param {string} filename File name to pass to callRemoteTestUtil.
+ * @param {*} expectedResult Expected result for the remote call.
+ * @return {Promise} Promise which will be fullfiled when the expected result is
+ *     given.
+ */
+function waitForFunctionResult(funcName, filename, expectedResult) {
+  return repeatUntil(function() {
+    return remoteCallVideoPlayer.callRemoteTestUtil(funcName, null, [filename])
+        .then(function(result) {
+          if (result === expectedResult)
+            return true;
+          return pending('Waiting for %s return %s.', funcName, expectedResult);
+        });
+  });
+}
+
+/**
+ * The openSingleImage test for Downloads.
+ * @return {Promise} Promise to be fulfilled with on success.
+ */
+testcase.clickControlButtons = function() {
+  var openVideo = openSingleVideo('local', 'downloads', ENTRIES.world);
+  var appId;
+  return openVideo.then(function(args) {
+    appId = args[0];
+    // Video player starts playing given file automatically.
+    return waitForFunctionResult('isPlaying', 'world.ogv', true);
+  }).then(function() {
+    // Play will finish in 2 seconds (world.ogv is 2-second short movie.)
+    return waitForFunctionResult('isPlaying', 'world.ogv', false);
+  }).then(function() {
+    // Conform that clicking play button will re-play the video.
+    return remoteCallVideoPlayer.callRemoteTestUtil(
+        'fakeMouseClick', appId, ['.media-button.play']); }).then(function() {
+    return waitForFunctionResult('isPlaying', 'world.ogv', true);
+  }).then(function() {
+    // Confirm that clicking volume button mutes the video.
+    return remoteCallVideoPlayer.callRemoteTestUtil(
+        'fakeMouseClick', appId, ['.media-button.sound']);
+  }).then(function() {
+    return waitForFunctionResult('isMuted', 'world.ogv', true);
+  }).then(function() {
+    // Confirm that clicking volume button again unmutes the video.
+    return remoteCallVideoPlayer.callRemoteTestUtil(
+        'fakeMouseClick', appId, ['.media-button.sound']);
+  }).then(function() {
+    return waitForFunctionResult('isMuted', 'world.ogv', false);
+  }).then(function() {
+    // Confirm that clicking fullscreen button enables fullscreen mode.
+    return remoteCallVideoPlayer.callRemoteTestUtil(
+        'fakeMouseClick', appId, ['.media-button.fullscreen']);
+  }).then(function() {
+    return remoteCallVideoPlayer.waitForElement(appId,
+        '#controls[fullscreen]');
+  }).then(function() {
+    // Confirm that clicking fullscreen-exit button disables fullscreen mode.
+    return remoteCallVideoPlayer.callRemoteTestUtil(
+        'fakeMouseClick', appId, ['.media-button.fullscreen']);
+  }).then(function() {
+    return remoteCallVideoPlayer.waitForElement(appId,
+        '#controls:not([fullscreen])');
+  });
+};
diff --git a/ui/file_manager/integration_tests/video_player_test_manifest.json b/ui/file_manager/integration_tests/video_player_test_manifest.json
index 5a85ce1..cd2623c 100644
--- a/ui/file_manager/integration_tests/video_player_test_manifest.json
+++ b/ui/file_manager/integration_tests/video_player_test_manifest.json
@@ -11,7 +11,8 @@
       "remote_call.js",
       "video_player/background.js",
       "video_player/open_video_files.js",
-      "video_player/check_elements.js"
+      "video_player/check_elements.js",
+      "video_player/click_control_buttons.js"
     ]},
   "incognito" : "split",
   "permissions": ["commandLinePrivate"]
diff --git a/ui/file_manager/video_player/js/test_util.js b/ui/file_manager/video_player/js/test_util.js
index 787d74f..2415cd6 100644
--- a/ui/file_manager/video_player/js/test_util.js
+++ b/ui/file_manager/video_player/js/test_util.js
@@ -3,23 +3,45 @@
 // found in the LICENSE file.
 
 /**
- * Returns if the specified file is being played.
- *
- * @param {string} filename Name of audio file to be checked. This must be same
- *     as entry.name() of the audio file.
- * @return {boolean} True if the video is playing, false otherwise.
+ * Returns if a video element playing the specified file meet the condition
+ * which is given by a parameter.
+ * @param {string} filename Name of video file to be checked. This must be same
+ *     as entry.name() of the video file.
+ * @param {function(!HTMLElement):boolean} testFunction
  */
-test.util.sync.isPlaying = function(filename) {
+function testElement(filename, testFunction) {
   for (var appId in window.background.appWindows) {
     var contentWindow = window.background.appWindows[appId].contentWindow;
     if (contentWindow &&
         contentWindow.document.title === filename) {
       var element = contentWindow.document.querySelector('video[src]');
-      if (element && !element.paused)
+      if (element && testFunction(element))
         return true;
     }
   }
   return false;
+}
+
+/**
+ * Returns if the specified file is being played.
+ *
+ * @param {string} filename Name of video file to be checked. This must be same
+ *     as entry.name() of the video file.
+ * @return {boolean} True if the video is playing, false otherwise.
+ */
+test.util.sync.isPlaying = function(filename) {
+  return testElement(filename, element => !element.paused);
+};
+
+/**
+ * Returns if the specified file is being played.
+ *
+ * @param {string} filename Name of video file to be checked. This must be same
+ *     as entry.name() of the video file.
+ * @return {boolean} True if the video is playing, false otherwise.
+ */
+test.util.sync.isMuted = function(filename) {
+  return testElement(filename, element => element.volume === 0);
 };
 
 /**
diff --git a/ui/file_manager/video_player/js/video_player.js b/ui/file_manager/video_player/js/video_player.js
index 6420f6c..94c3367 100644
--- a/ui/file_manager/video_player/js/video_player.js
+++ b/ui/file_manager/video_player/js/video_player.js
@@ -145,8 +145,7 @@
     this.decodeErrorOccured = true;
   }
 
-  // Disable inactivity watcher, and disable the ui, by hiding tools manually.
-  this.getInactivityWatcher().disabled = true;
+  // Disable controls on the ui.
   getRequiredElement('video-player').setAttribute('disabled', 'true');
 
   // Detach the video element, since it may be unreliable and reset stored
@@ -230,6 +229,17 @@
       getRequiredElement('video-container'),
       getRequiredElement('controls'));
 
+  var observer = new MutationObserver(function(mutations) {
+    var isLoadingOrDisabledChanged = mutations.some(function(mutation) {
+      return mutation.attributeName === 'loading' ||
+             mutation.attributeName === 'disabled';
+    });
+    if (isLoadingOrDisabledChanged)
+      this.updateInactivityWatcherState_();
+  }.bind(this));
+  observer.observe(getRequiredElement('video-player'),
+      { attributes: true, childList: false });
+
   var reloadVideo = function(e) {
     if (this.controls_.decodeErrorOccured &&
         // Ignore shortcut keys
@@ -297,7 +307,6 @@
     getRequiredElement('video-player').removeAttribute('disabled');
     getRequiredElement('error').removeAttribute('visible');
     this.controls.detachMedia();
-    this.controls.getInactivityWatcher().disabled = true;
     this.controls.decodeErrorOccured = false;
     this.controls.casting = !!this.currentCast_;
 
@@ -377,7 +386,6 @@
               if (opt_callback)
                 opt_callback();
               videoPlayerElement.removeAttribute('loading');
-              this.controls.getInactivityWatcher().disabled = false;
             }
 
             this.videoElement_.removeEventListener('loadedmetadata', handler);
@@ -387,10 +395,12 @@
 
           this.videoElement_.addEventListener('play', function() {
             chrome.power.requestKeepAwake('display');
-          }.wrap());
+            this.updateInactivityWatcherState_();
+          }.wrap(this));
           this.videoElement_.addEventListener('pause', function() {
             chrome.power.releaseKeepAwake();
-          }.wrap());
+            this.updateInactivityWatcherState_();
+          }.wrap(this));
 
           this.videoElement_.load();
           callback();
@@ -635,6 +645,23 @@
     this.unloadVideo();
 };
 
+/**
+ * Updates the MouseInactivityWatcher's disable property to prevent control
+ * panel from being hidden in some situations.
+ * @private
+ */
+VideoPlayer.prototype.updateInactivityWatcherState_ = function() {
+  var videoPlayerElement = getRequiredElement('video-player');
+  // If any of following condition is met, we don't hide the tool bar.
+  // - Loaded video is paused.
+  // - Loading a video is in progress.
+  // - Opening video has an error.
+  this.controls.getInactivityWatcher().disabled =
+      (this.videoElement_ && this.videoElement_.paused) ||
+      videoPlayerElement.hasAttribute('loading') ||
+      videoPlayerElement.hasAttribute('disabled');
+};
+
 var player = new VideoPlayer();
 
 /**
diff --git a/ui/gfx/native_widget_types.h b/ui/gfx/native_widget_types.h
index 96201452..b39ab51 100644
--- a/ui/gfx/native_widget_types.h
+++ b/ui/gfx/native_widget_types.h
@@ -32,9 +32,6 @@
 //     unless you're in the IPC layer, which will be translating between
 //     NativeViewIds from the renderer and NativeViews.
 //
-//   NativeEditView: a handle to a native edit-box. The Mac folks wanted this
-//     specific typedef.
-//
 //   NativeImage: The platform-specific image type used for drawing UI elements
 //     in the browser.
 //
@@ -141,12 +138,10 @@
 
 #if defined(OS_WIN)
 typedef HFONT NativeFont;
-typedef HWND NativeEditView;
 typedef HDC NativeDrawingContext;
 typedef IAccessible* NativeViewAccessible;
 #elif defined(OS_IOS)
 typedef UIFont* NativeFont;
-typedef UITextField* NativeEditView;
 typedef CGContext* NativeDrawingContext;
 #ifdef __OBJC__
 typedef id NativeViewAccessible;
@@ -155,7 +150,6 @@
 #endif  // __OBJC__
 #elif defined(OS_MACOSX)
 typedef NSFont* NativeFont;
-typedef NSTextField* NativeEditView;
 typedef CGContext* NativeDrawingContext;
 #ifdef __OBJC__
 typedef id NativeViewAccessible;
@@ -164,7 +158,6 @@
 #endif  // __OBJC__
 #else  // Android, Linux, Chrome OS, etc.
 // Linux doesn't have a native font type.
-typedef void* NativeEditView;
 #if defined(USE_CAIRO)
 typedef cairo_t* NativeDrawingContext;
 #else
diff --git a/ui/gl/gl_surface_ozone.cc b/ui/gl/gl_surface_ozone.cc
index 978c982..a75680c 100644
--- a/ui/gl/gl_surface_ozone.cc
+++ b/ui/gl/gl_surface_ozone.cc
@@ -388,9 +388,14 @@
     unsubmitted_frames_.weak_erase(unsubmitted_frames_.begin());
     swap_buffers_pending_ = true;
 
-    last_swap_buffers_result_ =
-        frame->ScheduleOverlayPlanes(widget_) &&
-        ozone_surface_->OnSwapBuffersAsync(frame->callback);
+    if (!frame->ScheduleOverlayPlanes(widget_)) {
+      // |callback| is a wrapper for SwapCompleted(). Call it to properly
+      // propagate the failed state.
+      frame->callback.Run(gfx::SwapResult::SWAP_FAILED);
+      return;
+    }
+
+    ozone_surface_->OnSwapBuffersAsync(frame->callback);
   }
 }
 
@@ -413,6 +418,10 @@
     gfx::SwapResult result) {
   callback.Run(result);
   swap_buffers_pending_ = false;
+  if (result == gfx::SwapResult::SWAP_FAILED) {
+    last_swap_buffers_result_ = false;
+    return;
+  }
 
   SubmitFrame();
 }
diff --git a/ui/ozone/BUILD.gn b/ui/ozone/BUILD.gn
index fb13cd3..f529692 100644
--- a/ui/ozone/BUILD.gn
+++ b/ui/ozone/BUILD.gn
@@ -19,9 +19,9 @@
   ozone_platform_deps += [ "platform/egltest" ]
 }
 
-if (ozone_platform_test) {
-  ozone_platforms += [ "test" ]
-  ozone_platform_deps += [ "platform/test" ]
+if (ozone_platform_headless) {
+  ozone_platforms += [ "headless" ]
+  ozone_platform_deps += [ "platform/headless" ]
 }
 
 if (ozone_platform_caca) {
@@ -131,6 +131,7 @@
         "//ui/display/types",
         "//ui/display/util",
         "//ui/events",
+        "//ui/events/devices",
         "//ui/events/ozone:events_ozone",
         "//ui/gfx",
         "//ui/gfx/geometry",
diff --git a/ui/ozone/ozone.gni b/ui/ozone/ozone.gni
index cb6f62e..15e909de 100644
--- a/ui/ozone/ozone.gni
+++ b/ui/ozone/ozone.gni
@@ -26,14 +26,14 @@
   ozone_platform_egltest = false
   ozone_platform_gbm = false
   ozone_platform_ozonex = false
-  ozone_platform_test = false
+  ozone_platform_headless = false
 
   if (ozone_auto_platforms) {
     if (is_chromecast) {
       # The default platform used at runtime is "cast".
       ozone_platform = "cast"
       ozone_platform_cast = true
-      ozone_platform_test = true
+      ozone_platform_headless = true
 
       # For desktop Chromecast builds, override the default "cast" platform with
       # --ozone_platform=egltest
@@ -42,13 +42,13 @@
         ozone_platform_ozonex = true
       }
     } else {
-      # Use test as the default platform.
-      ozone_platform = "test"
+      # Use headless as the default platform.
+      ozone_platform = "headless"
 
       # Build all platforms whose deps are in install-build-deps.sh.
       # Only these platforms will be compile tested by buildbots.
       ozone_platform_gbm = true
-      ozone_platform_test = true
+      ozone_platform_headless = true
       ozone_platform_egltest = true
     }
   }
diff --git a/ui/ozone/ozone.gyp b/ui/ozone/ozone.gyp
index 1f4bfc41..d0b81a7 100644
--- a/ui/ozone/ozone.gyp
+++ b/ui/ozone/ozone.gyp
@@ -240,9 +240,9 @@
         'platform/drm/gbm.gypi',
       ],
     }],
-    ['<(ozone_platform_test) == 1', {
+    ['<(ozone_platform_headless) == 1', {
       'includes': [
-        'platform/test/test.gypi',
+        'platform/headless/headless.gypi',
       ],
     }],
   ],
diff --git a/ui/ozone/platform/cast/surface_ozone_egl_cast.cc b/ui/ozone/platform/cast/surface_ozone_egl_cast.cc
index 56dee58..bbe8d3c8 100644
--- a/ui/ozone/platform/cast/surface_ozone_egl_cast.cc
+++ b/ui/ozone/platform/cast/surface_ozone_egl_cast.cc
@@ -21,10 +21,9 @@
   return true;
 }
 
-bool SurfaceOzoneEglCast::OnSwapBuffersAsync(
+void SurfaceOzoneEglCast::OnSwapBuffersAsync(
     const SwapCompletionCallback& callback) {
   callback.Run(gfx::SwapResult::SWAP_ACK);
-  return true;
 }
 
 bool SurfaceOzoneEglCast::ResizeNativeWindow(const gfx::Size& viewport_size) {
diff --git a/ui/ozone/platform/cast/surface_ozone_egl_cast.h b/ui/ozone/platform/cast/surface_ozone_egl_cast.h
index 197ef0b..964b845 100644
--- a/ui/ozone/platform/cast/surface_ozone_egl_cast.h
+++ b/ui/ozone/platform/cast/surface_ozone_egl_cast.h
@@ -20,7 +20,7 @@
   // SurfaceOzoneEGL implementation:
   intptr_t GetNativeWindow() override;
   bool OnSwapBuffers() override;
-  bool OnSwapBuffersAsync(const SwapCompletionCallback& callback) override;
+  void OnSwapBuffersAsync(const SwapCompletionCallback& callback) override;
   bool ResizeNativeWindow(const gfx::Size& viewport_size) override;
   scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override;
 
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index 6b110e9..737a066 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -40,11 +40,10 @@
   return false;
 }
 
-bool GbmSurfaceless::OnSwapBuffersAsync(
+void GbmSurfaceless::OnSwapBuffersAsync(
     const SwapCompletionCallback& callback) {
   window_->SchedulePageFlip(planes_, callback);
   planes_.clear();
-  return true;
 }
 
 scoped_ptr<gfx::VSyncProvider> GbmSurfaceless::CreateVSyncProvider() {
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
index 54f749e..99abc24 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -36,7 +36,7 @@
   intptr_t GetNativeWindow() override;
   bool ResizeNativeWindow(const gfx::Size& viewport_size) override;
   bool OnSwapBuffers() override;
-  bool OnSwapBuffersAsync(const SwapCompletionCallback& callback) override;
+  void OnSwapBuffersAsync(const SwapCompletionCallback& callback) override;
   scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override;
   bool IsUniversalDisplayLinkDevice() override;
 
diff --git a/ui/ozone/platform/egltest/ozone_platform_egltest.cc b/ui/ozone/platform/egltest/ozone_platform_egltest.cc
index cae3695..1bf2d2b 100644
--- a/ui/ozone/platform/egltest/ozone_platform_egltest.cc
+++ b/ui/ozone/platform/egltest/ozone_platform_egltest.cc
@@ -226,9 +226,8 @@
 
   bool OnSwapBuffers() override { return true; }
 
-  bool OnSwapBuffersAsync(const SwapCompletionCallback& callback) override {
+  void OnSwapBuffersAsync(const SwapCompletionCallback& callback) override {
     callback.Run(gfx::SwapResult::SWAP_ACK);
-    return true;
   }
 
   bool ResizeNativeWindow(const gfx::Size& viewport_size) override {
diff --git a/ui/ozone/platform/headless/BUILD.gn b/ui/ozone/platform/headless/BUILD.gn
new file mode 100644
index 0000000..fb731a2
--- /dev/null
+++ b/ui/ozone/platform/headless/BUILD.gn
@@ -0,0 +1,27 @@
+# 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.
+
+source_set("headless") {
+  sources = [
+    "client_native_pixmap_factory_headless.cc",
+    "client_native_pixmap_factory_headless.h",
+    "headless_surface_factory.cc",
+    "headless_surface_factory.h",
+    "headless_window.cc",
+    "headless_window.h",
+    "headless_window_manager.cc",
+    "headless_window_manager.h",
+    "ozone_platform_headless.cc",
+    "ozone_platform_headless.h",
+  ]
+
+  deps = [
+    "//base",
+    "//skia",
+    "//ui/base",
+    "//ui/gfx/geometry",
+    "//ui/events/ozone:events_ozone_layout",
+    "//ui/events/platform",
+  ]
+}
diff --git a/ui/ozone/platform/test/DEPS b/ui/ozone/platform/headless/DEPS
similarity index 100%
rename from ui/ozone/platform/test/DEPS
rename to ui/ozone/platform/headless/DEPS
diff --git a/ui/ozone/platform/test/client_native_pixmap_factory_test.cc b/ui/ozone/platform/headless/client_native_pixmap_factory_headless.cc
similarity index 67%
rename from ui/ozone/platform/test/client_native_pixmap_factory_test.cc
rename to ui/ozone/platform/headless/client_native_pixmap_factory_headless.cc
index 9a8e3e2..1f409eb 100644
--- a/ui/ozone/platform/test/client_native_pixmap_factory_test.cc
+++ b/ui/ozone/platform/headless/client_native_pixmap_factory_headless.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/ozone/platform/test/client_native_pixmap_factory_test.h"
+#include "ui/ozone/platform/headless/client_native_pixmap_factory_headless.h"
 
 #include "ui/ozone/common/stub_client_native_pixmap_factory.h"
 
 namespace ui {
 
-ClientNativePixmapFactory* CreateClientNativePixmapFactoryTest() {
+ClientNativePixmapFactory* CreateClientNativePixmapFactoryHeadless() {
   return CreateStubClientNativePixmapFactory();
 }
 
diff --git a/ui/ozone/platform/headless/client_native_pixmap_factory_headless.h b/ui/ozone/platform/headless/client_native_pixmap_factory_headless.h
new file mode 100644
index 0000000..675eec15
--- /dev/null
+++ b/ui/ozone/platform/headless/client_native_pixmap_factory_headless.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 UI_OZONE_PLATFORM_HEADLESS_CLIENT_NATIVE_PIXMAP_FACTORY_HEADLESS_H_
+#define UI_OZONE_PLATFORM_HEADLESS_CLIENT_NATIVE_PIXMAP_FACTORY_HEADLESS_H_
+
+namespace ui {
+
+class ClientNativePixmapFactory;
+
+// Constructor hook for use in constructor_list.cc
+ClientNativePixmapFactory* CreateClientNativePixmapFactoryHeadless();
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_HEADLESS_CLIENT_NATIVE_PIXMAP_FACTORY_HEADLESS_H_
diff --git a/ui/ozone/platform/headless/headless.gypi b/ui/ozone/platform/headless/headless.gypi
new file mode 100644
index 0000000..65de1fa
--- /dev/null
+++ b/ui/ozone/platform/headless/headless.gypi
@@ -0,0 +1,43 @@
+# 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': {
+    'internal_ozone_platform_deps': [
+      'ozone_platform_headless',
+    ],
+    'internal_ozone_platforms': [
+      'headless'
+    ],
+  },
+  'targets': [
+    {
+      'target_name': 'ozone_platform_headless',
+      'type': 'static_library',
+      'defines': [
+        'OZONE_IMPLEMENTATION',
+      ],
+      'dependencies': [
+        '../../base/base.gyp:base',
+        '../base/ui_base.gyp:ui_base',
+        '../events/events.gyp:events',
+        '../events/ozone/events_ozone.gyp:events_ozone_layout',
+        '../events/platform/events_platform.gyp:events_platform',
+        '../gfx/gfx.gyp:gfx',
+      ],
+      'sources': [
+        'client_native_pixmap_factory_headless.cc',
+        'client_native_pixmap_factory_headless.h',
+        'ozone_platform_headless.cc',
+        'ozone_platform_headless.h',
+        'headless_surface_factory.cc',
+        'headless_surface_factory.h',
+        'headless_window.cc',
+        'headless_window.h',
+        'headless_window_manager.cc',
+        'headless_window_manager.h',
+      ],
+    },
+  ],
+}
diff --git a/ui/ozone/platform/test/test_surface_factory.cc b/ui/ozone/platform/headless/headless_surface_factory.cc
similarity index 77%
rename from ui/ozone/platform/test/test_surface_factory.cc
rename to ui/ozone/platform/headless/headless_surface_factory.cc
index b513441..3262e69 100644
--- a/ui/ozone/platform/test/test_surface_factory.cc
+++ b/ui/ozone/platform/headless/headless_surface_factory.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 "ui/ozone/platform/test/test_surface_factory.h"
+#include "ui/ozone/platform/headless/headless_surface_factory.h"
 
 #include "base/bind.h"
 #include "base/files/file_util.h"
@@ -14,8 +14,8 @@
 #include "ui/gfx/codec/png_codec.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/vsync_provider.h"
-#include "ui/ozone/platform/test/test_window.h"
-#include "ui/ozone/platform/test/test_window_manager.h"
+#include "ui/ozone/platform/headless/headless_window.h"
+#include "ui/ozone/platform/headless/headless_window_manager.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
 
 namespace ui {
@@ -31,6 +31,7 @@
                   png_data.size());
 }
 
+// TODO(altimin): Find a proper way to capture rendering output.
 class FileSurface : public SurfaceOzoneCanvas {
  public:
   FileSurface(const base::FilePath& location) : location_(location) {}
@@ -66,20 +67,22 @@
 
 }  // namespace
 
-TestSurfaceFactory::TestSurfaceFactory() : TestSurfaceFactory(nullptr) {}
+HeadlessSurfaceFactory::HeadlessSurfaceFactory()
+    : HeadlessSurfaceFactory(nullptr) {}
 
-TestSurfaceFactory::TestSurfaceFactory(TestWindowManager* window_manager)
+HeadlessSurfaceFactory::HeadlessSurfaceFactory(
+    HeadlessWindowManager* window_manager)
     : window_manager_(window_manager) {}
 
-TestSurfaceFactory::~TestSurfaceFactory() {}
+HeadlessSurfaceFactory::~HeadlessSurfaceFactory() {}
 
-scoped_ptr<SurfaceOzoneCanvas> TestSurfaceFactory::CreateCanvasForWidget(
+scoped_ptr<SurfaceOzoneCanvas> HeadlessSurfaceFactory::CreateCanvasForWidget(
     gfx::AcceleratedWidget widget) {
-  TestWindow* window = window_manager_->GetWindow(widget);
+  HeadlessWindow* window = window_manager_->GetWindow(widget);
   return make_scoped_ptr<SurfaceOzoneCanvas>(new FileSurface(window->path()));
 }
 
-bool TestSurfaceFactory::LoadEGLGLES2Bindings(
+bool HeadlessSurfaceFactory::LoadEGLGLES2Bindings(
     AddGLLibraryCallback add_gl_library,
     SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
   return false;
diff --git a/ui/ozone/platform/headless/headless_surface_factory.h b/ui/ozone/platform/headless/headless_surface_factory.h
new file mode 100644
index 0000000..b715cbc
--- /dev/null
+++ b/ui/ozone/platform/headless/headless_surface_factory.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 UI_OZONE_PLATFORM_HEADLESS_HEADLESS_SURFACE_FACTORY_H_
+#define UI_OZONE_PLATFORM_HEADLESS_HEADLESS_SURFACE_FACTORY_H_
+
+#include "base/macros.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+class HeadlessWindowManager;
+
+class HeadlessSurfaceFactory : public SurfaceFactoryOzone {
+ public:
+  HeadlessSurfaceFactory();
+  explicit HeadlessSurfaceFactory(HeadlessWindowManager* window_manager);
+  ~HeadlessSurfaceFactory() override;
+
+  // SurfaceFactoryOzone:
+  scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
+      gfx::AcceleratedWidget w) override;
+  bool LoadEGLGLES2Bindings(
+      AddGLLibraryCallback add_gl_library,
+      SetGLGetProcAddressProcCallback set_gl_get_proc_address) override;
+
+ private:
+  HeadlessWindowManager* window_manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(HeadlessSurfaceFactory);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_HEADLESS_HEADLESS_SURFACE_FACTORY_H_
diff --git a/ui/ozone/platform/headless/headless_window.cc b/ui/ozone/platform/headless/headless_window.cc
new file mode 100644
index 0000000..75f86a1
--- /dev/null
+++ b/ui/ozone/platform/headless/headless_window.cc
@@ -0,0 +1,77 @@
+// 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 "ui/ozone/platform/headless/headless_window.h"
+
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/strings/string_number_conversions.h"
+#include "ui/events/platform/platform_event_source.h"
+#include "ui/ozone/platform/headless/headless_window_manager.h"
+#include "ui/platform_window/platform_window_delegate.h"
+
+namespace ui {
+
+HeadlessWindow::HeadlessWindow(PlatformWindowDelegate* delegate,
+                               HeadlessWindowManager* manager,
+                               const gfx::Rect& bounds)
+    : delegate_(delegate), manager_(manager), bounds_(bounds) {
+  widget_ = manager_->AddWindow(this);
+  delegate_->OnAcceleratedWidgetAvailable(widget_, 1.f);
+}
+
+HeadlessWindow::~HeadlessWindow() {
+  manager_->RemoveWindow(widget_, this);
+}
+
+base::FilePath HeadlessWindow::path() {
+  base::FilePath base_path = manager_->base_path();
+  if (base_path.empty() || base_path == base::FilePath("/dev/null"))
+    return base_path;
+
+  // Disambiguate multiple window output files with the window id.
+  return base_path.Append(base::IntToString(widget_));
+}
+
+gfx::Rect HeadlessWindow::GetBounds() {
+  return bounds_;
+}
+
+void HeadlessWindow::SetBounds(const gfx::Rect& bounds) {
+  bounds_ = bounds;
+  delegate_->OnBoundsChanged(bounds);
+}
+
+void HeadlessWindow::SetTitle(const base::string16& title) {}
+
+void HeadlessWindow::Show() {}
+
+void HeadlessWindow::Hide() {}
+
+void HeadlessWindow::Close() {}
+
+void HeadlessWindow::SetCapture() {}
+
+void HeadlessWindow::ReleaseCapture() {}
+
+void HeadlessWindow::ToggleFullscreen() {}
+
+void HeadlessWindow::Maximize() {}
+
+void HeadlessWindow::Minimize() {}
+
+void HeadlessWindow::Restore() {}
+
+void HeadlessWindow::SetCursor(PlatformCursor cursor) {}
+
+void HeadlessWindow::MoveCursorTo(const gfx::Point& location) {}
+
+void HeadlessWindow::ConfineCursorToBounds(const gfx::Rect& bounds) {}
+
+PlatformImeController* HeadlessWindow::GetPlatformImeController() {
+  return nullptr;
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/test/test_window.h b/ui/ozone/platform/headless/headless_window.h
similarity index 70%
rename from ui/ozone/platform/test/test_window.h
rename to ui/ozone/platform/headless/headless_window.h
index 0dacf33..5587b65 100644
--- a/ui/ozone/platform/test/test_window.h
+++ b/ui/ozone/platform/headless/headless_window.h
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_OZONE_PLATFORM_TEST_TEST_WINDOW_H_
-#define UI_OZONE_PLATFORM_TEST_TEST_WINDOW_H_
+#ifndef UI_OZONE_PLATFORM_HEADLESS_HEADLESS_WINDOW_H_
+#define UI_OZONE_PLATFORM_HEADLESS_HEADLESS_WINDOW_H_
 
 #include "base/files/file_path.h"
+#include "base/macros.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/platform_window/platform_window.h"
@@ -13,14 +14,14 @@
 namespace ui {
 
 class PlatformWindowDelegate;
-class TestWindowManager;
+class HeadlessWindowManager;
 
-class TestWindow : public PlatformWindow {
+class HeadlessWindow : public PlatformWindow {
  public:
-  TestWindow(PlatformWindowDelegate* delegate,
-             TestWindowManager* manager,
-             const gfx::Rect& bounds);
-  ~TestWindow() override;
+  HeadlessWindow(PlatformWindowDelegate* delegate,
+                 HeadlessWindowManager* manager,
+                 const gfx::Rect& bounds);
+  ~HeadlessWindow() override;
 
   // Path for image file for this window.
   base::FilePath path();
@@ -45,13 +46,13 @@
 
  private:
   PlatformWindowDelegate* delegate_;
-  TestWindowManager* manager_;
+  HeadlessWindowManager* manager_;
   gfx::Rect bounds_;
   gfx::AcceleratedWidget widget_;
 
-  DISALLOW_COPY_AND_ASSIGN(TestWindow);
+  DISALLOW_COPY_AND_ASSIGN(HeadlessWindow);
 };
 
 }  // namespace ui
 
-#endif  // UI_OZONE_PLATFORM_TEST_TEST_WINDOW_H_
+#endif  // UI_OZONE_PLATFORM_HEADLESS_HEADLESS_WINDOW_H_
diff --git a/ui/ozone/platform/headless/headless_window_manager.cc b/ui/ozone/platform/headless/headless_window_manager.cc
new file mode 100644
index 0000000..eb6b483
--- /dev/null
+++ b/ui/ozone/platform/headless/headless_window_manager.cc
@@ -0,0 +1,48 @@
+// 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 "ui/ozone/platform/headless/headless_window_manager.h"
+
+#include "base/files/file_util.h"
+#include "base/location.h"
+
+namespace ui {
+
+HeadlessWindowManager::HeadlessWindowManager(
+    const base::FilePath& dump_location)
+    : location_(dump_location) {}
+
+HeadlessWindowManager::~HeadlessWindowManager() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+}
+
+void HeadlessWindowManager::Initialize() {
+  if (location_.empty())
+    return;
+  if (!DirectoryExists(location_) && !base::CreateDirectory(location_) &&
+      location_ != base::FilePath("/dev/null"))
+    PLOG(FATAL) << "unable to create output directory";
+  if (!base::PathIsWritable(location_))
+    PLOG(FATAL) << "unable to write to output location";
+}
+
+int32_t HeadlessWindowManager::AddWindow(HeadlessWindow* window) {
+  return windows_.Add(window);
+}
+
+void HeadlessWindowManager::RemoveWindow(int32_t window_id,
+                                         HeadlessWindow* window) {
+  DCHECK_EQ(window, windows_.Lookup(window_id));
+  windows_.Remove(window_id);
+}
+
+HeadlessWindow* HeadlessWindowManager::GetWindow(int32_t window_id) {
+  return windows_.Lookup(window_id);
+}
+
+base::FilePath HeadlessWindowManager::base_path() const {
+  return location_;
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/headless/headless_window_manager.h b/ui/ozone/platform/headless/headless_window_manager.h
new file mode 100644
index 0000000..f2710bc
--- /dev/null
+++ b/ui/ozone/platform/headless/headless_window_manager.h
@@ -0,0 +1,51 @@
+// 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 UI_OZONE_PLATFORM_HEADLESS_HEADLESS_WINDOW_MANAGER_H_
+#define UI_OZONE_PLATFORM_HEADLESS_HEADLESS_WINDOW_MANAGER_H_
+
+#include "base/files/file_path.h"
+#include "base/id_map.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/ozone/public/surface_factory_ozone.h"
+
+namespace ui {
+
+class HeadlessWindow;
+
+class HeadlessWindowManager {
+ public:
+  explicit HeadlessWindowManager(const base::FilePath& dump_location);
+  ~HeadlessWindowManager();
+
+  // Initialize (mainly check that we have a place to write output to).
+  void Initialize();
+
+  // Register a new window. Returns the window id.
+  int32_t AddWindow(HeadlessWindow* window);
+
+  // Remove a window.
+  void RemoveWindow(int32_t window_id, HeadlessWindow* window);
+
+  // Find a window object by id;
+  HeadlessWindow* GetWindow(int32_t window_id);
+
+  // User-supplied path for images.
+  base::FilePath base_path() const;
+
+ private:
+  base::FilePath location_;
+
+  IDMap<HeadlessWindow> windows_;
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(HeadlessWindowManager);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_HEADLESS_HEADLESS_WINDOW_MANAGER_H_
diff --git a/ui/ozone/platform/test/ozone_platform_test.cc b/ui/ozone/platform/headless/ozone_platform_headless.cc
similarity index 71%
rename from ui/ozone/platform/test/ozone_platform_test.cc
rename to ui/ozone/platform/headless/ozone_platform_headless.cc
index ed693886..0fc1f19 100644
--- a/ui/ozone/platform/test/ozone_platform_test.cc
+++ b/ui/ozone/platform/headless/ozone_platform_headless.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 "ui/ozone/platform/test/ozone_platform_test.h"
+#include "ui/ozone/platform/headless/ozone_platform_headless.h"
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -12,9 +12,9 @@
 #include "ui/events/platform/platform_event_source.h"
 #include "ui/ozone/common/native_display_delegate_ozone.h"
 #include "ui/ozone/common/stub_overlay_manager.h"
-#include "ui/ozone/platform/test/test_surface_factory.h"
-#include "ui/ozone/platform/test/test_window.h"
-#include "ui/ozone/platform/test/test_window_manager.h"
+#include "ui/ozone/platform/headless/headless_surface_factory.h"
+#include "ui/ozone/platform/headless/headless_window.h"
+#include "ui/ozone/platform/headless/headless_window_manager.h"
 #include "ui/ozone/public/cursor_factory_ozone.h"
 #include "ui/ozone/public/gpu_platform_support.h"
 #include "ui/ozone/public/gpu_platform_support_host.h"
@@ -27,24 +27,24 @@
 
 namespace {
 
-// A test implementation of PlatformEventSource that we can instantiate to make
+// A headless implementation of PlatformEventSource that we can instantiate to
+// make
 // sure that the PlatformEventSource has an instance while in unit tests.
-class TestPlatformEventSource : public ui::PlatformEventSource {
+class HeadlessPlatformEventSource : public ui::PlatformEventSource {
  public:
-  TestPlatformEventSource() {}
-  ~TestPlatformEventSource() override {}
+  HeadlessPlatformEventSource() {}
+  ~HeadlessPlatformEventSource() override {}
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(TestPlatformEventSource);
+  DISALLOW_COPY_AND_ASSIGN(HeadlessPlatformEventSource);
 };
 
-// OzonePlatform for testing
-//
-// This platform dumps images to a file for testing purposes.
-class OzonePlatformTest : public OzonePlatform {
+// OzonePlatform for headless mode
+class OzonePlatformHeadless : public OzonePlatform {
  public:
-  OzonePlatformTest(const base::FilePath& dump_file) : file_path_(dump_file) {}
-  ~OzonePlatformTest() override {}
+  OzonePlatformHeadless(const base::FilePath& dump_file)
+      : file_path_(dump_file) {}
+  ~OzonePlatformHeadless() override {}
 
   // OzonePlatform:
   ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override {
@@ -72,7 +72,7 @@
       PlatformWindowDelegate* delegate,
       const gfx::Rect& bounds) override {
     return make_scoped_ptr<PlatformWindow>(
-        new TestWindow(delegate, window_manager_.get(), bounds));
+        new HeadlessWindow(delegate, window_manager_.get(), bounds));
   }
   scoped_ptr<NativeDisplayDelegate> CreateNativeDisplayDelegate() override {
     return make_scoped_ptr(new NativeDisplayDelegateOzone());
@@ -82,12 +82,12 @@
   }
 
   void InitializeUI() override {
-    window_manager_.reset(new TestWindowManager(file_path_));
+    window_manager_.reset(new HeadlessWindowManager(file_path_));
     window_manager_->Initialize();
-    surface_factory_.reset(new TestSurfaceFactory(window_manager_.get()));
+    surface_factory_.reset(new HeadlessSurfaceFactory(window_manager_.get()));
     // This unbreaks tests that create their own.
     if (!PlatformEventSource::GetInstance())
-      platform_event_source_.reset(new TestPlatformEventSource);
+      platform_event_source_.reset(new HeadlessPlatformEventSource);
     KeyboardLayoutEngineManager::SetKeyboardLayoutEngine(
         make_scoped_ptr(new StubKeyboardLayoutEngine()));
 
@@ -99,13 +99,13 @@
 
   void InitializeGPU() override {
     if (!surface_factory_)
-      surface_factory_.reset(new TestSurfaceFactory());
+      surface_factory_.reset(new HeadlessSurfaceFactory());
     gpu_platform_support_.reset(CreateStubGpuPlatformSupport());
   }
 
  private:
-  scoped_ptr<TestWindowManager> window_manager_;
-  scoped_ptr<TestSurfaceFactory> surface_factory_;
+  scoped_ptr<HeadlessWindowManager> window_manager_;
+  scoped_ptr<HeadlessSurfaceFactory> surface_factory_;
   scoped_ptr<PlatformEventSource> platform_event_source_;
   scoped_ptr<CursorFactoryOzone> cursor_factory_ozone_;
   scoped_ptr<InputController> input_controller_;
@@ -114,17 +114,17 @@
   scoped_ptr<OverlayManagerOzone> overlay_manager_;
   base::FilePath file_path_;
 
-  DISALLOW_COPY_AND_ASSIGN(OzonePlatformTest);
+  DISALLOW_COPY_AND_ASSIGN(OzonePlatformHeadless);
 };
 
 }  // namespace
 
-OzonePlatform* CreateOzonePlatformTest() {
+OzonePlatform* CreateOzonePlatformHeadless() {
   base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
   base::FilePath location;
   if (cmd->HasSwitch(switches::kOzoneDumpFile))
     location = cmd->GetSwitchValuePath(switches::kOzoneDumpFile);
-  return new OzonePlatformTest(location);
+  return new OzonePlatformHeadless(location);
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/headless/ozone_platform_headless.h b/ui/ozone/platform/headless/ozone_platform_headless.h
new file mode 100644
index 0000000..0c3e94c
--- /dev/null
+++ b/ui/ozone/platform/headless/ozone_platform_headless.h
@@ -0,0 +1,17 @@
+// 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 UI_OZONE_PLATFORM_HEADLESS_OZONE_PLATFORM_HEADLESS_H_
+#define UI_OZONE_PLATFORM_HEADLESS_OZONE_PLATFORM_HEADLESS_H_
+
+namespace ui {
+
+class OzonePlatform;
+
+// Constructor hook for use in ozone_platform_list.cc
+OzonePlatform* CreateOzonePlatformHeadless();
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_HEADLESS_OZONE_PLATFORM_HEADLESS_H_
diff --git a/ui/ozone/platform/test/BUILD.gn b/ui/ozone/platform/test/BUILD.gn
deleted file mode 100644
index 2148d7b3..0000000
--- a/ui/ozone/platform/test/BUILD.gn
+++ /dev/null
@@ -1,27 +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.
-
-source_set("test") {
-  sources = [
-    "client_native_pixmap_factory_test.cc",
-    "client_native_pixmap_factory_test.h",
-    "ozone_platform_test.cc",
-    "ozone_platform_test.h",
-    "test_surface_factory.cc",
-    "test_surface_factory.h",
-    "test_window.cc",
-    "test_window.h",
-    "test_window_manager.cc",
-    "test_window_manager.h",
-  ]
-
-  deps = [
-    "//base",
-    "//skia",
-    "//ui/base",
-    "//ui/gfx/geometry",
-    "//ui/events/ozone:events_ozone_layout",
-    "//ui/events/platform",
-  ]
-}
diff --git a/ui/ozone/platform/test/client_native_pixmap_factory_test.h b/ui/ozone/platform/test/client_native_pixmap_factory_test.h
deleted file mode 100644
index ed2ead8..0000000
--- a/ui/ozone/platform/test/client_native_pixmap_factory_test.h
+++ /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.
-
-#ifndef UI_OZONE_PLATFORM_TEST_CLIENT_NATIVE_PIXMAP_FACTORY_TEST_H_
-#define UI_OZONE_PLATFORM_TEST_CLIENT_NATIVE_PIXMAP_FACTORY_TEST_H_
-
-namespace ui {
-
-class ClientNativePixmapFactory;
-
-// Constructor hook for use in constructor_list.cc
-ClientNativePixmapFactory* CreateClientNativePixmapFactoryTest();
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_TEST_CLIENT_NATIVE_PIXMAP_FACTORY_TEST_H_
diff --git a/ui/ozone/platform/test/ozone_platform_test.h b/ui/ozone/platform/test/ozone_platform_test.h
deleted file mode 100644
index fb25fd6..0000000
--- a/ui/ozone/platform/test/ozone_platform_test.h
+++ /dev/null
@@ -1,17 +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 UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_TEST_H_
-#define UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_TEST_H_
-
-namespace ui {
-
-class OzonePlatform;
-
-// Constructor hook for use in ozone_platform_list.cc
-OzonePlatform* CreateOzonePlatformTest();
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_TEST_OZONE_PLATFORM_TEST_H_
diff --git a/ui/ozone/platform/test/test.gypi b/ui/ozone/platform/test/test.gypi
deleted file mode 100644
index 6b2794b..0000000
--- a/ui/ozone/platform/test/test.gypi
+++ /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.
-
-{
-  'variables': {
-    'internal_ozone_platform_deps': [
-      'ozone_platform_test',
-    ],
-    'internal_ozone_platforms': [
-      'test'
-    ],
-  },
-  'targets': [
-    {
-      'target_name': 'ozone_platform_test',
-      'type': 'static_library',
-      'defines': [
-        'OZONE_IMPLEMENTATION',
-      ],
-      'dependencies': [
-        '../../base/base.gyp:base',
-        '../base/ui_base.gyp:ui_base',
-        '../events/events.gyp:events',
-        '../events/ozone/events_ozone.gyp:events_ozone_layout',
-        '../events/platform/events_platform.gyp:events_platform',
-        '../gfx/gfx.gyp:gfx',
-      ],
-      'sources': [
-        'client_native_pixmap_factory_test.cc',
-        'client_native_pixmap_factory_test.h',
-        'ozone_platform_test.cc',
-        'ozone_platform_test.h',
-        'test_surface_factory.cc',
-        'test_surface_factory.h',
-        'test_window.cc',
-        'test_window.h',
-        'test_window_manager.cc',
-        'test_window_manager.h',
-      ],
-    },
-  ],
-}
diff --git a/ui/ozone/platform/test/test_surface_factory.h b/ui/ozone/platform/test/test_surface_factory.h
deleted file mode 100644
index 98002ec..0000000
--- a/ui/ozone/platform/test/test_surface_factory.h
+++ /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.
-
-#ifndef UI_OZONE_PLATFORM_TEST_TEST_SURFACE_FACTORY_H_
-#define UI_OZONE_PLATFORM_TEST_TEST_SURFACE_FACTORY_H_
-
-#include "ui/ozone/public/surface_factory_ozone.h"
-
-namespace ui {
-
-class TestWindowManager;
-
-class TestSurfaceFactory : public SurfaceFactoryOzone {
- public:
-  TestSurfaceFactory();
-  explicit TestSurfaceFactory(TestWindowManager* window_manager);
-  ~TestSurfaceFactory() override;
-
-  // SurfaceFactoryOzone:
-  scoped_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
-      gfx::AcceleratedWidget w) override;
-  bool LoadEGLGLES2Bindings(
-      AddGLLibraryCallback add_gl_library,
-      SetGLGetProcAddressProcCallback set_gl_get_proc_address) override;
-
- private:
-  TestWindowManager* window_manager_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestSurfaceFactory);
-};
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_TEST_TEST_SURFACE_FACTORY_H_
diff --git a/ui/ozone/platform/test/test_window.cc b/ui/ozone/platform/test/test_window.cc
deleted file mode 100644
index 8cbe171..0000000
--- a/ui/ozone/platform/test/test_window.cc
+++ /dev/null
@@ -1,90 +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 "ui/ozone/platform/test/test_window.h"
-
-#include <string>
-
-#include "base/files/file_path.h"
-#include "base/strings/string_number_conversions.h"
-#include "ui/events/platform/platform_event_source.h"
-#include "ui/ozone/platform/test/test_window_manager.h"
-#include "ui/platform_window/platform_window_delegate.h"
-
-namespace ui {
-
-TestWindow::TestWindow(PlatformWindowDelegate* delegate,
-                       TestWindowManager* manager,
-                       const gfx::Rect& bounds)
-    : delegate_(delegate), manager_(manager), bounds_(bounds) {
-  widget_ = manager_->AddWindow(this);
-  delegate_->OnAcceleratedWidgetAvailable(widget_, 1.f);
-}
-
-TestWindow::~TestWindow() {
-  manager_->RemoveWindow(widget_, this);
-}
-
-base::FilePath TestWindow::path() {
-  base::FilePath base_path = manager_->base_path();
-  if (base_path.empty() || base_path == base::FilePath("/dev/null"))
-    return base_path;
-
-  // Disambiguate multiple window output files with the window id.
-  return base_path.Append(base::IntToString(widget_));
-}
-
-gfx::Rect TestWindow::GetBounds() {
-  return bounds_;
-}
-
-void TestWindow::SetBounds(const gfx::Rect& bounds) {
-  bounds_ = bounds;
-  delegate_->OnBoundsChanged(bounds);
-}
-
-void TestWindow::SetTitle(const base::string16& title) {
-}
-
-void TestWindow::Show() {
-}
-
-void TestWindow::Hide() {
-}
-
-void TestWindow::Close() {
-}
-
-void TestWindow::SetCapture() {
-}
-
-void TestWindow::ReleaseCapture() {
-}
-
-void TestWindow::ToggleFullscreen() {
-}
-
-void TestWindow::Maximize() {
-}
-
-void TestWindow::Minimize() {
-}
-
-void TestWindow::Restore() {
-}
-
-void TestWindow::SetCursor(PlatformCursor cursor) {
-}
-
-void TestWindow::MoveCursorTo(const gfx::Point& location) {
-}
-
-void TestWindow::ConfineCursorToBounds(const gfx::Rect& bounds) {
-}
-
-PlatformImeController* TestWindow::GetPlatformImeController() {
-  return nullptr;
-}
-
-}  // namespace ui
diff --git a/ui/ozone/platform/test/test_window_manager.cc b/ui/ozone/platform/test/test_window_manager.cc
deleted file mode 100644
index 1887c62..0000000
--- a/ui/ozone/platform/test/test_window_manager.cc
+++ /dev/null
@@ -1,47 +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 "ui/ozone/platform/test/test_window_manager.h"
-
-#include "base/files/file_util.h"
-#include "base/location.h"
-
-namespace ui {
-
-TestWindowManager::TestWindowManager(const base::FilePath& dump_location)
-    : location_(dump_location) {
-}
-
-TestWindowManager::~TestWindowManager() {
-  DCHECK(thread_checker_.CalledOnValidThread());
-}
-
-void TestWindowManager::Initialize() {
-  if (location_.empty())
-    return;
-  if (!DirectoryExists(location_) && !base::CreateDirectory(location_) &&
-      location_ != base::FilePath("/dev/null"))
-    PLOG(FATAL) << "unable to create output directory";
-  if (!base::PathIsWritable(location_))
-    PLOG(FATAL) << "unable to write to output location";
-}
-
-int32_t TestWindowManager::AddWindow(TestWindow* window) {
-  return windows_.Add(window);
-}
-
-void TestWindowManager::RemoveWindow(int32_t window_id, TestWindow* window) {
-  DCHECK_EQ(window, windows_.Lookup(window_id));
-  windows_.Remove(window_id);
-}
-
-TestWindow* TestWindowManager::GetWindow(int32_t window_id) {
-  return windows_.Lookup(window_id);
-}
-
-base::FilePath TestWindowManager::base_path() const {
-  return location_;
-}
-
-}  // namespace ui
diff --git a/ui/ozone/platform/test/test_window_manager.h b/ui/ozone/platform/test/test_window_manager.h
deleted file mode 100644
index b7adc14..0000000
--- a/ui/ozone/platform/test/test_window_manager.h
+++ /dev/null
@@ -1,50 +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 UI_OZONE_PLATFORM_TEST_TEST_WINDOW_MANAGER_H_
-#define UI_OZONE_PLATFORM_TEST_TEST_WINDOW_MANAGER_H_
-
-#include "base/files/file_path.h"
-#include "base/id_map.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/threading/thread_checker.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/ozone/public/surface_factory_ozone.h"
-
-namespace ui {
-
-class TestWindow;
-
-class TestWindowManager {
- public:
-  explicit TestWindowManager(const base::FilePath& dump_location);
-  ~TestWindowManager();
-
-  // Initialize (mainly check that we have a place to write output to).
-  void Initialize();
-
-  // Register a new window. Returns the window id.
-  int32_t AddWindow(TestWindow* window);
-
-  // Remove a window.
-  void RemoveWindow(int32_t window_id, TestWindow* window);
-
-  // Find a window object by id;
-  TestWindow* GetWindow(int32_t window_id);
-
-  // User-supplied path for images.
-  base::FilePath base_path() const;
-
- private:
-  base::FilePath location_;
-
-  IDMap<TestWindow> windows_;
-  base::ThreadChecker thread_checker_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestWindowManager);
-};
-
-}  // namespace ui
-
-#endif  // UI_OZONE_PLATFORM_TEST_TEST_WINDOW_MANAGER_H_
diff --git a/ui/ozone/public/surface_ozone_egl.h b/ui/ozone/public/surface_ozone_egl.h
index 3056dec..c2f06c0 100644
--- a/ui/ozone/public/surface_ozone_egl.h
+++ b/ui/ozone/public/surface_ozone_egl.h
@@ -46,7 +46,7 @@
   // be used to present the new front buffer if the platform requires this.
   // The callback should be run on the calling thread
   // (i.e. same thread SwapBuffersAsync is called).
-  virtual bool OnSwapBuffersAsync(const SwapCompletionCallback& callback) = 0;
+  virtual void OnSwapBuffersAsync(const SwapCompletionCallback& callback) = 0;
 
   // Returns a gfx::VsyncProvider for this surface. Note that this may be
   // called after we have entered the sandbox so if there are operations (e.g.
diff --git a/ui/views/mus/aura_init.cc b/ui/views/mus/aura_init.cc
index 653c9c37..e3e4d80 100644
--- a/ui/views/mus/aura_init.cc
+++ b/ui/views/mus/aura_init.cc
@@ -4,7 +4,6 @@
 
 #include "ui/views/mus/aura_init.h"
 
-#include "base/i18n/icu_util.h"
 #include "base/lazy_instance.h"
 #include "base/path_service.h"
 #include "components/resource_provider/public/cpp/resource_loader.h"
@@ -77,9 +76,6 @@
   if (!resource_loader.BlockUntilLoaded())
     return;
   CHECK(resource_loader.loaded());
-  base::i18n::InitializeICUWithFileDescriptor(
-      resource_loader.GetICUFile().TakePlatformFile(),
-      base::MemoryMappedFile::Region::kWholeFile);
   ui::RegisterPathProvider();
   base::File pak_file = resource_loader.ReleaseFile(resource_file_);
   base::File pak_file_2 = pak_file.Duplicate();
diff --git a/win8/metro_driver/metro_driver.gyp b/win8/metro_driver/metro_driver.gyp
index b1c17fd..c58ae33 100644
--- a/win8/metro_driver/metro_driver.gyp
+++ b/win8/metro_driver/metro_driver.gyp
@@ -119,8 +119,7 @@
                 'resources/Logo.png',
                 'resources/SecondaryTile.png',
                 'resources/SmallLogo.png',
-                'resources/splash-620x300.png',
-                'resources/VisualElementsManifest.xml',
+                'resources/chrome.VisualElementsManifest.xml',
               ],
             },
           ],
diff --git a/win8/metro_driver/resources/Logo.png b/win8/metro_driver/resources/Logo.png
index 16d18e3..eff95d996 100644
--- a/win8/metro_driver/resources/Logo.png
+++ b/win8/metro_driver/resources/Logo.png
Binary files differ
diff --git a/win8/metro_driver/resources/SmallLogo.png b/win8/metro_driver/resources/SmallLogo.png
index c25cfb4..eff95d996 100644
--- a/win8/metro_driver/resources/SmallLogo.png
+++ b/win8/metro_driver/resources/SmallLogo.png
Binary files differ
diff --git a/win8/metro_driver/resources/VisualElementsManifest.xml b/win8/metro_driver/resources/VisualElementsManifest.xml
deleted file mode 100644
index b9c765f..0000000
--- a/win8/metro_driver/resources/VisualElementsManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<!-- This is only meant to be copied by chrome.exe in developer builds. -->

-<Application

-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

-    <VisualElements

-        DisplayName="Developer Chrome"

-        Logo="Logo.png"

-        SmallLogo="SmallLogo.png"

-        ForegroundText="light"

-        BackgroundColor="white">

-        <DefaultTile

-            ShortName="DevChrome"

-            ShowName="allLogos"

-            />

-        <SplashScreen

-            Image="splash-620x300.png"/>

-    </VisualElements>

-</Application>

diff --git a/win8/metro_driver/resources/chrome.VisualElementsManifest.xml b/win8/metro_driver/resources/chrome.VisualElementsManifest.xml
new file mode 100644
index 0000000..640ef97
--- /dev/null
+++ b/win8/metro_driver/resources/chrome.VisualElementsManifest.xml
@@ -0,0 +1,9 @@
+<!-- This is only meant to be copied by chrome.exe in developer builds. -->
+<Application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+  <VisualElements
+    BackgroundColor="#323232"
+    ShowNameOnSquare150x150Logo="on"
+    ForegroundText="light"
+    Square150x150Logo="Logo.png"
+    Square70x70Logo="SmallLogo.png"/>
+</Application>
diff --git a/win8/metro_driver/resources/splash-620x300.png b/win8/metro_driver/resources/splash-620x300.png
deleted file mode 100644
index 41a3e02..0000000
--- a/win8/metro_driver/resources/splash-620x300.png
+++ /dev/null
Binary files differ