diff --git a/DEPS b/DEPS
index a864b57..a0847ba 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,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': '65a88fadab72abd104fdf4cc4a97488b2e901c60',
+  'skia_revision': '0ac06e47269a40c177747310a613d213c95d1d6d',
   # 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': '0a326e1f76471a5009e18f970bfa7a0778575323',
+  'v8_revision': 'ca06d3ccb68a47c86cae4c403289667617876d9b',
   # 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.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': 'a1a4adff333a739a9126801f008adf97d1487f39',
+  'catapult_revision': '6065b9274f907f556afab696d631dd816e325ff8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -130,7 +130,7 @@
     Var('chromium_git') + '/chromium/buildtools.git' + '@' +  Var('buildtools_revision'),
 
   'src/sdch/open-vcdiff':
-    Var('chromium_git') + '/external/github.com/google/open-vcdiff.git' + '@' + '2b9bd1fe548520e9355e457a134bab7e2f9c56c0',
+    Var('chromium_git') + '/external/github.com/google/open-vcdiff.git' + '@' + '7162d8ee5a7f1cca110749ec5c7585cdab3f0144',
 
   'src/third_party/freetype/src':
     Var('chromium_git') + '/chromium/src/third_party/freetype2.git' + '@' + Var('freetype_revision'),
@@ -1208,7 +1208,7 @@
       'action': [
         'python',
         'src/build/fuchsia/update_sdk.py',
-        'bb4f07c0178ae528aeb9d284333e3d0bf59a0eb7',
+        '2dea304860bf6cd92b68d20195c46adabc6ad33d',
       ],
     },
   ],
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc
index 07715b2885..7f05440 100644
--- a/android_webview/browser/aw_browser_main_parts.cc
+++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -122,17 +122,6 @@
       base::android::AttachCurrentThread());
   breakpad::CrashDumpObserver::Create();
 
-  if (crash_reporter::IsCrashReporterEnabled()) {
-    base::FilePath crash_dir;
-    if (PathService::Get(android_webview::DIR_CRASH_DUMPS, &crash_dir)) {
-      if (!base::PathExists(crash_dir))
-        base::CreateDirectory(crash_dir);
-      breakpad::CrashDumpObserver::GetInstance()->RegisterClient(
-          base::MakeUnique<breakpad::CrashDumpManager>(
-              crash_dir, kAndroidMinidumpDescriptor));
-    }
-  }
-
   // We need to create the safe browsing specific directory even if the
   // AwSafeBrowsingConfigHelper::GetSafeBrowsingEnabled() is false
   // initially, because safe browsing can be enabled later at runtime
@@ -144,11 +133,19 @@
       base::CreateDirectory(safe_browsing_dir);
   }
 
+  base::FilePath crash_dir;
+  if (crash_reporter::IsCrashReporterEnabled()) {
+    if (PathService::Get(android_webview::DIR_CRASH_DUMPS, &crash_dir)) {
+      if (!base::PathExists(crash_dir))
+        base::CreateDirectory(crash_dir);
+    }
+  }
+
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kWebViewSandboxedRenderer)) {
     // Create the renderers crash manager on the UI thread.
     breakpad::CrashDumpObserver::GetInstance()->RegisterClient(
-        base::MakeUnique<AwBrowserTerminator>());
+        base::MakeUnique<AwBrowserTerminator>(crash_dir));
   }
 
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/android_webview/browser/aw_browser_terminator.cc b/android_webview/browser/aw_browser_terminator.cc
index 77f89227..03637aa0 100644
--- a/android_webview/browser/aw_browser_terminator.cc
+++ b/android_webview/browser/aw_browser_terminator.cc
@@ -14,6 +14,7 @@
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/sync_socket.h"
+#include "base/task_scheduler/post_task.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/notification_service.h"
@@ -89,16 +90,14 @@
   }
 
   // By this point we have moved the minidump to the crash directory, so it can
-  // now be copied and uploaded. This is guaranteed by the order in which we
-  // register breakpad::CrashDumpManager and AwBrowserTerminator as
-  // breakpad::CrashDumpObserver clients over in AwBrowserMainParts
-  // (CrashDumpManager is registered first).
+  // now be copied and uploaded.
   TriggerMinidumpUploading();
 }
 
 }  // namespace
 
-AwBrowserTerminator::AwBrowserTerminator() {}
+AwBrowserTerminator::AwBrowserTerminator(base::FilePath crash_dump_dir)
+    : crash_dump_dir_(crash_dump_dir) {}
 
 AwBrowserTerminator::~AwBrowserTerminator() {}
 
@@ -117,12 +116,33 @@
     mappings->Transfer(kAndroidWebViewCrashSignalDescriptor,
                        base::ScopedFD(dup(child_pipe->handle())));
   }
+  if (crash_reporter::IsCrashReporterEnabled()) {
+    base::ScopedFD file(
+        breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFileForChild(
+            child_process_id));
+    if (file != base::kInvalidPlatformFile)
+      mappings->Transfer(kAndroidMinidumpDescriptor, std::move(file));
+  }
 }
 
-void AwBrowserTerminator::ProcessTerminationStatus(
+void AwBrowserTerminator::OnChildExitAsync(
     int child_process_id,
     base::ProcessHandle pid,
+    content::ProcessType process_type,
+    base::TerminationStatus termination_status,
+    base::android::ApplicationState app_state,
+    base::FilePath crash_dump_dir,
     std::unique_ptr<base::SyncSocket> pipe) {
+  if (crash_reporter::IsCrashReporterEnabled()) {
+    breakpad::CrashDumpManager::GetInstance()->ProcessMinidumpFileFromChild(
+        crash_dump_dir, child_process_id, process_type, termination_status,
+        app_state);
+  }
+
+  if (!pipe.get() ||
+      termination_status == base::TERMINATION_STATUS_NORMAL_TERMINATION)
+    return;
+
   bool crashed = false;
 
   // If the child process hasn't written anything into the pipe. This implies
@@ -150,23 +170,27 @@
 
   {
     base::AutoLock auto_lock(child_process_id_to_pipe_lock_);
+    // We might get a NOTIFICATION_RENDERER_PROCESS_TERMINATED and a
+    // NOTIFICATION_RENDERER_PROCESS_CLOSED. In that case we only want
+    // to process the first notification.
     const auto& iter = child_process_id_to_pipe_.find(child_process_id);
-    if (iter == child_process_id_to_pipe_.end()) {
-      // We might get a NOTIFICATION_RENDERER_PROCESS_TERMINATED and a
-      // NOTIFICATION_RENDERER_PROCESS_CLOSED.
-      return;
+    if (iter != child_process_id_to_pipe_.end()) {
+      pipe = std::move(iter->second);
+      DCHECK(pipe->handle() != base::SyncSocket::kInvalidHandle);
+      child_process_id_to_pipe_.erase(iter);
     }
-    pipe = std::move(iter->second);
-    child_process_id_to_pipe_.erase(iter);
   }
-  if (termination_status == base::TERMINATION_STATUS_NORMAL_TERMINATION)
-    return;
-  OnRenderProcessGone(child_process_id);
-  DCHECK(pipe->handle() != base::SyncSocket::kInvalidHandle);
-  BrowserThread::PostTask(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&AwBrowserTerminator::ProcessTerminationStatus,
-                 child_process_id, pid, base::Passed(std::move(pipe))));
+  if (pipe.get()) {
+    OnRenderProcessGone(child_process_id);
+  }
+
+  base::PostTaskWithTraits(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+      base::Bind(&AwBrowserTerminator::OnChildExitAsync, child_process_id, pid,
+                 process_type, termination_status, app_state, crash_dump_dir_,
+                 base::Passed(std::move(pipe))));
 }
 
 }  // namespace android_webview
diff --git a/android_webview/browser/aw_browser_terminator.h b/android_webview/browser/aw_browser_terminator.h
index 98430307..a13ce0c8 100644
--- a/android_webview/browser/aw_browser_terminator.h
+++ b/android_webview/browser/aw_browser_terminator.h
@@ -8,6 +8,7 @@
 #include <map>
 
 #include "base/synchronization/lock.h"
+#include "components/crash/content/browser/crash_dump_manager_android.h"
 #include "components/crash/content/browser/crash_dump_observer_android.h"
 
 namespace base {
@@ -26,7 +27,7 @@
 // crash status.
 class AwBrowserTerminator : public breakpad::CrashDumpObserver::Client {
  public:
-  AwBrowserTerminator();
+  AwBrowserTerminator(base::FilePath crash_dump_dir);
   ~AwBrowserTerminator() override;
 
   // breakpad::CrashDumpObserver::Client implementation.
@@ -39,9 +40,15 @@
                    base::android::ApplicationState app_state) override;
 
  private:
-  static void ProcessTerminationStatus(int child_process_id,
-                                       base::ProcessHandle pid,
-                                       std::unique_ptr<base::SyncSocket> pipe);
+  static void OnChildExitAsync(int child_process_id,
+                               base::ProcessHandle pid,
+                               content::ProcessType process_type,
+                               base::TerminationStatus termination_status,
+                               base::android::ApplicationState app_state,
+                               base::FilePath crash_dump_dir,
+                               std::unique_ptr<base::SyncSocket> pipe);
+
+  base::FilePath crash_dump_dir_;
 
   // This map should only be accessed with its lock aquired as it is accessed
   // from the PROCESS_LAUNCHER, FILE, and UI threads.
diff --git a/android_webview/browser/aw_contents_io_thread_client.cc b/android_webview/browser/aw_contents_io_thread_client.cc
index 75a73d5..02ebae7 100644
--- a/android_webview/browser/aw_contents_io_thread_client.cc
+++ b/android_webview/browser/aw_contents_io_thread_client.cc
@@ -310,6 +310,8 @@
 std::unique_ptr<AwWebResourceResponse> RunShouldInterceptRequest(
     const AwWebResourceRequest& request,
     JavaObjectWeakGlobalRef ref) {
+  base::ThreadRestrictions::AssertIOAllowed();
+
   JNIEnv* env = AttachCurrentThread();
   base::android::ScopedJavaLocalRef<jobject> obj = ref.get(env);
   if (obj.is_null())
diff --git a/ash/accelerators/accelerator_controller.cc b/ash/accelerators/accelerator_controller.cc
index ab41f72f..68c6c81 100644
--- a/ash/accelerators/accelerator_controller.cc
+++ b/ash/accelerators/accelerator_controller.cc
@@ -54,6 +54,7 @@
 #include "chromeos/chromeos_switches.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power_manager_client.h"
+#include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/presenter/app_list.h"
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/accelerators/accelerator_manager.h"
@@ -448,7 +449,7 @@
 void HandleToggleAppList(const ui::Accelerator& accelerator) {
   if (accelerator.key_code() == ui::VKEY_LWIN)
     base::RecordAction(UserMetricsAction("Accel_Search_LWin"));
-  Shell::Get()->ToggleAppList();
+  Shell::Get()->ToggleAppList(app_list::kSearchKey);
 }
 
 void HandleToggleFullscreen(const ui::Accelerator& accelerator) {
diff --git a/ash/mus/shell_delegate_mus.cc b/ash/mus/shell_delegate_mus.cc
index 4b945f524..f5b3253 100644
--- a/ash/mus/shell_delegate_mus.cc
+++ b/ash/mus/shell_delegate_mus.cc
@@ -132,14 +132,6 @@
   return nullptr;
 }
 
-PrefService* ShellDelegateMus::GetLocalStatePrefService() const {
-  // This code should never be called in the case of Config::MASH. Rather, the
-  // PrefService instance is stored by Shell when it manages to connect to the
-  // pref service in Chrome.
-  NOTREACHED();
-  return nullptr;
-}
-
 bool ShellDelegateMus::IsTouchscreenEnabledInPrefs(bool use_local_state) const {
   NOTIMPLEMENTED();
   return true;
diff --git a/ash/mus/shell_delegate_mus.h b/ash/mus/shell_delegate_mus.h
index 97c140c..ecd4156 100644
--- a/ash/mus/shell_delegate_mus.h
+++ b/ash/mus/shell_delegate_mus.h
@@ -45,7 +45,6 @@
   base::string16 GetProductName() const override;
   gfx::Image GetDeprecatedAcceleratorImage() const override;
   PrefService* GetActiveUserPrefService() const override;
-  PrefService* GetLocalStatePrefService() const override;
   bool IsTouchscreenEnabledInPrefs(bool use_local_state) const override;
   void SetTouchscreenEnabledInPrefs(bool enabled,
                                     bool use_local_state) override;
diff --git a/ash/shelf/app_list_button.h b/ash/shelf/app_list_button.h
index 45a0f56..2bf9232 100644
--- a/ash/shelf/app_list_button.h
+++ b/ash/shelf/app_list_button.h
@@ -75,7 +75,7 @@
 
   // Helper function to determine whether and event at |location| should be
   // handled by the back button or the app list circle. Returns false if we are
-  // not in maximized mode (there is no back button).
+  // not in tablet mode (there is no back button).
   bool IsBackEvent(const gfx::Point& location);
 
   // Generate and send a VKEY_BROWSER_BACK key event when the back button
diff --git a/ash/shelf/app_list_shelf_item_delegate.cc b/ash/shelf/app_list_shelf_item_delegate.cc
index a8cc9bf..62eb73e 100644
--- a/ash/shelf/app_list_shelf_item_delegate.cc
+++ b/ash/shelf/app_list_shelf_item_delegate.cc
@@ -8,6 +8,7 @@
 
 #include "ash/public/cpp/shelf_model.h"
 #include "ash/shell.h"
+#include "ui/app_list/app_list_constants.h"
 
 namespace ash {
 
@@ -20,7 +21,7 @@
                                             int64_t display_id,
                                             ShelfLaunchSource source,
                                             ItemSelectedCallback callback) {
-  Shell::Get()->ToggleAppList();
+  Shell::Get()->ToggleAppList(app_list::kShelfButton);
   std::move(callback).Run(SHELF_ACTION_APP_LIST_SHOWN, base::nullopt);
 }
 
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 85a0845..869b5b6a 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -29,6 +29,8 @@
 #include "base/auto_reset.h"
 #include "base/command_line.h"
 #include "base/i18n/rtl.h"
+#include "base/metrics/histogram_macros.h"
+#include "ui/app_list/app_list_constants.h"
 #include "ui/app_list/app_list_features.h"
 #include "ui/app_list/views/app_list_view.h"
 #include "ui/base/ui_base_switches.h"
@@ -1112,7 +1114,7 @@
   if (CanStartFullscreenAppListDrag(
           gesture_in_screen.details().scroll_y_hint())) {
     gesture_drag_status_ = GESTURE_DRAG_APPLIST_IN_PROGRESS;
-    Shell::Get()->ShowAppList();
+    Shell::Get()->ShowAppList(app_list::kSwipeFromShelf);
     Shell::Get()->UpdateAppListYPositionAndOpacity(
         gesture_in_screen.location().y(),
         GetAppListBackgroundOpacityOnShelfOpacity(),
@@ -1234,6 +1236,10 @@
             .work_area()
             .y(),
         GetAppListBackgroundOpacityOnShelfOpacity(), true /* is_end_gesture */);
+    UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
+                              app_list::kSwipeFromShelf,
+                              app_list::kMaxAppListToggleMethod);
+
   } else {
     Shell::Get()->DismissAppList();
   }
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 3ced02a..c2e2b71e 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -31,7 +31,7 @@
 namespace ui {
 class ImplicitAnimationObserver;
 class MouseEvent;
-}
+}  // namespace ui
 
 namespace ash {
 
@@ -326,7 +326,7 @@
   // Do any windows overlap the shelf? This is maintained by WorkspaceManager.
   bool window_overlaps_shelf_;
 
-  // Is the AppList visible? This is maintained by
+  // Whether the app list is visible. This is maintained by
   // OnAppListVisibilityChanged.
   bool is_app_list_visible_ = false;
 
diff --git a/ash/shell.cc b/ash/shell.cc
index 2482f44..9b151c25 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -128,6 +128,7 @@
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
 #include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/sys_info.h"
 #include "base/threading/sequenced_worker_pool.h"
 #include "base/trace_event/trace_event.h"
@@ -425,16 +426,16 @@
 
 PrefService* Shell::GetActiveUserPrefService() const {
   if (shell_port_->GetAshConfig() == Config::MASH)
-    return profile_pref_service_.get();
+    return profile_pref_service_mash_.get();
 
   return shell_delegate_->GetActiveUserPrefService();
 }
 
 PrefService* Shell::GetLocalStatePrefService() const {
   if (shell_port_->GetAshConfig() == Config::MASH)
-    return local_state_.get();
+    return local_state_mash_.get();
 
-  return shell_delegate_->GetLocalStatePrefService();
+  return local_state_non_mash_;
 }
 
 WebNotificationTray* Shell::GetWebNotificationTray() {
@@ -496,7 +497,11 @@
   shell_observers_.RemoveObserver(observer);
 }
 
-void Shell::ShowAppList() {
+void Shell::ShowAppList(app_list::AppListShowSource toggle_method) {
+  if (IsAppListVisible()) {
+    UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
+                              toggle_method, app_list::kMaxAppListToggleMethod);
+  }
   // Show the app list on the default display for new windows.
   app_list_->Show(display::Screen::GetScreen()
                       ->GetDisplayNearestWindow(GetRootWindowForNewWindows())
@@ -514,7 +519,11 @@
   app_list_->Dismiss();
 }
 
-void Shell::ToggleAppList() {
+void Shell::ToggleAppList(app_list::AppListShowSource toggle_method) {
+  if (IsAppListVisible()) {
+    UMA_HISTOGRAM_ENUMERATION(app_list::kAppListToggleMethodHistogram,
+                              toggle_method, app_list::kMaxAppListToggleMethod);
+  }
   // Toggle the app list on the default display for new windows.
   app_list_->ToggleAppList(
       display::Screen::GetScreen()
@@ -592,6 +601,15 @@
   g_is_browser_process_with_mash = true;
 }
 
+void Shell::SetLocalStatePrefService(PrefService* local_state) {
+  DCHECK(GetAshConfig() != Config::MASH);
+  DCHECK(local_state);
+  local_state_non_mash_ = local_state;
+
+  for (auto& observer : shell_observers_)
+    observer.OnLocalStatePrefServiceInitialized(local_state_non_mash_);
+}
+
 void Shell::NotifyAppListVisibilityChanged(bool visible,
                                            aura::Window* root_window) {
   for (auto& observer : shell_observers_)
@@ -840,7 +858,9 @@
   // NightLightController depeneds on the PrefService and must be destructed
   // before it. crbug.com/724231.
   night_light_controller_ = nullptr;
-  profile_pref_service_ = nullptr;
+  profile_pref_service_mash_.reset();
+  local_state_mash_.reset();
+  local_state_non_mash_ = nullptr;
   shell_delegate_.reset();
 
   for (auto& observer : shell_observers_)
@@ -1335,22 +1355,28 @@
 
 void Shell::OnProfilePrefServiceInitialized(
     std::unique_ptr<PrefService> pref_service) {
+  DCHECK(GetAshConfig() == Config::MASH);
   // Keep the old PrefService object alive so OnActiveUserPrefServiceChanged()
   // clients can unregister pref observers on the old service.
-  std::unique_ptr<PrefService> old_service = std::move(profile_pref_service_);
-  profile_pref_service_ = std::move(pref_service);
+  std::unique_ptr<PrefService> old_service =
+      std::move(profile_pref_service_mash_);
+  profile_pref_service_mash_ = std::move(pref_service);
   // |pref_service| can be null if can't connect to Chrome (as happens when
   // running mash outside of chrome --mash and chrome isn't built).
   for (auto& observer : shell_observers_)
-    observer.OnActiveUserPrefServiceChanged(profile_pref_service_.get());
+    observer.OnActiveUserPrefServiceChanged(profile_pref_service_mash_.get());
   // |old_service| is deleted.
 }
 
 void Shell::OnLocalStatePrefServiceInitialized(
     std::unique_ptr<::PrefService> pref_service) {
+  DCHECK(GetAshConfig() == Config::MASH);
   // |pref_service| is null if can't connect to Chrome (as happens when
   // running mash outside of chrome --mash and chrome isn't built).
-  local_state_ = std::move(pref_service);
+  local_state_mash_ = std::move(pref_service);
+
+  for (auto& observer : shell_observers_)
+    observer.OnLocalStatePrefServiceInitialized(local_state_mash_.get());
 }
 
 }  // namespace ash
diff --git a/ash/shell.h b/ash/shell.h
index 08b86645..1a34aebd 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -18,6 +18,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
+#include "ui/app_list/app_list_constants.h"
 #include "ui/aura/window.h"
 #include "ui/display/screen.h"
 #include "ui/events/event_target.h"
@@ -37,7 +38,7 @@
 class Window;
 class WindowManagerClient;
 class WindowTreeClient;
-}
+}  // namespace aura
 
 namespace chromeos {
 class AudioA11yController;
@@ -45,13 +46,13 @@
 
 namespace app_list {
 class AppList;
-}
+}  // namespace app_list
 
 namespace display {
 class DisplayChangeObserver;
 class DisplayConfigurator;
 class DisplayManager;
-}
+}  // namespace display
 
 namespace gfx {
 class Insets;
@@ -60,7 +61,7 @@
 namespace ui {
 class UserActivityDetector;
 class UserActivityPowerManagerNotifier;
-}
+}  // namespace ui
 
 namespace views {
 class NonClientFrameView;
@@ -68,7 +69,7 @@
 namespace corewm {
 class TooltipController;
 }
-}
+}  // namespace views
 
 namespace wm {
 class AcceleratorFilter;
@@ -78,7 +79,7 @@
 class ShadowController;
 class VisibilityController;
 class WindowModalityController;
-}
+}  // namespace wm
 
 namespace ash {
 
@@ -544,7 +545,7 @@
   void RemoveShellObserver(ShellObserver* observer);
 
   // Shows the app list on the active root window.
-  void ShowAppList();
+  void ShowAppList(app_list::AppListShowSource toggle_method);
 
   // Updates y position and opacity of app list. |is_end_gesture| means it is
   // the end of the gesture dragging of app list from shelf and should restore
@@ -557,7 +558,7 @@
   void DismissAppList();
 
   // Shows the app list if it's not visible. Dismisses it otherwise.
-  void ToggleAppList();
+  void ToggleAppList(app_list::AppListShowSource toggle_method);
 
   // Returns app list actual visibility. This might differ from
   // GetAppListTargetVisibility() when hiding animation is still in flight.
@@ -611,6 +612,9 @@
   // Used to provide better error messages for Shell::Get() under mash.
   static void SetIsBrowserProcessWithMash();
 
+  // Used when Chrome owns the pref service (not mash).
+  void SetLocalStatePrefService(PrefService* local_state);
+
   void NotifyAppListVisibilityChanged(bool visible, aura::Window* root_window);
 
   void NotifyVoiceInteractionStatusChanged(bool running);
@@ -736,8 +740,13 @@
   // Only initialized for mash. Can be null in ash_standalone (when chrome is
   // not running) or when reconnecting to the mojo pref service after
   // multiuser profile switch.
-  std::unique_ptr<::PrefService> profile_pref_service_;
-  std::unique_ptr<::PrefService> local_state_;
+  std::unique_ptr<PrefService> profile_pref_service_mash_;
+
+  // Used in non-mash. Owned by chrome.
+  PrefService* local_state_non_mash_ = nullptr;
+
+  // Used in mash.
+  std::unique_ptr<PrefService> local_state_mash_;
 
   std::unique_ptr<views::corewm::TooltipController> tooltip_controller_;
   LinkHandlerModelFactory* link_handler_model_factory_;
diff --git a/ash/shell/shell_delegate_impl.cc b/ash/shell/shell_delegate_impl.cc
index 0fd30d7ed..4e83767 100644
--- a/ash/shell/shell_delegate_impl.cc
+++ b/ash/shell/shell_delegate_impl.cc
@@ -145,10 +145,6 @@
   return nullptr;
 }
 
-PrefService* ShellDelegateImpl::GetLocalStatePrefService() const {
-  return nullptr;
-}
-
 bool ShellDelegateImpl::IsTouchscreenEnabledInPrefs(
     bool use_local_state) const {
   return true;
diff --git a/ash/shell/shell_delegate_impl.h b/ash/shell/shell_delegate_impl.h
index 0924384..fa4e693 100644
--- a/ash/shell/shell_delegate_impl.h
+++ b/ash/shell/shell_delegate_impl.h
@@ -47,7 +47,6 @@
   base::string16 GetProductName() const override;
   gfx::Image GetDeprecatedAcceleratorImage() const override;
   PrefService* GetActiveUserPrefService() const override;
-  PrefService* GetLocalStatePrefService() const override;
   bool IsTouchscreenEnabledInPrefs(bool use_local_state) const override;
   void SetTouchscreenEnabledInPrefs(bool enabled,
                                     bool use_local_state) override;
diff --git a/ash/shell_delegate.h b/ash/shell_delegate.h
index 98932ce..6f013d0 100644
--- a/ash/shell_delegate.h
+++ b/ash/shell_delegate.h
@@ -122,10 +122,9 @@
 
   virtual gfx::Image GetDeprecatedAcceleratorImage() const = 0;
 
+  // Not used in mash because ash owns the PrefService.
   virtual PrefService* GetActiveUserPrefService() const = 0;
 
-  virtual PrefService* GetLocalStatePrefService() const = 0;
-
   // If |use_local_state| is true, returns the touchscreen status from local
   // state, otherwise from user prefs.
   virtual bool IsTouchscreenEnabledInPrefs(bool use_local_state) const = 0;
diff --git a/ash/shell_observer.h b/ash/shell_observer.h
index 1eadbff..fbf20b4 100644
--- a/ash/shell_observer.h
+++ b/ash/shell_observer.h
@@ -78,6 +78,10 @@
   // most of Shell's state has been deleted.
   virtual void OnShellDestroyed() {}
 
+  // Called when local state prefs are available. This occurs an arbitrary
+  // amount of time after Shell initialization. Only called once.
+  virtual void OnLocalStatePrefServiceInitialized(PrefService* pref_service) {}
+
   // Called when the user profile pref service is available. Also called after
   // multiprofile user switch. Never called with the login screen profile.
   // May be called with null in tests.
diff --git a/ash/shell_test_api.cc b/ash/shell_test_api.cc
index 99decb71..8d77a0b 100644
--- a/ash/shell_test_api.cc
+++ b/ash/shell_test_api.cc
@@ -9,6 +9,7 @@
 #include "ash/palette_delegate.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
+#include "components/prefs/testing_pref_service.h"
 
 namespace ash {
 
@@ -41,4 +42,9 @@
   shell_->palette_delegate_ = std::move(palette_delegate);
 }
 
+void ShellTestApi::OnLocalStatePrefServiceInitialized(
+    std::unique_ptr<PrefService> pref_service) {
+  shell_->OnLocalStatePrefServiceInitialized(std::move(pref_service));
+}
+
 }  // namespace ash
diff --git a/ash/shell_test_api.h b/ash/shell_test_api.h
index 9c4c8e6..30e5d3e 100644
--- a/ash/shell_test_api.h
+++ b/ash/shell_test_api.h
@@ -9,6 +9,8 @@
 
 #include "base/macros.h"
 
+class PrefService;
+
 namespace ash {
 class NativeCursorManagerAsh;
 class DragDropController;
@@ -34,6 +36,10 @@
 
   void SetPaletteDelegate(std::unique_ptr<PaletteDelegate> palette_delegate);
 
+  // Calls the private method.
+  void OnLocalStatePrefServiceInitialized(
+      std::unique_ptr<PrefService> pref_service);
+
  private:
   Shell* shell_;  // not owned
 
diff --git a/ash/shell_unittest.cc b/ash/shell_unittest.cc
index bd4b2a2..21b6f487 100644
--- a/ash/shell_unittest.cc
+++ b/ash/shell_unittest.cc
@@ -139,11 +139,15 @@
   ~TestShellObserver() override = default;
 
   // ShellObserver:
+  void OnLocalStatePrefServiceInitialized(PrefService* pref_service) override {
+    last_local_state_ = pref_service;
+  }
   void OnActiveUserPrefServiceChanged(PrefService* pref_service) override {
-    last_pref_service_ = pref_service;
+    last_user_pref_service_ = pref_service;
   }
 
-  PrefService* last_pref_service_ = nullptr;
+  PrefService* last_local_state_ = nullptr;
+  PrefService* last_user_pref_service_ = nullptr;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TestShellObserver);
@@ -583,13 +587,64 @@
   ash_test_helper()->test_shell_delegate()->set_active_user_pref_service(
       &pref_service1_);
   session->SwitchActiveUser(AccountId::FromUserEmail("user1@test.com"));
-  EXPECT_EQ(&pref_service1_, observer.last_pref_service_);
+  EXPECT_EQ(&pref_service1_, observer.last_user_pref_service_);
 
   // Switching users notifies observers of the new user pref service.
   ash_test_helper()->test_shell_delegate()->set_active_user_pref_service(
       &pref_service2_);
   session->SwitchActiveUser(AccountId::FromUserEmail("user2@test.com"));
-  EXPECT_EQ(&pref_service2_, observer.last_pref_service_);
+  EXPECT_EQ(&pref_service2_, observer.last_user_pref_service_);
+
+  Shell::Get()->RemoveShellObserver(&observer);
+}
+
+// Tests the local state code path used with Config::CLASSIC and Config::MUS.
+class ShellLocalStateTestNonMash : public NoSessionAshTestBase {
+ public:
+  ShellLocalStateTestNonMash() = default;
+  ~ShellLocalStateTestNonMash() override = default;
+
+  // Must outlive Shell.
+  TestingPrefServiceSimple local_state_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ShellLocalStateTestNonMash);
+};
+
+TEST_F(ShellLocalStateTestNonMash, LocalState) {
+  if (Shell::GetAshConfig() == Config::MASH)
+    return;
+
+  TestShellObserver observer;
+  Shell::Get()->AddShellObserver(&observer);
+
+  // In classic ash, chrome calls into ash to set up local state.
+  Shell::RegisterLocalStatePrefs(local_state_.registry());
+  Shell::Get()->SetLocalStatePrefService(&local_state_);
+  EXPECT_EQ(&local_state_, observer.last_local_state_);
+  EXPECT_EQ(&local_state_, Shell::Get()->GetLocalStatePrefService());
+
+  Shell::Get()->RemoveShellObserver(&observer);
+}
+
+// Tests the local state code path used with Config::MASH.
+using ShellLocalStateTestMash = ShellTest;
+
+TEST_F(ShellLocalStateTestMash, LocalState) {
+  if (Shell::GetAshConfig() != Config::MASH)
+    return;
+
+  TestShellObserver observer;
+  Shell::Get()->AddShellObserver(&observer);
+
+  // In mash, prefs service wrapper code creates a PrefService.
+  std::unique_ptr<TestingPrefServiceSimple> local_state =
+      base::MakeUnique<TestingPrefServiceSimple>();
+  Shell::RegisterLocalStatePrefs(local_state->registry());
+  TestingPrefServiceSimple* local_state_ptr = local_state.get();
+  ShellTestApi().OnLocalStatePrefServiceInitialized(std::move(local_state));
+  EXPECT_EQ(local_state_ptr, observer.last_local_state_);
+  EXPECT_EQ(local_state_ptr, Shell::Get()->GetLocalStatePrefService());
 
   Shell::Get()->RemoveShellObserver(&observer);
 }
diff --git a/ash/system/palette/palette_tray.cc b/ash/system/palette/palette_tray.cc
index 113fdff..39ed70a 100644
--- a/ash/system/palette/palette_tray.cc
+++ b/ash/system/palette/palette_tray.cc
@@ -236,6 +236,31 @@
   }
 }
 
+void PaletteTray::OnLocalStatePrefServiceInitialized(
+    PrefService* pref_service) {
+  local_state_pref_service_ = pref_service;
+
+  // May be null in mash_unittests where there is no mojo pref service.
+  if (!local_state_pref_service_)
+    return;
+
+  // If a device has an internal stylus or the flag to force stylus is set, mark
+  // the has seen stylus flag as true since we know the user has a stylus.
+  if (palette_utils::HasInternalStylus() ||
+      palette_utils::HasForcedStylusInput()) {
+    local_state_pref_service_->SetBoolean(prefs::kHasSeenStylus, true);
+  }
+
+  pref_change_registrar_ = base::MakeUnique<PrefChangeRegistrar>();
+  pref_change_registrar_->Init(local_state_pref_service_);
+  pref_change_registrar_->Add(
+      prefs::kHasSeenStylus,
+      base::Bind(&PaletteTray::OnHasSeenStylusPrefChanged,
+                 base::Unretained(this)));
+
+  OnHasSeenStylusPrefChanged();
+}
+
 void PaletteTray::ClickedOutsideBubble() {
   if (num_actions_in_bubble_ == 0)
     RecordPaletteOptionsUsage(PaletteTrayOptions::PALETTE_CLOSED_NO_ACTION);
@@ -386,29 +411,6 @@
   // which will take care of showing the palette.
   palette_enabled_subscription_ = delegate->AddPaletteEnableListener(base::Bind(
       &PaletteTray::OnPaletteEnabledPrefChanged, weak_factory_.GetWeakPtr()));
-
-  local_state_pref_service_ = Shell::Get()->GetLocalStatePrefService();
-
-  // |local_state_pref_service_| may be null in tests.
-  // TODO(crbug.com/751191): Remove the check for Mash.
-  if (Shell::GetAshConfig() == Config::MASH || !local_state_pref_service_)
-    return;
-
-  // If a device has an internal stylus or the flag to force stylus is set, mark
-  // the has seen stylus flag as true since we know the user has a stylus.
-  if (palette_utils::HasInternalStylus() ||
-      palette_utils::HasForcedStylusInput()) {
-    local_state_pref_service_->SetBoolean(prefs::kHasSeenStylus, true);
-  }
-
-  pref_change_registrar_ = base::MakeUnique<PrefChangeRegistrar>();
-  pref_change_registrar_->Init(local_state_pref_service_);
-  pref_change_registrar_->Add(
-      prefs::kHasSeenStylus,
-      base::Bind(&PaletteTray::OnHasSeenStylusPrefChanged,
-                 base::Unretained(this)));
-
-  OnHasSeenStylusPrefChanged();
 }
 
 bool PaletteTray::PerformAction(const ui::Event& event) {
diff --git a/ash/system/palette/palette_tray.h b/ash/system/palette/palette_tray.h
index 5221dbc..affbfc1 100644
--- a/ash/system/palette/palette_tray.h
+++ b/ash/system/palette/palette_tray.h
@@ -76,6 +76,7 @@
 
   // ShellObserver:
   void OnLockStateChanged(bool locked) override;
+  void OnLocalStatePrefServiceInitialized(PrefService* pref_service) override;
 
   // TrayBackgroundView:
   void ClickedOutsideBubble() override;
diff --git a/ash/system/palette/palette_tray_unittest.cc b/ash/system/palette/palette_tray_unittest.cc
index 5cf52292..5e53490b 100644
--- a/ash/system/palette/palette_tray_unittest.cc
+++ b/ash/system/palette/palette_tray_unittest.cc
@@ -43,8 +43,6 @@
     palette_utils::SetHasStylusInputForTesting();
 
     Shell::RegisterLocalStatePrefs(pref_service_.registry());
-    ash_test_helper()->test_shell_delegate()->set_local_state_pref_service(
-        &pref_service_);
 
     palette_tray_ =
         StatusAreaWidgetTestHelper::GetStatusAreaWidget()->palette_tray();
@@ -57,15 +55,7 @@
     // from the palette delegate. (It was initialized without the delegate in
     // AshTestBase::SetUp()).
     palette_tray_->Initialize();
-  }
-
-  // Adds the command line flag which states this device has an internal stylus.
-  void InitForInternalStylus() {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kHasInternalStylus);
-    // Initialize the palette tray again so the changes from adding this switch
-    // are applied.
-    palette_tray_->Initialize();
+    palette_tray_->OnLocalStatePrefServiceInitialized(&pref_service_);
   }
 
   // Performs a tap on the palette tray button.
@@ -94,10 +84,6 @@
 // Verify that if the has seen stylus pref is not set initially, the palette
 // tray's touch event watcher should be active.
 TEST_F(PaletteTrayTest, PaletteTrayStylusWatcherAlive) {
-  // TODO(crbug.com/752997): Remove the check for Mash.
-  if (Shell::GetAshConfig() == Config::MASH)
-    return;
-
   ASSERT_FALSE(palette_tray_->visible());
 
   EXPECT_TRUE(test_api_->IsStylusWatcherActive());
@@ -106,10 +92,6 @@
 // Verify if the has seen stylus pref is not set initially, the palette tray
 // should become visible after seeing a stylus event.
 TEST_F(PaletteTrayTest, PaletteTrayVisibleAfterStylusSeen) {
-  // TODO(crbug.com/752997): Remove the check for Mash.
-  if (Shell::GetAshConfig() == Config::MASH)
-    return;
-
   ASSERT_FALSE(palette_tray_->visible());
   ASSERT_FALSE(pref_service_.GetBoolean(prefs::kHasSeenStylus));
   ASSERT_TRUE(test_api_->IsStylusWatcherActive());
@@ -129,10 +111,6 @@
 // Verify if the has seen stylus pref is initially set, the palette tray is
 // visible.
 TEST_F(PaletteTrayTest, StylusSeenPrefInitiallySet) {
-  // TODO(crbug.com/752997): Remove the check for Mash.
-  if (Shell::GetAshConfig() == Config::MASH)
-    return;
-
   ASSERT_FALSE(palette_tray_->visible());
   pref_service_.SetBoolean(prefs::kHasSeenStylus, true);
 
@@ -140,45 +118,6 @@
   EXPECT_FALSE(test_api_->IsStylusWatcherActive());
 }
 
-// Verify the palette tray button exists and is visible if the device has an
-// internal stylus.
-TEST_F(PaletteTrayTest, PaletteTrayIsVisibleForInternalStylus) {
-  // TODO(crbug.com/752997): Remove the check for Mash.
-  if (Shell::GetAshConfig() == Config::MASH)
-    return;
-
-  InitForInternalStylus();
-  ASSERT_TRUE(palette_tray_);
-  EXPECT_TRUE(palette_tray_->visible());
-}
-
-// Verify that when entering or exiting the lock screen, the behavior of the
-// palette tray button is as expected.
-TEST_F(PaletteTrayTest, PaletteTrayOnLockScreenBehavior) {
-  // TODO(crbug.com/752997): Remove the check for Mash.
-  if (Shell::GetAshConfig() == Config::MASH)
-    return;
-
-  InitForInternalStylus();
-  ASSERT_TRUE(palette_tray_->visible());
-
-  PaletteToolManager* manager = test_api_->GetPaletteToolManager();
-  manager->ActivateTool(PaletteToolId::LASER_POINTER);
-  EXPECT_TRUE(manager->IsToolActive(PaletteToolId::LASER_POINTER));
-
-  // Verify that when entering the lock screen, the palette tray button is
-  // hidden, and the tool that was active is no longer active.
-  GetSessionControllerClient()->RequestLockScreen();
-  EXPECT_FALSE(manager->IsToolActive(PaletteToolId::LASER_POINTER));
-  EXPECT_FALSE(palette_tray_->visible());
-
-  // Verify that when logging back in the tray is visible, but the tool that was
-  // active before locking the screen is still inactive.
-  GetSessionControllerClient()->UnlockScreen();
-  EXPECT_TRUE(palette_tray_->visible());
-  EXPECT_FALSE(manager->IsToolActive(PaletteToolId::LASER_POINTER));
-}
-
 // Verify taps on the palette tray button results in expected behaviour.
 TEST_F(PaletteTrayTest, PaletteTrayWorkflow) {
   // Verify the palette tray button is not active, and the palette tray bubble
@@ -245,4 +184,46 @@
   EXPECT_FALSE(palette_tray_->is_active());
 }
 
+// Base class for tests that need to simulate an internal stylus.
+class PaletteTrayTestWithInternalStylus : public PaletteTrayTest {
+ public:
+  PaletteTrayTestWithInternalStylus() {
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kHasInternalStylus);
+  }
+  ~PaletteTrayTestWithInternalStylus() override = default;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PaletteTrayTestWithInternalStylus);
+};
+
+// Verify the palette tray button exists and is visible if the device has an
+// internal stylus.
+TEST_F(PaletteTrayTestWithInternalStylus, Visible) {
+  ASSERT_TRUE(palette_tray_);
+  EXPECT_TRUE(palette_tray_->visible());
+}
+
+// Verify that when entering or exiting the lock screen, the behavior of the
+// palette tray button is as expected.
+TEST_F(PaletteTrayTestWithInternalStylus, PaletteTrayOnLockScreenBehavior) {
+  ASSERT_TRUE(palette_tray_->visible());
+
+  PaletteToolManager* manager = test_api_->GetPaletteToolManager();
+  manager->ActivateTool(PaletteToolId::LASER_POINTER);
+  EXPECT_TRUE(manager->IsToolActive(PaletteToolId::LASER_POINTER));
+
+  // Verify that when entering the lock screen, the palette tray button is
+  // hidden, and the tool that was active is no longer active.
+  GetSessionControllerClient()->RequestLockScreen();
+  EXPECT_FALSE(manager->IsToolActive(PaletteToolId::LASER_POINTER));
+  EXPECT_FALSE(palette_tray_->visible());
+
+  // Verify that when logging back in the tray is visible, but the tool that was
+  // active before locking the screen is still inactive.
+  GetSessionControllerClient()->UnlockScreen();
+  EXPECT_TRUE(palette_tray_->visible());
+  EXPECT_FALSE(manager->IsToolActive(PaletteToolId::LASER_POINTER));
+}
+
 }  // namespace ash
diff --git a/ash/test_shell_delegate.cc b/ash/test_shell_delegate.cc
index 7ab82b20..b6920eb 100644
--- a/ash/test_shell_delegate.cc
+++ b/ash/test_shell_delegate.cc
@@ -139,10 +139,6 @@
   return active_user_pref_service_;
 }
 
-PrefService* TestShellDelegate::GetLocalStatePrefService() const {
-  return local_state_pref_service_;
-}
-
 bool TestShellDelegate::IsTouchscreenEnabledInPrefs(
     bool use_local_state) const {
   return use_local_state ? touchscreen_enabled_in_local_pref_ : true;
diff --git a/ash/test_shell_delegate.h b/ash/test_shell_delegate.h
index bcf7cd8..ebbe439 100644
--- a/ash/test_shell_delegate.h
+++ b/ash/test_shell_delegate.h
@@ -34,10 +34,6 @@
     active_user_pref_service_ = pref_service;
   }
 
-  void set_local_state_pref_service(PrefService* pref_service) {
-    local_state_pref_service_ = pref_service;
-  }
-
   // Overridden from ShellDelegate:
   ::service_manager::Connector* GetShellConnector() const override;
   bool IsIncognitoAllowed() const override;
@@ -62,7 +58,6 @@
   base::string16 GetProductName() const override;
   gfx::Image GetDeprecatedAcceleratorImage() const override;
   PrefService* GetActiveUserPrefService() const override;
-  PrefService* GetLocalStatePrefService() const override;
   bool IsTouchscreenEnabledInPrefs(bool use_local_state) const override;
   void SetTouchscreenEnabledInPrefs(bool enabled,
                                     bool use_local_state) override;
@@ -86,7 +81,6 @@
   bool media_sessions_suspended_ = false;
   std::unique_ptr<ShelfInitializer> shelf_initializer_;
   PrefService* active_user_pref_service_ = nullptr;  // Not owned.
-  PrefService* local_state_pref_service_ = nullptr;  // Not owned.
 
   DISALLOW_COPY_AND_ASSIGN(TestShellDelegate);
 };
diff --git a/ash/wallpaper/wallpaper_controller.cc b/ash/wallpaper/wallpaper_controller.cc
index 165416e..b79db51e 100644
--- a/ash/wallpaper/wallpaper_controller.cc
+++ b/ash/wallpaper/wallpaper_controller.cc
@@ -302,12 +302,6 @@
     session_manager::SessionState state) {
   CalculateWallpaperColors();
 
-  // The wallpaper may be dimmed/blurred based on session state. The color of
-  // the dimming overlay depends on the prominent color cached from a previous
-  // calculation, or a default color if cache is not available. It should never
-  // depend on any in-flight color calculation.
-  InstallDesktopControllerForAllWindows();
-
   if (state == session_manager::SessionState::ACTIVE)
     MoveToUnlockedContainer();
   else
diff --git a/ash/wallpaper/wallpaper_view.cc b/ash/wallpaper/wallpaper_view.cc
index ec74bc7..17f34a1 100644
--- a/ash/wallpaper/wallpaper_view.cc
+++ b/ash/wallpaper/wallpaper_view.cc
@@ -4,7 +4,6 @@
 
 #include "ash/wallpaper/wallpaper_view.h"
 
-#include "ash/login/ui/login_constants.h"
 #include "ash/root_window_controller.h"
 #include "ash/session/session_controller.h"
 #include "ash/shell.h"
@@ -19,8 +18,6 @@
 #include "ui/display/manager/managed_display_info.h"
 #include "ui/display/screen.h"
 #include "ui/gfx/canvas.h"
-#include "ui/gfx/color_analysis.h"
-#include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/transform.h"
@@ -74,23 +71,6 @@
   DISALLOW_COPY_AND_ASSIGN(LayerControlView);
 };
 
-// Returns the color used to darken the wallpaper, needed by login, lock, OOBE
-// and add user screens.
-SkColor GetWallpaperDarkenColor() {
-  SkColor darken_color =
-      Shell::Get()->wallpaper_controller()->GetProminentColor(
-          color_utils::ColorProfile(color_utils::LumaRange::DARK,
-                                    color_utils::SaturationRange::MUTED));
-  if (darken_color == WallpaperController::kInvalidColor)
-    darken_color = login_constants::kDefaultBaseColor;
-
-  darken_color = color_utils::GetResultingPaintColor(
-      SkColorSetA(login_constants::kDefaultBaseColor,
-                  login_constants::kTranslucentColorDarkenAlpha),
-      SkColorSetA(darken_color, 0xFF));
-  return SkColorSetA(darken_color, login_constants::kTranslucentAlpha);
-}
-
 }  // namespace
 
 // This event handler receives events in the pre-target phase and takes care of
@@ -159,12 +139,6 @@
   if (wallpaper.isNull())
     return;
 
-  cc::PaintFlags flags;
-  if (Shell::Get()->session_controller()->IsUserSessionBlocked()) {
-    flags.setColorFilter(SkColorFilter::MakeModeFilter(
-        GetWallpaperDarkenColor(), SkBlendMode::kDarken));
-  }
-
   if (layout == wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED) {
     // The dimension with the smallest ratio must be cropped, the other one
     // is preserved. Both are set in gfx::Size cropped_size.
@@ -190,14 +164,13 @@
     canvas->DrawImageInt(
         wallpaper, wallpaper_cropped_rect.x(), wallpaper_cropped_rect.y(),
         wallpaper_cropped_rect.width(), wallpaper_cropped_rect.height(), 0, 0,
-        width(), height(), true, flags);
+        width(), height(), true);
   } else if (layout == wallpaper::WALLPAPER_LAYOUT_TILE) {
-    canvas->TileImageInt(wallpaper, 0, 0, 0, 0, width(), height(), 1.0f,
-                         &flags);
+    canvas->TileImageInt(wallpaper, 0, 0, width(), height());
   } else if (layout == wallpaper::WALLPAPER_LAYOUT_STRETCH) {
     // This is generally not recommended as it may show artifacts.
     canvas->DrawImageInt(wallpaper, 0, 0, wallpaper.width(), wallpaper.height(),
-                         0, 0, width(), height(), true, flags);
+                         0, 0, width(), height(), true);
   } else {
     float image_scale = canvas->image_scale();
     gfx::Rect wallpaper_rect(0, 0, wallpaper.width() / image_scale,
@@ -206,8 +179,7 @@
     canvas->DrawImageInt(wallpaper, 0, 0, wallpaper.width(), wallpaper.height(),
                          (width() - wallpaper_rect.width()) / 2,
                          (height() - wallpaper_rect.height()) / 2,
-                         wallpaper_rect.width(), wallpaper_rect.height(), true,
-                         flags);
+                         wallpaper_rect.width(), wallpaper_rect.height(), true);
   }
 }
 
@@ -263,9 +235,6 @@
 
   aura::Window* container = root_window->GetChildById(container_id);
   wallpaper_widget->SetBounds(container->bounds());
-  if (Shell::Get()->session_controller()->IsUserSessionBlocked())
-    wallpaper_widget->GetLayer()->SetLayerBlur(login_constants::kBlurSigma);
-
   return wallpaper_widget;
 }
 
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 6cbc5fd..40c944aa 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -33,6 +33,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/user_action_tester.h"
+#include "ui/app_list/app_list_constants.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/focus_client.h"
 #include "ui/aura/test/test_windows.h"
@@ -496,7 +497,9 @@
   EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
   EXPECT_EQ(window1.get(), wm::GetFocusedWindow());
 
-  Shell::Get()->ToggleAppList();
+  // Pass an enum to satisfy the function, it is arbitrary and will not effect
+  // histograms.
+  Shell::Get()->ToggleAppList(app_list::kShelfButton);
 
   // Activating overview cancels the App-list which normally would activate the
   // previously active |window1|. Overview mode should properly transfer focus
diff --git a/base/process/process_handle.h b/base/process/process_handle.h
index bc0e08e1..4ce05e2b 100644
--- a/base/process/process_handle.h
+++ b/base/process/process_handle.h
@@ -44,6 +44,15 @@
 const ProcessId kNullProcessId = 0;
 #endif  // defined(OS_WIN)
 
+// To print ProcessIds portably use CrPRIdPid (based on PRIuS and friends from
+// C99 and format_macros.h) like this:
+// base::StringPrintf("PID is %" CrPRIdPid ".\n", pid);
+#if defined(OS_WIN)
+#define CrPRIdPid "ld"
+#else
+#define CrPRIdPid "d"
+#endif
+
 // Returns the id of the current process.
 // Note that on some platforms, this is not guaranteed to be unique across
 // processes (use GetUniqueIdForProcess if uniqueness is required).
diff --git a/build/args/headless.gn b/build/args/headless.gn
index 9452c15..2f8a2633 100644
--- a/build/args/headless.gn
+++ b/build/args/headless.gn
@@ -15,6 +15,9 @@
 # Embed resource.pak into binary to simplify deployment.
 headless_use_embedded_resources = true
 
+# Expose headless bindings for freetype library bundled with Chromium.
+headless_fontconfig_utils = true
+
 # Remove a dependency on a system fontconfig library.
 use_bundled_fontconfig = true
 
diff --git a/build/config/ui.gni b/build/config/ui.gni
index 6ce77e6..ce384b5 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -31,7 +31,7 @@
 
   # Indicates if Aura is enabled. Aura is a low-level windowing library, sort
   # of a replacement for GDI or GTK.
-  use_aura = is_win || is_linux || is_fuchsia
+  use_aura = is_win || is_linux
 
   # Whether we should use glib, a low level C utility library.
   use_glib = is_linux
@@ -39,8 +39,8 @@
 
 declare_args() {
   # True means the UI is built using the "views" framework.
-  toolkit_views = (is_mac || is_win || is_chromeos || use_aura) &&
-                  !is_chromecast && !is_fuchsia
+  toolkit_views =
+      (is_mac || is_win || is_chromeos || use_aura) && !is_chromecast
 }
 
 # Additional dependent variables -----------------------------------------------
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 24cd3fb..ef4042c 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -853,6 +853,7 @@
     "//media",
     "//mojo/edk/system",
     "//mojo/public/cpp/bindings",
+    "//services/viz/public/interfaces/compositing",
     "//skia",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/cc/ipc/BUILD.gn b/cc/ipc/BUILD.gn
index 4df7c2e..f3714f9 100644
--- a/cc/ipc/BUILD.gn
+++ b/cc/ipc/BUILD.gn
@@ -40,7 +40,6 @@
 mojom("interfaces") {
   sources = [
     "begin_frame_args.mojom",
-    "compositor_frame.mojom",
     "compositor_frame_metadata.mojom",
     "copy_output_request.mojom",
     "copy_output_result.mojom",
diff --git a/cc/ipc/DEPS b/cc/ipc/DEPS
index 44e573a..a21ff764 100644
--- a/cc/ipc/DEPS
+++ b/cc/ipc/DEPS
@@ -6,4 +6,5 @@
   "+ui/gfx/geometry/mojo",
   "+ui/latency/ipc",
   "+ui/latency/mojo",
+  "+services/viz/public",
 ]
diff --git a/cc/ipc/cc_serialization_perftest.cc b/cc/ipc/cc_serialization_perftest.cc
index 4bd3d0d..20360903 100644
--- a/cc/ipc/cc_serialization_perftest.cc
+++ b/cc/ipc/cc_serialization_perftest.cc
@@ -8,9 +8,7 @@
 #include "base/test/test_suite.h"
 #include "cc/ipc/begin_frame_args_struct_traits.h"
 #include "cc/ipc/cc_param_traits.h"
-#include "cc/ipc/compositor_frame.mojom.h"
 #include "cc/ipc/compositor_frame_metadata_struct_traits.h"
-#include "cc/ipc/compositor_frame_struct_traits.h"
 #include "cc/ipc/render_pass_struct_traits.h"
 #include "cc/ipc/selection_struct_traits.h"
 #include "cc/ipc/shared_quad_state_struct_traits.h"
@@ -23,6 +21,8 @@
 #include "gpu/ipc/common/sync_token_struct_traits.h"
 #include "ipc/ipc_message.h"
 #include "mojo/public/cpp/bindings/message.h"
+#include "services/viz/public/cpp/compositing/compositor_frame_struct_traits.h"
+#include "services/viz/public/interfaces/compositing/compositor_frame.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/perf/perf_test.h"
 #include "third_party/skia/include/effects/SkBlurImageFilter.h"
@@ -141,10 +141,11 @@
       const std::string& test_name,
       const CompositorFrame& frame,
       UseSingleSharedQuadState single_sqs) {
-    mojo::Message message = mojom::CompositorFrame::SerializeAsMessage(&frame);
+    mojo::Message message =
+        viz::mojom::CompositorFrame::SerializeAsMessage(&frame);
     for (int i = 0; i < kNumWarmupRuns; ++i) {
       CompositorFrame compositor_frame;
-      mojom::CompositorFrame::Deserialize(
+      viz::mojom::CompositorFrame::Deserialize(
           message.payload(), message.payload_num_bytes(), &compositor_frame);
     }
 
@@ -157,7 +158,7 @@
     while (start < end) {
       for (int i = 0; i < kTimeCheckInterval; ++i) {
         CompositorFrame compositor_frame;
-        mojom::CompositorFrame::Deserialize(
+        viz::mojom::CompositorFrame::Deserialize(
             message.payload(), message.payload_num_bytes(), &compositor_frame);
         now = base::TimeTicks::Now();
         // We don't count iterations after the end time.
@@ -191,7 +192,7 @@
       UseSingleSharedQuadState single_sqs) {
     for (int i = 0; i < kNumWarmupRuns; ++i) {
       mojo::Message message =
-          mojom::CompositorFrame::SerializeAsMessage(&frame);
+          viz::mojom::CompositorFrame::SerializeAsMessage(&frame);
     }
 
     base::TimeTicks start = base::TimeTicks::Now();
@@ -203,7 +204,7 @@
     while (start < end) {
       for (int i = 0; i < kTimeCheckInterval; ++i) {
         mojo::Message message =
-            mojom::CompositorFrame::SerializeAsMessage(&frame);
+            viz::mojom::CompositorFrame::SerializeAsMessage(&frame);
         now = base::TimeTicks::Now();
         // We don't count iterations after the end time.
         if (now < end)
diff --git a/cc/ipc/compositor_frame.typemap b/cc/ipc/compositor_frame.typemap
deleted file mode 100644
index 8908d15..0000000
--- a/cc/ipc/compositor_frame.typemap
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//cc/ipc/compositor_frame.mojom"
-public_headers = [ "//cc/output/compositor_frame.h" ]
-traits_headers = [ "//cc/ipc/compositor_frame_struct_traits.h" ]
-sources = [
-  "compositor_frame_struct_traits.cc",
-]
-deps = [
-  "//cc",
-]
-type_mappings = [ "cc.mojom.CompositorFrame=cc::CompositorFrame[move_only]" ]
diff --git a/cc/ipc/compositor_frame_struct_traits.h b/cc/ipc/compositor_frame_struct_traits.h
deleted file mode 100644
index a90dd6f..0000000
--- a/cc/ipc/compositor_frame_struct_traits.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_IPC_COMPOSITOR_FRAME_STRUCT_TRAITS_H_
-#define CC_IPC_COMPOSITOR_FRAME_STRUCT_TRAITS_H_
-
-#include "cc/ipc/compositor_frame.mojom-shared.h"
-#include "cc/output/compositor_frame.h"
-
-namespace mojo {
-
-template <>
-struct StructTraits<cc::mojom::CompositorFrameDataView, cc::CompositorFrame> {
-  static const cc::CompositorFrameMetadata& metadata(
-      const cc::CompositorFrame& input) {
-    return input.metadata;
-  }
-
-  static const std::vector<viz::TransferableResource>& resources(
-      const cc::CompositorFrame& input) {
-    return input.resource_list;
-  }
-
-  static const cc::RenderPassList& passes(const cc::CompositorFrame& input) {
-    return input.render_pass_list;
-  }
-
-  static bool Read(cc::mojom::CompositorFrameDataView data,
-                   cc::CompositorFrame* out);
-};
-
-}  // namespace mojo
-
-#endif  // CC_IPC_COMPOSITOR_FRAME_STRUCT_TRAITS_H_
diff --git a/cc/ipc/struct_traits_unittest.cc b/cc/ipc/struct_traits_unittest.cc
index c7eb120..95877e8 100644
--- a/cc/ipc/struct_traits_unittest.cc
+++ b/cc/ipc/struct_traits_unittest.cc
@@ -51,11 +51,6 @@
     std::move(callback).Run(b);
   }
 
-  void EchoCompositorFrame(CompositorFrame c,
-                           EchoCompositorFrameCallback callback) override {
-    std::move(callback).Run(std::move(c));
-  }
-
   void EchoCompositorFrameMetadata(
       CompositorFrameMetadata c,
       EchoCompositorFrameMetadataCallback callback) override {
@@ -205,128 +200,6 @@
   EXPECT_FALSE(output.has_damage);
 }
 
-// Note that this is a fairly trivial test of CompositorFrame serialization as
-// most of the heavy lifting has already been done by CompositorFrameMetadata,
-// RenderPass, and QuadListBasic unit tests.
-TEST_F(StructTraitsTest, CompositorFrame) {
-  std::unique_ptr<RenderPass> render_pass = RenderPass::Create();
-  render_pass->SetNew(1, gfx::Rect(5, 6), gfx::Rect(2, 3), gfx::Transform());
-
-  // SharedQuadState.
-  const gfx::Transform sqs_quad_to_target_transform(
-      1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f,
-      15.f, 16.f);
-  const gfx::Rect sqs_layer_rect(1234, 5678);
-  const gfx::Rect sqs_visible_layer_rect(12, 34, 56, 78);
-  const gfx::Rect sqs_clip_rect(123, 456, 789, 101112);
-  const bool sqs_is_clipped = true;
-  const float sqs_opacity = 0.9f;
-  const SkBlendMode sqs_blend_mode = SkBlendMode::kSrcOver;
-  const int sqs_sorting_context_id = 1337;
-  SharedQuadState* sqs = render_pass->CreateAndAppendSharedQuadState();
-  sqs->SetAll(sqs_quad_to_target_transform, sqs_layer_rect,
-              sqs_visible_layer_rect, sqs_clip_rect, sqs_is_clipped,
-              sqs_opacity, sqs_blend_mode, sqs_sorting_context_id);
-
-  // DebugBorderDrawQuad.
-  const gfx::Rect rect1(1234, 4321, 1357, 7531);
-  const SkColor color1 = SK_ColorRED;
-  const int32_t width1 = 1337;
-  DebugBorderDrawQuad* debug_quad =
-      render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
-  debug_quad->SetNew(sqs, rect1, rect1, color1, width1);
-
-  // SolidColorDrawQuad.
-  const gfx::Rect rect2(2468, 8642, 4321, 1234);
-  const uint32_t color2 = 0xffffffff;
-  const bool force_anti_aliasing_off = true;
-  SolidColorDrawQuad* solid_quad =
-      render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
-  solid_quad->SetNew(sqs, rect2, rect2, color2, force_anti_aliasing_off);
-
-  // viz::TransferableResource constants.
-  const uint32_t tr_id = 1337;
-  const viz::ResourceFormat tr_format = viz::ALPHA_8;
-  const gfx::BufferFormat tr_buffer_format = gfx::BufferFormat::R_8;
-  const uint32_t tr_filter = 1234;
-  const gfx::Size tr_size(1234, 5678);
-  viz::TransferableResource resource;
-  resource.id = tr_id;
-  resource.format = tr_format;
-  resource.buffer_format = tr_buffer_format;
-  resource.filter = tr_filter;
-  resource.size = tr_size;
-
-  // CompositorFrameMetadata constants.
-  const float device_scale_factor = 2.6f;
-  const gfx::Vector2dF root_scroll_offset(1234.5f, 6789.1f);
-  const float page_scale_factor = 1337.5f;
-  const gfx::SizeF scrollable_viewport_size(1337.7f, 1234.5f);
-  const uint32_t content_source_id = 3;
-  const viz::BeginFrameAck begin_frame_ack(5, 10, false);
-
-  CompositorFrame input;
-  input.metadata.device_scale_factor = device_scale_factor;
-  input.metadata.root_scroll_offset = root_scroll_offset;
-  input.metadata.page_scale_factor = page_scale_factor;
-  input.metadata.scrollable_viewport_size = scrollable_viewport_size;
-  input.render_pass_list.push_back(std::move(render_pass));
-  input.resource_list.push_back(resource);
-  input.metadata.content_source_id = content_source_id;
-  input.metadata.begin_frame_ack = begin_frame_ack;
-
-  mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
-  CompositorFrame output;
-  proxy->EchoCompositorFrame(std::move(input), &output);
-
-  EXPECT_EQ(device_scale_factor, output.metadata.device_scale_factor);
-  EXPECT_EQ(root_scroll_offset, output.metadata.root_scroll_offset);
-  EXPECT_EQ(page_scale_factor, output.metadata.page_scale_factor);
-  EXPECT_EQ(scrollable_viewport_size, output.metadata.scrollable_viewport_size);
-  EXPECT_EQ(content_source_id, output.metadata.content_source_id);
-  EXPECT_EQ(begin_frame_ack, output.metadata.begin_frame_ack);
-
-  ASSERT_EQ(1u, output.resource_list.size());
-  viz::TransferableResource out_resource = output.resource_list[0];
-  EXPECT_EQ(tr_id, out_resource.id);
-  EXPECT_EQ(tr_format, out_resource.format);
-  EXPECT_EQ(tr_buffer_format, out_resource.buffer_format);
-  EXPECT_EQ(tr_filter, out_resource.filter);
-  EXPECT_EQ(tr_size, out_resource.size);
-
-  EXPECT_EQ(1u, output.render_pass_list.size());
-  const RenderPass* out_render_pass = output.render_pass_list[0].get();
-  ASSERT_EQ(2u, out_render_pass->quad_list.size());
-  ASSERT_EQ(1u, out_render_pass->shared_quad_state_list.size());
-
-  const SharedQuadState* out_sqs =
-      out_render_pass->shared_quad_state_list.ElementAt(0);
-  EXPECT_EQ(sqs_quad_to_target_transform, out_sqs->quad_to_target_transform);
-  EXPECT_EQ(sqs_layer_rect, out_sqs->quad_layer_rect);
-  EXPECT_EQ(sqs_visible_layer_rect, out_sqs->visible_quad_layer_rect);
-  EXPECT_EQ(sqs_clip_rect, out_sqs->clip_rect);
-  EXPECT_EQ(sqs_is_clipped, out_sqs->is_clipped);
-  EXPECT_EQ(sqs_opacity, out_sqs->opacity);
-  EXPECT_EQ(sqs_blend_mode, out_sqs->blend_mode);
-  EXPECT_EQ(sqs_sorting_context_id, out_sqs->sorting_context_id);
-
-  const DebugBorderDrawQuad* out_debug_border_draw_quad =
-      DebugBorderDrawQuad::MaterialCast(
-          out_render_pass->quad_list.ElementAt(0));
-  EXPECT_EQ(rect1, out_debug_border_draw_quad->rect);
-  EXPECT_EQ(rect1, out_debug_border_draw_quad->visible_rect);
-  EXPECT_EQ(color1, out_debug_border_draw_quad->color);
-  EXPECT_EQ(width1, out_debug_border_draw_quad->width);
-
-  const SolidColorDrawQuad* out_solid_color_draw_quad =
-      SolidColorDrawQuad::MaterialCast(out_render_pass->quad_list.ElementAt(1));
-  EXPECT_EQ(rect2, out_solid_color_draw_quad->rect);
-  EXPECT_EQ(rect2, out_solid_color_draw_quad->visible_rect);
-  EXPECT_EQ(color2, out_solid_color_draw_quad->color);
-  EXPECT_EQ(force_anti_aliasing_off,
-            out_solid_color_draw_quad->force_anti_aliasing_off);
-}
-
 TEST_F(StructTraitsTest, CompositorFrameMetadata) {
   const float device_scale_factor = 2.6f;
   const gfx::Vector2dF root_scroll_offset(1234.5f, 6789.1f);
diff --git a/cc/ipc/traits_test_service.mojom b/cc/ipc/traits_test_service.mojom
index 71d2064..6ae6939 100644
--- a/cc/ipc/traits_test_service.mojom
+++ b/cc/ipc/traits_test_service.mojom
@@ -5,7 +5,6 @@
 module cc.mojom;
 
 import "cc/ipc/begin_frame_args.mojom";
-import "cc/ipc/compositor_frame.mojom";
 import "cc/ipc/compositor_frame_metadata.mojom";
 import "cc/ipc/copy_output_request.mojom";
 import "cc/ipc/copy_output_result.mojom";
@@ -31,9 +30,6 @@
   EchoBeginFrameAck(BeginFrameAck b) => (BeginFrameAck pass);
 
   [Sync]
-  EchoCompositorFrame(CompositorFrame c) => (CompositorFrame pass);
-
-  [Sync]
   EchoCompositorFrameMetadata(CompositorFrameMetadata c) =>
       (CompositorFrameMetadata pass);
 
diff --git a/cc/ipc/typemaps.gni b/cc/ipc/typemaps.gni
index cca6caa..b5d695ce 100644
--- a/cc/ipc/typemaps.gni
+++ b/cc/ipc/typemaps.gni
@@ -4,7 +4,6 @@
 
 typemaps = [
   "//cc/ipc/begin_frame_args.typemap",
-  "//cc/ipc/compositor_frame.typemap",
   "//cc/ipc/compositor_frame_metadata.typemap",
   "//cc/ipc/copy_output_request.typemap",
   "//cc/ipc/copy_output_result.typemap",
diff --git a/cc/output/overlay_candidate.cc b/cc/output/overlay_candidate.cc
index 903498f5..9a8a214 100644
--- a/cc/output/overlay_candidate.cc
+++ b/cc/output/overlay_candidate.cc
@@ -380,8 +380,7 @@
     OverlayCandidateList&& other) = default;
 
 void OverlayCandidateList::AddPromotionHint(const OverlayCandidate& candidate) {
-  promotion_hint_info_map_[candidate.resource_id] =
-      candidate.display_rect.origin();
+  promotion_hint_info_map_[candidate.resource_id] = candidate.display_rect;
 }
 
 }  // namespace cc
diff --git a/cc/output/overlay_candidate.h b/cc/output/overlay_candidate.h
index 22b40c6..2f3f597 100644
--- a/cc/output/overlay_candidate.h
+++ b/cc/output/overlay_candidate.h
@@ -126,8 +126,8 @@
   OverlayCandidateList& operator=(const OverlayCandidateList&);
   OverlayCandidateList& operator=(OverlayCandidateList&&);
 
-  // [id] == origin of candidate's |display_rect| for all promotable resources.
-  using PromotionHintInfoMap = std::map<viz::ResourceId, gfx::PointF>;
+  // [id] == candidate's |display_rect| for all promotable resources.
+  using PromotionHintInfoMap = std::map<viz::ResourceId, gfx::RectF>;
 
   // For android, this provides a set of resources that could be promoted to
   // overlay, if one backs them with a SurfaceView.
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index a7828f7e..494111ef 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -1650,7 +1650,9 @@
       bool promotable = iter != promotion_hints.end();
       gl->OverlayPromotionHintCHROMIUM(resource->gl_id, promotable,
                                        promotable ? iter->second.x() : 0,
-                                       promotable ? iter->second.y() : 0);
+                                       promotable ? iter->second.y() : 0,
+                                       promotable ? iter->second.width() : 0,
+                                       promotable ? iter->second.height() : 0);
     }
     UnlockForRead(id);
   }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
index d03a0b00c..5ade18fa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/password/PasswordEntryEditor.java
@@ -20,6 +20,7 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowManager.LayoutParams;
 import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.TextView;
@@ -252,6 +253,8 @@
     }
 
     private void displayPassword() {
+        getActivity().getWindow().setFlags(LayoutParams.FLAG_SECURE, LayoutParams.FLAG_SECURE);
+
         changeHowPasswordIsDisplayed(
                 R.drawable.ic_visibility_off, InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
     }
diff --git a/chrome/app/theme/default_100_percent/common/notification_extension_installed.png b/chrome/app/theme/default_100_percent/common/notification_extension_installed.png
deleted file mode 100644
index 94d75021..0000000
--- a/chrome/app/theme/default_100_percent/common/notification_extension_installed.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/notification_usb_icon.png b/chrome/app/theme/default_100_percent/common/notification_usb_icon.png
deleted file mode 100644
index 8b1d24c..0000000
--- a/chrome/app/theme/default_100_percent/common/notification_usb_icon.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_100_percent/common/info_small.png b/chrome/app/theme/default_100_percent/legacy/info_small.png
similarity index 100%
rename from chrome/app/theme/default_100_percent/common/info_small.png
rename to chrome/app/theme/default_100_percent/legacy/info_small.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/notification_extension_installed.png b/chrome/app/theme/default_200_percent/common/notification_extension_installed.png
deleted file mode 100644
index c0609b24..0000000
--- a/chrome/app/theme/default_200_percent/common/notification_extension_installed.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/notification_usb_icon.png b/chrome/app/theme/default_200_percent/common/notification_usb_icon.png
deleted file mode 100644
index 4c372b1f..0000000
--- a/chrome/app/theme/default_200_percent/common/notification_usb_icon.png
+++ /dev/null
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/common/info_small.png b/chrome/app/theme/default_200_percent/legacy/info_small.png
similarity index 100%
rename from chrome/app/theme/default_200_percent/common/info_small.png
rename to chrome/app/theme/default_200_percent/legacy/info_small.png
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index 647640fe..26c4f42 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -214,7 +214,9 @@
         <structure type="chrome_scaled_image" name="IDR_ICON_USER_MANAGER_TUTORIAL_FRIENDS" file="common/user_manager_tutorial/family_and_friends.png" />
         <structure type="chrome_scaled_image" name="IDR_ICON_USER_MANAGER_TUTORIAL_COMPLETE" file="common/user_manager_tutorial/complete.png" />
       </if>
-      <structure type="chrome_scaled_image" name="IDR_INFO" file="common/info_small.png" />
+      <if expr="is_macosx">
+        <structure type="chrome_scaled_image" name="IDR_INFO" file="legacy/info_small.png" />
+      </if>
       <structure type="chrome_scaled_image" name="IDR_INFOBAR_3D_BLOCKED" file="common/infobar_3d_blocked.png" />
       <structure type="chrome_scaled_image" name="IDR_INFOBAR_MEDIA_STREAM_CAMERA" file="common/infobar_media_stream_camera.png" />
       <structure type="chrome_scaled_image" name="IDR_INFOBAR_MEDIA_STREAM_MIC" file="common/infobar_media_stream_mic.png" />
@@ -268,7 +270,6 @@
         <structure type="chrome_scaled_image" name="IDR_PORTAL_DETECTION_ALERT" file="cros/captive_portal_icon.png" />
         <structure type="chrome_scaled_image" name="IDR_ARC_PLAY_STORE_NOTIFICATION" file="cros/notification_play_store.png" />
         <structure type="chrome_scaled_image" name="IDR_ARC_PLAY_STORE_OPTIN_IN_PROGRESS_NOTIFICATION" file="cros/notification_play_store_optin_in_progress.png" />
-        <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_EXTENSION_INSTALLED" file="common/notification_extension_installed.png" />
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SCREENSHOT_ANNOTATE" file="cros/notification_screenshot_annotate.png" />
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_SCREENSHOT_COPY_TO_CLIPBOARD" file="cros/notification_screenshot_copy_to_clipboard.png" />
         <structure type="chrome_scaled_image" name="IDR_NOTIFICATION_EASYUNLOCK_ENABLED" file="cros/notification_easyunlock_enabled.png" />
@@ -515,7 +516,6 @@
         <structure type="chrome_scaled_image" name="IDR_TRANSLATE" file="legacy/translate.png" />
       </if>
       <structure type="chrome_scaled_image" name="IDR_TRANSLATE_BUBBLE_ICON" file="common/translate_bubble_icon.png" />
-      <structure type="chrome_scaled_image" name="IDR_USB_NOTIFICATION_ICON" file="common/notification_usb_icon.png" />
       <if expr="chromeos">
         <structure type="chrome_scaled_image" name="IDR_USER_IMAGE_CAPTURE" file="cros/snapshot_wide.png" />
         <structure type="chrome_scaled_image" name="IDR_USER_IMAGE_RECYCLE" file="cros/discard_wide.png" />
diff --git a/chrome/browser/android/locale/special_locale_handler.cc b/chrome/browser/android/locale/special_locale_handler.cc
index d0fd86f..689db1f 100644
--- a/chrome/browser/android/locale/special_locale_handler.cc
+++ b/chrome/browser/android/locale/special_locale_handler.cc
@@ -75,9 +75,9 @@
     // Otherwise, matching based on keyword is sufficient and preferred as
     // some logically distinct search engines share the same prepopulate ID and
     // only differ on keyword.
-    const TemplateURL* existing_url =
+    const TemplateURL* matching_url =
         template_url_service_->GetTemplateURLForKeyword(data_url->keyword());
-    bool exists = existing_url != nullptr;
+    bool exists = matching_url != nullptr;
     if (!exists &&
         data_url->prepopulate_id == TemplateURLPrepopulateData::google.id) {
       auto existing_urls = template_url_service_->GetTemplateURLs();
@@ -85,6 +85,7 @@
       for (auto* existing_url : existing_urls) {
         if (existing_url->prepopulate_id() ==
             TemplateURLPrepopulateData::google.id) {
+          matching_url = existing_url;
           exists = true;
           break;
         }
@@ -95,12 +96,12 @@
       // Update the visit time of any existing custom search engines to ensure
       // they are not filtered out in TemplateUrlServicAndroid::LoadTemplateURLs
       if (!template_url_service_->IsPrepopulatedOrCreatedByPolicy(
-              existing_url)) {
+              matching_url)) {
         UIThreadSearchTermsData search_terms_data(profile_);
 
         TemplateURLService::URLVisitedDetails visited_details;
         visited_details.url =
-            existing_url->GenerateSearchURL(search_terms_data);
+            matching_url->GenerateSearchURL(search_terms_data);
         visited_details.is_keyword_transition = false;
         template_url_service_->OnHistoryURLVisited(visited_details);
       }
diff --git a/chrome/browser/android/locale/special_locale_handler_unittest.cc b/chrome/browser/android/locale/special_locale_handler_unittest.cc
index 81019fc2..7234699 100644
--- a/chrome/browser/android/locale/special_locale_handler_unittest.cc
+++ b/chrome/browser/android/locale/special_locale_handler_unittest.cc
@@ -14,6 +14,7 @@
 #include "components/search_engines/template_url_prepopulate_data.h"
 #include "components/search_engines/template_url_service.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class MockSpecialLocaleHandler : public SpecialLocaleHandler {
@@ -33,6 +34,8 @@
         TemplateURLPrepopulateData::so_360));
     result.push_back(TemplateURLDataFromPrepopulatedEngine(
         TemplateURLPrepopulateData::naver));
+    result.push_back(TemplateURLDataFromPrepopulatedEngine(
+        TemplateURLPrepopulateData::google));
     return result;
   }
 
@@ -123,3 +126,24 @@
   ASSERT_EQ(TemplateURLPrepopulateData::google.id,
             model()->GetDefaultSearchProvider()->prepopulate_id());
 }
+
+TEST_F(SpecialLocaleHandlerTest, ChangedGoogleBaseURL) {
+  test_util()->VerifyLoad();
+  auto google_keyword = base::ASCIIToUTF16("google.com");
+  ASSERT_THAT(model()->GetTemplateURLForKeyword(google_keyword),
+              testing::NotNull());
+  test_util()->SetGoogleBaseURL(GURL("http://google.de"));
+
+  // After changing the base URL, the previous google keyword will no longer
+  // match.
+  ASSERT_EQ(nullptr, model()->GetTemplateURLForKeyword(google_keyword));
+
+  ASSERT_TRUE(handler()->LoadTemplateUrls(NULL, JavaParamRef<jobject>(NULL)));
+
+  auto template_urls = model()->GetTemplateURLs();
+  ASSERT_EQ(1, std::count_if(template_urls.begin(), template_urls.end(),
+                             [](TemplateURL* template_url) {
+                               return template_url->prepopulate_id() ==
+                                      TemplateURLPrepopulateData::google.id;
+                             }));
+}
diff --git a/chrome/browser/autofill/content_autofill_driver_browsertest.cc b/chrome/browser/autofill/content_autofill_driver_browsertest.cc
index 117c6ae3..a65633d 100644
--- a/chrome/browser/autofill/content_autofill_driver_browsertest.cc
+++ b/chrome/browser/autofill/content_autofill_driver_browsertest.cc
@@ -10,6 +10,7 @@
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
 #include "components/autofill/content/browser/content_autofill_driver.h"
 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
 #include "components/autofill/core/browser/autofill_manager.h"
@@ -21,7 +22,10 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/url_constants.h"
+#include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
+#include "net/dns/mock_host_resolver.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/rect.h"
@@ -29,6 +33,9 @@
 namespace autofill {
 namespace {
 
+const base::FilePath::CharType kDocRoot[] =
+    FILE_PATH_LITERAL("chrome/test/data");
+
 class MockAutofillClient : public TestAutofillClient {
  public:
   MockAutofillClient() {}
@@ -92,6 +99,17 @@
     ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
         web_contents, &autofill_client_, "en-US",
         AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER);
+
+    embedded_test_server()->AddDefaultHandlers(base::FilePath(kDocRoot));
+    // Serve both a.com and b.com (and any other domain).
+    host_resolver()->AddRule("*", "127.0.0.1");
+    ASSERT_TRUE(embedded_test_server()->Start());
+  }
+
+  void TearDownOnMainThread() override {
+    // Verify the expectations here, because closing the browser may incur
+    // other calls in |autofill_client_| e.g., HideAutofillPopup.
+    testing::Mock::VerifyAndClearExpectations(&autofill_client_);
   }
 
   void WasHidden() override {
@@ -106,20 +124,30 @@
 
     if (!nav_entry_committed_callback_.is_null())
       nav_entry_committed_callback_.Run();
+
+    if (navigation_handle->IsSameDocument() &&
+        !same_document_navigation_callback_.is_null()) {
+      same_document_navigation_callback_.Run();
+    }
+
+    if (!navigation_handle->IsInMainFrame() &&
+        !subframe_navigation_callback_.is_null()) {
+      subframe_navigation_callback_.Run();
+    }
   }
 
  protected:
   base::Closure web_contents_hidden_callback_;
   base::Closure nav_entry_committed_callback_;
+  base::Closure same_document_navigation_callback_;
+  base::Closure subframe_navigation_callback_;
 
   testing::NiceMock<MockAutofillClient> autofill_client_;
 };
 
 IN_PROC_BROWSER_TEST_F(ContentAutofillDriverBrowserTest,
                        SwitchTabAndHideAutofillPopup) {
-  // Notification is different on platforms. On linux this will be called twice,
-  // while on windows only once.
-  EXPECT_CALL(autofill_client_, HideAutofillPopup()).Times(testing::AtLeast(1));
+  EXPECT_CALL(autofill_client_, HideAutofillPopup()).Times(1);
 
   scoped_refptr<content::MessageLoopRunner> runner =
       new content::MessageLoopRunner;
@@ -132,13 +160,57 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ContentAutofillDriverBrowserTest,
-                       TestPageNavigationHidingAutofillPopup) {
-  // Notification is different on platforms. On linux this will be called twice,
-  // while on windows only once.
+                       SameDocumentNavigationHideAutofillPopup) {
+  ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL("/autofill/autofill_test_form.html"));
+
+  // The Autofill popup should be hidden for same document navigations. It may
+  // called twice because the zoom changed event may also fire for same-page
+  // navigations.
   EXPECT_CALL(autofill_client_, HideAutofillPopup()).Times(testing::AtLeast(1));
 
   scoped_refptr<content::MessageLoopRunner> runner =
       new content::MessageLoopRunner;
+  same_document_navigation_callback_ = runner->QuitClosure();
+  ui_test_utils::NavigateToURL(
+      browser(),
+      embedded_test_server()->GetURL("/autofill/autofill_test_form.html#foo"));
+  // This will block until a same document navigation is observed.
+  runner->Run();
+  same_document_navigation_callback_.Reset();
+}
+
+IN_PROC_BROWSER_TEST_F(ContentAutofillDriverBrowserTest,
+                       SubframeNavigationDoesntHideAutofillPopup) {
+  // Main frame is on a.com, iframe is on b.com.
+  GURL url = embedded_test_server()->GetURL(
+      "a.com", "/autofill/cross_origin_iframe.html");
+  ui_test_utils::NavigateToURL(browser(), url);
+
+  // The Autofill popup should NOT be hidden for subframe navigations.
+  EXPECT_CALL(autofill_client_, HideAutofillPopup()).Times(0);
+
+  scoped_refptr<content::MessageLoopRunner> runner =
+      new content::MessageLoopRunner;
+  subframe_navigation_callback_ = runner->QuitClosure();
+  GURL iframe_url = embedded_test_server()->GetURL(
+      "b.com", "/autofill/autofill_test_form.html");
+  EXPECT_TRUE(content::NavigateIframeToURL(
+      browser()->tab_strip_model()->GetActiveWebContents(), "crossFrame",
+      iframe_url));
+  // This will block until a subframe navigation is observed.
+  runner->Run();
+  subframe_navigation_callback_.Reset();
+}
+
+IN_PROC_BROWSER_TEST_F(ContentAutofillDriverBrowserTest,
+                       TestPageNavigationHidingAutofillPopup) {
+  // HideAutofillPopup is called once for each navigation.
+  EXPECT_CALL(autofill_client_, HideAutofillPopup()).Times(2);
+
+  scoped_refptr<content::MessageLoopRunner> runner =
+      new content::MessageLoopRunner;
   nav_entry_committed_callback_ = runner->QuitClosure();
   browser()->OpenURL(content::OpenURLParams(
       GURL(chrome::kChromeUIBookmarksURL), content::Referrer(),
diff --git a/chrome/browser/chrome_browser_main_android.cc b/chrome/browser/chrome_browser_main_android.cc
index 8803d5a..4bf799d3 100644
--- a/chrome/browser/chrome_browser_main_android.cc
+++ b/chrome/browser/chrome_browser_main_android.cc
@@ -19,7 +19,8 @@
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/descriptors_android.h"
 #include "components/crash/content/app/breakpad_linux.h"
-#include "components/crash/content/browser/crash_dump_manager_android.h"
+#include "components/crash/content/browser/child_process_crash_observer_android.h"
+#include "components/crash/content/browser/crash_dump_observer_android.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "content/public/browser/android/compositor.h"
 #include "content/public/browser/browser_thread.h"
@@ -40,11 +41,11 @@
 int ChromeBrowserMainPartsAndroid::PreCreateThreads() {
   TRACE_EVENT0("startup", "ChromeBrowserMainPartsAndroid::PreCreateThreads")
 
-  // The CrashDumpManager must be registered before any child process is
-  // created (as it needs to be notified during child process
-  // creation). Such processes are created on the PROCESS_LAUNCHER
-  // thread, and so the observer is initialized and the manager
-  // registered before that thread is created.
+  // The ChildProcessCrashObserver must be registered before any child
+  // process is created (as it needs to be notified during child
+  // process creation). Such processes are created on the
+  // PROCESS_LAUNCHER thread, and so the observer is initialized and
+  // the manager registered before that thread is created.
   breakpad::CrashDumpObserver::Create();
 
 #if defined(GOOGLE_CHROME_BUILD)
@@ -65,7 +66,7 @@
     base::FilePath crash_dump_dir;
     PathService::Get(chrome::DIR_CRASH_DUMPS, &crash_dump_dir);
     breakpad::CrashDumpObserver::GetInstance()->RegisterClient(
-        base::MakeUnique<breakpad::CrashDumpManager>(
+        base::MakeUnique<breakpad::ChildProcessCrashObserver>(
             crash_dump_dir, kAndroidMinidumpDescriptor));
   }
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index dfb3a991..3f69c8f6 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -272,7 +272,7 @@
 #include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h"
 #include "chrome/browser/chrome_browser_main_android.h"
 #include "chrome/common/descriptors_android.h"
-#include "components/crash/content/browser/crash_dump_manager_android.h"
+#include "components/crash/content/browser/crash_dump_observer_android.h"
 #include "components/navigation_interception/intercept_navigation_delegate.h"
 #include "content/public/browser/android/java_interfaces.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
diff --git a/chrome/browser/chromeos/login/app_launch_controller.cc b/chrome/browser/chromeos/login/app_launch_controller.cc
index dfee29f..c9136c83 100644
--- a/chrome/browser/chromeos/login/app_launch_controller.cc
+++ b/chrome/browser/chromeos/login/app_launch_controller.cc
@@ -368,9 +368,8 @@
       return should_prompt;
     }
 
-    // Network configuration has to be explicitly allowed by the policy.
-    // Default to false if the policy is missing.
-    return false;
+    // Default to true to allow network configuration if the policy is missing.
+    return true;
   }
 
   return user_manager::UserManager::Get()->GetOwnerAccountId().is_valid();
diff --git a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
index 4ebc720..299accbb 100644
--- a/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
+++ b/chrome/browser/chromeos/policy/proto/chrome_device_policy.proto
@@ -376,16 +376,16 @@
   optional bool enable_auto_login_bailout = 4 [default = true];
 
   // Whether network configuration should be offered or not when the device
-  // does not have access to the Internet. If the policy is set to true, the
-  // network configuration will be offered. Otherwise (policy is omitted or set
-  // to false), only an error message is displayed.
-  // Note: If enable_auto_login_bailout policy above is set to false and this
-  // policy is omitted or set to false, there are chances that the device might
-  // become totally unusable when there is no Internet access and has to go
-  // through the recovery process.
+  // does not have access to the Internet. If the policy is omitted or set to
+  // true, the network configuration will be offered. Otherwise, only an error
+  // message is displayed.
+  // Note: If both this policy and enable_auto_login_bailout policy above is
+  // set to false, there are chances that the device might become totally
+  // unusable when there is no Internet access and has to go through the
+  // recovery process.
   // If the device is offline at startup then the network configuration screen
   // is always shown, before auto-login kicks in.
-  optional bool prompt_for_network_when_offline = 5 [default = false];
+  optional bool prompt_for_network_when_offline = 5 [default = true];
 }
 
 message AllowRedeemChromeOsRegistrationOffersProto {
diff --git a/chrome/browser/content_settings/content_settings_default_provider_unittest.cc b/chrome/browser/content_settings/content_settings_default_provider_unittest.cc
index d6d43b2..4dc420f 100644
--- a/chrome/browser/content_settings/content_settings_default_provider_unittest.cc
+++ b/chrome/browser/content_settings/content_settings_default_provider_unittest.cc
@@ -4,7 +4,9 @@
 
 #include <memory>
 
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
+#include "build/build_config.h"
 #include "chrome/browser/content_settings/content_settings_mock_observer.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_profile.h"
@@ -24,12 +26,13 @@
 
 namespace content_settings {
 
-class DefaultProviderTest : public testing::Test {
+class ContentSettingsDefaultProviderTest : public testing::Test {
  public:
-  DefaultProviderTest()
-      : provider_(profile_.GetPrefs(), false) {
+  ContentSettingsDefaultProviderTest()
+      : provider_(profile_.GetPrefs(), false) {}
+  ~ContentSettingsDefaultProviderTest() override {
+    provider_.ShutdownOnUIThread();
   }
-  ~DefaultProviderTest() override { provider_.ShutdownOnUIThread(); }
 
  protected:
   content::TestBrowserThreadBundle thread_bundle_;
@@ -37,7 +40,7 @@
   DefaultProvider provider_;
 };
 
-TEST_F(DefaultProviderTest, DefaultValues) {
+TEST_F(ContentSettingsDefaultProviderTest, DefaultValues) {
   // Check setting defaults.
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
             TestUtils::GetContentSetting(&provider_, GURL(), GURL(),
@@ -71,7 +74,7 @@
   EXPECT_FALSE(value.get());
 }
 
-TEST_F(DefaultProviderTest, IgnoreNonDefaultSettings) {
+TEST_F(ContentSettingsDefaultProviderTest, IgnoreNonDefaultSettings) {
   GURL primary_url("http://www.google.com");
   GURL secondary_url("http://www.google.com");
 
@@ -93,7 +96,7 @@
                                          std::string(), false));
 }
 
-TEST_F(DefaultProviderTest, Observer) {
+TEST_F(ContentSettingsDefaultProviderTest, Observer) {
   MockObserver mock_observer;
   EXPECT_CALL(mock_observer,
               OnContentSettingChanged(
@@ -113,8 +116,7 @@
                               new base::Value(CONTENT_SETTING_BLOCK));
 }
 
-
-TEST_F(DefaultProviderTest, ObservePref) {
+TEST_F(ContentSettingsDefaultProviderTest, ObservePref) {
   PrefService* prefs = profile_.GetPrefs();
 
   provider_.SetWebsiteSetting(ContentSettingsPattern::Wildcard(),
@@ -142,7 +144,7 @@
 }
 
 // Tests that fullscreen and mouselock content settings are cleared.
-TEST_F(DefaultProviderTest, DiscardObsoletePreferences) {
+TEST_F(ContentSettingsDefaultProviderTest, DiscardObsoletePreferences) {
   static const char kFullscreenPrefPath[] =
       "profile.default_content_setting_values.fullscreen";
 #if !defined(OS_ANDROID)
@@ -173,7 +175,42 @@
   EXPECT_EQ(CONTENT_SETTING_BLOCK, prefs->GetInteger(kGeolocationPrefPath));
 }
 
-TEST_F(DefaultProviderTest, OffTheRecord) {
+#if !defined(OS_IOS) && !defined(OS_ANDROID)
+TEST_F(ContentSettingsDefaultProviderTest, DiscardObsoletePluginsAllow) {
+  PrefService* prefs = profile_.GetPrefs();
+  const std::string& plugins_pref_path =
+      WebsiteSettingsRegistry::GetInstance()
+          ->Get(ContentSettingsType::CONTENT_SETTINGS_TYPE_PLUGINS)
+          ->default_value_pref_name();
+
+  // The ALLOW value of the plugins content setting should be discarded.
+  {
+    prefs->SetInteger(plugins_pref_path, CONTENT_SETTING_ALLOW);
+    DefaultProvider provider(prefs, false);
+    EXPECT_FALSE(prefs->HasPrefPath(plugins_pref_path));
+  }
+
+  // Other values of the plugins content setting should be preserved.
+  {
+    prefs->SetInteger(plugins_pref_path, CONTENT_SETTING_BLOCK);
+    DefaultProvider provider(prefs, false);
+    EXPECT_TRUE(prefs->HasPrefPath(plugins_pref_path));
+    EXPECT_EQ(CONTENT_SETTING_BLOCK, prefs->GetInteger(plugins_pref_path));
+  }
+
+  {
+    prefs->SetInteger(plugins_pref_path,
+                      CONTENT_SETTING_DETECT_IMPORTANT_CONTENT);
+    DefaultProvider provider(prefs, false);
+
+    EXPECT_TRUE(prefs->HasPrefPath(plugins_pref_path));
+    EXPECT_EQ(CONTENT_SETTING_DETECT_IMPORTANT_CONTENT,
+              prefs->GetInteger(plugins_pref_path));
+  }
+}
+#endif  // !defined(OS_IOS) && !defined(OS_ANDROID)
+
+TEST_F(ContentSettingsDefaultProviderTest, OffTheRecord) {
   DefaultProvider otr_provider(profile_.GetPrefs(), true /* incognito */);
 
   EXPECT_EQ(CONTENT_SETTING_ALLOW,
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index eb5b3a00..bb23cb3 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -188,6 +188,8 @@
     "api/extension_action/extension_action_api.h",
     "api/extension_action/extension_page_actions_api_constants.cc",
     "api/extension_action/extension_page_actions_api_constants.h",
+    "api/feedback_private/chrome_feedback_private_delegate.cc",
+    "api/feedback_private/chrome_feedback_private_delegate.h",
     "api/feedback_private/feedback_private_api.cc",
     "api/feedback_private/feedback_private_api.h",
     "api/feedback_private/feedback_service.cc",
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
index ad8547a3..e24adde 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.cc
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/extensions/api/chrome_device_permissions_prompt.h"
 #include "chrome/browser/extensions/api/declarative_content/chrome_content_rules_registry.h"
 #include "chrome/browser/extensions/api/declarative_content/default_content_predicate_evaluators.h"
+#include "chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.h"
 #include "chrome/browser/extensions/api/file_system/chrome_file_system_delegate.h"
 #include "chrome/browser/extensions/api/management/chrome_management_api_delegate.h"
 #include "chrome/browser/extensions/api/messaging/chrome_messaging_delegate.h"
@@ -193,6 +194,15 @@
   return messaging_delegate_.get();
 }
 
+FeedbackPrivateDelegate*
+ChromeExtensionsAPIClient::GetFeedbackPrivateDelegate() {
+  if (!feedback_private_delegate_) {
+    feedback_private_delegate_ =
+        base::MakeUnique<ChromeFeedbackPrivateDelegate>();
+  }
+  return feedback_private_delegate_.get();
+}
+
 #if defined(OS_CHROMEOS)
 NonNativeFileSystemDelegate*
 ChromeExtensionsAPIClient::GetNonNativeFileSystemDelegate() {
diff --git a/chrome/browser/extensions/api/chrome_extensions_api_client.h b/chrome/browser/extensions/api/chrome_extensions_api_client.h
index ee8d8c8..b1c93a7 100644
--- a/chrome/browser/extensions/api/chrome_extensions_api_client.h
+++ b/chrome/browser/extensions/api/chrome_extensions_api_client.h
@@ -57,6 +57,7 @@
   NetworkingCastPrivateDelegate* GetNetworkingCastPrivateDelegate() override;
   FileSystemDelegate* GetFileSystemDelegate() override;
   MessagingDelegate* GetMessagingDelegate() override;
+  FeedbackPrivateDelegate* GetFeedbackPrivateDelegate() override;
 
 #if defined(OS_CHROMEOS)
   NonNativeFileSystemDelegate* GetNonNativeFileSystemDelegate() override;
@@ -75,6 +76,7 @@
       networking_cast_private_delegate_;
   std::unique_ptr<FileSystemDelegate> file_system_delegate_;
   std::unique_ptr<MessagingDelegate> messaging_delegate_;
+  std::unique_ptr<FeedbackPrivateDelegate> feedback_private_delegate_;
 
 #if defined(OS_CHROMEOS)
   std::unique_ptr<NonNativeFileSystemDelegate> non_native_file_system_delegate_;
diff --git a/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.cc b/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.cc
new file mode 100644
index 0000000..13c4e52
--- /dev/null
+++ b/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.cc
@@ -0,0 +1,89 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.h"
+
+#include <string>
+
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "content/public/browser/browser_context.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/webui/web_ui_util.h"
+
+#if defined(OS_CHROMEOS)
+#include "chrome/browser/chromeos/arc/arc_util.h"
+#include "chrome/browser/profiles/profile.h"
+#endif  // defined(OS_CHROMEOS)
+
+namespace extensions {
+
+ChromeFeedbackPrivateDelegate::ChromeFeedbackPrivateDelegate() = default;
+ChromeFeedbackPrivateDelegate::~ChromeFeedbackPrivateDelegate() = default;
+
+std::unique_ptr<base::DictionaryValue>
+ChromeFeedbackPrivateDelegate::GetStrings(
+    content::BrowserContext* browser_context,
+    bool from_crash) const {
+  std::unique_ptr<base::DictionaryValue> dict =
+      base::MakeUnique<base::DictionaryValue>();
+
+#define SET_STRING(id, idr) dict->SetString(id, l10n_util::GetStringUTF16(idr))
+  SET_STRING("page-title", from_crash
+                               ? IDS_FEEDBACK_REPORT_PAGE_TITLE_SAD_TAB_FLOW
+                               : IDS_FEEDBACK_REPORT_PAGE_TITLE);
+  SET_STRING("additionalInfo", IDS_FEEDBACK_ADDITIONAL_INFO_LABEL);
+  SET_STRING("minimize-btn-label", IDS_FEEDBACK_MINIMIZE_BUTTON_LABEL);
+  SET_STRING("close-btn-label", IDS_FEEDBACK_CLOSE_BUTTON_LABEL);
+  SET_STRING("page-url", IDS_FEEDBACK_REPORT_URL_LABEL);
+  SET_STRING("screenshot", IDS_FEEDBACK_SCREENSHOT_LABEL);
+  SET_STRING("user-email", IDS_FEEDBACK_USER_EMAIL_LABEL);
+  SET_STRING("anonymous-user", IDS_FEEDBACK_ANONYMOUS_EMAIL_OPTION);
+#if defined(OS_CHROMEOS)
+  if (arc::IsArcPlayStoreEnabledForProfile(
+          Profile::FromBrowserContext(browser_context))) {
+    SET_STRING("sys-info",
+               IDS_FEEDBACK_INCLUDE_SYSTEM_INFORMATION_AND_METRICS_CHKBOX_ARC);
+  } else {
+    SET_STRING("sys-info",
+               IDS_FEEDBACK_INCLUDE_SYSTEM_INFORMATION_AND_METRICS_CHKBOX);
+  }
+#else
+  SET_STRING("sys-info", IDS_FEEDBACK_INCLUDE_SYSTEM_INFORMATION_CHKBOX);
+#endif
+  SET_STRING("attach-file-label", IDS_FEEDBACK_ATTACH_FILE_LABEL);
+  SET_STRING("attach-file-note", IDS_FEEDBACK_ATTACH_FILE_NOTE);
+  SET_STRING("attach-file-to-big", IDS_FEEDBACK_ATTACH_FILE_TO_BIG);
+  SET_STRING("reading-file", IDS_FEEDBACK_READING_FILE);
+  SET_STRING("send-report", IDS_FEEDBACK_SEND_REPORT);
+  SET_STRING("cancel", IDS_CANCEL);
+  SET_STRING("no-description", IDS_FEEDBACK_NO_DESCRIPTION);
+  SET_STRING("privacy-note", IDS_FEEDBACK_PRIVACY_NOTE);
+  SET_STRING("performance-trace",
+             IDS_FEEDBACK_INCLUDE_PERFORMANCE_TRACE_CHECKBOX);
+  // Add the localized strings needed for the "system information" page.
+  SET_STRING("sysinfoPageTitle", IDS_FEEDBACK_SYSINFO_PAGE_TITLE);
+  SET_STRING("sysinfoPageDescription", IDS_ABOUT_SYS_DESC);
+  SET_STRING("sysinfoPageTableTitle", IDS_ABOUT_SYS_TABLE_TITLE);
+  SET_STRING("sysinfoPageExpandAllBtn", IDS_ABOUT_SYS_EXPAND_ALL);
+  SET_STRING("sysinfoPageCollapseAllBtn", IDS_ABOUT_SYS_COLLAPSE_ALL);
+  SET_STRING("sysinfoPageExpandBtn", IDS_ABOUT_SYS_EXPAND);
+  SET_STRING("sysinfoPageCollapseBtn", IDS_ABOUT_SYS_COLLAPSE);
+  SET_STRING("sysinfoPageStatusLoading", IDS_FEEDBACK_SYSINFO_PAGE_LOADING);
+  // And the localized strings needed for the SRT Download Prompt.
+  SET_STRING("srtPromptBody", IDS_FEEDBACK_SRT_PROMPT_BODY);
+  SET_STRING("srtPromptAcceptButton", IDS_FEEDBACK_SRT_PROMPT_ACCEPT_BUTTON);
+  SET_STRING("srtPromptDeclineButton", IDS_FEEDBACK_SRT_PROMPT_DECLINE_BUTTON);
+#undef SET_STRING
+
+  const std::string& app_locale = g_browser_process->GetApplicationLocale();
+  webui::SetLoadTimeDataDefaults(app_locale, dict.get());
+
+  return dict;
+}
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.h b/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.h
new file mode 100644
index 0000000..0e02e5b
--- /dev/null
+++ b/chrome/browser/extensions/api/feedback_private/chrome_feedback_private_delegate.h
@@ -0,0 +1,32 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_API_FEEDBACK_PRIVATE_CHROME_FEEDBACK_PRIVATE_DELEGATE_H_
+#define CHROME_BROWSER_EXTENSIONS_API_FEEDBACK_PRIVATE_CHROME_FEEDBACK_PRIVATE_DELEGATE_H_
+
+#include "extensions/browser/api/feedback_private/feedback_private_delegate.h"
+
+#include <memory>
+
+#include "base/macros.h"
+
+namespace extensions {
+
+class ChromeFeedbackPrivateDelegate : public FeedbackPrivateDelegate {
+ public:
+  ChromeFeedbackPrivateDelegate();
+  ~ChromeFeedbackPrivateDelegate() override;
+
+  // FeedbackPrivateDelegate:
+  std::unique_ptr<base::DictionaryValue> GetStrings(
+      content::BrowserContext* browser_context,
+      bool from_crash) const override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ChromeFeedbackPrivateDelegate);
+};
+
+}  // namespace extensions
+
+#endif  // CHROME_BROWSER_EXTENSIONS_API_FEEDBACK_PRIVATE_CHROME_FEEDBACK_PRIVATE_DELEGATE_H_
diff --git a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
index e99d991..09a5063 100644
--- a/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
+++ b/chrome/browser/extensions/api/feedback_private/feedback_private_api.cc
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/lazy_instance.h"
+#include "base/logging.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/metrics/statistics_recorder.h"
@@ -28,15 +29,13 @@
 #include "chrome/grit/generated_resources.h"
 #include "components/feedback/tracing_manager.h"
 #include "components/signin/core/browser/signin_manager.h"
-#include "components/strings/grit/components_strings.h"
+#include "extensions/browser/api/extensions_api_client.h"
+#include "extensions/browser/api/feedback_private/feedback_private_delegate.h"
 #include "extensions/browser/event_router.h"
-#include "extensions/browser/extensions_browser_client.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/webui/web_ui_util.h"
 #include "url/url_util.h"
 
 #if defined(OS_CHROMEOS)
-#include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/extensions/api/feedback_private/log_source_access_manager.h"
 #endif  // defined(OS_CHROMEOS)
 
@@ -188,63 +187,13 @@
   auto params = feedback_private::GetStrings::Params::Create(*args_);
   EXTENSION_FUNCTION_VALIDATE(params.get());
 
-  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-
-#define SET_STRING(id, idr) \
-  dict->SetString(id, l10n_util::GetStringUTF16(idr))
-  SET_STRING("page-title",
-             params->flow == FeedbackFlow::FEEDBACK_FLOW_SADTABCRASH
-                 ? IDS_FEEDBACK_REPORT_PAGE_TITLE_SAD_TAB_FLOW
-                 : IDS_FEEDBACK_REPORT_PAGE_TITLE);
-  SET_STRING("additionalInfo", IDS_FEEDBACK_ADDITIONAL_INFO_LABEL);
-  SET_STRING("minimize-btn-label", IDS_FEEDBACK_MINIMIZE_BUTTON_LABEL);
-  SET_STRING("close-btn-label", IDS_FEEDBACK_CLOSE_BUTTON_LABEL);
-  SET_STRING("page-url", IDS_FEEDBACK_REPORT_URL_LABEL);
-  SET_STRING("screenshot", IDS_FEEDBACK_SCREENSHOT_LABEL);
-  SET_STRING("user-email", IDS_FEEDBACK_USER_EMAIL_LABEL);
-  SET_STRING("anonymous-user", IDS_FEEDBACK_ANONYMOUS_EMAIL_OPTION);
-#if defined(OS_CHROMEOS)
-  if (arc::IsArcPlayStoreEnabledForProfile(
-          Profile::FromBrowserContext(browser_context()))) {
-    SET_STRING("sys-info",
-               IDS_FEEDBACK_INCLUDE_SYSTEM_INFORMATION_AND_METRICS_CHKBOX_ARC);
-  } else {
-    SET_STRING("sys-info",
-               IDS_FEEDBACK_INCLUDE_SYSTEM_INFORMATION_AND_METRICS_CHKBOX);
-  }
-#else
-  SET_STRING("sys-info", IDS_FEEDBACK_INCLUDE_SYSTEM_INFORMATION_CHKBOX);
-#endif
-  SET_STRING("attach-file-label", IDS_FEEDBACK_ATTACH_FILE_LABEL);
-  SET_STRING("attach-file-note", IDS_FEEDBACK_ATTACH_FILE_NOTE);
-  SET_STRING("attach-file-to-big", IDS_FEEDBACK_ATTACH_FILE_TO_BIG);
-  SET_STRING("reading-file", IDS_FEEDBACK_READING_FILE);
-  SET_STRING("send-report", IDS_FEEDBACK_SEND_REPORT);
-  SET_STRING("cancel", IDS_CANCEL);
-  SET_STRING("no-description", IDS_FEEDBACK_NO_DESCRIPTION);
-  SET_STRING("privacy-note", IDS_FEEDBACK_PRIVACY_NOTE);
-  SET_STRING("performance-trace",
-             IDS_FEEDBACK_INCLUDE_PERFORMANCE_TRACE_CHECKBOX);
-  // Add the localized strings needed for the "system information" page.
-  SET_STRING("sysinfoPageTitle", IDS_FEEDBACK_SYSINFO_PAGE_TITLE);
-  SET_STRING("sysinfoPageDescription", IDS_ABOUT_SYS_DESC);
-  SET_STRING("sysinfoPageTableTitle", IDS_ABOUT_SYS_TABLE_TITLE);
-  SET_STRING("sysinfoPageExpandAllBtn", IDS_ABOUT_SYS_EXPAND_ALL);
-  SET_STRING("sysinfoPageCollapseAllBtn", IDS_ABOUT_SYS_COLLAPSE_ALL);
-  SET_STRING("sysinfoPageExpandBtn", IDS_ABOUT_SYS_EXPAND);
-  SET_STRING("sysinfoPageCollapseBtn", IDS_ABOUT_SYS_COLLAPSE);
-  SET_STRING("sysinfoPageStatusLoading", IDS_FEEDBACK_SYSINFO_PAGE_LOADING);
-  // And the localized strings needed for the SRT Download Prompt.
-  SET_STRING("srtPromptBody", IDS_FEEDBACK_SRT_PROMPT_BODY);
-  SET_STRING("srtPromptAcceptButton", IDS_FEEDBACK_SRT_PROMPT_ACCEPT_BUTTON);
-  SET_STRING("srtPromptDeclineButton",
-             IDS_FEEDBACK_SRT_PROMPT_DECLINE_BUTTON);
-#undef SET_STRING
-
-  const std::string& app_locale =
-      ExtensionsBrowserClient::Get()->GetApplicationLocale();
-  webui::SetLoadTimeDataDefaults(app_locale, dict.get());
-
+  FeedbackPrivateDelegate* feedback_private_delegate =
+      ExtensionsAPIClient::Get()->GetFeedbackPrivateDelegate();
+  DCHECK(feedback_private_delegate);
+  std::unique_ptr<base::DictionaryValue> dict =
+      feedback_private_delegate->GetStrings(
+          browser_context(),
+          params->flow == FeedbackFlow::FEEDBACK_FLOW_SADTABCRASH);
 
   if (test_callback_ && !test_callback_->is_null())
     test_callback_->Run();
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
index 14aef77a..19cfdbe 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.cc
@@ -167,16 +167,15 @@
 }
 
 bool ImageWriterPrivateListRemovableStorageDevicesFunction::RunAsync() {
-  RemovableStorageProvider::GetAllDevices(
-    base::Bind(
+  RemovableStorageProvider::GetAllDevices(base::BindOnce(
       &ImageWriterPrivateListRemovableStorageDevicesFunction::OnDeviceListReady,
       this));
   return true;
 }
 
 void ImageWriterPrivateListRemovableStorageDevicesFunction::OnDeviceListReady(
-    scoped_refptr<StorageDeviceList> device_list,
-    bool success) {
+    scoped_refptr<StorageDeviceList> device_list) {
+  const bool success = device_list.get() != nullptr;
   if (success) {
     results_ = image_writer_api::ListRemovableStorageDevices::Results::Create(
         device_list->data);
diff --git a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.h b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.h
index a7abf444..68b17d7 100644
--- a/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.h
+++ b/chrome/browser/extensions/api/image_writer_private/image_writer_private_api.h
@@ -72,8 +72,7 @@
  private:
   ~ImageWriterPrivateListRemovableStorageDevicesFunction() override;
   bool RunAsync() override;
-  void OnDeviceListReady(scoped_refptr<StorageDeviceList> device_list,
-                         bool success);
+  void OnDeviceListReady(scoped_refptr<StorageDeviceList> device_list);
 };
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider.cc b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider.cc
index 1b2a3cd..c16b847 100644
--- a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider.cc
+++ b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider.cc
@@ -5,6 +5,7 @@
 
 #include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h"
 #include "base/lazy_instance.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/public/browser/browser_thread.h"
 
@@ -19,29 +20,30 @@
 
 void RemovableStorageProvider::GetAllDevices(DeviceListReadyCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (g_test_device_list.Get().get() != NULL) {
+  if (g_test_device_list.Get().get() != nullptr) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(callback, g_test_device_list.Get(), true));
+        FROM_HERE,
+        base::BindOnce(std::move(callback), g_test_device_list.Get()));
     return;
   }
-
-  scoped_refptr<StorageDeviceList> device_list(new StorageDeviceList);
-
   // We need to do some file i/o to get the device block size
-  content::BrowserThread::PostTaskAndReplyWithResult(
-      content::BrowserThread::FILE,
+  base::PostTaskWithTraitsAndReplyWithResult(
       FROM_HERE,
-      base::Bind(PopulateDeviceList, device_list),
-      base::Bind(callback, device_list));
+      {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+      base::BindOnce(&RemovableStorageProvider::PopulateDeviceList),
+      std::move(callback));
 }
 
+// static
 void RemovableStorageProvider::SetDeviceListForTesting(
     scoped_refptr<StorageDeviceList> device_list) {
   g_test_device_list.Get() = device_list;
 }
 
+// static
 void RemovableStorageProvider::ClearDeviceListForTesting() {
-  g_test_device_list.Get() = NULL;
+  g_test_device_list.Get() = nullptr;
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h
index 7c67242..5dd0087 100644
--- a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h
+++ b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h
@@ -19,8 +19,8 @@
 // storage devices
 class RemovableStorageProvider {
  public:
-  typedef base::Callback<void(scoped_refptr<StorageDeviceList>, bool)>
-    DeviceListReadyCallback;
+  using DeviceListReadyCallback =
+      base::OnceCallback<void(scoped_refptr<StorageDeviceList>)>;
 
   // Gets the list of all available devices and returns it via callback.
   static void GetAllDevices(DeviceListReadyCallback callback);
@@ -34,8 +34,9 @@
   static void ClearDeviceListForTesting();
 
  private:
-  // Fills the provided empty device list with the available devices.
-  static bool PopulateDeviceList(scoped_refptr<StorageDeviceList> device_list);
+  // Returns available list of devices. If there is an error retrieving devices,
+  // then returns nullptr.
+  static scoped_refptr<StorageDeviceList> PopulateDeviceList();
 };
 
 } // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos.cc b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos.cc
index 6dfc9f1..c359977 100644
--- a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos.cc
+++ b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos.cc
@@ -17,10 +17,11 @@
 // fixed disk.  In fact, some SD cards will present themselves as fixed disks
 // (see http://crbug.com/340761).  Thus we just expose all USB and SD drives.
 // static
-bool RemovableStorageProvider::PopulateDeviceList(
-    scoped_refptr<StorageDeviceList> device_list) {
+scoped_refptr<StorageDeviceList>
+RemovableStorageProvider::PopulateDeviceList() {
   DiskMountManager* disk_mount_manager = DiskMountManager::GetInstance();
   const DiskMountManager::DiskMap& disks = disk_mount_manager->disks();
+  scoped_refptr<StorageDeviceList> device_list(new StorageDeviceList());
 
   for (DiskMountManager::DiskMap::const_iterator iter = disks.begin();
        iter != disks.end();
@@ -48,7 +49,7 @@
     }
   }
 
-  return true;
+  return device_list;
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos_unittest.cc b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos_unittest.cc
index 098f786..70687146 100644
--- a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos_unittest.cc
+++ b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_chromeos_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "chrome/browser/extensions/api/image_writer_private/removable_storage_provider.h"
 #include "chromeos/disks/mock_disk_mount_manager.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -33,6 +34,9 @@
 
 class RemovableStorageProviderChromeOsUnitTest : public testing::Test {
  public:
+  RemovableStorageProviderChromeOsUnitTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::UI) {}
   void SetUp() override {
     disk_mount_manager_mock_ = new MockDiskMountManager();
     DiskMountManager::InitializeForTesting(disk_mount_manager_mock_);
@@ -41,7 +45,7 @@
 
   void TearDown() override { DiskMountManager::Shutdown(); }
 
-  void DevicesCallback(scoped_refptr<StorageDeviceList> devices, bool success) {
+  void DevicesCallback(scoped_refptr<StorageDeviceList> devices) {
     devices_ = devices;
   }
 
@@ -109,6 +113,7 @@
     EXPECT_EQ(capacity, device->capacity);
   }
 
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   MockDiskMountManager* disk_mount_manager_mock_;
   scoped_refptr<StorageDeviceList> devices_;
 
@@ -132,7 +137,7 @@
       base::Bind(&RemovableStorageProviderChromeOsUnitTest::DevicesCallback,
                  base::Unretained(this)));
 
-  base::RunLoop().RunUntilIdle();
+  scoped_task_environment_.RunUntilIdle();
 
   ASSERT_EQ(2U, devices_->data.size());
 
@@ -153,7 +158,7 @@
       base::Bind(&RemovableStorageProviderChromeOsUnitTest::DevicesCallback,
                  base::Unretained(this)));
 
-  base::RunLoop().RunUntilIdle();
+  scoped_task_environment_.RunUntilIdle();
 
   ASSERT_EQ(2U, devices_->data.size());
 
diff --git a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_linux.cc b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_linux.cc
index 60921f31..389479b1 100644
--- a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_linux.cc
+++ b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_linux.cc
@@ -42,14 +42,16 @@
   return blk_size;
 }
 
-bool RemovableStorageProvider::PopulateDeviceList(
-    scoped_refptr<StorageDeviceList> device_list) {
+// static
+scoped_refptr<StorageDeviceList>
+RemovableStorageProvider::PopulateDeviceList() {
   device::ScopedUdevPtr udev(device::udev_new());
   if (!udev) {
     DLOG(ERROR) << "Can't create udev";
-    return false;
+    return nullptr;
   }
 
+  scoped_refptr<StorageDeviceList> device_list(new StorageDeviceList());
   /* Create a list of the devices in the 'block' subsystem. */
   device::ScopedUdevEnumeratePtr enumerate(
       device::udev_enumerate_new(udev.get()));
@@ -106,7 +108,7 @@
     device_list->data.push_back(std::move(device_item));
   }
 
-  return true;
+  return device_list;
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_mac.cc b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_mac.cc
index ad1f5d3..8191b1c 100644
--- a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_mac.cc
+++ b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_mac.cc
@@ -22,8 +22,8 @@
 namespace extensions {
 
 // static
-bool RemovableStorageProvider::PopulateDeviceList(
-    scoped_refptr<StorageDeviceList> device_list) {
+scoped_refptr<StorageDeviceList>
+RemovableStorageProvider::PopulateDeviceList() {
   base::ThreadRestrictions::AssertIOAllowed();
   // Match only writable whole-disks.
   CFMutableDictionaryRef matching = IOServiceMatching(kIOMediaClass);
@@ -34,11 +34,12 @@
   if (IOServiceGetMatchingServices(
           kIOMasterPortDefault, matching, &disk_iterator) != KERN_SUCCESS) {
     LOG(ERROR) << "Unable to get disk services.";
-    return false;
+    return nullptr;
   }
   base::mac::ScopedIOObject<io_service_t> iterator_ref(disk_iterator);
 
   io_object_t disk_obj;
+  scoped_refptr<StorageDeviceList> device_list(new StorageDeviceList());
   while ((disk_obj = IOIteratorNext(disk_iterator))) {
     base::mac::ScopedIOObject<io_object_t> disk_obj_ref(disk_obj);
 
@@ -100,7 +101,7 @@
     device_list->data.push_back(std::move(device));
   }
 
-  return true;
+  return device_list;
 }
 
 } // namespace extensions
diff --git a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc
index a48c2b7e..51db3d51 100644
--- a/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc
+++ b/chrome/browser/extensions/api/image_writer_private/removable_storage_provider_win.cc
@@ -174,8 +174,9 @@
 
 }  // namespace
 
-bool RemovableStorageProvider::PopulateDeviceList(
-    scoped_refptr<StorageDeviceList> device_list) {
+// static
+scoped_refptr<StorageDeviceList>
+RemovableStorageProvider::PopulateDeviceList() {
   HDEVINFO interface_enumerator = SetupDiGetClassDevs(
       &DiskClassGuid,
       NULL, // Enumerator.
@@ -185,13 +186,14 @@
 
   if (interface_enumerator == INVALID_HANDLE_VALUE) {
     DPLOG(ERROR) << "SetupDiGetClassDevs failed.";
-    return false;
+    return nullptr;
   }
 
   DWORD index = 0;
   SP_DEVICE_INTERFACE_DATA interface_data;
   interface_data.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
 
+  scoped_refptr<StorageDeviceList> device_list(new StorageDeviceList());
   while (SetupDiEnumDeviceInterfaces(
       interface_enumerator,
       NULL,                    // Device Info data.
@@ -207,11 +209,11 @@
   if (error_code != ERROR_NO_MORE_ITEMS) {
     PLOG(ERROR) << "SetupDiEnumDeviceInterfaces failed";
     SetupDiDestroyDeviceInfoList(interface_enumerator);
-    return false;
+    return nullptr;
   }
 
   SetupDiDestroyDeviceInfoList(interface_enumerator);
-  return true;
+  return device_list;
 }
 
 } // namespace extensions
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 349f7c5a..9d797e6 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -445,6 +445,14 @@
         password_field_exists);
   }
 }
+
+void ChromePasswordManagerClient::LogPasswordReuseDetectedEvent() {
+  safe_browsing::PasswordProtectionService* pps =
+      GetPasswordProtectionService();
+  if (pps) {
+    pps->MaybeLogPasswordReuseDetectedEvent(web_contents());
+  }
+}
 #endif
 
 ukm::UkmRecorder* ChromePasswordManagerClient::GetUkmRecorder() {
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index f9b6ee7..9c01080 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -115,6 +115,8 @@
 
   void CheckProtectedPasswordEntry(const std::string& password_saved_domain,
                                    bool password_field_exists) override;
+
+  void LogPasswordReuseDetectedEvent() override;
 #endif
 
   ukm::UkmRecorder* GetUkmRecorder() override;
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index 334ed68..aa4f4314 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -85,6 +85,7 @@
   MOCK_METHOD0(IsIncognito, bool());
   MOCK_METHOD2(IsPingingEnabled, bool(const base::Feature&, RequestOutcome*));
   MOCK_METHOD0(IsHistorySyncEnabled, bool());
+  MOCK_METHOD1(MaybeLogPasswordReuseDetectedEvent, void(WebContents*));
   MOCK_METHOD4(MaybeStartPasswordFieldOnFocusRequest,
                void(WebContents*, const GURL&, const GURL&, const GURL&));
   MOCK_METHOD4(MaybeStartProtectedPasswordEntryRequest,
@@ -642,4 +643,16 @@
   client->CheckProtectedPasswordEntry(std::string("saved_domain.com"), true);
 }
 
+TEST_F(ChromePasswordManagerClientTest, VerifyLogPasswordReuseDetectedEvent) {
+  std::unique_ptr<WebContents> test_web_contents(
+      content::WebContentsTester::CreateTestWebContents(
+          web_contents()->GetBrowserContext(), nullptr));
+  std::unique_ptr<MockChromePasswordManagerClient> client(
+      new MockChromePasswordManagerClient(test_web_contents.get()));
+  EXPECT_CALL(*client->password_protection_service(),
+              MaybeLogPasswordReuseDetectedEvent(test_web_contents.get()))
+      .Times(1);
+  client->LogPasswordReuseDetectedEvent();
+}
+
 #endif
diff --git a/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc b/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc
index 9940399..566eec3d 100644
--- a/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc
+++ b/chrome/browser/printing/cloud_print/test/cloud_print_proxy_process_browsertest.cc
@@ -470,7 +470,7 @@
   EXPECT_FALSE(CheckServiceProcessReady());
 
   startup_channel_handle_ = mojo::edk::NamedPlatformHandle(
-      base::StringPrintf("%d.%p.%d", base::GetCurrentProcId(), this,
+      base::StringPrintf("%" CrPRIdPid ".%p.%d", base::GetCurrentProcId(), this,
                          base::RandInt(0, std::numeric_limits<int>::max())));
   startup_channel_ = IPC::ChannelProxy::Create(
       peer_connection_
diff --git a/chrome/browser/referrer_policy_browsertest.cc b/chrome/browser/referrer_policy_browsertest.cc
index 5c97e7aa..395e78b 100644
--- a/chrome/browser/referrer_policy_browsertest.cc
+++ b/chrome/browser/referrer_policy_browsertest.cc
@@ -516,6 +516,15 @@
   // Watch for all possible outcomes to avoid timeouts if something breaks.
   AddAllPossibleTitles(start_url, &title_watcher);
 
+  // Erase the current title in the NavigationEntry.
+  //
+  // TitleWatcher overrides WebContentObserver's TitleWasSet() but also
+  // DidStopLoading(). The page that is being reloaded sets its title after load
+  // is complete, so the title change is missed because the title is checked on
+  // load. Clearing the title ensures that TitleWatcher will wait for the actual
+  // title setting.
+  tab->GetController().GetActiveEntry()->SetTitle(base::string16());
+
   // Request tablet version.
   chrome::ToggleRequestTabletSite(browser());
   EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
diff --git a/chrome/browser/resources/chromeos/arc_support/background.js b/chrome/browser/resources/chromeos/arc_support/background.js
index 8e02a25..91d507f4 100644
--- a/chrome/browser/resources/chromeos/arc_support/background.js
+++ b/chrome/browser/resources/chromeos/arc_support/background.js
@@ -447,7 +447,7 @@
     // end of the SAML flow. Before that, we're on the Active Directory
     // Federation Services server.
     if (this.deviceManagementUrlPrefix_ &&
-        details.url.startsWith(this.deviceManagementUrlPrefix)) {
+        details.url.startsWith(this.deviceManagementUrlPrefix_)) {
       // Did it actually work?
       if (details.statusCode == 200) {
         // 'code' is unused, but it needs to be there.
diff --git a/chrome/browser/resources/inspect/inspect.css b/chrome/browser/resources/inspect/inspect.css
index 8c3957b..13875de 100644
--- a/chrome/browser/resources/inspect/inspect.css
+++ b/chrome/browser/resources/inspect/inspect.css
@@ -182,8 +182,7 @@
 }
 
 .used-for-port-forwarding {
-  background-image: -webkit-image-set(url(chrome://theme/IDR_INFO) 1x,
-                                      url(chrome://theme/IDR_INFO@2x) 2x);
+  background-image: url(../../../../ui/webui/resources/images/info.svg);
   height: 15px;
   margin-left: 20px;
   width: 15px;
diff --git a/chrome/browser/resources/options/clear_browser_data_overlay.css b/chrome/browser/resources/options/clear_browser_data_overlay.css
index 2cfeb46..555ff4dc 100644
--- a/chrome/browser/resources/options/clear_browser_data_overlay.css
+++ b/chrome/browser/resources/options/clear_browser_data_overlay.css
@@ -71,7 +71,7 @@
 }
 
 #clear-browser-data-general-footer {
-  background: url(info.svg) left no-repeat;
+  background: url(../../../../ui/webui/resources/images/info.svg) left no-repeat;
   margin: 0;
   min-height: 18px;
 }
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_browsertest_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_browsertest_win.cc
new file mode 100644
index 0000000..4ba4c5a
--- /dev/null
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_browsertest_win.cc
@@ -0,0 +1,113 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_win.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "chrome/browser/lifetime/keep_alive_types.h"
+#include "chrome/browser/lifetime/scoped_keep_alive.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_window.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace safe_browsing {
+namespace {
+
+using ::testing::_;
+using ::testing::StrictMock;
+using ::testing::Return;
+
+class MockChromeCleanerPromptDelegate : public ChromeCleanerPromptDelegate {
+ public:
+  MOCK_METHOD3(ShowChromeCleanerPrompt,
+               void(Browser* browser,
+                    ChromeCleanerDialogController* dialog_controller,
+                    ChromeCleanerController* cleaner_controller));
+};
+
+class MockChromeCleanerController
+    : public safe_browsing::ChromeCleanerController {
+ public:
+  MOCK_METHOD0(ShouldShowCleanupInSettingsUI, bool());
+  MOCK_METHOD0(IsPoweredByPartner, bool());
+  MOCK_CONST_METHOD0(state, State());
+  MOCK_CONST_METHOD0(idle_reason, IdleReason());
+  MOCK_METHOD1(SetLogsEnabled, void(bool));
+  MOCK_CONST_METHOD0(logs_enabled, bool());
+  MOCK_METHOD0(ResetIdleState, void());
+  MOCK_METHOD1(AddObserver, void(Observer*));
+  MOCK_METHOD1(RemoveObserver, void(Observer*));
+  MOCK_METHOD1(Scan, void(const safe_browsing::SwReporterInvocation&));
+  MOCK_METHOD2(ReplyWithUserResponse, void(Profile*, UserResponse));
+  MOCK_METHOD0(Reboot, void());
+};
+
+class ChromeCleanerPromptUserTest : public InProcessBrowserTest {
+ public:
+  void SetUpInProcessBrowserTestFixture() override {
+// dialog_controller_ expects that the cleaner controller would be on
+// scanning state.
+#if DCHECK_IS_ON()
+    EXPECT_CALL(mock_cleaner_controller_, state())
+        .WillOnce(Return(ChromeCleanerController::State::kScanning));
+#endif
+    EXPECT_CALL(mock_cleaner_controller_, AddObserver(_));
+    dialog_controller_ =
+        new ChromeCleanerDialogControllerImpl(&mock_cleaner_controller_);
+    dialog_controller_->SetPromptDelegateForTests(&mock_delegate_);
+  }
+
+ protected:
+  MockChromeCleanerController mock_cleaner_controller_;
+  ChromeCleanerDialogControllerImpl* dialog_controller_;
+  StrictMock<MockChromeCleanerPromptDelegate> mock_delegate_;
+};
+
+IN_PROC_BROWSER_TEST_F(ChromeCleanerPromptUserTest,
+                       OnInfectedBrowserAvailable) {
+  EXPECT_CALL(mock_delegate_, ShowChromeCleanerPrompt(_, _, _)).Times(1);
+  dialog_controller_->OnInfected(std::set<base::FilePath>());
+}
+
+IN_PROC_BROWSER_TEST_F(ChromeCleanerPromptUserTest,
+                       OnInfectedBrowserNotAvailable) {
+  browser()->window()->Minimize();
+  base::RunLoop().RunUntilIdle();
+  dialog_controller_->OnInfected(std::set<base::FilePath>());
+
+  // We only set the expectation here because we want to make sure that the
+  // prompt is shown only when the window is restored.
+  EXPECT_CALL(mock_delegate_, ShowChromeCleanerPrompt(_, _, _)).Times(1);
+
+  browser()->window()->Restore();
+  base::RunLoop().RunUntilIdle();
+}
+
+IN_PROC_BROWSER_TEST_F(ChromeCleanerPromptUserTest, AllBrowsersClosed) {
+  std::unique_ptr<ScopedKeepAlive> keep_alive =
+      base::MakeUnique<ScopedKeepAlive>(KeepAliveOrigin::BROWSER,
+                                        KeepAliveRestartOption::DISABLED);
+
+  CloseAllBrowsers();
+  base::RunLoop().RunUntilIdle();
+  dialog_controller_->OnInfected(std::set<base::FilePath>());
+
+  // We only set the expectation here because we want to make sure that the
+  // prompt is shown only when the window is restored.
+  EXPECT_CALL(mock_delegate_, ShowChromeCleanerPrompt(_, _, _)).Times(1);
+
+  CreateBrowser(ProfileManager::GetActiveUserProfile());
+  base::RunLoop().RunUntilIdle();
+}
+
+}  // namespace
+}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_win.cc
index 949162f..52dbed6 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_win.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_dialogs.h"
+#include "chrome/browser/ui/browser_list.h"
 #include "ui/base/window_open_disposition.h"
 
 namespace safe_browsing {
@@ -43,14 +44,30 @@
 
 }  // namespace
 
+ChromeCleanerPromptDelegate::~ChromeCleanerPromptDelegate() = default;
+
+class ChromeCleanerPromptDelegateImpl : public ChromeCleanerPromptDelegate {
+ public:
+  void ShowChromeCleanerPrompt(
+      Browser* browser,
+      ChromeCleanerDialogController* dialog_controller,
+      ChromeCleanerController* cleaner_controller) override {
+    chrome::ShowChromeCleanerPrompt(browser, dialog_controller,
+                                    cleaner_controller);
+  }
+};
+
 ChromeCleanerDialogControllerImpl::ChromeCleanerDialogControllerImpl(
     ChromeCleanerController* cleaner_controller)
-    : cleaner_controller_(cleaner_controller) {
+    : cleaner_controller_(cleaner_controller),
+      prompt_delegate_impl_(
+          base::MakeUnique<ChromeCleanerPromptDelegateImpl>()) {
   DCHECK(cleaner_controller_);
   DCHECK_EQ(ChromeCleanerController::State::kScanning,
             cleaner_controller_->state());
 
   cleaner_controller_->AddObserver(this);
+  prompt_delegate_ = prompt_delegate_impl_.get();
 }
 
 ChromeCleanerDialogControllerImpl::~ChromeCleanerDialogControllerImpl() =
@@ -173,18 +190,15 @@
 
   browser_ = chrome_cleaner_util::FindBrowser();
   if (!browser_) {
-    // TODO(alito): Register with chrome::BrowserListObserver to get notified
-    // later if a suitable browser window becomes available to show the
-    // prompt. http://crbug.com/734677
     RecordPromptNotShownWithReasonHistogram(
-        NO_PROMPT_REASON_BROWSER_NOT_AVAILABLE);
-    OnInteractionDone();
+        NO_PROMPT_REASON_WAITING_FOR_BROWSER);
+    prompt_pending_ = true;
+    BrowserList::AddObserver(this);
     return;
   }
-
-  chrome::ShowChromeCleanerPrompt(browser_, this, cleaner_controller_);
-  RecordPromptShownHistogram();
-  dialog_shown_ = true;
+  ShowChromeCleanerPrompt();
+  RecordPromptShownWithTypeHistogram(
+      PromptTypeHistogramValue::PROMPT_TYPE_ON_TRANSITION_TO_INFECTED_STATE);
 }
 
 void ChromeCleanerDialogControllerImpl::OnCleaning(
@@ -198,7 +212,37 @@
     OnInteractionDone();
 }
 
+void ChromeCleanerDialogControllerImpl::OnBrowserSetLastActive(
+    Browser* browser) {
+  DCHECK(prompt_pending_);
+  DCHECK(browser);
+  DCHECK(!browser_);
+
+  browser_ = browser;
+  ShowChromeCleanerPrompt();
+  RecordPromptShownWithTypeHistogram(
+      PromptTypeHistogramValue::PROMPT_TYPE_ON_BROWSER_WINDOW_AVAILABLE);
+  prompt_pending_ = false;
+  BrowserList::RemoveObserver(this);
+}
+
+void ChromeCleanerDialogControllerImpl::SetPromptDelegateForTests(
+    ChromeCleanerPromptDelegate* delegate) {
+  prompt_delegate_ = delegate;
+}
+
+void ChromeCleanerDialogControllerImpl::ShowChromeCleanerPrompt() {
+  prompt_delegate_->ShowChromeCleanerPrompt(browser_, this,
+                                            cleaner_controller_);
+  dialog_shown_ = true;
+}
+
 void ChromeCleanerDialogControllerImpl::OnInteractionDone() {
+  if (prompt_pending_) {
+    BrowserList::RemoveObserver(this);
+    prompt_pending_ = false;
+  }
+
   cleaner_controller_->RemoveObserver(this);
   delete this;
 }
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_win.h b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_win.h
index 36274977..ef46c39 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_win.h
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_win.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_DIALOG_CONTROLLER_IMPL_WIN_H_
 #define CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_CLEANER_DIALOG_CONTROLLER_IMPL_WIN_H_
 
+#include <memory>
 #include <set>
 
 #include "base/files/file_path.h"
@@ -12,14 +13,25 @@
 #include "base/time/time.h"
 #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_win.h"
 #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_win.h"
+#include "chrome/browser/ui/browser_list_observer.h"
 
 class Browser;
 
 namespace safe_browsing {
 
+class ChromeCleanerPromptDelegate {
+ public:
+  virtual void ShowChromeCleanerPrompt(
+      Browser* browser,
+      safe_browsing::ChromeCleanerDialogController* dialog_controller,
+      safe_browsing::ChromeCleanerController* cleaner_controller) = 0;
+  virtual ~ChromeCleanerPromptDelegate();
+};
+
 class ChromeCleanerDialogControllerImpl
     : public ChromeCleanerDialogController,
-      public ChromeCleanerController::Observer {
+      public ChromeCleanerController::Observer,
+      public chrome::BrowserListObserver {
  public:
   // An instance should only be created when |cleaner_controller| is in the
   // kScanning state.
@@ -43,16 +55,29 @@
   void OnCleaning(const std::set<base::FilePath>& files_to_delete) override;
   void OnRebootRequired() override;
 
+  // chrome::BrowserListObserver overrides.
+  void OnBrowserSetLastActive(Browser* browser) override;
+
+  // Test specific methods.
+  void SetPromptDelegateForTests(ChromeCleanerPromptDelegate* delegate);
+
  protected:
   ~ChromeCleanerDialogControllerImpl() override;
 
  private:
   void OnInteractionDone();
+  void ShowChromeCleanerPrompt();
 
   ChromeCleanerController* cleaner_controller_ = nullptr;
   bool dialog_shown_ = false;
+
+  // In case there is no browser available to prompt a user
+  // signal it, this way we can prompt it once a browser gets available..
+  bool prompt_pending_ = false;
   base::Time time_dialog_shown_;  // Used for reporting metrics.
   Browser* browser_ = nullptr;
+  std::unique_ptr<ChromeCleanerPromptDelegate> prompt_delegate_impl_;
+  ChromeCleanerPromptDelegate* prompt_delegate_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeCleanerDialogControllerImpl);
 };
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc
index 4bcd0ae..40b155a 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.cc
@@ -37,9 +37,6 @@
     "https://dl.google.com/dl"
     "/softwareremovaltool/win/c/chrome_cleanup_tool.exe?chrome-prompt=1";
 
-constexpr char kSoftwareReporterPromptShownMetricName[] =
-    "SoftwareReporter.PromptShown";
-
 }  // namespace
 
 namespace safe_browsing {
@@ -114,13 +111,13 @@
                             SRT_PROMPT_MAX);
 }
 
-void RecordPromptShownHistogram() {
-  UMA_HISTOGRAM_BOOLEAN(kSoftwareReporterPromptShownMetricName, true);
+void RecordPromptShownWithTypeHistogram(PromptTypeHistogramValue value) {
+  UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.PromptShownWithType", value,
+                            PROMPT_TYPE_MAX);
 }
 
 void RecordPromptNotShownWithReasonHistogram(
     NoPromptReasonHistogramValue value) {
-  UMA_HISTOGRAM_BOOLEAN(kSoftwareReporterPromptShownMetricName, false);
   UMA_HISTOGRAM_ENUMERATION("SoftwareReporter.NoPromptReason", value,
                             NO_PROMPT_REASON_MAX);
 }
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h
index ff3c316..d75cdaea6d 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h
+++ b/chrome/browser/safe_browsing/chrome_cleaner/srt_field_trial_win.h
@@ -37,10 +37,21 @@
   NO_PROMPT_REASON_BROWSER_NOT_AVAILABLE = 5,
   NO_PROMPT_REASON_NOT_ON_IDLE_STATE = 6,
   NO_PROMPT_REASON_IPC_CONNECTION_BROKEN = 7,
+  NO_PROMPT_REASON_WAITING_FOR_BROWSER = 8,
 
   NO_PROMPT_REASON_MAX,
 };
 
+// These values are used to send UMA information about the histogram type
+// and are replicated in the histograms.xml file, so the order MUST NOT CHANGE.
+enum PromptTypeHistogramValue {
+  PROMPT_TYPE_LEGACY_PROMPT_SHOWN = 0,
+  PROMPT_TYPE_ON_TRANSITION_TO_INFECTED_STATE = 1,
+  PROMPT_TYPE_ON_BROWSER_WINDOW_AVAILABLE = 2,
+
+  PROMPT_TYPE_MAX,
+};
+
 // When enabled, all user interaction with the Chrome Cleaner will happen from
 // within Chrome.
 extern const base::Feature kInBrowserCleanerUIFeature;
@@ -66,8 +77,8 @@
 // Records a value for the SRT Prompt Histogram.
 void RecordSRTPromptHistogram(SRTPromptHistogramValue value);
 
-// Records a SoftwareReporter.PromptShown histogram with value true.
-void RecordPromptShownHistogram();
+// Records a value for SoftwareReporter.PromptShownWithType Histogram
+void RecordPromptShownWithTypeHistogram(PromptTypeHistogramValue value);
 
 // Records a SoftwareReporter.PromptShown histogram with value false and
 // a SoftwareReporter.NoPromptReason histogram with the reason corresponding
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/srt_global_error_win.cc b/chrome/browser/safe_browsing/chrome_cleaner/srt_global_error_win.cc
index afc8a40..a46d7015 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/srt_global_error_win.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/srt_global_error_win.cc
@@ -137,7 +137,8 @@
 
 void SRTGlobalError::ShowBubbleView(Browser* browser) {
   RecordSRTPromptHistogram(SRT_PROMPT_SHOWN);
-  RecordPromptShownHistogram();
+  RecordPromptShownWithTypeHistogram(
+      PromptTypeHistogramValue::PROMPT_TYPE_LEGACY_PROMPT_SHOWN);
   GlobalErrorWithStandardBubble::ShowBubbleView(browser);
 }
 
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
index 01e155a..6f8096cb 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
+#include "chrome/browser/sync/user_event_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -27,12 +28,17 @@
 #include "components/signin/core/browser/account_info.h"
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "components/signin/core/browser/signin_manager.h"
+#include "components/sync/protocol/user_event_specifics.pb.h"
+#include "components/sync/user_events/user_event_service.h"
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
 
 using content::BrowserThread;
+using sync_pb::UserEventSpecifics;
+using SafeBrowsingStatus = UserEventSpecifics::SyncPasswordReuseEvent::
+    PasswordReuseDetected::SafeBrowsingStatus;
 
 namespace safe_browsing {
 
@@ -45,6 +51,10 @@
 // for 2 days.
 const int kOverrideVerdictCacheDurationSec = 2 * 24 * 60 * 60;
 
+int64_t GetMicrosecondsSinceWindowsEpoch(base::Time time) {
+  return (time - base::Time()).InMicroseconds();
+}
+
 }  // namespace
 
 ChromePasswordProtectionService::ChromePasswordProtectionService(
@@ -96,24 +106,27 @@
       SafeBrowsingNavigationObserverManager::ATTRIBUTION_FAILURE_TYPE_MAX);
 }
 
+PrefService* ChromePasswordProtectionService::GetPrefs() {
+  return profile_->GetPrefs();
+}
+
+bool ChromePasswordProtectionService::IsSafeBrowsingEnabled() {
+  return GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled);
+}
+
 bool ChromePasswordProtectionService::IsExtendedReporting() {
-  return IsExtendedReportingEnabled(*profile_->GetPrefs());
+  return IsExtendedReportingEnabled(*GetPrefs());
 }
 
 bool ChromePasswordProtectionService::IsIncognito() {
-  DCHECK(profile_);
   return profile_->IsOffTheRecord();
 }
 
 bool ChromePasswordProtectionService::IsPingingEnabled(
     const base::Feature& feature,
     RequestOutcome* reason) {
-  // Don't start pinging on an invalid profile, or if user turns off Safe
-  // Browsing service.
-  if (!profile_ ||
-      !profile_->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled)) {
+  if (!IsSafeBrowsingEnabled())
     return false;
-  }
 
   DCHECK(feature.name == kProtectedPasswordEntryPinging.name ||
          feature.name == kPasswordFieldOnFocusPinging.name);
@@ -146,6 +159,48 @@
          sync->GetActiveDataTypes().Has(syncer::HISTORY_DELETE_DIRECTIVES);
 }
 
+void ChromePasswordProtectionService::MaybeLogPasswordReuseDetectedEvent(
+    content::WebContents* web_contents) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  if (!base::FeatureList::IsEnabled(safe_browsing::kSyncPasswordReuseEvent))
+    return;
+
+  syncer::UserEventService* user_event_service =
+      browser_sync::UserEventServiceFactory::GetForProfile(profile_);
+  content::NavigationEntry* navigation =
+      web_contents->GetController().GetLastCommittedEntry();
+  if (!user_event_service || !navigation)
+    return;
+
+  auto specifics = base::MakeUnique<UserEventSpecifics>();
+  specifics->set_event_time_usec(
+      GetMicrosecondsSinceWindowsEpoch(base::Time::Now()));
+  specifics->set_navigation_id(
+      GetMicrosecondsSinceWindowsEpoch(navigation->GetTimestamp()));
+  auto* const status = specifics->mutable_sync_password_reuse_event()
+                           ->mutable_reuse_detected()
+                           ->mutable_status();
+
+  status->set_enabled(IsSafeBrowsingEnabled());
+
+  safe_browsing::ExtendedReportingLevel erl =
+      safe_browsing::GetExtendedReportingLevel(*GetPrefs());
+  switch (erl) {
+    case safe_browsing::SBER_LEVEL_OFF:
+      status->set_safe_browsing_reporting_population(SafeBrowsingStatus::NONE);
+      break;
+    case safe_browsing::SBER_LEVEL_LEGACY:
+      status->set_safe_browsing_reporting_population(
+          SafeBrowsingStatus::EXTENDED_REPORTING);
+      break;
+    case safe_browsing::SBER_LEVEL_SCOUT:
+      status->set_safe_browsing_reporting_population(SafeBrowsingStatus::SCOUT);
+      break;
+  }
+  user_event_service->RecordUserEvent(std::move(specifics));
+}
+
 PasswordProtectionService::SyncAccountType
 ChromePasswordProtectionService::GetSyncAccountType() {
   DCHECK(profile_);
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.h b/chrome/browser/safe_browsing/chrome_password_protection_service.h
index d954a04..5a22f4a 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.h
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.h
@@ -7,6 +7,7 @@
 
 #include "components/safe_browsing/password_protection/password_protection_service.h"
 
+class PrefService;
 class Profile;
 
 namespace content {
@@ -50,6 +51,9 @@
   // If user enabled history syncing.
   bool IsHistorySyncEnabled() override;
 
+  void MaybeLogPasswordReuseDetectedEvent(
+      content::WebContents* web_contents) override;
+
   void ShowPhishingInterstitial(const GURL& phishing_url,
                                 const std::string& token,
                                 content::WebContents* web_contents) override;
@@ -67,11 +71,21 @@
   FRIEND_TEST_ALL_PREFIXES(ChromePasswordProtectionServiceTest,
                            VerifyUserPopulationForProtectedPasswordEntryPing);
   FRIEND_TEST_ALL_PREFIXES(ChromePasswordProtectionServiceTest,
+                           VerifyPasswordReuseUserEventNotRecorded);
+  FRIEND_TEST_ALL_PREFIXES(ChromePasswordProtectionServiceTest,
+                           VerifyPasswordReuseUserEventRecorded);
+  FRIEND_TEST_ALL_PREFIXES(ChromePasswordProtectionServiceTest,
                            VerifyGetSyncAccountType);
   FRIEND_TEST_ALL_PREFIXES(ChromePasswordProtectionServiceTest,
                            VerifyUpdateSecurityState);
 
  private:
+  // Gets prefs associated with |profile_|.
+  PrefService* GetPrefs();
+
+  // Returns whether the profile is valid and has safe browsing service enabled.
+  bool IsSafeBrowsingEnabled();
+
   friend class MockChromePasswordProtectionService;
   // Constructor used for tests only.
   ChromePasswordProtectionService(
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index f669e21d7..0a02e37 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -16,6 +16,7 @@
 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
 #include "chrome/browser/signin/test_signin_client_builder.h"
+#include "chrome/browser/sync/user_event_service_factory.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
@@ -28,6 +29,7 @@
 #include "components/signin/core/browser/fake_account_fetcher_service.h"
 #include "components/signin/core/browser/signin_manager.h"
 #include "components/signin/core/browser/signin_manager_base.h"
+#include "components/sync/user_events/fake_user_event_service.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "components/variations/variations_params_manager.h"
 #include "content/public/browser/web_contents.h"
@@ -43,6 +45,11 @@
 const char kTestAccountID[] = "account_id";
 const char kTestEmail[] = "foo@example.com";
 
+std::unique_ptr<KeyedService> BuildFakeUserEventService(
+    content::BrowserContext* context) {
+  return base::MakeUnique<syncer::FakeUserEventService>();
+}
+
 }  // namespace
 
 class MockSafeBrowsingUIManager : public SafeBrowsingUIManager {
@@ -123,6 +130,10 @@
         profile(), content_setting_map_,
         new testing::StrictMock<MockSafeBrowsingUIManager>(
             SafeBrowsingService::CreateSafeBrowsingService()));
+    fake_user_event_service_ = static_cast<syncer::FakeUserEventService*>(
+        browser_sync::UserEventServiceFactory::GetInstance()
+            ->SetTestingFactoryAndUse(browser_context(),
+                                      &BuildFakeUserEventService));
   }
 
   void TearDown() override {
@@ -146,6 +157,14 @@
     return builder.Build().release();
   }
 
+  void EnableSyncPasswordReuseEvent() {
+    scoped_feature_list_.InitAndEnableFeature(kSyncPasswordReuseEvent);
+  }
+
+  syncer::FakeUserEventService* GetUserEventService() {
+    return fake_user_event_service_;
+  }
+
   void InitializeRequest(LoginReputationClientRequest::TriggerType type) {
     request_ = new PasswordProtectionRequest(web_contents(), GURL(kPhishingURL),
                                              GURL(), GURL(), std::string(),
@@ -183,6 +202,8 @@
   std::unique_ptr<MockChromePasswordProtectionService> service_;
   scoped_refptr<PasswordProtectionRequest> request_;
   std::unique_ptr<LoginReputationClientResponse> verdict_;
+  // Owned by KeyedServiceFactory.
+  syncer::FakeUserEventService* fake_user_event_service_;
 };
 
 TEST_F(ChromePasswordProtectionServiceTest,
@@ -332,4 +353,44 @@
       service_->GetCachedVerdict(
           url, LoginReputationClientRequest::PASSWORD_REUSE_EVENT, &verdict));
 }
+
+TEST_F(ChromePasswordProtectionServiceTest,
+       VerifyPasswordReuseUserEventNotRecorded) {
+  // Feature not enabled.
+  service_->MaybeLogPasswordReuseDetectedEvent(web_contents());
+  EXPECT_TRUE(GetUserEventService()->GetRecordedUserEvents().empty());
+
+  EnableSyncPasswordReuseEvent();
+  // Feature enabled but no committed navigation entry.
+  service_->MaybeLogPasswordReuseDetectedEvent(web_contents());
+  EXPECT_TRUE(GetUserEventService()->GetRecordedUserEvents().empty());
+}
+
+TEST_F(ChromePasswordProtectionServiceTest,
+       VerifyPasswordReuseUserEventRecorded) {
+  EnableSyncPasswordReuseEvent();
+  NavigateAndCommit(GURL("https://www.example.com/"));
+
+  // Case 1: safe_browsing_enabled = true
+  profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, true);
+  service_->MaybeLogPasswordReuseDetectedEvent(web_contents());
+  ASSERT_EQ(1ul, GetUserEventService()->GetRecordedUserEvents().size());
+  sync_pb::UserEventSpecifics::SyncPasswordReuseEvent event =
+      GetUserEventService()
+          ->GetRecordedUserEvents()[0]
+          .sync_password_reuse_event();
+  EXPECT_TRUE(event.reuse_detected().status().enabled());
+
+  // Case 2: safe_browsing_enabled = false
+  profile()->GetPrefs()->SetBoolean(prefs::kSafeBrowsingEnabled, false);
+  service_->MaybeLogPasswordReuseDetectedEvent(web_contents());
+  ASSERT_EQ(2ul, GetUserEventService()->GetRecordedUserEvents().size());
+  event = GetUserEventService()
+              ->GetRecordedUserEvents()[1]
+              .sync_password_reuse_event();
+  EXPECT_FALSE(event.reuse_detected().status().enabled());
+
+  // Not checking for the extended_reporting_level since that requires setting
+  // multiple prefs and doesn't add much verification value.
+}
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/sandboxed_zip_analyzer_unittest.cc b/chrome/browser/safe_browsing/sandboxed_zip_analyzer_unittest.cc
index 4b4cbe4e..a1a6f98e 100644
--- a/chrome/browser/safe_browsing/sandboxed_zip_analyzer_unittest.cc
+++ b/chrome/browser/safe_browsing/sandboxed_zip_analyzer_unittest.cc
@@ -12,14 +12,24 @@
 #include "base/macros.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
+#include "base/test/histogram_tester.h"
 #include "build/build_config.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "crypto/sha2.h"
+#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_MACOSX)
+namespace {
+
+const char kAppInZipHistogramName[] =
+    "SBClientDownload.ZipFileContainsAppDirectory";
+}
+#endif  // OS_MACOSX
+
 namespace safe_browsing {
 
 class SandboxedZipAnalyzerTest : public ::testing::Test {
@@ -351,11 +361,18 @@
 
 #if defined(OS_MACOSX)
 TEST_F(SandboxedZipAnalyzerTest, ZippedAppWithUnsignedAndSignedExecutable) {
+  base::HistogramTester histograms;
+  histograms.ExpectTotalCount(kAppInZipHistogramName, 0);
+
   ArchiveAnalyzerResults results;
   RunAnalyzer(dir_test_data_.AppendASCII(
                   "mach_o/zipped-app-two-executables-one-signed.zip"),
               &results);
-  ASSERT_TRUE(results.success);
+
+  EXPECT_THAT(histograms.GetAllSamples(kAppInZipHistogramName),
+              testing::ElementsAre(base::Bucket(/*bucket=*/true, /*count=*/1)));
+
+  EXPECT_TRUE(results.success);
   EXPECT_TRUE(results.has_executable);
   EXPECT_FALSE(results.has_archive);
   ASSERT_EQ(2, results.archived_binary.size());
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index b7d83d3..d76ff2b 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -676,8 +676,8 @@
       "apps/chrome_app_window_client.h",
       "apps/directory_access_confirmation_dialog.cc",
       "apps/directory_access_confirmation_dialog.h",
-      "blocked_content/app_modal_dialog_helper.cc",
-      "blocked_content/app_modal_dialog_helper.h",
+      "blocked_content/popunder_preventer.cc",
+      "blocked_content/popunder_preventer.h",
       "bluetooth/bluetooth_chooser_controller.cc",
       "bluetooth/bluetooth_chooser_controller.h",
       "bluetooth/bluetooth_chooser_desktop.cc",
diff --git a/chrome/browser/ui/ash/ash_init.cc b/chrome/browser/ui/ash/ash_init.cc
index 8786dc4..692ea91 100644
--- a/chrome/browser/ui/ash/ash_init.cc
+++ b/chrome/browser/ui/ash/ash_init.cc
@@ -116,6 +116,10 @@
 
   ash::Shell* shell = ash::Shell::Get();
 
+  // Under mash the local state pref service isn't available until after shell
+  // initialization. Make classic ash behave the same way.
+  shell->SetLocalStatePrefService(g_browser_process->local_state());
+
   ash::AcceleratorControllerDelegateClassic* accelerator_controller_delegate =
       nullptr;
   if (chromeos::GetAshConfig() == ash::Config::CLASSIC) {
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.cc b/chrome/browser/ui/ash/chrome_shell_delegate.cc
index f3ab97f..af9d1a5 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.cc
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.cc
@@ -552,10 +552,6 @@
   return profile ? profile->GetPrefs() : nullptr;
 }
 
-PrefService* ChromeShellDelegate::GetLocalStatePrefService() const {
-  return g_browser_process->local_state();
-}
-
 bool ChromeShellDelegate::IsTouchscreenEnabledInPrefs(
     bool use_local_state) const {
   return chromeos::system::InputDeviceSettings::Get()
diff --git a/chrome/browser/ui/ash/chrome_shell_delegate.h b/chrome/browser/ui/ash/chrome_shell_delegate.h
index cd09deb..4cae06d 100644
--- a/chrome/browser/ui/ash/chrome_shell_delegate.h
+++ b/chrome/browser/ui/ash/chrome_shell_delegate.h
@@ -55,7 +55,6 @@
   void OpenKeyboardShortcutHelpPage() const override;
   gfx::Image GetDeprecatedAcceleratorImage() const override;
   PrefService* GetActiveUserPrefService() const override;
-  PrefService* GetLocalStatePrefService() const override;
   bool IsTouchscreenEnabledInPrefs(bool use_local_state) const override;
   void SetTouchscreenEnabledInPrefs(bool enabled,
                                     bool use_local_state) override;
diff --git a/chrome/browser/ui/blocked_content/app_modal_dialog_helper.h b/chrome/browser/ui/blocked_content/app_modal_dialog_helper.h
deleted file mode 100644
index c085d9f..0000000
--- a/chrome/browser/ui/blocked_content/app_modal_dialog_helper.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_BLOCKED_CONTENT_APP_MODAL_DIALOG_HELPER_H_
-#define CHROME_BROWSER_UI_BLOCKED_CONTENT_APP_MODAL_DIALOG_HELPER_H_
-
-#include "base/macros.h"
-#include "content/public/browser/web_contents_observer.h"
-
-// A helper for app modal dialogs that blocks creation of pop-unders.
-class AppModalDialogHelper : public content::WebContentsObserver {
- public:
-  explicit AppModalDialogHelper(content::WebContents* dialog_host);
-  ~AppModalDialogHelper() override;
-
- private:
-  // Overridden from WebContentsObserver:
-  void WebContentsDestroyed() override;
-
-  content::WebContents* popup_;
-
-  DISALLOW_COPY_AND_ASSIGN(AppModalDialogHelper);
-};
-
-#endif  // CHROME_BROWSER_UI_BLOCKED_CONTENT_APP_MODAL_DIALOG_HELPER_H_
diff --git a/chrome/browser/ui/blocked_content/app_modal_dialog_helper.cc b/chrome/browser/ui/blocked_content/popunder_preventer.cc
similarity index 85%
rename from chrome/browser/ui/blocked_content/app_modal_dialog_helper.cc
rename to chrome/browser/ui/blocked_content/popunder_preventer.cc
index 5bbf2888..7cc1b00 100644
--- a/chrome/browser/ui/blocked_content/app_modal_dialog_helper.cc
+++ b/chrome/browser/ui/blocked_content/popunder_preventer.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/ui/blocked_content/app_modal_dialog_helper.h"
+#include "chrome/browser/ui/blocked_content/popunder_preventer.h"
 
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_finder.h"
@@ -16,7 +16,7 @@
 #include "components/guest_view/browser/guest_view_base.h"
 #endif
 
-AppModalDialogHelper::AppModalDialogHelper(content::WebContents* dialog_host)
+PopunderPreventer::PopunderPreventer(content::WebContents* activating_contents)
     : popup_(nullptr) {
   // If a popup is the active window, and the WebContents that is going to be
   // activated is in the opener chain of that popup, then we suspect that
@@ -32,12 +32,12 @@
   if (!active_popup)
     return;
 
-  content::WebContents* actual_host = dialog_host;
+  content::WebContents* actual_host = activating_contents;
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   // If the dialog was triggered via an PDF, get the actual web contents that
   // embeds the PDF.
   guest_view::GuestViewBase* guest =
-      guest_view::GuestViewBase::FromWebContents(dialog_host);
+      guest_view::GuestViewBase::FromWebContents(activating_contents);
   if (guest)
     actual_host = guest->embedder_web_contents();
 #endif
@@ -59,7 +59,7 @@
   }
 }
 
-AppModalDialogHelper::~AppModalDialogHelper() {
+PopunderPreventer::~PopunderPreventer() {
   if (!popup_)
     return;
 
@@ -70,6 +70,6 @@
   delegate->ActivateContents(popup_);
 }
 
-void AppModalDialogHelper::WebContentsDestroyed() {
+void PopunderPreventer::WebContentsDestroyed() {
   popup_ = nullptr;
 }
diff --git a/chrome/browser/ui/blocked_content/popunder_preventer.h b/chrome/browser/ui/blocked_content/popunder_preventer.h
new file mode 100644
index 0000000..5d7a3fac
--- /dev/null
+++ b/chrome/browser/ui/blocked_content/popunder_preventer.h
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_BLOCKED_CONTENT_POPUNDER_PREVENTER_H_
+#define CHROME_BROWSER_UI_BLOCKED_CONTENT_POPUNDER_PREVENTER_H_
+
+#include "base/macros.h"
+#include "content/public/browser/web_contents_observer.h"
+
+// An object to block creation of pop-unders.
+//
+// This must be used whenever a window is activated. To use it, simply
+// create an instance of PopunderPreventer *before* a WebContents is activated,
+// and pass to the constructor the WebContents that is about to be activated.
+class PopunderPreventer : public content::WebContentsObserver {
+ public:
+  explicit PopunderPreventer(content::WebContents* activating_contents);
+  ~PopunderPreventer() override;
+
+ private:
+  // Overridden from WebContentsObserver:
+  void WebContentsDestroyed() override;
+
+  content::WebContents* popup_;
+
+  DISALLOW_COPY_AND_ASSIGN(PopunderPreventer);
+};
+
+#endif  // CHROME_BROWSER_UI_BLOCKED_CONTENT_POPUNDER_PREVENTER_H_
diff --git a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h
index f364484e..04a258a 100644
--- a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h
+++ b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.h
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "components/app_modal/native_app_modal_dialog.h"
 
-class AppModalDialogHelper;
+class PopunderPreventer;
 
 namespace app_modal {
 class JavaScriptAppModalDialog;
@@ -50,7 +50,7 @@
   NSAlert* GetAlert() const;
 
   std::unique_ptr<app_modal::JavaScriptAppModalDialog> dialog_;
-  std::unique_ptr<AppModalDialogHelper> popup_helper_;
+  std::unique_ptr<PopunderPreventer> popunder_preventer_;
 
   // Created in the constructor and destroyed in the destructor.
   base::scoped_nsobject<JavaScriptAppModalDialogHelper> helper_;
diff --git a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
index 0e56c98..5566c214 100644
--- a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
+++ b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
@@ -14,7 +14,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/sys_string_conversions.h"
 #import "chrome/browser/chrome_browser_application_mac.h"
-#include "chrome/browser/ui/blocked_content/app_modal_dialog_helper.h"
+#include "chrome/browser/ui/blocked_content/popunder_preventer.h"
 #include "chrome/browser/ui/javascript_dialogs/chrome_javascript_native_dialog_factory.h"
 #include "components/app_modal/javascript_app_modal_dialog.h"
 #include "components/app_modal/javascript_dialog_manager.h"
@@ -229,7 +229,7 @@
 JavaScriptAppModalDialogCocoa::JavaScriptAppModalDialogCocoa(
     app_modal::JavaScriptAppModalDialog* dialog)
     : dialog_(dialog),
-      popup_helper_(new AppModalDialogHelper(dialog->web_contents())),
+      popunder_preventer_(new PopunderPreventer(dialog->web_contents())),
       is_showing_(false) {
   // Determine the names of the dialog buttons based on the flags. "Default"
   // is the OK button. "Other" is the cancel button. We don't use the
diff --git a/chrome/browser/ui/extensions/extension_installed_notification.cc b/chrome/browser/ui/extensions/extension_installed_notification.cc
index e424177..ddc513d 100644
--- a/chrome/browser/ui/extensions/extension_installed_notification.cc
+++ b/chrome/browser/ui/extensions/extension_installed_notification.cc
@@ -12,13 +12,14 @@
 #include "chrome/browser/ui/extensions/app_launch_params.h"
 #include "chrome/browser/ui/extensions/application_launch.h"
 #include "chrome/grit/generated_resources.h"
-#include "chrome/grit/theme_resources.h"
+#include "components/vector_icons/vector_icons.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_urls.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/paint_vector_icon.h"
 
 namespace {
 const char* kNotifierId = "app.downloaded-notification";
@@ -46,10 +47,10 @@
       message_center::NOTIFICATION_TYPE_SIMPLE,
       base::UTF8ToUTF16(extension->name()),
       l10n_util::GetStringUTF16(IDS_EXTENSION_NOTIFICATION_INSTALLED),
-      ui::ResourceBundle::GetSharedInstance().GetImageNamed(
-          IDR_NOTIFICATION_EXTENSION_INSTALLED),
-      message_center::NotifierId(
-          message_center::NotifierId::SYSTEM_COMPONENT, kNotifierId),
+      gfx::Image(gfx::CreateVectorIcon(vector_icons::kCheckCircleIcon, 40,
+                                       gfx::kGoogleGreen700)),
+      message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT,
+                                 kNotifierId),
       base::string16() /* display_source */,
       GURL(extension_urls::kChromeWebstoreBaseURL) /* origin_url */,
       kNotificationId, optional_field, this));
diff --git a/chrome/browser/ui/javascript_dialogs/javascript_dialog.cc b/chrome/browser/ui/javascript_dialogs/javascript_dialog.cc
index 4151a826..340a124 100644
--- a/chrome/browser/ui/javascript_dialogs/javascript_dialog.cc
+++ b/chrome/browser/ui/javascript_dialogs/javascript_dialog.cc
@@ -4,13 +4,13 @@
 
 #include "chrome/browser/ui/javascript_dialogs/javascript_dialog.h"
 
-#include "chrome/browser/ui/blocked_content/app_modal_dialog_helper.h"
+#include "chrome/browser/ui/blocked_content/popunder_preventer.h"
 #include "chrome/browser/ui/javascript_dialogs/javascript_dialog_views.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_delegate.h"
 
 JavaScriptDialog::JavaScriptDialog(content::WebContents* parent_web_contents) {
-  dialog_helper_.reset(new AppModalDialogHelper(parent_web_contents));
+  popunder_preventer_.reset(new PopunderPreventer(parent_web_contents));
   parent_web_contents->GetDelegate()->ActivateContents(parent_web_contents);
 }
 
diff --git a/chrome/browser/ui/javascript_dialogs/javascript_dialog.h b/chrome/browser/ui/javascript_dialogs/javascript_dialog.h
index 684f550..53b5029 100644
--- a/chrome/browser/ui/javascript_dialogs/javascript_dialog.h
+++ b/chrome/browser/ui/javascript_dialogs/javascript_dialog.h
@@ -10,7 +10,7 @@
 #include "base/memory/weak_ptr.h"
 #include "content/public/browser/javascript_dialog_manager.h"
 
-class AppModalDialogHelper;
+class PopunderPreventer;
 
 class JavaScriptDialog {
  public:
@@ -39,7 +39,7 @@
   explicit JavaScriptDialog(content::WebContents* parent_web_contents);
 
  private:
-  std::unique_ptr<AppModalDialogHelper> dialog_helper_;
+  std::unique_ptr<PopunderPreventer> popunder_preventer_;
 };
 
 #endif  // CHROME_BROWSER_UI_JAVASCRIPT_DIALOGS_JAVASCRIPT_DIALOG_H_
diff --git a/chrome/browser/ui/javascript_dialogs/javascript_dialog_mac.cc b/chrome/browser/ui/javascript_dialogs/javascript_dialog_mac.cc
index 3865f91a..1bc3cf1 100644
--- a/chrome/browser/ui/javascript_dialogs/javascript_dialog_mac.cc
+++ b/chrome/browser/ui/javascript_dialogs/javascript_dialog_mac.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/javascript_dialogs/javascript_dialog.h"
 
-#include "chrome/browser/ui/blocked_content/app_modal_dialog_helper.h"
+#include "chrome/browser/ui/blocked_content/popunder_preventer.h"
 #include "chrome/browser/ui/javascript_dialogs/javascript_dialog_cocoa.h"
 #include "chrome/browser/ui/javascript_dialogs/javascript_dialog_views.h"
 #include "content/public/browser/web_contents.h"
@@ -12,7 +12,7 @@
 #include "ui/base/material_design/material_design_controller.h"
 
 JavaScriptDialog::JavaScriptDialog(content::WebContents* parent_web_contents) {
-  dialog_helper_.reset(new AppModalDialogHelper(parent_web_contents));
+  popunder_preventer_.reset(new PopunderPreventer(parent_web_contents));
   parent_web_contents->GetDelegate()->ActivateContents(parent_web_contents);
 }
 
diff --git a/chrome/browser/ui/login/login_handler.cc b/chrome/browser/ui/login/login_handler.cc
index 18081f4..813f99f 100644
--- a/chrome/browser/ui/login/login_handler.cc
+++ b/chrome/browser/ui/login/login_handler.cc
@@ -51,7 +51,7 @@
 #endif
 
 #if !defined(OS_ANDROID)
-#include "chrome/browser/ui/blocked_content/app_modal_dialog_helper.h"
+#include "chrome/browser/ui/blocked_content/popunder_preventer.h"
 #endif
 
 using autofill::PasswordForm;
@@ -338,7 +338,7 @@
 #if !defined(OS_ANDROID)
   WebContents* requesting_contents = GetWebContentsForLogin();
   if (requesting_contents)
-    dialog_helper_.reset(new AppModalDialogHelper(requesting_contents));
+    popunder_preventer_.reset(new PopunderPreventer(requesting_contents));
 #endif
 }
 
@@ -449,7 +449,7 @@
   if (interstitial_delegate_)
     interstitial_delegate_->Proceed();
 #if !defined(OS_ANDROID)
-  dialog_helper_.reset();
+  popunder_preventer_.reset();
 #endif
 }
 
diff --git a/chrome/browser/ui/login/login_handler.h b/chrome/browser/ui/login/login_handler.h
index 8d5973f9..4d3142c 100644
--- a/chrome/browser/ui/login/login_handler.h
+++ b/chrome/browser/ui/login/login_handler.h
@@ -17,9 +17,9 @@
 #include "content/public/browser/resource_dispatcher_host_login_delegate.h"
 #include "content/public/browser/resource_request_info.h"
 
-class AppModalDialogHelper;
 class GURL;
 class LoginInterstitialDelegate;
+class PopunderPreventer;
 
 namespace content {
 class NotificationRegistrar;
@@ -247,7 +247,7 @@
   base::WeakPtr<LoginInterstitialDelegate> interstitial_delegate_;
 
 #if !defined(OS_ANDROID)
-  std::unique_ptr<AppModalDialogHelper> dialog_helper_;
+  std::unique_ptr<PopunderPreventer> popunder_preventer_;
 #endif
 };
 
diff --git a/chrome/browser/ui/page_info/page_info_ui.cc b/chrome/browser/ui/page_info/page_info_ui.cc
index ac53c088..45f7ea7 100644
--- a/chrome/browser/ui/page_info/page_info_ui.cc
+++ b/chrome/browser/ui/page_info/page_info_ui.cc
@@ -305,7 +305,7 @@
       return use_blocked ? info.blocked_icon_id : info.allowed_icon_id;
   }
   NOTREACHED();
-  return IDR_INFO;
+  return 0;
 }
 
 // static
diff --git a/chrome/browser/ui/views/chrome_javascript_native_dialog_factory_views.cc b/chrome/browser/ui/views/chrome_javascript_native_dialog_factory_views.cc
index 39adfd8d..46b25f5f 100644
--- a/chrome/browser/ui/views/chrome_javascript_native_dialog_factory_views.cc
+++ b/chrome/browser/ui/views/chrome_javascript_native_dialog_factory_views.cc
@@ -16,7 +16,7 @@
 #if defined(USE_X11) && !defined(OS_CHROMEOS)
 #include "chrome/browser/ui/views/javascript_app_modal_dialog_views_x11.h"
 #else
-#include "chrome/browser/ui/blocked_content/app_modal_dialog_helper.h"
+#include "chrome/browser/ui/blocked_content/popunder_preventer.h"
 #include "components/app_modal/javascript_app_modal_dialog.h"
 #include "components/app_modal/views/javascript_app_modal_dialog_views.h"
 #endif
@@ -34,11 +34,11 @@
   explicit ChromeJavaScriptAppModalDialogViews(
       app_modal::JavaScriptAppModalDialog* parent)
       : app_modal::JavaScriptAppModalDialogViews(parent),
-        helper_(new AppModalDialogHelper(parent->web_contents())) {}
+        popunder_preventer_(new PopunderPreventer(parent->web_contents())) {}
   ~ChromeJavaScriptAppModalDialogViews() override {}
 
  private:
-  std::unique_ptr<AppModalDialogHelper> helper_;
+  std::unique_ptr<PopunderPreventer> popunder_preventer_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeJavaScriptAppModalDialogViews);
 };
diff --git a/chrome/browser/ui/views/collected_cookies_views.cc b/chrome/browser/ui/views/collected_cookies_views.cc
index 1f9e404..b45cd14 100644
--- a/chrome/browser/ui/views/collected_cookies_views.cc
+++ b/chrome/browser/ui/views/collected_cookies_views.cc
@@ -25,20 +25,21 @@
 #include "chrome/browser/ui/views/harmony/chrome_layout_provider.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
-#include "chrome/grit/theme_resources.h"
 #include "components/constrained_window/constrained_window_views.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/content_settings/core/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
+#include "components/vector_icons/vector_icons.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_source.h"
 #include "content/public/browser/web_contents.h"
 #include "net/cookies/canonical_cookie.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/paint_vector_icon.h"
 #include "ui/views/border.h"
 #include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/controls/image_view.h"
@@ -99,9 +100,9 @@
     content_->SetBorder(
         views::CreateSolidBorder(kInfobarBorderSize, border_color));
 
-    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
     info_image_ = new views::ImageView();
-    info_image_->SetImage(rb.GetImageSkiaNamed(IDR_INFO));
+    info_image_->SetImage(gfx::CreateVectorIcon(vector_icons::kInfoOutlineIcon,
+                                                16, gfx::kChromeIconGrey));
     label_ = new views::Label();
   }
   ~InfobarView() override {}
diff --git a/chrome/browser/ui/views/javascript_app_modal_dialog_views_x11.cc b/chrome/browser/ui/views/javascript_app_modal_dialog_views_x11.cc
index 3c447617..1f6beca 100644
--- a/chrome/browser/ui/views/javascript_app_modal_dialog_views_x11.cc
+++ b/chrome/browser/ui/views/javascript_app_modal_dialog_views_x11.cc
@@ -4,7 +4,7 @@
 
 #include "chrome/browser/ui/views/javascript_app_modal_dialog_views_x11.h"
 
-#include "chrome/browser/ui/blocked_content/app_modal_dialog_helper.h"
+#include "chrome/browser/ui/blocked_content/popunder_preventer.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/views/javascript_app_modal_event_blocker_x11.h"
 #include "components/app_modal/javascript_app_modal_dialog.h"
@@ -13,7 +13,7 @@
 JavaScriptAppModalDialogViewsX11::JavaScriptAppModalDialogViewsX11(
     app_modal::JavaScriptAppModalDialog* parent)
     : app_modal::JavaScriptAppModalDialogViews(parent),
-      helper_(new AppModalDialogHelper(parent->web_contents())) {
+      popunder_preventer_(new PopunderPreventer(parent->web_contents())) {
   chrome::RecordDialogCreation(
       chrome::DialogIdentifier::JAVA_SCRIPT_APP_MODAL_X11);
 }
diff --git a/chrome/browser/ui/views/javascript_app_modal_dialog_views_x11.h b/chrome/browser/ui/views/javascript_app_modal_dialog_views_x11.h
index 9dc99479..38da771 100644
--- a/chrome/browser/ui/views/javascript_app_modal_dialog_views_x11.h
+++ b/chrome/browser/ui/views/javascript_app_modal_dialog_views_x11.h
@@ -10,8 +10,8 @@
 #include "base/macros.h"
 #include "components/app_modal/views/javascript_app_modal_dialog_views.h"
 
-class AppModalDialogHelper;
 class JavascriptAppModalEventBlockerX11;
+class PopunderPreventer;
 
 // JavaScriptAppModalDialog implmentation for linux desktop.
 class JavaScriptAppModalDialogViewsX11
@@ -31,7 +31,7 @@
   // Blocks events to other browser windows while the dialog is open.
   std::unique_ptr<JavascriptAppModalEventBlockerX11> event_blocker_x11_;
 
-  std::unique_ptr<AppModalDialogHelper> helper_;
+  std::unique_ptr<PopunderPreventer> popunder_preventer_;
 
   DISALLOW_COPY_AND_ASSIGN(JavaScriptAppModalDialogViewsX11);
 };
diff --git a/chrome/browser/usb/web_usb_detector.cc b/chrome/browser/usb/web_usb_detector.cc
index b084af60..193d6e0 100644
--- a/chrome/browser/usb/web_usb_detector.cc
+++ b/chrome/browser/usb/web_usb_detector.cc
@@ -20,7 +20,7 @@
 #include "chrome/browser/ui/tab_contents/tab_contents_iterator.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/grit/generated_resources.h"
-#include "chrome/grit/theme_resources.h"
+#include "components/vector_icons/vector_icons.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/origin_util.h"
 #include "device/base/device_client.h"
@@ -29,9 +29,10 @@
 #include "device/usb/usb_ids.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/page_transition_types.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "ui/base/window_open_disposition.h"
+#include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/image.h"
+#include "ui/gfx/paint_vector_icon.h"
 #include "ui/message_center/message_center.h"
 #include "ui/message_center/notification.h"
 #include "ui/message_center/notification_delegate.h"
@@ -212,7 +213,6 @@
 
   std::string notification_id = device->guid();
 
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   message_center::RichNotificationData rich_notification_data;
   std::unique_ptr<message_center::Notification> notification(
       new message_center::Notification(
@@ -222,8 +222,9 @@
           l10n_util::GetStringFUTF16(
               IDS_WEBUSB_DEVICE_DETECTED_NOTIFICATION,
               base::UTF8ToUTF16(landing_page.GetContent())),
-          rb.GetNativeImageNamed(IDR_USB_NOTIFICATION_ICON), base::string16(),
-          GURL(),
+          gfx::Image(gfx::CreateVectorIcon(vector_icons::kUsbIcon, 64,
+                                           gfx::kChromeIconGrey)),
+          base::string16(), GURL(),
           message_center::NotifierId(
               message_center::NotifierId::SYSTEM_COMPONENT, kNotifierWebUsb),
           rich_notification_data,
diff --git a/chrome/common/safe_browsing/zip_analyzer.cc b/chrome/common/safe_browsing/zip_analyzer.cc
index 4c8707a..0d31d080 100644
--- a/chrome/common/safe_browsing/zip_analyzer.cc
+++ b/chrome/common/safe_browsing/zip_analyzer.cc
@@ -13,6 +13,7 @@
 #include "base/i18n/streaming_utf8_validator.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
 #include "chrome/common/safe_browsing/archive_analyzer_results.h"
 #include "chrome/common/safe_browsing/binary_feature_extractor.h"
@@ -127,6 +128,9 @@
   }
 
   bool advanced = true;
+#if defined(OS_MACOSX)
+  bool zip_has_app_directory = false;
+#endif  // OS_MACOSX
   for (; reader.HasMore(); advanced = reader.AdvanceToNextEntry()) {
     if (!advanced) {
       DVLOG(1) << "Could not advance to next entry, aborting zip scan.";
@@ -167,6 +171,7 @@
       // to fail.
       if (file.Extension().compare(".app") == 0) {
         DVLOG(2) << "Downloaded a zipped .app directory: " << file.value();
+        zip_has_app_directory = true;
       } else {
 #endif  // OS_MACOSX
         DVLOG(2) << "Downloaded a zipped executable: " << file.value();
@@ -180,6 +185,12 @@
       DVLOG(3) << "Ignoring non-binary file: " << file.value();
     }
   }
+#if defined(OS_MACOSX)
+  UMA_HISTOGRAM_BOOLEAN(
+      "SBClientDownload."
+      "ZipFileContainsAppDirectory",
+      zip_has_app_directory);
+#endif  // OS_MACOSX
   results->archived_archive_filenames.assign(archived_archive_filenames.begin(),
                                              archived_archive_filenames.end());
   results->success = true;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 7cf8adc..a28f42b9 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1998,6 +1998,7 @@
         "../browser/extensions/webstore_reinstaller_browsertest.cc",
         "../browser/extensions/webstore_startup_installer_browsertest.cc",
         "../browser/extensions/window_open_apitest.cc",
+        "../browser/safe_browsing/chrome_cleaner/chrome_cleaner_dialog_controller_impl_browsertest_win.cc",
         "../browser/safe_browsing/chrome_cleaner/settings_resetter_browsertest_win.cc",
         "../browser/safe_browsing/settings_reset_prompt/default_settings_fetcher_browsertest.cc",
         "../browser/safe_browsing/settings_reset_prompt/settings_reset_dependency_browsertest_win.cc",
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 0b9f30b2..2249fbd 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -75,6 +75,11 @@
 _VERSION_SPECIFIC_FILTER['HEAD'] = [
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1819
     'ChromeExtensionsCapabilityTest.testIFrameWithExtensionsSource',
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1918
+    'ChromeDriverTest.testWindowPosition',
+    'ChromeDriverTest.testWindowSize',
+    'ChromeLoggingCapabilityTest.testPerformanceLogger',
+    'MobileEmulationCapabilityTest.testDeviceMetricsWithStandardWidth',
 ]
 _VERSION_SPECIFIC_FILTER['61'] = [
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1819
diff --git a/chrome/test/chromedriver/test/test_expectations b/chrome/test/chromedriver/test/test_expectations
index abdc1fa..676754f 100644
--- a/chrome/test/chromedriver/test/test_expectations
+++ b/chrome/test/chromedriver/test/test_expectations
@@ -137,6 +137,16 @@
     'CombinedInputActionsTest.testMouseMovementWorksWhenNavigatingToAnotherPage',
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1138
     'AlertsTest.testSettingTheValueOfAnAlertThrows',
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1910
+    'AlertsTest.testPromptShouldUseDefaultValueIfNoKeysSent',
+    'UnexpectedAlertBehaviorTest.canAcceptUnhandledAlert',
+    'UnexpectedAlertBehaviorTest.canSpecifyUnhandledAlertBehaviourUsingCapabilities',
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=1918
+    'WindowTest.testGetsThePositionOfTheCurrentWindow',
+    'WindowTest.testGetsTheSizeOfTheCurrentWindow',
+    'WindowTest.testSetsThePositionOfTheCurrentWindow',
+    'WindowTest.testSetsTheSizeOfTheCurrentWindowFromIframe',
+    'WindowTest.testSetsTheSizeOfTheCurrentWindowFromFrame',
 ]
 
 _OS_NEGATIVE_FILTER = {}
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index 5a20726..2fdd0337 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -17,182 +17,148 @@
 /**
  * Basic test fixture for the MD chrome://extensions page. Installs no
  * extensions.
- * @constructor
- * @extends {PolymerTest}
  */
-function CrExtensionsBrowserTest() {}
-
-CrExtensionsBrowserTest.prototype = {
-  __proto__: PolymerTest.prototype,
+var CrExtensionsBrowserTest = class extends PolymerTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://extensions/';
+  }
 
   /** @override */
-  browsePreload: 'chrome://extensions/',
+  get commandLineSwitches() {
+    return [{
+      switchName: 'enable-features',
+      switchValue: 'MaterialDesignExtensions',
+    }];
+  }
 
   /** @override */
-  commandLineSwitches: [{
-    switchName: 'enable-features',
-    switchValue: 'MaterialDesignExtensions',
-  }],
+  get extraLibraries() {
+    return PolymerTest.getLibraries(ROOT_PATH).concat([
+      ROOT_PATH + 'ui/webui/resources/js/assert.js',
+      'extension_test_util.js',
+      '../mock_controller.js',
+      '../../../../../ui/webui/resources/js/promise_resolver.js',
+      '../../../../../ui/webui/resources/js/webui_resource_test.js',
+    ]);
+  }
 
   /** @override */
-  extraLibraries: PolymerTest.getLibraries(ROOT_PATH).concat([
-    ROOT_PATH + 'ui/webui/resources/js/assert.js',
-    'extension_test_util.js',
-    '../mock_controller.js',
-    '../../../../../ui/webui/resources/js/promise_resolver.js',
-    '../../../../../ui/webui/resources/js/webui_resource_test.js',
-  ]),
-
-  /** @override */
-  typedefCppFixture: 'ExtensionSettingsUIBrowserTest',
+  get typedefCppFixture() {
+    return 'ExtensionSettingsUIBrowserTest';
+  }
 };
 
 /**
  * Test fixture with one installed extension.
- * @constructor
- * @extends {CrExtensionsBrowserTest}
  */
-function CrExtensionsBrowserTestWithInstalledExtension() {}
-
-CrExtensionsBrowserTestWithInstalledExtension.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsBrowserTestWithInstalledExtension =
+    class extends CrExtensionsBrowserTest {
   /** @override */
-  testGenPreamble: function() {
+  testGenPreamble() {
     GEN('  InstallGoodExtension();');
     GEN('  SetAutoConfirmUninstall();');
-  },
+  }
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Sidebar Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsSidebarTest() {}
-
-CrExtensionsSidebarTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsSidebarTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_sidebar_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_sidebar_test.js',
+    ]);
+  }
 };
 
-TEST_F(
-    'CrExtensionsSidebarTest', 'ExtensionSidebarLayoutAndClickHandlersTest',
-    function() {
-      mocha
-          .grep(
-              assert(extension_sidebar_tests.TestNames.LayoutAndClickHandlers))
-          .run();
-    });
+TEST_F('CrExtensionsSidebarTest', 'LayoutAndClickHandlers', function() {
+  mocha.grep(assert(extension_sidebar_tests.TestNames.LayoutAndClickHandlers))
+      .run();
+});
 
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Toolbar Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsToolbarTest() {}
-
-CrExtensionsToolbarTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsToolbarTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_toolbar_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_toolbar_test.js',
+    ]);
+  }
 };
 
-TEST_F('CrExtensionsToolbarTest', 'ExtensionToolbarLayoutTest', function() {
+TEST_F('CrExtensionsToolbarTest', 'Layout', function() {
   mocha.grep(assert(extension_toolbar_tests.TestNames.Layout)).run();
 });
 
-TEST_F(
-    'CrExtensionsToolbarTest', 'ExtensionToolbarClickHandlersTest', function() {
-      mocha.grep(assert(extension_toolbar_tests.TestNames.ClickHandlers)).run();
-    });
+TEST_F('CrExtensionsToolbarTest', 'ClickHandlers', function() {
+  mocha.grep(assert(extension_toolbar_tests.TestNames.ClickHandlers)).run();
+});
 
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Item Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsItemsTest() {}
-
-CrExtensionsItemsTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsItemsTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_item_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_item_test.js',
+    ]);
+  }
 };
 
-TEST_F('CrExtensionsItemsTest', 'ExtensionItemNormalStateTest', function() {
+TEST_F('CrExtensionsItemsTest', 'NormalState', function() {
   var TestNames = extension_item_tests.TestNames;
   mocha.grep(assert(TestNames.ElementVisibilityNormalState)).run();
 });
 
-TEST_F('CrExtensionsItemsTest', 'ExtensionItemDeveloperStateTest', function() {
+TEST_F('CrExtensionsItemsTest', 'DeveloperState', function() {
   var TestNames = extension_item_tests.TestNames;
   mocha.grep(assert(TestNames.ElementVisibilityDeveloperState)).run();
 });
 
-TEST_F('CrExtensionsItemsTest', 'ExtensionItemClickableItemsTest', function() {
+TEST_F('CrExtensionsItemsTest', 'ClickableItems', function() {
   var TestNames = extension_item_tests.TestNames;
   mocha.grep(assert(TestNames.ClickableItems)).run();
 });
 
-TEST_F('CrExtensionsItemsTest', 'ExtensionItemWarningsTest', function() {
+TEST_F('CrExtensionsItemsTest', 'Warnings', function() {
   mocha.grep(assert(extension_item_tests.TestNames.Warnings)).run();
 });
 
-TEST_F('CrExtensionsItemsTest', 'ExtensionItemSourceIndicatorTest', function() {
+TEST_F('CrExtensionsItemsTest', 'SourceIndicator', function() {
   mocha.grep(assert(extension_item_tests.TestNames.SourceIndicator)).run();
 });
 
-TEST_F('CrExtensionsItemsTest', 'ExtensionItemEnableToggleTest', function() {
+TEST_F('CrExtensionsItemsTest', 'EnableToggle', function() {
   mocha.grep(assert(extension_item_tests.TestNames.EnableToggle)).run();
 });
 
-TEST_F('CrExtensionsItemsTest', 'ExtensionItemRemoveButtonTest', function() {
+TEST_F('CrExtensionsItemsTest', 'RemoveButton', function() {
   mocha.grep(assert(extension_item_tests.TestNames.RemoveButton)).run();
 });
 
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Detail View Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsDetailViewTest() {}
-
-CrExtensionsDetailViewTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsDetailViewTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_detail_view_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_detail_view_test.js',
+    ]);
+  }
 };
 
-TEST_F(
-    'CrExtensionsDetailViewTest', 'ExtensionDetailViewLayoutTest', function() {
-      mocha.grep(assert(extension_detail_view_tests.TestNames.Layout)).run();
-    });
+TEST_F('CrExtensionsDetailViewTest', 'Layout', function() {
+  mocha.grep(assert(extension_detail_view_tests.TestNames.Layout)).run();
+});
 
 TEST_F(
-    'CrExtensionsDetailViewTest', 'ExtensionDetailViewClickableElementsTest',
-    function() {
+    'CrExtensionsDetailViewTest', 'ClickableElements', function() {
       mocha
           .grep(assert(extension_detail_view_tests.TestNames.ClickableElements))
           .run();
@@ -201,246 +167,183 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Item List Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsItemListTest() {}
-
-CrExtensionsItemListTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsItemListTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_item_list_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_item_list_test.js',
+    ]);
+  }
 };
 
-TEST_F('CrExtensionsItemListTest', 'ExtensionItemList', function() {
-  mocha.grep(
-      assert(extension_item_list_tests.TestNames.ItemListFiltering)).run();
+TEST_F('CrExtensionsItemListTest', 'Filtering', function() {
+  mocha.grep(assert(extension_item_list_tests.TestNames.Filtering)).run();
 });
 
-TEST_F('CrExtensionsItemListTest', 'ExtensionItemListEmpty', function() {
-  mocha.grep(assert(extension_item_list_tests.TestNames.ItemListNoItemsMsg))
+TEST_F('CrExtensionsItemListTest', 'NoItems', function() {
+  mocha.grep(assert(extension_item_list_tests.TestNames.NoItemsMsg)).run();
+});
+
+TEST_F('CrExtensionsItemListTest', 'NoSearchResults', function() {
+  mocha.grep(assert(extension_item_list_tests.TestNames.NoSearchResultsMsg))
       .run();
 });
 
-TEST_F(
-    'CrExtensionsItemListTest', 'ExtensionItemListNoSearchResults', function() {
-      mocha
-          .grep(assert(
-              extension_item_list_tests.TestNames.ItemListNoSearchResultsMsg))
-          .run();
-    });
-
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Load Error Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsLoadErrorTest() {}
-
-CrExtensionsLoadErrorTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsLoadErrorTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_load_error_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_load_error_test.js',
+    ]);
+  }
 };
 
-TEST_F(
-    'CrExtensionsLoadErrorTest', 'ExtensionLoadErrorInteractionTest',
-    function() {
-      mocha.grep(assert(extension_load_error_tests.TestNames.Interaction))
-          .run();
-    });
+TEST_F('CrExtensionsLoadErrorTest', 'Interaction', function() {
+  mocha.grep(assert(extension_load_error_tests.TestNames.Interaction)).run();
+});
 
-TEST_F(
-    'CrExtensionsLoadErrorTest', 'ExtensionLoadErrorCodeSectionTest',
-    function() {
-      mocha.grep(assert(extension_load_error_tests.TestNames.CodeSection))
-          .run();
-    });
+TEST_F('CrExtensionsLoadErrorTest', 'CodeSection', function() {
+  mocha.grep(assert(extension_load_error_tests.TestNames.CodeSection)).run();
+});
 
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Service Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTestWithInstalledExtension}
- */
-function CrExtensionsServiceTest() {}
-
-CrExtensionsServiceTest.prototype = {
-  __proto__: CrExtensionsBrowserTestWithInstalledExtension.prototype,
-
+var CrExtensionsServiceTest =
+    class extends CrExtensionsBrowserTestWithInstalledExtension {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTestWithInstalledExtension.prototype
-                      .extraLibraries.concat([
-                        'extension_service_test.js',
-                      ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_service_test.js',
+    ]);
+  }
 };
 
-TEST_F(
-    'CrExtensionsServiceTest', 'ExtensionServiceToggleEnableTest', function() {
-      mocha.grep(assert(extension_service_tests.TestNames.EnableAndDisable))
-          .run();
-    });
+TEST_F('CrExtensionsServiceTest', 'ToggleEnable', function() {
+  mocha.grep(assert(extension_service_tests.TestNames.EnableAndDisable)).run();
+});
 
 TEST_F(
-    'CrExtensionsServiceTest', 'ExtensionServiceToggleIncognitoTest',
-    function() {
+    'CrExtensionsServiceTest', 'ToggleIncognito', function() {
       mocha.grep(assert(extension_service_tests.TestNames.ToggleIncognitoMode))
           .run();
     });
 
-TEST_F('CrExtensionsServiceTest', 'ExtensionServiceUninstallTest', function() {
+TEST_F('CrExtensionsServiceTest', 'Uninstall', function() {
   mocha.grep(assert(extension_service_tests.TestNames.Uninstall)).run();
 });
 
-TEST_F(
-    'CrExtensionsServiceTest', 'ExtensionServiceProfileSettingsTest',
-    function() {
-      mocha.grep(assert(extension_service_tests.TestNames.ProfileSettings))
-          .run();
-    });
+TEST_F('CrExtensionsServiceTest', 'ProfileSettings', function() {
+  mocha.grep(assert(extension_service_tests.TestNames.ProfileSettings)).run();
+});
 
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Manager Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsManagerTest() {}
-
-CrExtensionsManagerTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsManagerTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_manager_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_manager_test.js',
+    ]);
+  }
 };
 
-/**
- * Test fixture with multiple installed extensions of different types.
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsManagerTestWithMultipleExtensionTypesInstalled() {}
-
-CrExtensionsManagerTestWithMultipleExtensionTypesInstalled.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
+var CrExtensionsManagerTestWithMultipleExtensionTypesInstalled =
+    class extends CrExtensionsBrowserTest {
+  /** @override */
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_manager_test.js',
+    ]);
+  }
 
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_manager_test.js',
-  ]),
-
-  /** @override */
-  testGenPreamble: function() {
+  testGenPreamble() {
     GEN('  InstallGoodExtension();');
     GEN('  InstallPackagedApp();');
     GEN('  InstallHostedApp();');
     GEN('  InstallPlatformApp();');
-  },
+  }
 };
 
-/**
- * Test fixture that navigates to chrome://extensions/?id=<id>.
- * @constructor
- * @extends {CrExtensionsBrowserTestWithInstalledExtension}
- */
-function CrExtensionsManagerTestWithIdQueryParam() {}
-
-CrExtensionsManagerTestWithIdQueryParam.prototype = {
-  __proto__: CrExtensionsBrowserTestWithInstalledExtension.prototype,
+var CrExtensionsManagerTestWithIdQueryParam =
+    class extends CrExtensionsBrowserTestWithInstalledExtension {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://extensions/?id=ldnnhddmnhbkjipkidpdiheffobcpfmf';
+  }
 
   /** @override */
-  browsePreload: 'chrome://extensions/?id=ldnnhddmnhbkjipkidpdiheffobcpfmf',
-
-  /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_manager_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_manager_test.js',
+    ]);
+  }
 };
 
-TEST_F('CrExtensionsManagerTest', 'ExtensionManagerItemOrderTest', function() {
+TEST_F('CrExtensionsManagerTest', 'ItemOrder', function() {
   mocha.grep(assert(extension_manager_tests.TestNames.ItemOrder)).run();
 });
 
 TEST_F(
     'CrExtensionsManagerTestWithMultipleExtensionTypesInstalled',
-    'ExtensionManagerItemListVisibilityTest', function() {
+    'ItemListVisibility', function() {
       mocha.grep(assert(extension_manager_tests.TestNames.ItemListVisibility))
           .run();
     });
 
 TEST_F(
-    'CrExtensionsManagerTestWithMultipleExtensionTypesInstalled',
-    'ExtensionManagerShowItemsTest', function() {
+    'CrExtensionsManagerTestWithMultipleExtensionTypesInstalled', 'ShowItems',
+    function() {
       mocha.grep(assert(extension_manager_tests.TestNames.ShowItems)).run();
     });
 
 TEST_F(
-    'CrExtensionsManagerTestWithMultipleExtensionTypesInstalled',
-    'ExtensionManagerChangePagesTest', function() {
+    'CrExtensionsManagerTestWithMultipleExtensionTypesInstalled', 'ChangePages',
+    function() {
       mocha.grep(assert(extension_manager_tests.TestNames.ChangePages)).run();
     });
 
 TEST_F(
-    'CrExtensionsManagerTestWithIdQueryParam',
-    'ExtensionManagerNavigationToDetailsTest', function() {
+    'CrExtensionsManagerTestWithIdQueryParam', 'NavigationToDetails',
+    function() {
       mocha
           .grep(
               assert(extension_manager_tests.TestNames.UrlNavigationToDetails))
           .run();
     });
 
-TEST_F(
-    'CrExtensionsManagerTest', 'ExtensionManagerUpdateItemDataTest',
-    function() {
-      mocha.grep(assert(extension_manager_tests.TestNames.UpdateItemData))
-          .run();
-    });
+TEST_F('CrExtensionsManagerTest', 'UpdateItemData', function() {
+  mocha.grep(assert(extension_manager_tests.TestNames.UpdateItemData)).run();
+});
 
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Keyboard Shortcuts Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsShortcutTest() {}
-
-CrExtensionsShortcutTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsShortcutTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_keyboard_shortcuts_test.js',
-    'extension_shortcut_input_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_keyboard_shortcuts_test.js',
+      'extension_shortcut_input_test.js',
+    ]);
+  }
 };
 
-TEST_F(
-    'CrExtensionsShortcutTest', 'ExtensionKeyboardShortcutsLayoutTest',
-    function() {
-      mocha.grep(assert(extension_keyboard_shortcut_tests.TestNames.Layout))
-          .run();
-    });
+TEST_F('CrExtensionsShortcutTest', 'Layout', function() {
+  mocha.grep(assert(extension_keyboard_shortcut_tests.TestNames.Layout)).run();
+});
 
-TEST_F('CrExtensionsShortcutTest', 'ExtensionShortcutUtilTest', function() {
+TEST_F('CrExtensionsShortcutTest', 'Util', function() {
   mocha.grep(
       assert(extension_keyboard_shortcut_tests.TestNames.ShortcutUtil)).run();
 });
 
-TEST_F('CrExtensionsShortcutTest', 'ExtensionShortcutInputTest', function() {
+TEST_F('CrExtensionsShortcutTest', 'Basic', function() {
   mocha.grep(
       assert(extension_shortcut_input_tests.TestNames.Basic)).run();
 });
@@ -448,166 +351,116 @@
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Pack Dialog Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsPackDialogTest() {}
-
-CrExtensionsPackDialogTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsPackDialogTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_pack_dialog_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_pack_dialog_test.js',
+    ]);
+  }
 };
 
-TEST_F(
-    'CrExtensionsPackDialogTest', 'ExtensionPackDialogInteractionTest',
-    function() {
-      mocha.grep(assert(extension_pack_dialog_tests.TestNames.Interaction))
-          .run();
-    });
+TEST_F('CrExtensionsPackDialogTest', 'Interaction', function() {
+  mocha.grep(assert(extension_pack_dialog_tests.TestNames.Interaction)).run();
+});
 
-TEST_F(
-    'CrExtensionsPackDialogTest', 'ExtensionPackDialogPackSuccessTest',
-    function() {
-      mocha.grep(assert(extension_pack_dialog_tests.TestNames.PackSuccess))
-          .run();
-    });
+TEST_F('CrExtensionsPackDialogTest', 'PackSuccess', function() {
+  mocha.grep(assert(extension_pack_dialog_tests.TestNames.PackSuccess)).run();
+});
 
-TEST_F(
-    'CrExtensionsPackDialogTest', 'ExtensionPackDialogPackErrorTest',
-    function() {
-      mocha.grep(assert(extension_pack_dialog_tests.TestNames.PackError)).run();
-    });
+TEST_F('CrExtensionsPackDialogTest', 'PackError', function() {
+  mocha.grep(assert(extension_pack_dialog_tests.TestNames.PackError)).run();
+});
 
-TEST_F(
-    'CrExtensionsPackDialogTest', 'ExtensionPackDialogPackWarningTest',
-    function() {
-      mocha.grep(assert(extension_pack_dialog_tests.TestNames.PackWarning))
-          .run();
-    });
+TEST_F('CrExtensionsPackDialogTest', 'PackWarning', function() {
+  mocha.grep(assert(extension_pack_dialog_tests.TestNames.PackWarning)).run();
+});
 
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Options Dialog Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsOptionsDialogTest() {}
-
-CrExtensionsOptionsDialogTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsOptionsDialogTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_options_dialog_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_options_dialog_test.js',
+    ]);
+  }
 };
 
-TEST_F(
-    'CrExtensionsOptionsDialogTest', 'ExtensionOptionsDialogInteractionTest',
-    function() {
-      mocha.grep(assert(extension_options_dialog_tests.TestNames.Layout)).run();
-    });
+TEST_F('CrExtensionsOptionsDialogTest', 'Layout', function() {
+  mocha.grep(assert(extension_options_dialog_tests.TestNames.Layout)).run();
+});
 
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Error Page Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsErrorPageTest() {}
-
-CrExtensionsErrorPageTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsErrorPageTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_error_page_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_error_page_test.js',
+    ]);
+  }
 };
 
-TEST_F('CrExtensionsErrorPageTest', 'ExtensionErrorPageLayoutTest', function() {
+TEST_F('CrExtensionsErrorPageTest', 'Layout', function() {
   mocha.grep(assert(extension_error_page_tests.TestNames.Layout)).run();
 });
 
-TEST_F(
-    'CrExtensionsErrorPageTest', 'ExtensionErrorPageCodeSectionTest',
-    function() {
-      mocha.grep(assert(extension_error_page_tests.TestNames.CodeSection))
-          .run();
-    });
+TEST_F('CrExtensionsErrorPageTest', 'CodeSection', function() {
+  mocha.grep(assert(extension_error_page_tests.TestNames.CodeSection)).run();
+});
 
-TEST_F(
-    'CrExtensionsErrorPageTest', 'ExtensionErrorPageErrorSelectionTest',
-    function() {
-      mocha.grep(assert(extension_error_page_tests.TestNames.ErrorSelection))
-          .run();
-    });
+TEST_F('CrExtensionsErrorPageTest', 'ErrorSelection', function() {
+  mocha.grep(assert(extension_error_page_tests.TestNames.ErrorSelection)).run();
+});
 
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Code Section Tests
 
-/**
- * @constructor
- * @extends {CrExtensionsBrowserTest}
- */
-function CrExtensionsCodeSectionTest() {}
-
-CrExtensionsCodeSectionTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
-
+var CrExtensionsCodeSectionTest = class extends CrExtensionsBrowserTest {
   /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_code_section_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_code_section_test.js',
+    ]);
+  }
 };
 
-TEST_F(
-    'CrExtensionsCodeSectionTest', 'ExtensionCodeSectionLayoutTest',
-    function() {
-      mocha.grep(assert(extension_code_section_tests.TestNames.Layout)).run();
-    });
+TEST_F('CrExtensionsCodeSectionTest', 'Layout', function() {
+  mocha.grep(assert(extension_code_section_tests.TestNames.Layout)).run();
+});
 
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Navigation Helper Tests
 
-function CrExtensionsNavigationHelperBrowserTest() {}
-
-// extensions.NavigationHelper observes window.location. In order to test this
-// without the "real" NavigationHelper joining the party, we navigate to
-// navigation_helper.html directly.
-CrExtensionsNavigationHelperBrowserTest.prototype = {
-  __proto__: CrExtensionsBrowserTest.prototype,
+var CrExtensionsNavigationHelperTest = class extends CrExtensionsBrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://extensions/navigation_helper.html';
+  }
 
   /** @override */
-  browsePreload: 'chrome://extensions/navigation_helper.html',
-
-  /** @override */
-  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
-    'extension_navigation_helper_test.js',
-  ]),
+  get extraLibraries() {
+    return super.extraLibraries.concat([
+      'extension_navigation_helper_test.js',
+    ]);
+  }
 };
 
-TEST_F('CrExtensionsNavigationHelperBrowserTest',
-       'ExtensionNavigationHelperBasicTest', function() {
+TEST_F('CrExtensionsNavigationHelperTest', 'Basic', function() {
   mocha.grep(assert(extension_navigation_helper_tests.TestNames.Basic)).run();
 });
 
-TEST_F('CrExtensionsNavigationHelperBrowserTest',
-       'ExtensionNavigationHelperConversionTest', function() {
+TEST_F('CrExtensionsNavigationHelperTest', 'Conversion', function() {
   mocha.grep(
       assert(extension_navigation_helper_tests.TestNames.Conversions)).run();
 });
 
-TEST_F('CrExtensionsNavigationHelperBrowserTest',
-       'ExtensionNavigationHelperPushAndReplaceStateTest', function() {
-  mocha.grep(
-      assert(extension_navigation_helper_tests.TestNames.PushAndReplaceState))
-          .run();
+TEST_F('CrExtensionsNavigationHelperTest', 'PushAndReplaceState', function() {
+  mocha
+      .grep(assert(
+          extension_navigation_helper_tests.TestNames.PushAndReplaceState))
+      .run();
 });
diff --git a/chrome/test/data/webui/extensions/extension_item_list_test.js b/chrome/test/data/webui/extensions/extension_item_list_test.js
index 20d398e..124e511 100644
--- a/chrome/test/data/webui/extensions/extension_item_list_test.js
+++ b/chrome/test/data/webui/extensions/extension_item_list_test.js
@@ -6,9 +6,9 @@
 cr.define('extension_item_list_tests', function() {
   /** @enum {string} */
   var TestNames = {
-    ItemListFiltering: 'item list filtering',
-    ItemListNoItemsMsg: 'empty item list',
-    ItemListNoSearchResultsMsg: 'empty item list filtering results',
+    Filtering: 'item list filtering',
+    NoItemsMsg: 'empty item list',
+    NoSearchResultsMsg: 'empty item list filtering results',
   };
 
   suite('ExtensionItemListTest', function() {
@@ -37,7 +37,7 @@
       document.body.appendChild(itemList);
     });
 
-    test(assert(TestNames.ItemListFiltering), function() {
+    test(assert(TestNames.Filtering), function() {
       var ironList = itemList.$.list;
       assert(ironList);
 
@@ -66,7 +66,7 @@
       expectEquals(3, ironList.items.length);
     });
 
-    test(assert(TestNames.ItemListNoItemsMsg), function() {
+    test(assert(TestNames.NoItemsMsg), function() {
       testVisible('#no-items', false);
       testVisible('#no-search-results', false);
 
@@ -75,7 +75,7 @@
       testVisible('#no-search-results', false);
     });
 
-    test(assert(TestNames.ItemListNoSearchResultsMsg), function() {
+    test(assert(TestNames.NoSearchResultsMsg), function() {
       testVisible('#no-items', false);
       testVisible('#no-search-results', false);
 
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index 617934a..d135f25a 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -79,7 +79,8 @@
 
 #if defined(OS_ANDROID)
 #include "chromecast/app/android/crash_handler.h"
-#include "components/crash/content/browser/crash_dump_manager_android.h"
+#include "components/crash/content/browser/child_process_crash_observer_android.h"
+#include "components/crash/content/browser/crash_dump_observer_android.h"
 #include "net/android/network_change_notifier_factory_android.h"
 #else
 #include "chromecast/net/network_change_notifier_factory_cast.h"
@@ -409,16 +410,16 @@
 
 int CastBrowserMainParts::PreCreateThreads() {
 #if defined(OS_ANDROID)
-  // GPU process is started immediately after threads are created, requiring
-  // CrashDumpManager to be initialized beforehand.
+  // GPU process is started immediately after threads are created,
+  // requiring ChildProcessCrashObserver to be initialized beforehand.
   base::FilePath crash_dumps_dir;
   if (!chromecast::CrashHandler::GetCrashDumpLocation(&crash_dumps_dir)) {
     LOG(ERROR) << "Could not find crash dump location.";
   }
   breakpad::CrashDumpObserver::Create();
   breakpad::CrashDumpObserver::GetInstance()->RegisterClient(
-      base::MakeUnique<breakpad::CrashDumpManager>(crash_dumps_dir,
-                                                   kAndroidMinidumpDescriptor));
+      base::MakeUnique<breakpad::ChildProcessCrashObserver>(
+          crash_dumps_dir, kAndroidMinidumpDescriptor));
 #else
   base::FilePath home_dir;
   CHECK(PathService::Get(DIR_CAST_HOME, &home_dir));
diff --git a/chromecast/browser/cast_content_browser_client.cc b/chromecast/browser/cast_content_browser_client.cc
index fd24a27..f66d5f96 100644
--- a/chromecast/browser/cast_content_browser_client.cc
+++ b/chromecast/browser/cast_content_browser_client.cc
@@ -72,7 +72,7 @@
 
 #if defined(OS_ANDROID)
 #include "components/cdm/browser/cdm_message_filter_android.h"
-#include "components/crash/content/browser/crash_dump_manager_android.h"
+#include "components/crash/content/browser/crash_dump_observer_android.h"
 #else
 #include "chromecast/browser/memory_pressure_controller_impl.h"
 #endif  // defined(OS_ANDROID)
diff --git a/components/autofill/content/browser/content_autofill_driver.cc b/components/autofill/content/browser/content_autofill_driver.cc
index 0d37b7c..f4e1ece 100644
--- a/components/autofill/content/browser/content_autofill_driver.cc
+++ b/components/autofill/content/browser/content_autofill_driver.cc
@@ -247,12 +247,12 @@
   autofill_handler_->OnSetDataList(values, labels);
 }
 
-void ContentAutofillDriver::DidNavigateFrame(
+void ContentAutofillDriver::DidNavigateMainFrame(
     content::NavigationHandle* navigation_handle) {
-  if (navigation_handle->IsInMainFrame() &&
-      !navigation_handle->IsSameDocument()) {
-    autofill_handler_->Reset();
-  }
+  if (navigation_handle->IsSameDocument())
+    return;
+
+  autofill_handler_->Reset();
 }
 
 void ContentAutofillDriver::SetAutofillManager(
diff --git a/components/autofill/content/browser/content_autofill_driver.h b/components/autofill/content/browser/content_autofill_driver.h
index f3592367..61684b5 100644
--- a/components/autofill/content/browser/content_autofill_driver.h
+++ b/components/autofill/content/browser/content_autofill_driver.h
@@ -96,8 +96,9 @@
   void SetDataList(const std::vector<base::string16>& values,
                    const std::vector<base::string16>& labels) override;
 
-  // Called when the frame has navigated.
-  void DidNavigateFrame(content::NavigationHandle* navigation_handle);
+  // Called when the main frame has navigated. Explicitely will not trigger for
+  // subframe navigations. See navigation_handle.h for details.
+  void DidNavigateMainFrame(content::NavigationHandle* navigation_handle);
 
   AutofillExternalDelegate* autofill_external_delegate() {
     return autofill_external_delegate_.get();
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc
index e3d822a1..b643b62 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -134,12 +134,18 @@
 
 void ContentAutofillDriverFactory::DidFinishNavigation(
     content::NavigationHandle* navigation_handle) {
-  if (!navigation_handle->HasCommitted())
+  // For the purposes of this code, a navigation is not important if it has not
+  // committed yet or if it's in a subframe.
+  if (!navigation_handle->HasCommitted() ||
+      !navigation_handle->IsInMainFrame()) {
     return;
+  }
 
+  // A main frame navigation has occured. We suppress the autofill popup and
+  // tell the autofill driver.
   NavigationFinished();
   DriverForFrame(navigation_handle->GetRenderFrameHost())
-      ->DidNavigateFrame(navigation_handle);
+      ->DidNavigateMainFrame(navigation_handle);
 }
 
 void ContentAutofillDriverFactory::WasHidden() {
diff --git a/components/autofill/content/browser/content_autofill_driver_unittest.cc b/components/autofill/content/browser/content_autofill_driver_unittest.cc
index 3ae21b4..d12dd886 100644
--- a/components/autofill/content/browser/content_autofill_driver_unittest.cc
+++ b/components/autofill/content/browser/content_autofill_driver_unittest.cc
@@ -29,6 +29,7 @@
 #include "content/public/common/frame_navigate_params.h"
 #include "content/public/test/test_renderer_host.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "net/base/net_errors.h"
 #include "services/service_manager/public/cpp/interface_provider.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -264,7 +265,7 @@
     return static_cast<MockAutofillManager*>(autofill_manager());
   }
 
-  using ContentAutofillDriver::DidNavigateFrame;
+  using ContentAutofillDriver::DidNavigateMainFrame;
 };
 
 class ContentAutofillDriverTest : public content::RenderViewHostTestHarness {
@@ -294,16 +295,11 @@
     content::RenderViewHostTestHarness::TearDown();
   }
 
-  void Navigate(bool main_frame) {
-    content::RenderFrameHost* rfh = main_rfh();
-    content::RenderFrameHostTester* rfh_tester =
-        content::RenderFrameHostTester::For(rfh);
-    if (!main_frame)
-      rfh = rfh_tester->AppendChild("subframe");
+  void Navigate(bool same_document) {
     std::unique_ptr<content::NavigationHandle> navigation_handle =
         content::NavigationHandle::CreateNavigationHandleForTesting(
-            GURL(), rfh, true);
-   driver_->DidNavigateFrame(navigation_handle.get());
+            GURL(), main_rfh(), /*committed=*/true, net::OK, same_document);
+    driver_->DidNavigateMainFrame(navigation_handle.get());
   }
 
  protected:
@@ -322,14 +318,14 @@
   EXPECT_EQ(request_context, expected_request_context);
 }
 
-TEST_F(ContentAutofillDriverTest, NavigatedToDifferentPage) {
+TEST_F(ContentAutofillDriverTest, NavigatedMainFrameDifferentDocument) {
   EXPECT_CALL(*driver_->mock_autofill_manager(), Reset());
-  Navigate(true);
+  Navigate(/*same_document=*/false);
 }
 
-TEST_F(ContentAutofillDriverTest, NavigatedWithinSamePage) {
+TEST_F(ContentAutofillDriverTest, NavigatedMainFrameSameDocument) {
   EXPECT_CALL(*driver_->mock_autofill_manager(), Reset()).Times(0);
-  Navigate(false);
+  Navigate(/*same_document=*/true);
 }
 
 TEST_F(ContentAutofillDriverTest, FormDataSentToRenderer_FillForm) {
diff --git a/components/autofill/core/browser/autofill_driver_factory.h b/components/autofill/core/browser/autofill_driver_factory.h
index f5e21c6..cfb7d05b 100644
--- a/components/autofill/core/browser/autofill_driver_factory.h
+++ b/components/autofill/core/browser/autofill_driver_factory.h
@@ -28,7 +28,7 @@
   // null if there is none.
   AutofillDriver* DriverForKey(void* key);
 
-  // Handles finished navigation in any of the frames.
+  // Handles finished navigation in the main frame.
   void NavigationFinished();
 
   // Handles hiding of the corresponding tab.
diff --git a/components/browser_watcher/stability_paths.cc b/components/browser_watcher/stability_paths.cc
index 0bd5a4ac..70dc55ea 100644
--- a/components/browser_watcher/stability_paths.cc
+++ b/components/browser_watcher/stability_paths.cc
@@ -72,7 +72,8 @@
   int64_t creation_time_us =
       creation_time.tv_sec * kMicrosecondsPerSecond + creation_time.tv_usec;
 
-  std::string file_name = base::StringPrintf("%lu-%lld", pid, creation_time_us);
+  std::string file_name =
+      base::StringPrintf("%" CrPRIdPid "-%lld", pid, creation_time_us);
   return stability_dir.AppendASCII(file_name).AddExtension(
       base::PersistentMemoryAllocator::kFileExtension);
 }
diff --git a/components/content_settings/core/browser/content_settings_default_provider.cc b/components/content_settings/core/browser/content_settings_default_provider.cc
index d0cb24cc..8636b48b 100644
--- a/components/content_settings/core/browser/content_settings_default_provider.cc
+++ b/components/content_settings/core/browser/content_settings_default_provider.cc
@@ -382,6 +382,14 @@
   prefs_->ClearPref(kObsoleteFullscreenDefaultPref);
 #if !defined(OS_ANDROID)
   prefs_->ClearPref(kObsoleteMouseLockDefaultPref);
+
+  // ALLOW-by-default is an obsolete pref value for plugins (Flash). Erase that
+  // pref and fall back to the default behavior - but preserve other values.
+  const std::string& plugins_pref = GetPrefName(CONTENT_SETTINGS_TYPE_PLUGINS);
+  if (IntToContentSetting(prefs_->GetInteger(plugins_pref)) ==
+      ContentSetting::CONTENT_SETTING_ALLOW) {
+    prefs_->ClearPref(plugins_pref);
+  }
 #endif  // !defined(OS_ANDROID)
 #endif  // !defined(OS_IOS)
 }
diff --git a/components/crash/content/browser/BUILD.gn b/components/crash/content/browser/BUILD.gn
index 31fb1d1a..94e18cb 100644
--- a/components/crash/content/browser/BUILD.gn
+++ b/components/crash/content/browser/BUILD.gn
@@ -8,6 +8,8 @@
 
 source_set("browser") {
   sources = [
+    "child_process_crash_observer_android.cc",
+    "child_process_crash_observer_android.h",
     "crash_dump_manager_android.cc",
     "crash_dump_manager_android.h",
     "crash_dump_observer_android.cc",
diff --git a/components/crash/content/browser/child_process_crash_observer_android.cc b/components/crash/content/browser/child_process_crash_observer_android.cc
new file mode 100644
index 0000000..b9ae22bb
--- /dev/null
+++ b/components/crash/content/browser/child_process_crash_observer_android.cc
@@ -0,0 +1,52 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/crash/content/browser/child_process_crash_observer_android.h"
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "components/crash/content/app/breakpad_linux.h"
+#include "components/crash/content/browser/crash_dump_manager_android.h"
+
+namespace breakpad {
+
+ChildProcessCrashObserver::ChildProcessCrashObserver(
+    const base::FilePath crash_dump_dir,
+    int descriptor_id)
+    : crash_dump_dir_(crash_dump_dir), descriptor_id_(descriptor_id) {}
+
+ChildProcessCrashObserver::~ChildProcessCrashObserver() {}
+
+void ChildProcessCrashObserver::OnChildStart(
+    int child_process_id,
+    content::PosixFileDescriptorInfo* mappings) {
+  if (!breakpad::IsCrashReporterEnabled())
+    return;
+
+  base::ScopedFD file(
+      CrashDumpManager::GetInstance()->CreateMinidumpFileForChild(
+          child_process_id));
+  if (file.is_valid())
+    mappings->Transfer(descriptor_id_, std::move(file));
+}
+
+void ChildProcessCrashObserver::OnChildExit(
+    int child_process_id,
+    base::ProcessHandle pid,
+    content::ProcessType process_type,
+    base::TerminationStatus termination_status,
+    base::android::ApplicationState app_state) {
+  // This might be called twice for a given child process, with a
+  // NOTIFICATION_RENDERER_PROCESS_TERMINATED and then with
+  // NOTIFICATION_RENDERER_PROCESS_CLOSED.
+  base::PostTaskWithTraits(
+      FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
+      base::Bind(&CrashDumpManager::ProcessMinidumpFileFromChild,
+                 base::Unretained(CrashDumpManager::GetInstance()),
+                 crash_dump_dir_, pid, process_type, termination_status,
+                 app_state));
+}
+
+}  // namespace breakpad
diff --git a/components/crash/content/browser/child_process_crash_observer_android.h b/components/crash/content/browser/child_process_crash_observer_android.h
new file mode 100644
index 0000000..fad32f2
--- /dev/null
+++ b/components/crash/content/browser/child_process_crash_observer_android.h
@@ -0,0 +1,39 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_CRASH_CONTENT_BROWSER_CHILD_PROCESS_CRASH_OBSERVER_ANDROID_H_
+#define COMPONENTS_CRASH_CONTENT_BROWSER_CHILD_PROCESS_CRASH_OBSERVER_ANDROID_H_
+
+#include "base/files/file_path.h"
+#include "components/crash/content/browser/crash_dump_observer_android.h"
+
+namespace breakpad {
+
+class ChildProcessCrashObserver : public breakpad::CrashDumpObserver::Client {
+ public:
+  ChildProcessCrashObserver(const base::FilePath crash_dump_dir,
+                            int descriptor_id);
+  ~ChildProcessCrashObserver() override;
+
+  // breakpad::CrashDumpObserver::Client implementation:
+  void OnChildStart(int child_process_id,
+                    content::PosixFileDescriptorInfo* mappings) override;
+  void OnChildExit(int child_process_id,
+                   base::ProcessHandle pid,
+                   content::ProcessType process_type,
+                   base::TerminationStatus termination_status,
+                   base::android::ApplicationState app_state) override;
+
+ private:
+  base::FilePath crash_dump_dir_;
+  // The id used to identify the file descriptor in the set of file
+  // descriptor mappings passed to the child process.
+  int descriptor_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChildProcessCrashObserver);
+};
+
+}  // namespace breakpad
+
+#endif  // COMPONENTS_CRASH_CONTENT_BROWSER_CHILD_PROCESS_CRASH_OBSERVER_ANDROID_H_
diff --git a/components/crash/content/browser/crash_dump_manager_android.cc b/components/crash/content/browser/crash_dump_manager_android.cc
index 24a00b4..d7cadd74 100644
--- a/components/crash/content/browser/crash_dump_manager_android.cc
+++ b/components/crash/content/browser/crash_dump_manager_android.cc
@@ -11,41 +11,39 @@
 #include "base/bind.h"
 #include "base/files/file_util.h"
 #include "base/format_macros.h"
+#include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/posix/global_descriptors.h"
 #include "base/process/process.h"
 #include "base/rand_util.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
-#include "base/task_scheduler/post_task.h"
 #include "components/crash/content/app/breakpad_linux.h"
-#include "content/public/browser/child_process_data.h"
-#include "content/public/browser/notification_service.h"
-#include "content/public/browser/notification_types.h"
-#include "content/public/browser/posix_file_descriptor_info.h"
-#include "content/public/browser/render_process_host.h"
 #include "jni/CrashDumpManager_jni.h"
 
 namespace breakpad {
 
-CrashDumpManager::CrashDumpManager(const base::FilePath& crash_dump_dir,
-                                   int descriptor_id)
-    : crash_dump_dir_(crash_dump_dir), descriptor_id_(descriptor_id) {}
-
-CrashDumpManager::~CrashDumpManager() {
+namespace {
+base::LazyInstance<CrashDumpManager>::Leaky g_instance =
+    LAZY_INSTANCE_INITIALIZER;
 }
 
-void CrashDumpManager::OnChildStart(
-    int child_process_id,
-    content::PosixFileDescriptorInfo* mappings) {
-  if (!breakpad::IsCrashReporterEnabled())
-    return;
+// static
+CrashDumpManager* CrashDumpManager::GetInstance() {
+  return g_instance.Pointer();
+}
 
+CrashDumpManager::CrashDumpManager() {}
+
+CrashDumpManager::~CrashDumpManager() {}
+
+base::ScopedFD CrashDumpManager::CreateMinidumpFileForChild(
+    int child_process_id) {
+  base::ThreadRestrictions::AssertIOAllowed();
   base::FilePath minidump_path;
   if (!base::CreateTemporaryFile(&minidump_path)) {
     LOG(ERROR) << "Failed to create temporary file, crash won't be reported.";
-    return;
+    return base::ScopedFD();
   }
 
   // We need read permission as the minidump is generated in several phases
@@ -55,27 +53,26 @@
   base::File minidump_file(minidump_path, flags);
   if (!minidump_file.IsValid()) {
     LOG(ERROR) << "Failed to open temporary file, crash won't be reported.";
-    return;
+    return base::ScopedFD();
   }
 
-  {
-    base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_);
-    DCHECK(!base::ContainsKey(child_process_id_to_minidump_path_,
-                              child_process_id));
-    child_process_id_to_minidump_path_[child_process_id] = minidump_path;
-  }
-  mappings->Transfer(descriptor_id_,
-                     base::ScopedFD(minidump_file.TakePlatformFile()));
+  SetMinidumpPath(child_process_id, minidump_path);
+  return base::ScopedFD(minidump_file.TakePlatformFile());
 }
 
-// static
-void CrashDumpManager::ProcessMinidump(
-    const base::FilePath& minidump_path,
-    const base::FilePath& crash_dump_dir,
+void CrashDumpManager::ProcessMinidumpFileFromChild(
+    base::FilePath crash_dump_dir,
     base::ProcessHandle pid,
     content::ProcessType process_type,
     base::TerminationStatus termination_status,
     base::android::ApplicationState app_state) {
+  base::ThreadRestrictions::AssertIOAllowed();
+  base::FilePath minidump_path;
+  // If the minidump for a given child process has already been
+  // processed, then there is no more work to do.
+  if (!GetMinidumpPath(pid, &minidump_path))
+    return;
+
   int64_t file_size = 0;
   int r = base::GetFileSize(minidump_path, &file_size);
   DCHECK(r) << "Failed to retrieve size for minidump "
@@ -163,29 +160,25 @@
   Java_CrashDumpManager_tryToUploadMinidump(env, j_dest_path);
 }
 
-void CrashDumpManager::OnChildExit(int child_process_id,
-                                   base::ProcessHandle pid,
-                                   content::ProcessType process_type,
-                                   base::TerminationStatus termination_status,
-                                   base::android::ApplicationState app_state) {
-  base::FilePath minidump_path;
-  {
-    base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_);
-    ChildProcessIDToMinidumpPath::iterator iter =
-        child_process_id_to_minidump_path_.find(child_process_id);
-    if (iter == child_process_id_to_minidump_path_.end()) {
-      // We might get a NOTIFICATION_RENDERER_PROCESS_TERMINATED and a
-      // NOTIFICATION_RENDERER_PROCESS_CLOSED.
-      return;
-    }
-    minidump_path = iter->second;
-    child_process_id_to_minidump_path_.erase(iter);
+void CrashDumpManager::SetMinidumpPath(int child_process_id,
+                                       const base::FilePath& minidump_path) {
+  base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_);
+  DCHECK(
+      !base::ContainsKey(child_process_id_to_minidump_path_, child_process_id));
+  child_process_id_to_minidump_path_[child_process_id] = minidump_path;
+}
+
+bool CrashDumpManager::GetMinidumpPath(int child_process_id,
+                                       base::FilePath* minidump_path) {
+  base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_);
+  ChildProcessIDToMinidumpPath::iterator iter =
+      child_process_id_to_minidump_path_.find(child_process_id);
+  if (iter == child_process_id_to_minidump_path_.end()) {
+    return false;
   }
-  base::PostTaskWithTraits(
-      FROM_HERE, {base::MayBlock(), base::TaskPriority::BACKGROUND},
-      base::Bind(&CrashDumpManager::ProcessMinidump, minidump_path,
-                 crash_dump_dir_, pid, process_type, termination_status,
-                 app_state));
+  *minidump_path = iter->second;
+  child_process_id_to_minidump_path_.erase(iter);
+  return true;
 }
 
 }  // namespace breakpad
diff --git a/components/crash/content/browser/crash_dump_manager_android.h b/components/crash/content/browser/crash_dump_manager_android.h
index dde3f6e2..6aa58857 100644
--- a/components/crash/content/browser/crash_dump_manager_android.h
+++ b/components/crash/content/browser/crash_dump_manager_android.h
@@ -7,9 +7,13 @@
 
 #include <map>
 
+#include "base/android/application_status_listener.h"
 #include "base/files/file_path.h"
+#include "base/files/platform_file.h"
+#include "base/lazy_instance.h"
+#include "base/process/kill.h"
 #include "base/synchronization/lock.h"
-#include "components/crash/content/browser/crash_dump_observer_android.h"
+#include "content/public/common/process_type.h"
 
 namespace breakpad {
 
@@ -23,21 +27,24 @@
 // This class creates these file descriptors and associates them with render
 // processes and takes the appropriate action when the render process
 // terminates.
-class CrashDumpManager : public breakpad::CrashDumpObserver::Client {
+class CrashDumpManager {
  public:
-  CrashDumpManager(const base::FilePath& crash_dump_dir, int descriptor_id);
-  ~CrashDumpManager() override;
+  static CrashDumpManager* GetInstance();
 
-  // breakpad::CrashDumpObserver::Client implementation:
-  void OnChildStart(int child_process_id,
-                    content::PosixFileDescriptorInfo* mappings) override;
-  void OnChildExit(int child_process_id,
-                   base::ProcessHandle pid,
-                   content::ProcessType process_type,
-                   base::TerminationStatus termination_status,
-                   base::android::ApplicationState app_state) override;
+  void ProcessMinidumpFileFromChild(base::FilePath crash_dump_dir,
+                                    base::ProcessHandle pid,
+                                    content::ProcessType process_type,
+                                    base::TerminationStatus termination_status,
+                                    base::android::ApplicationState app_state);
+
+  base::ScopedFD CreateMinidumpFileForChild(int child_process_id);
 
  private:
+  friend struct base::LazyInstanceTraitsBase<CrashDumpManager>;
+
+  CrashDumpManager();
+  ~CrashDumpManager();
+
   typedef std::map<int, base::FilePath> ChildProcessIDToMinidumpPath;
 
   // This enum is used to back a UMA histogram, and must be treated as
@@ -52,25 +59,15 @@
     MINIDUMP_STATUS_COUNT
   };
 
-  static void ProcessMinidump(const base::FilePath& minidump_path,
-                              const base::FilePath& crash_dump_dir,
-                              base::ProcessHandle pid,
-                              content::ProcessType process_type,
-                              base::TerminationStatus termination_status,
-                              base::android::ApplicationState app_state);
+  void SetMinidumpPath(int child_process_id,
+                       const base::FilePath& minidump_path);
+  bool GetMinidumpPath(int child_process_id, base::FilePath* minidump_path);
 
   // This map should only be accessed with its lock aquired as it is accessed
   // from the PROCESS_LAUNCHER and UI threads.
   base::Lock child_process_id_to_minidump_path_lock_;
   ChildProcessIDToMinidumpPath child_process_id_to_minidump_path_;
 
-  // The directory in which temporary minidump files should be created.
-  base::FilePath crash_dump_dir_;
-
-  // The id used to identify the file descriptor in the set of file
-  // descriptor mappings passed to the child process.
-  int descriptor_id_;
-
   DISALLOW_COPY_AND_ASSIGN(CrashDumpManager);
 };
 
diff --git a/components/metrics/call_stack_profile_metrics_provider.cc b/components/metrics/call_stack_profile_metrics_provider.cc
index 3914b4c..a64816e8 100644
--- a/components/metrics/call_stack_profile_metrics_provider.cc
+++ b/components/metrics/call_stack_profile_metrics_provider.cc
@@ -508,9 +508,22 @@
   // calls base::FeatureList::IsEnabled() internally. While extremely unlikely,
   // it is possible that the profiler callback and therefore this function get
   // called before FeatureList initialization (e.g. if machine was suspended).
-  return base::FeatureList::GetInstance() != nullptr &&
-         base::GetFieldTrialParamByFeatureAsBool(kEnableReporting, "periodic",
-                                                 false);
+  //
+  // The result is cached in a static to avoid a shutdown hang calling into the
+  // API while FieldTrialList is being destroyed. See also the comment below in
+  // Init().
+  static const bool is_enabled = base::FeatureList::GetInstance() != nullptr &&
+                                 base::GetFieldTrialParamByFeatureAsBool(
+                                     kEnableReporting, "periodic", false);
+  return is_enabled;
+}
+
+void CallStackProfileMetricsProvider::Init() {
+  // IsPeriodicSamplingEnabled() caches the result in a local static, so that
+  // future calls will return it directly. Calling it in Init() will cache the
+  // result, which will ensure we won't call into FieldTrialList during
+  // shutdown which can hang if it's in the middle of being destroyed.
+  CallStackProfileMetricsProvider::IsPeriodicSamplingEnabled();
 }
 
 void CallStackProfileMetricsProvider::OnRecordingEnabled() {
diff --git a/components/metrics/call_stack_profile_metrics_provider.h b/components/metrics/call_stack_profile_metrics_provider.h
index a8178bd..d778ad34 100644
--- a/components/metrics/call_stack_profile_metrics_provider.h
+++ b/components/metrics/call_stack_profile_metrics_provider.h
@@ -71,6 +71,7 @@
   static bool IsPeriodicSamplingEnabled();
 
   // MetricsProvider:
+  void Init() override;
   void OnRecordingEnabled() override;
   void OnRecordingDisabled() override;
   void ProvideCurrentSessionData(
diff --git a/components/ntp_tiles/BUILD.gn b/components/ntp_tiles/BUILD.gn
index d970418..300d475 100644
--- a/components/ntp_tiles/BUILD.gn
+++ b/components/ntp_tiles/BUILD.gn
@@ -28,6 +28,7 @@
     "popular_sites_impl.h",
     "pref_names.cc",
     "pref_names.h",
+    "section_type.h",
     "switches.cc",
     "switches.h",
     "tile_source.h",
@@ -111,6 +112,7 @@
 if (is_android) {
   java_cpp_enum("ntp_tiles_enums_java") {
     sources = [
+      "section_type.h",
       "tile_source.h",
       "tile_visual_type.h",
     ]
diff --git a/components/ntp_tiles/constants.cc b/components/ntp_tiles/constants.cc
index d9085ac..4eaafbb5 100644
--- a/components/ntp_tiles/constants.cc
+++ b/components/ntp_tiles/constants.cc
@@ -21,6 +21,9 @@
 extern const base::Feature kLowerResolutionFaviconsFeature{
     "NTPTilesLowerResolutionFavicons", base::FEATURE_DISABLED_BY_DEFAULT};
 
+extern const base::Feature kSitesExplorationFeature{
+    "SitesExplorationFeature", base::FEATURE_DISABLED_BY_DEFAULT};
+
 bool AreNtpMostLikelyFaviconsFromServerEnabled() {
   // Check if the experimental flag is forced on or off.
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
diff --git a/components/ntp_tiles/constants.h b/components/ntp_tiles/constants.h
index 7afb9f07..e81cb0a 100644
--- a/components/ntp_tiles/constants.h
+++ b/components/ntp_tiles/constants.h
@@ -27,6 +27,9 @@
 // Tab Page.
 extern const base::Feature kLowerResolutionFaviconsFeature;
 
+// Feature to provide site exploration tiles in addition to personal tiles.
+extern const base::Feature kSitesExplorationFeature;
+
 // Use this to find out whether the kNtpMostLikelyFaviconsFromServerFeature is
 // enabled. This helper function abstracts iOS special way to override the
 // feature (via command-line params).
diff --git a/components/ntp_tiles/most_visited_sites.cc b/components/ntp_tiles/most_visited_sites.cc
index 464f2c1..b41a0993 100644
--- a/components/ntp_tiles/most_visited_sites.cc
+++ b/components/ntp_tiles/most_visited_sites.cc
@@ -361,7 +361,9 @@
   // Collect non-blacklisted popular suggestions, skipping those already present
   // in the personal suggestions.
   NTPTilesVector popular_sites_tiles;
-  for (const PopularSites::Site& popular_site : popular_sites_->sites()) {
+  const PopularSites::SitesVector& popular_sites =
+      popular_sites_->sections().at(SectionType::PERSONALIZED);
+  for (const PopularSites::Site& popular_site : popular_sites) {
     if (popular_sites_tiles.size() + num_actual_tiles >= num_sites_)
       break;
 
@@ -506,7 +508,9 @@
     return;
   }
 
-  for (const PopularSites::Site& popular_site : popular_sites_->sites()) {
+  const PopularSites::SitesVector& popular_sites =
+      popular_sites_->sections().at(SectionType::PERSONALIZED);
+  for (const PopularSites::Site& popular_site : popular_sites) {
     // Ignore callback; these icons will be seen on the *next* NTP.
     icon_cacher_->StartFetchPopularSites(popular_site, base::Closure(),
                                          base::Closure());
diff --git a/components/ntp_tiles/most_visited_sites_unittest.cc b/components/ntp_tiles/most_visited_sites_unittest.cc
index aae946e..5ba7f59 100644
--- a/components/ntp_tiles/most_visited_sites_unittest.cc
+++ b/components/ntp_tiles/most_visited_sites_unittest.cc
@@ -273,10 +273,10 @@
     PopularSitesImpl::RegisterProfilePrefs(pref_service->registry());
     if (enabled) {
       prefs_->SetString(prefs::kPopularSitesOverrideCountry, "IN");
-      prefs_->SetString(prefs::kPopularSitesOverrideVersion, "7");
+      prefs_->SetString(prefs::kPopularSitesOverrideVersion, "5");
 
       url_fetcher_factory_.SetFakeResponse(
-          GURL("https://www.gstatic.com/chrome/ntp/suggested_sites_IN_7.json"),
+          GURL("https://www.gstatic.com/chrome/ntp/suggested_sites_IN_5.json"),
           R"([{
                 "title": "PopularSite1",
                 "url": "http://popularsite1/",
diff --git a/components/ntp_tiles/popular_sites.h b/components/ntp_tiles/popular_sites.h
index f1e207f..407950a 100644
--- a/components/ntp_tiles/popular_sites.h
+++ b/components/ntp_tiles/popular_sites.h
@@ -5,12 +5,14 @@
 #ifndef COMPONENTS_NTP_TILES_POPULAR_SITES_H_
 #define COMPONENTS_NTP_TILES_POPULAR_SITES_H_
 
+#include <map>
 #include <string>
 #include <vector>
 
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "components/ntp_tiles/section_type.h"
 #include "url/gurl.h"
 
 namespace base {
@@ -60,8 +62,8 @@
   virtual bool MaybeStartFetch(bool force_download,
                                const FinishedCallback& callback) = 0;
 
-  // Returns the list of available sites.
-  virtual const SitesVector& sites() const = 0;
+  // Returns the cached list of available sections and their sites.
+  virtual const std::map<SectionType, SitesVector>& sections() const = 0;
 
   // Various internals exposed publicly for diagnostic pages only.
   virtual GURL GetLastURLFetched() const = 0;
diff --git a/components/ntp_tiles/popular_sites_impl.cc b/components/ntp_tiles/popular_sites_impl.cc
index 7abdc92..903c8bf 100644
--- a/components/ntp_tiles/popular_sites_impl.cc
+++ b/components/ntp_tiles/popular_sites_impl.cc
@@ -5,13 +5,16 @@
 #include "components/ntp_tiles/popular_sites_impl.h"
 
 #include <stddef.h>
+#include <map>
 #include <utility>
 
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "base/feature_list.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
@@ -53,12 +56,9 @@
 const char kPopularSitesDefaultDirectory[] = "chrome/ntp/";
 const char kPopularSitesDefaultCountryCode[] = "DEFAULT";
 const char kPopularSitesDefaultVersion[] = "5";
+const int kSitesExplorationStartVersion = 6;
 const int kPopularSitesRedownloadIntervalHours = 24;
 
-const char kPopularSitesLastDownloadPref[] = "popular_sites_last_download";
-const char kPopularSitesURLPref[] = "popular_sites_url";
-const char kPopularSitesJsonPref[] = "suggested_sites_json";
-
 GURL GetPopularSitesURL(const std::string& directory,
                         const std::string& country,
                         const std::string& version) {
@@ -132,6 +132,60 @@
   return sites;
 }
 
+std::map<SectionType, PopularSites::SitesVector> ParseVersion5(
+    const base::ListValue& list) {
+  return {{SectionType::PERSONALIZED, ParseSiteList(list)}};
+}
+
+std::map<SectionType, PopularSites::SitesVector> ParseVersion6OrAbove(
+    const base::ListValue& list) {
+  // Valid lists would have contained at least the PERSONALIZED section.
+  std::map<SectionType, PopularSites::SitesVector> sections = {
+      std::make_pair(SectionType::PERSONALIZED, PopularSites::SitesVector{})};
+  for (size_t i = 0; i < list.GetSize(); i++) {
+    const base::DictionaryValue* item;
+    if (!list.GetDictionary(i, &item)) {
+      LOG(WARNING) << "Parsed SitesExploration list contained an invalid "
+                   << "section at position " << i << ".";
+      continue;
+    }
+    int section;
+    if (!item->GetInteger("section", &section) || section < 0 ||
+        section > static_cast<int>(SectionType::LAST)) {
+      LOG(WARNING) << "Parsed SitesExploration list contained a section with "
+                   << "invalid ID (" << section << ")";
+      continue;
+    }
+    SectionType section_type = static_cast<SectionType>(section);
+    if (section_type == SectionType::UNKNOWN) {
+      LOG(WARNING) << "Dropped an unknown section in SitesExploration list.";
+      continue;
+    }
+    const base::ListValue* sites_list;
+    if (!item->GetList("sites", &sites_list)) {
+      continue;
+    }
+    sections[section_type] = ParseSiteList(*sites_list);
+  }
+  if (!base::FeatureList::IsEnabled(kSitesExplorationFeature)) {
+    // New versions of popular sites that should act like old versions will
+    // mimic having only the personalized list.
+    return {std::make_pair(SectionType::PERSONALIZED,
+                           std::move(sections[SectionType::PERSONALIZED]))};
+  }
+  return sections;
+}
+
+std::map<SectionType, PopularSites::SitesVector> ParseSites(
+    const base::ListValue& list,
+    int version) {
+  if (version >= kSitesExplorationStartVersion) {
+    return ParseVersion6OrAbove(list);
+  } else {
+    return ParseVersion5(list);
+  }
+}
+
 #if defined(GOOGLE_CHROME_BUILD) && (defined(OS_ANDROID) || defined(OS_IOS))
 void SetDefaultResourceForSite(int index,
                                int resource_id,
@@ -201,7 +255,9 @@
       download_context_(download_context),
       parse_json_(std::move(parse_json)),
       is_fallback_(false),
-      sites_(ParseSiteList(*prefs->GetList(kPopularSitesJsonPref))),
+      sections_(
+          ParseSites(*prefs->GetList(prefs::kPopularSitesJsonPref),
+                     prefs_->GetInteger(prefs::kPopularSitesVersionPref))),
       weak_ptr_factory_(this) {}
 
 PopularSitesImpl::~PopularSitesImpl() {}
@@ -212,7 +268,7 @@
   callback_ = callback;
 
   const base::Time last_download_time = base::Time::FromInternalValue(
-      prefs_->GetInt64(kPopularSitesLastDownloadPref));
+      prefs_->GetInt64(prefs::kPopularSitesLastDownloadPref));
   const base::TimeDelta time_since_last_download =
       base::Time::Now() - last_download_time;
   const base::TimeDelta redownload_interval =
@@ -221,7 +277,7 @@
 
   pending_url_ = GetURLToFetch();
   const bool url_changed =
-      pending_url_.spec() != prefs_->GetString(kPopularSitesURLPref);
+      pending_url_.spec() != prefs_->GetString(prefs::kPopularSitesURLPref);
 
   // Download forced, or we need to download a new file.
   if (force_download || download_time_is_future ||
@@ -232,18 +288,20 @@
   return false;
 }
 
-const PopularSites::SitesVector& PopularSitesImpl::sites() const {
-  return sites_;
+const std::map<SectionType, PopularSitesImpl::SitesVector>&
+PopularSitesImpl::sections() const {
+  return sections_;
 }
 
 GURL PopularSitesImpl::GetLastURLFetched() const {
-  return GURL(prefs_->GetString(kPopularSitesURLPref));
+  return GURL(prefs_->GetString(prefs::kPopularSitesURLPref));
 }
 
 GURL PopularSitesImpl::GetURLToFetch() {
   const std::string directory = GetDirectoryToFetch();
   const std::string country = GetCountryToFetch();
   const std::string version = GetVersionToFetch();
+  base::StringToInt(version, &version_in_pending_url_);
 
   const GURL override_url =
       GURL(prefs_->GetString(ntp_tiles::prefs::kPopularSitesOverrideURL));
@@ -311,7 +369,7 @@
 }
 
 const base::ListValue* PopularSitesImpl::GetCachedJson() {
-  return prefs_->GetList(kPopularSitesJsonPref);
+  return prefs_->GetList(prefs::kPopularSitesJsonPref);
 }
 
 // static
@@ -326,9 +384,13 @@
   user_prefs->RegisterStringPref(ntp_tiles::prefs::kPopularSitesOverrideVersion,
                                  std::string());
 
-  user_prefs->RegisterInt64Pref(kPopularSitesLastDownloadPref, 0);
-  user_prefs->RegisterStringPref(kPopularSitesURLPref, std::string());
-  user_prefs->RegisterListPref(kPopularSitesJsonPref, DefaultPopularSites());
+  user_prefs->RegisterInt64Pref(prefs::kPopularSitesLastDownloadPref, 0);
+  user_prefs->RegisterStringPref(prefs::kPopularSitesURLPref, std::string());
+  user_prefs->RegisterListPref(prefs::kPopularSitesJsonPref,
+                               DefaultPopularSites());
+  int version;
+  base::StringToInt(kPopularSitesDefaultVersion, &version);
+  user_prefs->RegisterIntegerPref(prefs::kPopularSitesVersionPref, version);
 }
 
 void PopularSitesImpl::FetchPopularSites() {
@@ -390,13 +452,13 @@
     OnDownloadFailed();
     return;
   }
-
-  prefs_->Set(kPopularSitesJsonPref, *list);
-  prefs_->SetInt64(kPopularSitesLastDownloadPref,
+  prefs_->Set(prefs::kPopularSitesJsonPref, *list);
+  prefs_->SetInt64(prefs::kPopularSitesLastDownloadPref,
                    base::Time::Now().ToInternalValue());
-  prefs_->SetString(kPopularSitesURLPref, pending_url_.spec());
+  prefs_->SetInteger(prefs::kPopularSitesVersionPref, version_in_pending_url_);
+  prefs_->SetString(prefs::kPopularSitesURLPref, pending_url_.spec());
 
-  sites_ = ParseSiteList(*list);
+  sections_ = ParseSites(*list, version_in_pending_url_);
   callback_.Run(true);
 }
 
diff --git a/components/ntp_tiles/popular_sites_impl.h b/components/ntp_tiles/popular_sites_impl.h
index 1162973..c58dbf35 100644
--- a/components/ntp_tiles/popular_sites_impl.h
+++ b/components/ntp_tiles/popular_sites_impl.h
@@ -5,6 +5,7 @@
 #ifndef COMPONENTS_NTP_TILES_POPULAR_SITES_IMPL_H_
 #define COMPONENTS_NTP_TILES_POPULAR_SITES_IMPL_H_
 
+#include <map>
 #include <memory>
 #include <string>
 #include <vector>
@@ -59,7 +60,7 @@
   // PopularSites implementation.
   bool MaybeStartFetch(bool force_download,
                        const FinishedCallback& callback) override;
-  const SitesVector& sites() const override;
+  const std::map<SectionType, SitesVector>& sections() const override;
   GURL GetLastURLFetched() const override;
   GURL GetURLToFetch() override;
   std::string GetDirectoryToFetch() override;
@@ -95,8 +96,9 @@
 
   std::unique_ptr<net::URLFetcher> fetcher_;
   bool is_fallback_;
-  SitesVector sites_;
+  std::map<SectionType, SitesVector> sections_;
   GURL pending_url_;
+  int version_in_pending_url_;
 
   base::WeakPtrFactory<PopularSitesImpl> weak_ptr_factory_;
 
diff --git a/components/ntp_tiles/popular_sites_impl_unittest.cc b/components/ntp_tiles/popular_sites_impl_unittest.cc
index d29217f2..27cd087 100644
--- a/components/ntp_tiles/popular_sites_impl_unittest.cc
+++ b/components/ntp_tiles/popular_sites_impl_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/optional.h"
 #include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/values.h"
@@ -33,9 +34,15 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using testing::_;
+using testing::Contains;
+using testing::ElementsAre;
 using testing::Eq;
 using testing::Gt;
 using testing::IsEmpty;
+using testing::Not;
+using testing::Pair;
+using testing::SizeIs;
 
 namespace ntp_tiles {
 namespace {
@@ -44,9 +51,13 @@
 const char kUrl[] = "url";
 const char kLargeIconUrl[] = "large_icon_url";
 const char kFaviconUrl[] = "favicon_url";
+const char kSection[] = "section";
+const char kSites[] = "sites";
 
 using TestPopularSite = std::map<std::string, std::string>;
 using TestPopularSiteVector = std::vector<TestPopularSite>;
+using TestPopularSection = std::pair<SectionType, TestPopularSiteVector>;
+using TestPopularSectionVector = std::vector<TestPopularSection>;
 
 ::testing::Matcher<const base::string16&> Str16Eq(const std::string& s) {
   return ::testing::Eq(base::UTF8ToUTF16(s));
@@ -95,18 +106,38 @@
     prefs_->SetString(prefs::kPopularSitesOverrideVersion, version);
   }
 
-  void RespondWithJSON(const std::string& url,
-                       const TestPopularSiteVector& sites) {
-    base::ListValue sites_value;
+  std::unique_ptr<base::ListValue> CreateListFromTestSites(
+      const TestPopularSiteVector& sites) {
+    auto sites_value = base::MakeUnique<base::ListValue>();
     for (const TestPopularSite& site : sites) {
       auto site_value = base::MakeUnique<base::DictionaryValue>();
       for (const std::pair<std::string, std::string>& kv : site) {
         site_value->SetString(kv.first, kv.second);
       }
-      sites_value.Append(std::move(site_value));
+      sites_value->Append(std::move(site_value));
+    }
+    return sites_value;
+  }
+
+  void RespondWithV5JSON(const std::string& url,
+                         const TestPopularSiteVector& sites) {
+    std::string sites_string;
+    base::JSONWriter::Write(*CreateListFromTestSites(sites), &sites_string);
+    url_fetcher_factory_.SetFakeResponse(GURL(url), sites_string, net::HTTP_OK,
+                                         net::URLRequestStatus::SUCCESS);
+  }
+
+  void RespondWithV6JSON(const std::string& url,
+                         const TestPopularSectionVector& sections) {
+    base::ListValue sections_value;
+    for (const TestPopularSection& section : sections) {
+      auto section_value = base::MakeUnique<base::DictionaryValue>();
+      section_value->SetInteger(kSection, static_cast<int>(section.first));
+      section_value->SetList(kSites, CreateListFromTestSites(section.second));
+      sections_value.Append(std::move(section_value));
     }
     std::string sites_string;
-    base::JSONWriter::Write(sites_value, &sites_string);
+    base::JSONWriter::Write(sections_value, &sites_string);
     url_fetcher_factory_.SetFakeResponse(GURL(url), sites_string, net::HTTP_OK,
                                          net::URLRequestStatus::SUCCESS);
   }
@@ -130,6 +161,18 @@
   // called at all, and if yes which was the returned bool value.
   base::Optional<bool> FetchPopularSites(bool force_download,
                                          PopularSites::SitesVector* sites) {
+    std::map<SectionType, PopularSites::SitesVector> sections;
+    base::Optional<bool> save_success =
+        FetchAllSections(force_download, &sections);
+    *sites = sections.at(SectionType::PERSONALIZED);
+    return save_success;
+  }
+
+  // Returns an optional bool representing whether the completion callback was
+  // called at all, and if yes which was the returned bool value.
+  base::Optional<bool> FetchAllSections(
+      bool force_download,
+      std::map<SectionType, PopularSites::SitesVector>* sections) {
     scoped_refptr<net::TestURLRequestContextGetter> url_request_context(
         new net::TestURLRequestContextGetter(
             base::ThreadTaskRunnerHandle::Get()));
@@ -148,7 +191,7 @@
                                 &save_success, &loop))) {
       loop.Run();
     }
-    *sites = popular_sites->sites();
+    *sections = popular_sites->sections();
     return save_success;
   }
 
@@ -176,8 +219,10 @@
           base::ThreadTaskRunnerHandle::Get()));
 
   auto popular_sites = CreatePopularSites(url_request_context.get());
-  EXPECT_THAT(popular_sites->sites().size(),
-              Eq(GetNumberOfDefaultPopularSitesForPlatform()));
+  EXPECT_THAT(
+      popular_sites->sections(),
+      ElementsAre(Pair(SectionType::PERSONALIZED,
+                       SizeIs(GetNumberOfDefaultPopularSitesForPlatform()))));
 }
 
 TEST_F(PopularSitesTest, IsEmptyOnConstructionIfDisabledByTrial) {
@@ -190,17 +235,18 @@
           base::ThreadTaskRunnerHandle::Get()));
   auto popular_sites = CreatePopularSites(url_request_context.get());
 
-  EXPECT_THAT(popular_sites->sites().size(), Eq(0ul));
+  EXPECT_THAT(popular_sites->sections(),
+              ElementsAre(Pair(SectionType::PERSONALIZED, IsEmpty())));
 }
 
 TEST_F(PopularSitesTest, ShouldSucceedFetching) {
-  SetCountryAndVersion("ZZ", "9");
-  RespondWithJSON(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+  SetCountryAndVersion("ZZ", "5");
+  RespondWithV5JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
       {kWikipedia});
 
   PopularSites::SitesVector sites;
-  EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
+  EXPECT_THAT(FetchPopularSites(/*force_download=*/true, &sites),
               Eq(base::Optional<bool>(true)));
 
   ASSERT_THAT(sites.size(), Eq(1u));
@@ -212,10 +258,10 @@
 }
 
 TEST_F(PopularSitesTest, Fallback) {
-  SetCountryAndVersion("ZZ", "9");
+  SetCountryAndVersion("ZZ", "5");
   RespondWith404(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
-  RespondWithJSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
+  RespondWithV5JSON(
       "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
       {kYouTube, kChromium});
 
@@ -237,9 +283,9 @@
 }
 
 TEST_F(PopularSitesTest, PopulatesWithDefaultResoucesOnFailure) {
-  SetCountryAndVersion("ZZ", "9");
+  SetCountryAndVersion("ZZ", "5");
   RespondWith404(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
   RespondWith404(
       "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json");
 
@@ -257,17 +303,19 @@
       CreatePopularSites(url_request_context.get());
 
 #if defined(GOOGLE_CHROME_BUILD) && (defined(OS_ANDROID) || defined(OS_IOS))
-  ASSERT_FALSE(popular_sites->sites().empty());
-  for (const auto& site : popular_sites->sites()) {
+  const PopularSites::SitesVector& sites =
+      popular_sites->sections().at(SectionType::PERSONALIZED);
+  ASSERT_FALSE(sites.empty());
+  for (const auto& site : sites) {
     EXPECT_THAT(site.default_icon_resource, Gt(0));
   }
 #endif
 }
 
 TEST_F(PopularSitesTest, ProvidesDefaultSitesUntilCallbackReturns) {
-  SetCountryAndVersion("ZZ", "9");
-  RespondWithJSON(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+  SetCountryAndVersion("ZZ", "5");
+  RespondWithV5JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
       {kWikipedia});
   scoped_refptr<net::TestURLRequestContextGetter> url_request_context(
       new net::TestURLRequestContextGetter(
@@ -290,20 +338,21 @@
   // Assert that callback was scheduled so we can wait for its completion.
   ASSERT_TRUE(callback_was_scheduled);
   // There should be 8 default sites as nothing was fetched yet.
-  EXPECT_THAT(popular_sites->sites().size(),
+  EXPECT_THAT(popular_sites->sections().at(SectionType::PERSONALIZED).size(),
               Eq(GetNumberOfDefaultPopularSitesForPlatform()));
 
   loop.Run();  // Wait for the fetch to finish and the callback to return.
 
   EXPECT_TRUE(save_success.value());
   // The 1 fetched site should replace the default sites.
-  EXPECT_THAT(popular_sites->sites().size(), Eq(1ul));
+  EXPECT_THAT(popular_sites->sections(),
+              ElementsAre(Pair(SectionType::PERSONALIZED, SizeIs(1ul))));
 }
 
 TEST_F(PopularSitesTest, UsesCachedJson) {
-  SetCountryAndVersion("ZZ", "9");
-  RespondWithJSON(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+  SetCountryAndVersion("ZZ", "5");
+  RespondWithV5JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
       {kWikipedia});
 
   // First request succeeds and gets cached.
@@ -313,17 +362,17 @@
 
   // File disappears from server, but we don't need it because it's cached.
   RespondWith404(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
   EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
               Eq(base::nullopt));
   EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
 }
 
 TEST_F(PopularSitesTest, CachesEmptyFile) {
-  SetCountryAndVersion("ZZ", "9");
+  SetCountryAndVersion("ZZ", "5");
   RespondWithData(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json", "[]");
-  RespondWithJSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json", "[]");
+  RespondWithV5JSON(
       "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
       {kWikipedia});
 
@@ -334,8 +383,8 @@
   EXPECT_THAT(sites, IsEmpty());
 
   // File appears on server, but we continue to use our cached empty file.
-  RespondWithJSON(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+  RespondWithV5JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
       {kWikipedia});
   EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
               Eq(base::nullopt));
@@ -343,9 +392,9 @@
 }
 
 TEST_F(PopularSitesTest, DoesntUseCachedFileIfDownloadForced) {
-  SetCountryAndVersion("ZZ", "9");
-  RespondWithJSON(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+  SetCountryAndVersion("ZZ", "5");
+  RespondWithV5JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
       {kWikipedia});
 
   // First request succeeds and gets cached.
@@ -355,41 +404,65 @@
   EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
 
   // File disappears from server. Download is forced, so we get the new file.
-  RespondWithJSON(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+  RespondWithV5JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
       {kChromium});
   EXPECT_THAT(FetchPopularSites(/*force_download=*/true, &sites),
               Eq(base::Optional<bool>(true)));
   EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
 }
 
-TEST_F(PopularSitesTest, RefetchesAfterCountryMoved) {
-  RespondWithJSON(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+TEST_F(PopularSitesTest, DoesntUseCacheWithDeprecatedVersion) {
+  SetCountryAndVersion("ZZ", "5");
+  RespondWithV5JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
       {kWikipedia});
-  RespondWithJSON(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZX_9.json",
+
+  // First request succeeds and gets cached.
+  PopularSites::SitesVector sites;
+  EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
+              Eq(base::Optional<bool>(true)));
+  EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
+  EXPECT_THAT(prefs_->GetInteger(prefs::kPopularSitesVersionPref), Eq(5));
+
+  // The client is updated to use V6. Drop old data and refetch.
+  SetCountryAndVersion("ZZ", "6");
+  RespondWithV6JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+      {{SectionType::PERSONALIZED, {kChromium}}});
+  EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
+              Eq(base::Optional<bool>(true)));
+  EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
+  EXPECT_THAT(prefs_->GetInteger(prefs::kPopularSitesVersionPref), Eq(6));
+}
+
+TEST_F(PopularSitesTest, RefetchesAfterCountryMoved) {
+  RespondWithV5JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
+      {kWikipedia});
+  RespondWithV5JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZX_5.json",
       {kChromium});
 
   PopularSites::SitesVector sites;
 
   // First request (in ZZ) saves Wikipedia.
-  SetCountryAndVersion("ZZ", "9");
+  SetCountryAndVersion("ZZ", "5");
   EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
               Eq(base::Optional<bool>(true)));
   EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
 
   // Second request (now in ZX) saves Chromium.
-  SetCountryAndVersion("ZX", "9");
+  SetCountryAndVersion("ZX", "5");
   EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
               base::Optional<bool>(true));
   EXPECT_THAT(sites[0].url, URLEq("https://www.chromium.org/"));
 }
 
 TEST_F(PopularSitesTest, DoesntCacheInvalidFile) {
-  SetCountryAndVersion("ZZ", "9");
+  SetCountryAndVersion("ZZ", "5");
   RespondWithData(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
       "ceci n'est pas un json");
   RespondWith404(
       "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json");
@@ -400,8 +473,8 @@
               Eq(base::Optional<bool>(false)));
 
   // Second request refetches ZZ_9, which now has data.
-  RespondWithJSON(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+  RespondWithV5JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
       {kChromium});
   EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
               Eq(base::Optional<bool>(true)));
@@ -410,10 +483,10 @@
 }
 
 TEST_F(PopularSitesTest, RefetchesAfterFallback) {
-  SetCountryAndVersion("ZZ", "9");
+  SetCountryAndVersion("ZZ", "5");
   RespondWith404(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json");
-  RespondWithJSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json");
+  RespondWithV5JSON(
       "https://www.gstatic.com/chrome/ntp/suggested_sites_DEFAULT_5.json",
       {kWikipedia});
 
@@ -425,8 +498,8 @@
   EXPECT_THAT(sites[0].url, URLEq("https://zz.m.wikipedia.org/"));
 
   // Second request refetches ZZ_9, which now has data.
-  RespondWithJSON(
-      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_9.json",
+  RespondWithV5JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_5.json",
       {kChromium});
   EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
               Eq(base::Optional<bool>(true)));
@@ -435,10 +508,10 @@
 }
 
 TEST_F(PopularSitesTest, ShouldOverrideDirectory) {
-  SetCountryAndVersion("ZZ", "9");
+  SetCountryAndVersion("ZZ", "5");
   prefs_->SetString(prefs::kPopularSitesOverrideDirectory, "foo/bar/");
-  RespondWithJSON("https://www.gstatic.com/foo/bar/suggested_sites_ZZ_9.json",
-                  {kWikipedia});
+  RespondWithV5JSON("https://www.gstatic.com/foo/bar/suggested_sites_ZZ_5.json",
+                    {kWikipedia});
 
   PopularSites::SitesVector sites;
   EXPECT_THAT(FetchPopularSites(/*force_download=*/false, &sites),
@@ -447,5 +520,64 @@
   EXPECT_THAT(sites.size(), Eq(1u));
 }
 
+TEST_F(PopularSitesTest, DoesNotFetchExplorationSitesWithoutFeature) {
+  base::test::ScopedFeatureList override_features;
+  override_features.InitAndDisableFeature(kSitesExplorationFeature);
+
+  SetCountryAndVersion("ZZ", "6");
+  RespondWithV6JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+      {{SectionType::PERSONALIZED, {kChromium}},
+       {SectionType::NEWS, {kYouTube}}});
+
+  std::map<SectionType, PopularSites::SitesVector> sections;
+  EXPECT_THAT(FetchAllSections(/*force_download=*/false, &sections),
+              Eq(base::Optional<bool>(true)));
+
+  // The fetched news section should not be propagated without enabled feature.
+  EXPECT_THAT(sections, Not(Contains(Pair(SectionType::NEWS, _))));
+}
+
+TEST_F(PopularSitesTest, FetchesExplorationSitesWithFeature) {
+  base::test::ScopedFeatureList override_features;
+  override_features.InitAndEnableFeature(kSitesExplorationFeature);
+  SetCountryAndVersion("ZZ", "6");
+  RespondWithV6JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+      {{SectionType::PERSONALIZED, {kChromium}},
+       {SectionType::ENTERTAINMENT, {kWikipedia, kYouTube}},
+       {SectionType::NEWS, {kYouTube}},
+       {SectionType::TOOLS, TestPopularSiteVector{}}});
+
+  std::map<SectionType, PopularSites::SitesVector> sections;
+  EXPECT_THAT(FetchAllSections(/*force_download=*/false, &sections),
+              Eq(base::Optional<bool>(true)));
+
+  EXPECT_THAT(sections, ElementsAre(Pair(SectionType::PERSONALIZED, SizeIs(1)),
+                                    Pair(SectionType::ENTERTAINMENT, SizeIs(2)),
+                                    Pair(SectionType::NEWS, SizeIs(1)),
+                                    Pair(SectionType::TOOLS, IsEmpty())));
+}
+
+TEST_F(PopularSitesTest, FetchesExplorationSitesIgnoreUnknownSections) {
+  base::test::ScopedFeatureList override_features;
+  override_features.InitAndEnableFeature(kSitesExplorationFeature);
+
+  SetCountryAndVersion("ZZ", "6");
+  RespondWithV6JSON(
+      "https://www.gstatic.com/chrome/ntp/suggested_sites_ZZ_6.json",
+      {{SectionType::UNKNOWN, {kChromium}},
+       {SectionType::NEWS, {kYouTube}},
+       {SectionType::UNKNOWN, {kWikipedia, kYouTube}}});
+
+  std::map<SectionType, PopularSites::SitesVector> sections;
+  EXPECT_THAT(FetchAllSections(/*force_download=*/false, &sections),
+              Eq(base::Optional<bool>(true)));
+
+  // Expect that there are four sections, none of which is empty.
+  EXPECT_THAT(sections, ElementsAre(Pair(SectionType::PERSONALIZED, SizeIs(0)),
+                                    Pair(SectionType::NEWS, SizeIs(1))));
+}
+
 }  // namespace
 }  // namespace ntp_tiles
diff --git a/components/ntp_tiles/pref_names.cc b/components/ntp_tiles/pref_names.cc
index c8839987..409de49b 100644
--- a/components/ntp_tiles/pref_names.cc
+++ b/components/ntp_tiles/pref_names.cc
@@ -25,5 +25,11 @@
 // If set, this will override the default file version for popular sites.
 const char kPopularSitesOverrideVersion[] = "popular_sites.override_version";
 
+// Prefs used to cache suggested sites and store caching meta data.
+const char kPopularSitesLastDownloadPref[] = "popular_sites_last_download";
+const char kPopularSitesURLPref[] = "popular_sites_url";
+const char kPopularSitesJsonPref[] = "suggested_sites_json";
+const char kPopularSitesVersionPref[] = "suggested_sites_version";
+
 }  // namespace prefs
 }  // namespace ntp_tiles
diff --git a/components/ntp_tiles/pref_names.h b/components/ntp_tiles/pref_names.h
index 9c4de063..687f5577 100644
--- a/components/ntp_tiles/pref_names.h
+++ b/components/ntp_tiles/pref_names.h
@@ -15,6 +15,11 @@
 extern const char kPopularSitesOverrideCountry[];
 extern const char kPopularSitesOverrideVersion[];
 
+extern const char kPopularSitesLastDownloadPref[];
+extern const char kPopularSitesURLPref[];
+extern const char kPopularSitesJsonPref[];
+extern const char kPopularSitesVersionPref[];
+
 }  // namespace prefs
 }  // namespace ntp_tiles
 
diff --git a/components/ntp_tiles/section_type.h b/components/ntp_tiles/section_type.h
new file mode 100644
index 0000000..f1f9f5c
--- /dev/null
+++ b/components/ntp_tiles/section_type.h
@@ -0,0 +1,30 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_NTP_TILES_SECTION_TYPE_H_
+#define COMPONENTS_NTP_TILES_SECTION_TYPE_H_
+
+namespace ntp_tiles {
+
+// The type of a section means all its tiles originate here. Ranked descendingly
+// from most important section to least important.
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.suggestions
+// GENERATED_JAVA_CLASS_NAME_OVERRIDE: TileSectionType
+enum class SectionType {
+  UNKNOWN,
+  PERSONALIZED,
+  SOCIAL,
+  ENTERTAINMENT,
+  NEWS,
+  ECOMMERCE,
+  TOOLS,
+  TRAVEL,
+
+  LAST = TRAVEL
+};
+
+}  // namespace ntp_tiles
+
+#endif  // COMPONENTS_NTP_TILES_SECTION_TYPE_H_
diff --git a/components/password_manager/core/browser/password_manager_client.h b/components/password_manager/core/browser/password_manager_client.h
index 58bc5ed..5f01d31 100644
--- a/components/password_manager/core/browser/password_manager_client.h
+++ b/components/password_manager/core/browser/password_manager_client.h
@@ -215,6 +215,9 @@
   virtual void CheckProtectedPasswordEntry(
       const std::string& password_saved_domain,
       bool password_field_exists) = 0;
+
+  // Records a Chrome Sync event that sync password reuse was detected.
+  virtual void LogPasswordReuseDetectedEvent() = 0;
 #endif
 
   // Gets the UKM service associated with this client (for metrics).
diff --git a/components/password_manager/core/browser/password_reuse_detection_manager.cc b/components/password_manager/core/browser/password_reuse_detection_manager.cc
index 27dd293..2dfc1df2 100644
--- a/components/password_manager/core/browser/password_reuse_detection_manager.cc
+++ b/components/password_manager/core/browser/password_reuse_detection_manager.cc
@@ -94,6 +94,11 @@
 #if defined(SAFE_BROWSING_DB_LOCAL)
   // TODO(jialiul): After CSD whitelist being added to Android, we should gate
   // this by either SAFE_BROWSING_DB_LOCAL or SAFE_BROWSING_DB_REMOTE.
+  if (!number_matches) {
+    // |number_matches| == 0 means sync password reuse was detected.
+    client_->LogPasswordReuseDetectedEvent();
+  }
+
   client_->CheckProtectedPasswordEntry(legitimate_domain,
                                        password_field_detected);
 #endif
diff --git a/components/password_manager/core/browser/stub_password_manager_client.cc b/components/password_manager/core/browser/stub_password_manager_client.cc
index 14a3cbb..b351cc42 100644
--- a/components/password_manager/core/browser/stub_password_manager_client.cc
+++ b/components/password_manager/core/browser/stub_password_manager_client.cc
@@ -80,6 +80,8 @@
 void StubPasswordManagerClient::CheckProtectedPasswordEntry(
     const std::string& password_saved_domain,
     bool password_field_exists) {}
+
+void StubPasswordManagerClient::LogPasswordReuseDetectedEvent() {}
 #endif
 
 ukm::UkmRecorder* StubPasswordManagerClient::GetUkmRecorder() {
diff --git a/components/password_manager/core/browser/stub_password_manager_client.h b/components/password_manager/core/browser/stub_password_manager_client.h
index a33c7b2c..7e6dbfe3 100644
--- a/components/password_manager/core/browser/stub_password_manager_client.h
+++ b/components/password_manager/core/browser/stub_password_manager_client.h
@@ -52,6 +52,7 @@
                                    const GURL& frame_url) override;
   void CheckProtectedPasswordEntry(const std::string& password_saved_domain,
                                    bool password_field_exists) override;
+  void LogPasswordReuseDetectedEvent() override;
 #endif
   ukm::UkmRecorder* GetUkmRecorder() override;
   ukm::SourceId GetUkmSourceId() override;
diff --git a/components/policy/core/common/policy_loader_win_unittest.cc b/components/policy/core/common/policy_loader_win_unittest.cc
index e973049..ee83abf8 100644
--- a/components/policy/core/common/policy_loader_win_unittest.cc
+++ b/components/policy/core/common/policy_loader_win_unittest.cc
@@ -311,7 +311,7 @@
   // makes sure that tests executing in parallel won't delete each other's
   // key, at DeleteKeys().
   key_name_ = base::ASCIIToUTF16(base::StringPrintf(
-        "SOFTWARE\\chromium unittest %d", base::GetCurrentProcId()));
+      "SOFTWARE\\chromium unittest %" CrPRIdPid, base::GetCurrentProcId()));
   std::wstring hklm_key_name = key_name_ + L"\\HKLM";
   std::wstring hkcu_key_name = key_name_ + L"\\HKCU";
 
diff --git a/components/safe_browsing/features.cc b/components/safe_browsing/features.cc
index 560dbc6..190d84f 100644
--- a/components/safe_browsing/features.cc
+++ b/components/safe_browsing/features.cc
@@ -39,12 +39,9 @@
 const base::Feature kProtectedPasswordEntryPinging{
     "ProtectedPasswordEntryPinging", base::FEATURE_ENABLED_BY_DEFAULT};
 
-// Specifies which non-resource HTML Elements to collect based on their tag and
-// attributes. It's a single param containing a comma-separated list of pairs.
-// For example: "tag1,id,tag1,height,tag2,foo" - this will collect elements with
-// tag "tag1" that have attribute "id" or "height" set, and elements of tag
-// "tag2" if they have attribute "foo" set. All tag names and attributes should
-// be lower case.
+const base::Feature kSyncPasswordReuseEvent{"SyncPasswordReuseEvent",
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kThreatDomDetailsTagAndAttributeFeature{
     "ThreatDomDetailsTagAttributes", base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -66,6 +63,7 @@
     {&kPasswordFieldOnFocusPinging, true},
     {&kPasswordProtectionInterstitial, false},
     {&kProtectedPasswordEntryPinging, true},
+    {&kSyncPasswordReuseEvent, true},
     {&kThreatDomDetailsTagAndAttributeFeature, false},
     {&kV4OnlyEnabled, true},
 };
diff --git a/components/safe_browsing/features.h b/components/safe_browsing/features.h
index 67f838a..dfd8a38c 100644
--- a/components/safe_browsing/features.h
+++ b/components/safe_browsing/features.h
@@ -25,6 +25,14 @@
 extern const base::Feature kPasswordFieldOnFocusPinging;
 extern const base::Feature kPasswordProtectionInterstitial;
 extern const base::Feature kProtectedPasswordEntryPinging;
+// Gates registration for SyncPasswordReuseEvent events.
+extern const base::Feature kSyncPasswordReuseEvent;
+// Specifies which non-resource HTML Elements to collect based on their tag and
+// attributes. It's a single param containing a comma-separated list of pairs.
+// For example: "tag1,id,tag1,height,tag2,foo" - this will collect elements with
+// tag "tag1" that have attribute "id" or "height" set, and elements of tag
+// "tag2" if they have attribute "foo" set. All tag names and attributes should
+// be lower case.
 extern const base::Feature kThreatDomDetailsTagAndAttributeFeature;
 extern const base::Feature kV4OnlyEnabled;
 
diff --git a/components/safe_browsing/password_protection/password_protection_service.h b/components/safe_browsing/password_protection/password_protection_service.h
index bb841d0..28f79d5 100644
--- a/components/safe_browsing/password_protection/password_protection_service.h
+++ b/components/safe_browsing/password_protection/password_protection_service.h
@@ -164,6 +164,10 @@
       const std::string& saved_domain,
       bool password_field_exists);
 
+  // Records a Chrome Sync event that sync password reuse was detected.
+  virtual void MaybeLogPasswordReuseDetectedEvent(
+      content::WebContents* web_contents) = 0;
+
   scoped_refptr<SafeBrowsingDatabaseManager> database_manager();
 
   // Safe Browsing backend cannot get a reliable reputation of a URL if
diff --git a/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index eb9a597..62a879b 100644
--- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -106,6 +106,9 @@
 
   void set_incognito(bool enabled) { is_incognito_ = enabled; }
 
+  void MaybeLogPasswordReuseDetectedEvent(
+      content::WebContents* web_contents) override {}
+
   bool IsPingingEnabled(const base::Feature& feature,
                         RequestOutcome* reason) override {
     checked_feature_name_ = feature.name;
diff --git a/components/vector_icons/BUILD.gn b/components/vector_icons/BUILD.gn
index 3d6eb013..1b8d75b4 100644
--- a/components/vector_icons/BUILD.gn
+++ b/components/vector_icons/BUILD.gn
@@ -36,6 +36,7 @@
     "reload.icon",
     "screen_share.icon",
     "search.icon",
+    "usb.icon",
     "videocam.icon",
     "warning.icon",
   ]
diff --git a/components/vector_icons/usb.icon b/components/vector_icons/usb.icon
new file mode 100644
index 0000000..61d9679
--- /dev/null
+++ b/components/vector_icons/usb.icon
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+MOVE_TO, 30, 14,
+R_V_LINE_TO, 8,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, 4,
+R_H_LINE_TO, -6,
+V_LINE_TO, 10,
+R_H_LINE_TO, 4,
+R_LINE_TO, -6, -8,
+R_LINE_TO, -6, 8,
+R_H_LINE_TO, 4,
+R_V_LINE_TO, 16,
+R_H_LINE_TO, -6,
+R_V_LINE_TO, -4.14f,
+R_CUBIC_TO, 1.41f, -0.73f, 2.4f, -2.16f, 2.4f, -3.86f,
+R_CUBIC_TO, 0, -2.43f, -1.97f, -4.4f, -4.4f, -4.4f,
+R_CUBIC_TO, -2.43f, 0, -4.4f, 1.97f, -4.4f, 4.4f,
+R_CUBIC_TO, 0, 1.7f, 0.99f, 3.13f, 2.4f, 3.86f,
+V_LINE_TO, 26,
+R_CUBIC_TO, 0, 2.21f, 1.79f, 4, 4, 4,
+R_H_LINE_TO, 6,
+R_V_LINE_TO, 6.1f,
+R_CUBIC_TO, -1.42f, 0.73f, -2.4f, 2.19f, -2.4f, 3.9f,
+R_CUBIC_TO, 0, 2.43f, 1.97f, 4.4f, 4.4f, 4.4f,
+R_CUBIC_TO, 2.43f, 0, 4.4f, -1.97f, 4.4f, -4.4f,
+R_CUBIC_TO, 0, -1.71f, -0.98f, -3.17f, -2.4f, -3.9f,
+V_LINE_TO, 30,
+R_H_LINE_TO, 6,
+R_CUBIC_TO, 2.21f, 0, 4, -1.79f, 4, -4,
+R_V_LINE_TO, -4,
+R_H_LINE_TO, 2,
+R_V_LINE_TO, -8,
+R_H_LINE_TO, -8,
+CLOSE,
+END
diff --git a/components/viz/host/host_frame_sink_client.h b/components/viz/host/host_frame_sink_client.h
index bd9e8bd..d02f661 100644
--- a/components/viz/host/host_frame_sink_client.h
+++ b/components/viz/host/host_frame_sink_client.h
@@ -11,9 +11,9 @@
 
 class HostFrameSinkClient {
  public:
-  // Runs when a CompositorFrame is received for the given SurfaceInfo for the
-  // first time.
-  virtual void OnSurfaceCreated(const SurfaceInfo& surface_info) = 0;
+  // Called when a CompositorFrame with a new SurfaceId activates for the first
+  // time.
+  virtual void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) = 0;
 
  protected:
   virtual ~HostFrameSinkClient() {}
diff --git a/components/viz/host/host_frame_sink_manager.cc b/components/viz/host/host_frame_sink_manager.cc
index d8b5ed7..cc5fa91 100644
--- a/components/viz/host/host_frame_sink_manager.cc
+++ b/components/viz/host/host_frame_sink_manager.cc
@@ -165,7 +165,8 @@
   frame_sink_manager_->DropTemporaryReference(surface_id);
 }
 
-void HostFrameSinkManager::OnSurfaceCreated(const SurfaceInfo& surface_info) {
+void HostFrameSinkManager::OnFirstSurfaceActivation(
+    const SurfaceInfo& surface_info) {
   auto it = frame_sink_data_map_.find(surface_info.id().frame_sink_id());
   // If we've received a bogus or stale SurfaceId from Viz then just ignore it.
   if (it == frame_sink_data_map_.end()) {
@@ -177,7 +178,7 @@
 
   FrameSinkData& frame_sink_data = it->second;
   if (frame_sink_data.client)
-    frame_sink_data.client->OnSurfaceCreated(surface_info);
+    frame_sink_data.client->OnFirstSurfaceActivation(surface_info);
 
   if (frame_sink_manager_impl_ &&
       frame_sink_manager_impl_->surface_manager()->using_surface_references()) {
diff --git a/components/viz/host/host_frame_sink_manager.h b/components/viz/host/host_frame_sink_manager.h
index 0633903..1c8fbe5 100644
--- a/components/viz/host/host_frame_sink_manager.h
+++ b/components/viz/host/host_frame_sink_manager.h
@@ -139,7 +139,7 @@
   void PerformAssignTemporaryReference(const SurfaceId& surface_id);
 
   // mojom::FrameSinkManagerClient:
-  void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override;
   void OnClientConnectionClosed(const FrameSinkId& frame_sink_id) override;
   void OnAggregatedHitTestRegionListUpdated(
       const FrameSinkId& frame_sink_id,
diff --git a/components/viz/host/host_frame_sink_manager_unittests.cc b/components/viz/host/host_frame_sink_manager_unittests.cc
index b21ba8ab..ba9d3df 100644
--- a/components/viz/host/host_frame_sink_manager_unittests.cc
+++ b/components/viz/host/host_frame_sink_manager_unittests.cc
@@ -46,7 +46,7 @@
   ~FakeHostFrameSinkClient() override = default;
 
   // HostFrameSinkClient implementation.
-  void OnSurfaceCreated(const SurfaceInfo& surface_info) override {}
+  void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override {}
 
  private:
   DISALLOW_COPY_AND_ASSIGN(FakeHostFrameSinkClient);
@@ -217,11 +217,12 @@
   host_manager().RegisterFrameSinkHierarchy(kParentFrameSinkId,
                                             surface_id.frame_sink_id());
 
-  // When HostFrameSinkManager gets OnSurfaceCreated() it should assign the
-  // temporary reference to the registered parent |kParentFrameSinkId|.
+  // When HostFrameSinkManager gets OnFirstSurfaceActivation() it should assign
+  // the temporary reference to the registered parent |kParentFrameSinkId|.
   EXPECT_CALL(manager_impl(),
               AssignTemporaryReference(surface_id, kParentFrameSinkId));
-  GetFrameSinkManagerClient()->OnSurfaceCreated(MakeSurfaceInfo(surface_id));
+  GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
+      MakeSurfaceInfo(surface_id));
 }
 
 TEST_F(HostFrameSinkManagerTest, DropTemporaryReference) {
@@ -229,10 +230,11 @@
   auto support = CreateCompositorFrameSinkSupport(surface_id.frame_sink_id(),
                                                   false /* is_root */);
 
-  // When HostFrameSinkManager gets OnSurfaceCreated() it should find no
+  // When HostFrameSinkManager gets OnFirstSurfaceActivation() it should find no
   // registered parent and drop the temporary reference.
   EXPECT_CALL(manager_impl(), DropTemporaryReference(surface_id));
-  GetFrameSinkManagerClient()->OnSurfaceCreated(MakeSurfaceInfo(surface_id));
+  GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
+      MakeSurfaceInfo(surface_id));
 }
 
 TEST_F(HostFrameSinkManagerTest, DropTemporaryReferenceForStaleClient) {
@@ -258,7 +260,7 @@
       .Times(0);
   EXPECT_CALL(manager_impl(), AssignTemporaryReference(client_surface_id, _))
       .Times(1);
-  GetFrameSinkManagerClient()->OnSurfaceCreated(
+  GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
       MakeSurfaceInfo(client_surface_id));
   testing::Mock::VerifyAndClearExpectations(&manager_impl());
 
@@ -269,7 +271,7 @@
   const SurfaceId client_surface_id2 = MakeSurfaceId(kClientFrameSinkId, 2);
   EXPECT_CALL(manager_impl(), DropTemporaryReference(client_surface_id2))
       .Times(1);
-  GetFrameSinkManagerClient()->OnSurfaceCreated(
+  GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
       MakeSurfaceInfo(client_surface_id2));
 
   support_parent.reset();
@@ -281,11 +283,12 @@
   auto support = CreateCompositorFrameSinkSupport(surface_id.frame_sink_id(),
                                                   true /* is_root */);
 
-  // When HostFrameSinkManager gets OnSurfaceCreated() it should do nothing
-  // since |kParentFrameSinkId| is a display root.
+  // When HostFrameSinkManager gets OnFirstSurfaceActivation() it should do
+  // nothing since |kParentFrameSinkId| is a display root.
   EXPECT_CALL(manager_impl(), DropTemporaryReference(surface_id)).Times(0);
   EXPECT_CALL(manager_impl(), AssignTemporaryReference(surface_id, _)).Times(0);
-  GetFrameSinkManagerClient()->OnSurfaceCreated(MakeSurfaceInfo(surface_id));
+  GetFrameSinkManagerClient()->OnFirstSurfaceActivation(
+      MakeSurfaceInfo(surface_id));
 }
 
 }  // namespace test
diff --git a/components/viz/service/display/display_scheduler.cc b/components/viz/service/display/display_scheduler.cc
index 3894115..2b52e82 100644
--- a/components/viz/service/display/display_scheduler.cc
+++ b/components/viz/service/display/display_scheduler.cc
@@ -277,7 +277,8 @@
     NOTIMPLEMENTED();
 }
 
-void DisplayScheduler::OnSurfaceCreated(const SurfaceInfo& surface_info) {}
+void DisplayScheduler::OnFirstSurfaceActivation(
+    const SurfaceInfo& surface_info) {}
 
 void DisplayScheduler::OnSurfaceDestroyed(const SurfaceId& surface_id) {
   auto it = surface_states_.find(surface_id);
diff --git a/components/viz/service/display/display_scheduler.h b/components/viz/service/display/display_scheduler.h
index 9be510e..d341df0 100644
--- a/components/viz/service/display/display_scheduler.h
+++ b/components/viz/service/display/display_scheduler.h
@@ -65,7 +65,7 @@
   void OnBeginFrameSourcePausedChanged(bool paused) override;
 
   // SurfaceObserver implementation.
-  void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override;
   void OnSurfaceDestroyed(const SurfaceId& surface_id) override;
   bool OnSurfaceDamaged(const SurfaceId& surface_id,
                         const BeginFrameAck& ack) override;
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
index a451d023..cdddcca 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.cc
@@ -60,16 +60,6 @@
 void CompositorFrameSinkSupport::OnSurfaceActivated(Surface* surface) {
   DCHECK(surface->HasActiveFrame());
   const cc::CompositorFrame& frame = surface->GetActiveFrame();
-  if (!seen_first_frame_activation_) {
-    // SurfaceCreated only applies for the first Surface activation.
-    seen_first_frame_activation_ = true;
-
-    gfx::Size frame_size = frame.render_pass_list.back()->output_rect.size();
-    surface_manager_->SurfaceCreated(SurfaceInfo(
-        surface->surface_id(), frame.metadata.device_scale_factor, frame_size));
-  }
-  // Fire SurfaceCreated first so that a temporary reference is added before
-  // it is potentially transformed into a real reference by the client.
   DCHECK(surface->active_referenced_surfaces());
   UpdateSurfaceReferences(surface->surface_id().local_surface_id(),
                           *surface->active_referenced_surfaces());
@@ -345,7 +335,6 @@
 
 Surface* CompositorFrameSinkSupport::CreateSurface(
     const SurfaceInfo& surface_info) {
-  seen_first_frame_activation_ = false;
   return surface_manager_->CreateSurface(
       weak_factory_.GetWeakPtr(), surface_info,
       frame_sink_manager_->GetPrimaryBeginFrameSource(), needs_sync_tokens_);
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support.h b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
index 0148854..70d13c4 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support.h
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support.h
@@ -144,7 +144,6 @@
 
   const bool is_root_;
   const bool needs_sync_tokens_;
-  bool seen_first_frame_activation_ = false;
 
   // A callback that will be run at the start of the destructor if set.
   base::OnceCallback<void()> destruction_callback_;
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index 10a10a6..0e07c38 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -320,7 +320,8 @@
   return false;
 }
 
-void FrameSinkManagerImpl::OnSurfaceCreated(const SurfaceInfo& surface_info) {
+void FrameSinkManagerImpl::OnFirstSurfaceActivation(
+    const SurfaceInfo& surface_info) {
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   DCHECK_GT(surface_info.device_scale_factor(), 0.0f);
 
@@ -330,7 +331,7 @@
   // temporary reference was created. It could be useful to let |client_| know
   // if it should find an owner.
   if (client_)
-    client_->OnSurfaceCreated(surface_info);
+    client_->OnFirstSurfaceActivation(surface_info);
 }
 
 bool FrameSinkManagerImpl::OnSurfaceDamaged(const SurfaceId& surface_id,
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index 87f7ffe..dae82bf 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -112,7 +112,7 @@
   SurfaceManager* surface_manager() { return &surface_manager_; }
 
   // SurfaceObserver implementation.
-  void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override;
   bool OnSurfaceDamaged(const SurfaceId& surface_id,
                         const BeginFrameAck& ack) override;
   void OnSurfaceDiscarded(const SurfaceId& surface_id) override;
diff --git a/components/viz/service/hit_test/hit_test_aggregator.h b/components/viz/service/hit_test/hit_test_aggregator.h
index b556fa78..b5d68146 100644
--- a/components/viz/service/hit_test/hit_test_aggregator.h
+++ b/components/viz/service/hit_test/hit_test_aggregator.h
@@ -48,7 +48,7 @@
 
  protected:
   // SurfaceObserver:
-  void OnSurfaceCreated(const SurfaceInfo& surface_info) override {}
+  void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override {}
   void OnSurfaceDestroyed(const SurfaceId& surface_id) override {}
   bool OnSurfaceDamaged(const SurfaceId& surface_id,
                         const BeginFrameAck& ack) override;
diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc
index 78d5b965..4218298 100644
--- a/components/viz/service/surfaces/surface.cc
+++ b/components/viz/service/surfaces/surface.cc
@@ -253,6 +253,11 @@
 
   UnrefFrameResourcesAndRunDrawCallback(std::move(previous_frame_data));
 
+  if (!seen_first_frame_activation_) {
+    seen_first_frame_activation_ = true;
+    surface_manager_->FirstSurfaceActivation(surface_info_);
+  }
+
   // TODO(fsamuel): If |surface_client_| is not available then we will not
   // immediately generate a display frame once the cc::CompositorFrame here
   // activates. This isn't a major issue though because this would only
diff --git a/components/viz/service/surfaces/surface.h b/components/viz/service/surfaces/surface.h
index c8e6405..a75fb8bf3 100644
--- a/components/viz/service/surfaces/surface.h
+++ b/components/viz/service/surfaces/surface.h
@@ -251,6 +251,7 @@
   base::Optional<FrameData> pending_frame_data_;
   base::Optional<FrameData> active_frame_data_;
   bool closed_ = false;
+  bool seen_first_frame_activation_ = false;
   const bool needs_sync_tokens_;
   std::vector<SurfaceSequence> destruction_dependencies_;
 
diff --git a/components/viz/service/surfaces/surface_manager.cc b/components/viz/service/surfaces/surface_manager.cc
index f56ba6ba..3504721 100644
--- a/components/viz/service/surfaces/surface_manager.cc
+++ b/components/viz/service/surfaces/surface_manager.cc
@@ -431,11 +431,11 @@
   return changed;
 }
 
-void SurfaceManager::SurfaceCreated(const SurfaceInfo& surface_info) {
+void SurfaceManager::FirstSurfaceActivation(const SurfaceInfo& surface_info) {
   CHECK(thread_checker_.CalledOnValidThread());
 
   for (auto& observer : observer_list_)
-    observer.OnSurfaceCreated(surface_info);
+    observer.OnFirstSurfaceActivation(surface_info);
 }
 
 void SurfaceManager::SurfaceActivated(Surface* surface) {
diff --git a/components/viz/service/surfaces/surface_manager.h b/components/viz/service/surfaces/surface_manager.h
index 33cb19b..71160b4d 100644
--- a/components/viz/service/surfaces/surface_manager.h
+++ b/components/viz/service/surfaces/surface_manager.h
@@ -96,8 +96,7 @@
   bool SurfaceModified(const SurfaceId& surface_id, const BeginFrameAck& ack);
 
   // Called when a surface has an active frame for the first time.
-  // TODO(fsamuel,samans): Rename to OnFirstSurfaceActivation.
-  void SurfaceCreated(const SurfaceInfo& surface_info);
+  void FirstSurfaceActivation(const SurfaceInfo& surface_info);
 
   // Called when a CompositorFrame within |surface| has activated.
   void SurfaceActivated(Surface* surface);
diff --git a/components/viz/service/surfaces/surface_observer.h b/components/viz/service/surfaces/surface_observer.h
index 44fd41d..30e144bb 100644
--- a/components/viz/service/surfaces/surface_observer.h
+++ b/components/viz/service/surfaces/surface_observer.h
@@ -14,9 +14,9 @@
 
 class SurfaceObserver {
  public:
-  // Runs when a CompositorFrame is activated for the given SurfaceInfo for the
-  // first time.
-  virtual void OnSurfaceCreated(const SurfaceInfo& surface_info) = 0;
+  // Runs when a CompositorFrame with a new SurfaceId activates for the first
+  // time.
+  virtual void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) = 0;
 
   // Runs when a Surface was marked to be destroyed.
   virtual void OnSurfaceDestroyed(const SurfaceId& surface_id) = 0;
diff --git a/components/viz/test/fake_surface_observer.cc b/components/viz/test/fake_surface_observer.cc
index 44a9b8ae..8b959d3 100644
--- a/components/viz/test/fake_surface_observer.cc
+++ b/components/viz/test/fake_surface_observer.cc
@@ -40,7 +40,8 @@
   will_draw_surfaces_.insert(surface_id);
 }
 
-void FakeSurfaceObserver::OnSurfaceCreated(const SurfaceInfo& surface_info) {
+void FakeSurfaceObserver::OnFirstSurfaceActivation(
+    const SurfaceInfo& surface_info) {
   last_created_surface_id_ = surface_info.id();
   last_surface_info_ = surface_info;
 }
diff --git a/components/viz/test/fake_surface_observer.h b/components/viz/test/fake_surface_observer.h
index 3c0a21f..5fc19690 100644
--- a/components/viz/test/fake_surface_observer.h
+++ b/components/viz/test/fake_surface_observer.h
@@ -38,7 +38,7 @@
   // SurfaceObserver implementation:
   bool OnSurfaceDamaged(const SurfaceId& surface_id,
                         const BeginFrameAck& ack) override;
-  void OnSurfaceCreated(const SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const SurfaceInfo& surface_info) override;
   void OnSurfaceDiscarded(const SurfaceId& surface_id) override {}
   void OnSurfaceDestroyed(const SurfaceId& surface_id) override {}
   void OnSurfaceDamageExpected(const SurfaceId& surface_id,
diff --git a/content/browser/accessibility/accessibility_event_recorder_win.cc b/content/browser/accessibility/accessibility_event_recorder_win.cc
index 77f6715a6..7f3e626 100644
--- a/content/browser/accessibility/accessibility_event_recorder_win.cc
+++ b/content/browser/accessibility/accessibility_event_recorder_win.cc
@@ -250,19 +250,17 @@
     if (event == IA2_EVENT_TEXT_REMOVED) {
       IA2TextSegment old_text;
       if (SUCCEEDED(accessible_text->get_oldText(&old_text))) {
-        log += base::StringPrintf(" old_text={'%s' start=%d end=%d}",
+        log += base::StringPrintf(" old_text={'%s' start=%ld end=%ld}",
                                   BstrToUTF8(old_text.text).c_str(),
-                                  old_text.start,
-                                  old_text.end);
+                                  old_text.start, old_text.end);
       }
     }
     if (event == IA2_EVENT_TEXT_INSERTED) {
       IA2TextSegment new_text;
       if (SUCCEEDED(accessible_text->get_newText(&new_text))) {
-        log += base::StringPrintf(" new_text={'%s' start=%d end=%d}",
+        log += base::StringPrintf(" new_text={'%s' start=%ld end=%ld}",
                                   BstrToUTF8(new_text.text).c_str(),
-                                  new_text.start,
-                                  new_text.end);
+                                  new_text.start, new_text.end);
       }
     }
   }
diff --git a/content/browser/devtools/service_worker_devtools_agent_host.cc b/content/browser/devtools/service_worker_devtools_agent_host.cc
index 5b8aef5..7e068d9 100644
--- a/content/browser/devtools/service_worker_devtools_agent_host.cc
+++ b/content/browser/devtools/service_worker_devtools_agent_host.cc
@@ -68,7 +68,7 @@
 
 std::string ServiceWorkerDevToolsAgentHost::GetTitle() {
   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id().first)) {
-    return base::StringPrintf("Worker pid:%d",
+    return base::StringPrintf("Worker pid:%" CrPRIdPid,
                               base::GetProcId(host->GetHandle()));
   }
   return "";
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 2ee1738..1129e675 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -420,12 +420,6 @@
       pending_entry_ = entry;
       pending_entry_index_ = current_index;
 
-      // The title of the page being reloaded might have been removed in the
-      // meanwhile, so we need to revert to the default title upon reload and
-      // invalidate the previously cached title (SetTitle will do both).
-      // See Chromium issue 96041.
-      pending_entry_->SetTitle(base::string16());
-
       pending_entry_->SetTransitionType(ui::PAGE_TRANSITION_RELOAD);
     }
 
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index 44ec4d70..9e3ff07e 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -1399,7 +1399,6 @@
   EXPECT_EQ(1U, navigation_entry_committed_counter_);
   navigation_entry_committed_counter_ = 0;
   ASSERT_TRUE(controller.GetVisibleEntry());
-  controller.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
   entry_id = controller.GetLastCommittedEntry()->GetUniqueID();
 
   controller.Reload(ReloadType::NORMAL, true);
@@ -1416,10 +1415,6 @@
   EXPECT_TRUE(controller.GetPendingEntry());
   EXPECT_FALSE(controller.CanGoBack());
   EXPECT_FALSE(controller.CanGoForward());
-  // Make sure the title has been cleared (will be redrawn just after reload).
-  // Avoids a stale cached title when the new page being reloaded has no title.
-  // See http://crbug.com/96041.
-  EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
 
   main_test_rfh()->PrepareForCommit();
   main_test_rfh()->SendNavigate(entry_id, false, url1);
@@ -1544,7 +1539,6 @@
   EXPECT_EQ(final_url, controller.GetVisibleEntry()->GetURL());
 
   // Reload using the original URL.
-  controller.GetVisibleEntry()->SetTitle(base::ASCIIToUTF16("Title"));
   controller.Reload(ReloadType::ORIGINAL_REQUEST_URL, false);
   EXPECT_EQ(0U, notifications.size());
 
@@ -1558,11 +1552,6 @@
   EXPECT_FALSE(controller.CanGoBack());
   EXPECT_FALSE(controller.CanGoForward());
 
-  // Make sure the title has been cleared (will be redrawn just after reload).
-  // Avoids a stale cached title when the new page being reloaded has no title.
-  // See http://crbug.com/96041.
-  EXPECT_TRUE(controller.GetVisibleEntry()->GetTitle().empty());
-
   // Send that the navigation has proceeded; say it got redirected again.
   main_test_rfh()->PrepareForCommitWithServerRedirect(final_url);
   main_test_rfh()->SendNavigate(entry_id, false, final_url);
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.cc b/content/browser/frame_host/render_widget_host_view_child_frame.cc
index 712a37d..9a8a794 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.cc
@@ -782,7 +782,7 @@
   renderer_compositor_frame_sink_->OnBeginFramePausedChanged(paused);
 }
 
-void RenderWidgetHostViewChildFrame::OnSurfaceCreated(
+void RenderWidgetHostViewChildFrame::OnFirstSurfaceActivation(
     const viz::SurfaceInfo& surface_info) {
   // TODO(fsamuel): Once surface synchronization is turned on, the fallback
   // surface should be set here.
diff --git a/content/browser/frame_host/render_widget_host_view_child_frame.h b/content/browser/frame_host/render_widget_host_view_child_frame.h
index 29abd318..f5a48b1c 100644
--- a/content/browser/frame_host/render_widget_host_view_child_frame.h
+++ b/content/browser/frame_host/render_widget_host_view_child_frame.h
@@ -184,7 +184,7 @@
   void OnBeginFramePausedChanged(bool paused) override;
 
   // viz::HostFrameSinkClient implementation.
-  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
 
   // Exposed for tests.
   bool IsChildFrameForTesting() const override;
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 172e1ae..4a6de58 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -938,7 +938,8 @@
                                                           frame_sink_id);
 }
 
-void CompositorImpl::OnSurfaceCreated(const viz::SurfaceInfo& surface_info) {
+void CompositorImpl::OnFirstSurfaceActivation(
+    const viz::SurfaceInfo& surface_info) {
   // TODO(fsamuel): Once surface synchronization is turned on, the fallback
   // surface should be set here.
 }
diff --git a/content/browser/renderer_host/compositor_impl_android.h b/content/browser/renderer_host/compositor_impl_android.h
index e601d4d..3e35d57 100644
--- a/content/browser/renderer_host/compositor_impl_android.h
+++ b/content/browser/renderer_host/compositor_impl_android.h
@@ -124,7 +124,7 @@
   void RemoveChildFrameSink(const viz::FrameSinkId& frame_sink_id) override;
 
   // viz::HostFrameSinkClient implementation.
-  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
 
   void SetVisible(bool visible);
   void CreateLayerTreeHost();
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index 40577a71..8c0c5a55 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -513,7 +513,7 @@
     renderer_compositor_frame_sink_->OnBeginFramePausedChanged(paused);
 }
 
-void DelegatedFrameHost::OnSurfaceCreated(
+void DelegatedFrameHost::OnFirstSurfaceActivation(
     const viz::SurfaceInfo& surface_info) {
   // TODO(fsamuel): Once surface synchronization is turned on, the fallback
   // surface should be set here.
diff --git a/content/browser/renderer_host/delegated_frame_host.h b/content/browser/renderer_host/delegated_frame_host.h
index 5b50b0b..b771339 100644
--- a/content/browser/renderer_host/delegated_frame_host.h
+++ b/content/browser/renderer_host/delegated_frame_host.h
@@ -118,7 +118,7 @@
   void OnBeginFramePausedChanged(bool paused) override;
 
   // viz::HostFrameSinkClient implementation.
-  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
 
   // Public interface exposed to RenderWidgetHostView.
 
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
index 3641d17..4f422e6 100644
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
@@ -284,7 +284,9 @@
 
   mojom::MediaStreamDispatcherPtr dispatcher =
       mojo::MakeProxy(std::move(dispatcher_info));
-  DCHECK(dispatcher.is_bound());
+  if (!dispatcher || !dispatcher.is_bound())
+    return;
+
   dispatcher->OnStreamGenerated(page_request_id, label, audio_devices,
                                 video_devices);
   dispatchers_[render_frame_id] = std::move(dispatcher);
@@ -299,7 +301,9 @@
 
   mojom::MediaStreamDispatcherPtr dispatcher =
       mojo::MakeProxy(std::move(dispatcher_info));
-  DCHECK(dispatcher.is_bound());
+  if (!dispatcher || !dispatcher.is_bound())
+    return;
+
   dispatcher->OnStreamGenerationFailed(page_request_id, result);
   dispatchers_[render_frame_id] = std::move(dispatcher);
 }
@@ -314,7 +318,9 @@
 
   mojom::MediaStreamDispatcherPtr dispatcher =
       mojo::MakeProxy(std::move(dispatcher_info));
-  DCHECK(dispatcher.is_bound());
+  if (!dispatcher || !dispatcher.is_bound())
+    return;
+
   dispatcher->OnDeviceOpened(page_request_id, label, video_device);
   dispatchers_[render_frame_id] = std::move(dispatcher);
 }
@@ -327,7 +333,9 @@
 
   mojom::MediaStreamDispatcherPtr dispatcher =
       mojo::MakeProxy(std::move(dispatcher_info));
-  DCHECK(dispatcher.is_bound());
+  if (!dispatcher || !dispatcher.is_bound())
+    return;
+
   dispatcher->OnDeviceOpenFailed(page_request_id);
   dispatchers_[render_frame_id] = std::move(dispatcher);
 }
@@ -341,7 +349,9 @@
 
   mojom::MediaStreamDispatcherPtr dispatcher =
       mojo::MakeProxy(std::move(dispatcher_info));
-  DCHECK(dispatcher.is_bound());
+  if (!dispatcher || !dispatcher.is_bound())
+    return;
+
   dispatcher->OnDeviceStopped(label, device);
   dispatchers_[render_frame_id] = std::move(dispatcher);
 }
diff --git a/content/browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc b/content/browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc
index ba00169d..ed5d7440 100644
--- a/content/browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc
+++ b/content/browser/renderer_host/offscreen_canvas_provider_impl_unittest.cc
@@ -55,7 +55,7 @@
 
  private:
   // blink::mojom::OffscreenCanvasSurfaceClient:
-  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override {
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override {
     last_surface_info_ = surface_info;
   }
 
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
index 233ba348..a23e2fc 100644
--- a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
+++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
@@ -58,13 +58,13 @@
   has_created_compositor_frame_sink_ = true;
 }
 
-void OffscreenCanvasSurfaceImpl::OnSurfaceCreated(
+void OffscreenCanvasSurfaceImpl::OnFirstSurfaceActivation(
     const viz::SurfaceInfo& surface_info) {
   DCHECK_EQ(surface_info.id().frame_sink_id(), frame_sink_id_);
 
   local_surface_id_ = surface_info.id().local_surface_id();
   if (client_)
-    client_->OnSurfaceCreated(surface_info);
+    client_->OnFirstSurfaceActivation(surface_info);
 }
 
 void OffscreenCanvasSurfaceImpl::Require(const viz::SurfaceId& surface_id,
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.h b/content/browser/renderer_host/offscreen_canvas_surface_impl.h
index 5498b76..7845e636 100644
--- a/content/browser/renderer_host/offscreen_canvas_surface_impl.h
+++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.h
@@ -53,7 +53,7 @@
       viz::mojom::CompositorFrameSinkRequest request);
 
   // viz::HostFrameSinkClient implementation.
-  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
 
   // blink::mojom::OffscreenCanvasSurface implementation.
   void Require(const viz::SurfaceId& surface_id,
diff --git a/content/browser/websockets/websocket_impl.cc b/content/browser/websockets/websocket_impl.cc
index 7019bc5..a6eba4d 100644
--- a/content/browser/websockets/websocket_impl.cc
+++ b/content/browser/websockets/websocket_impl.cc
@@ -514,14 +514,10 @@
 
   DCHECK(!channel_);
 
-  StoragePartition* partition = delegate_->GetStoragePartition();
-
   std::unique_ptr<net::WebSocketEventInterface> event_interface(
       new WebSocketEventHandler(this));
-  channel_.reset(
-      new net::WebSocketChannel(
-          std::move(event_interface),
-          partition->GetURLRequestContext()->GetURLRequestContext()));
+  channel_.reset(new net::WebSocketChannel(std::move(event_interface),
+                                           delegate_->GetURLRequestContext()));
 
   int64_t quota = pending_flow_control_quota_;
   pending_flow_control_quota_ = 0;
diff --git a/content/browser/websockets/websocket_impl.h b/content/browser/websockets/websocket_impl.h
index c6da1316..a64863c 100644
--- a/content/browser/websockets/websocket_impl.h
+++ b/content/browser/websockets/websocket_impl.h
@@ -25,11 +25,11 @@
 }  // namespace url
 
 namespace net {
+class URLRequestContext;
 class WebSocketChannel;
 }  // namespace net
 
 namespace content {
-class StoragePartition;
 
 // Host of net::WebSocketChannel.
 class CONTENT_EXPORT WebSocketImpl
@@ -39,7 +39,7 @@
    public:
     virtual ~Delegate() {}
     virtual int GetClientProcessId() = 0;
-    virtual StoragePartition* GetStoragePartition() = 0;
+    virtual net::URLRequestContext* GetURLRequestContext() = 0;
     virtual void OnReceivedResponseFromServer(WebSocketImpl* impl) = 0;
     virtual void OnLostConnectionToClient(WebSocketImpl* impl) = 0;
   };
diff --git a/content/browser/websockets/websocket_manager.cc b/content/browser/websockets/websocket_manager.cc
index 081c482..faf4c55 100644
--- a/content/browser/websockets/websocket_manager.cc
+++ b/content/browser/websockets/websocket_manager.cc
@@ -90,15 +90,14 @@
 WebSocketManager::WebSocketManager(int process_id,
                                    StoragePartition* storage_partition)
     : process_id_(process_id),
-      storage_partition_(storage_partition),
       num_pending_connections_(0),
       num_current_succeeded_connections_(0),
       num_previous_succeeded_connections_(0),
       num_current_failed_connections_(0),
       num_previous_failed_connections_(0),
       context_destroyed_(false) {
-  if (storage_partition_) {
-    url_request_context_getter_ = storage_partition_->GetURLRequestContext();
+  if (storage_partition) {
+    url_request_context_getter_ = storage_partition->GetURLRequestContext();
     // This unretained pointer is safe because we destruct a WebSocketManager
     // only via WebSocketManager::Handle::RenderProcessHostDestroyed which
     // posts a deletion task to the IO thread.
@@ -199,8 +198,8 @@
   return process_id_;
 }
 
-StoragePartition* WebSocketManager::GetStoragePartition() {
-  return storage_partition_;
+net::URLRequestContext* WebSocketManager::GetURLRequestContext() {
+  return url_request_context_getter_->GetURLRequestContext();
 }
 
 void WebSocketManager::OnReceivedResponseFromServer(WebSocketImpl* impl) {
diff --git a/content/browser/websockets/websocket_manager.h b/content/browser/websockets/websocket_manager.h
index 3e76c99..e42bc17 100644
--- a/content/browser/websockets/websocket_manager.h
+++ b/content/browser/websockets/websocket_manager.h
@@ -60,14 +60,13 @@
 
   // WebSocketImpl::Delegate methods:
   int GetClientProcessId() override;
-  StoragePartition* GetStoragePartition() override;
+  net::URLRequestContext* GetURLRequestContext() override;
   void OnReceivedResponseFromServer(WebSocketImpl* impl) override;
   void OnLostConnectionToClient(WebSocketImpl* impl) override;
 
   void ObserveURLRequestContextGetter();
 
   int process_id_;
-  StoragePartition* storage_partition_;
   scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
 
   std::set<WebSocketImpl*> impls_;
diff --git a/content/renderer/pepper/pepper_webplugin_impl.cc b/content/renderer/pepper/pepper_webplugin_impl.cc
index e714045..b620da7 100644
--- a/content/renderer/pepper/pepper_webplugin_impl.cc
+++ b/content/renderer/pepper/pepper_webplugin_impl.cc
@@ -310,6 +310,17 @@
     instance_->ReplaceSelection("");
     return true;
   }
+  if (name == "Paste") {
+    if (!CanEditText())
+      return false;
+
+    blink::WebString text =
+        blink::Platform::Current()->Clipboard()->ReadPlainText(
+            blink::WebClipboard::kBufferStandard);
+
+    instance_->ReplaceSelection(text.Utf8());
+    return true;
+  }
   return false;
 }
 
diff --git a/content/shell/browser/layout_test/blink_test_controller.cc b/content/shell/browser/layout_test/blink_test_controller.cc
index 8496853..a4365f0 100644
--- a/content/shell/browser/layout_test/blink_test_controller.cc
+++ b/content/shell/browser/layout_test/blink_test_controller.cc
@@ -531,7 +531,7 @@
                                         base::ProcessId plugin_pid) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   printer_->AddErrorMessage(
-      base::StringPrintf("#CRASHED - plugin (pid %d)", plugin_pid));
+      base::StringPrintf("#CRASHED - plugin (pid %" CrPRIdPid ")", plugin_pid));
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
       base::Bind(base::IgnoreResult(&BlinkTestController::DiscardMainWindow),
diff --git a/content/shell/browser/shell_browser_main_parts.cc b/content/shell/browser/shell_browser_main_parts.cc
index 4928be3..32524409 100644
--- a/content/shell/browser/shell_browser_main_parts.cc
+++ b/content/shell/browser/shell_browser_main_parts.cc
@@ -37,7 +37,7 @@
 
 #if defined(OS_ANDROID)
 #include "base/message_loop/message_loop.h"
-#include "components/crash/content/browser/crash_dump_manager_android.h"
+#include "components/crash/content/browser/child_process_crash_observer_android.h"
 #include "components/crash/content/browser/crash_dump_observer_android.h"
 #include "net/android/network_change_notifier_factory_android.h"
 #include "net/base/network_change_notifier.h"
@@ -174,7 +174,7 @@
         base::CommandLine::ForCurrentProcess()->GetSwitchValuePath(
             switches::kCrashDumpsDir);
     breakpad::CrashDumpObserver::GetInstance()->RegisterClient(
-        base::MakeUnique<breakpad::CrashDumpManager>(
+        base::MakeUnique<breakpad::ChildProcessCrashObserver>(
             crash_dumps_dir, kAndroidMinidumpDescriptor));
   }
 
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 33bbcd7..421fe84 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -52,7 +52,7 @@
 #if defined(OS_ANDROID)
 #include "base/android/apk_assets.h"
 #include "base/android/path_utils.h"
-#include "components/crash/content/browser/crash_dump_manager_android.h"
+#include "components/crash/content/browser/crash_dump_observer_android.h"
 #include "content/shell/android/shell_descriptors.h"
 #endif
 
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc
index e79f5225..3919f426 100644
--- a/content/test/test_render_view_host.cc
+++ b/content/test/test_render_view_host.cc
@@ -220,7 +220,7 @@
   return frame_sink_id_;
 }
 
-void TestRenderWidgetHostView::OnSurfaceCreated(
+void TestRenderWidgetHostView::OnFirstSurfaceActivation(
     const viz::SurfaceInfo& surface_info) {
   // TODO(fsamuel): Once surface synchronization is turned on, the fallback
   // surface should be set here.
diff --git a/content/test/test_render_view_host.h b/content/test/test_render_view_host.h
index 7a4d22c..1aa6354 100644
--- a/content/test/test_render_view_host.h
+++ b/content/test/test_render_view_host.h
@@ -132,7 +132,7 @@
   }
 
   // viz::HostFrameSinkClient implementation.
-  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
 
  protected:
   RenderWidgetHostImpl* rwh_;
diff --git a/device/test/usb_test_gadget_impl.cc b/device/test/usb_test_gadget_impl.cc
index 4c1c479..2324cd6 100644
--- a/device/test/usb_test_gadget_impl.cc
+++ b/device/test/usb_test_gadget_impl.cc
@@ -209,7 +209,8 @@
 
     static uint32_t next_session_id;
     base::ProcessId process_id = base::GetCurrentProcId();
-    session_id_ = base::StringPrintf("%d-%d", process_id, next_session_id++);
+    session_id_ =
+        base::StringPrintf("%" CrPRIdPid "-%d", process_id, next_session_id++);
 
     observer_.Add(usb_service_);
   }
diff --git a/extensions/browser/api/BUILD.gn b/extensions/browser/api/BUILD.gn
index f2a23a15..6f7f982 100644
--- a/extensions/browser/api/BUILD.gn
+++ b/extensions/browser/api/BUILD.gn
@@ -56,6 +56,7 @@
     "//extensions/browser/api/display_source",
     "//extensions/browser/api/dns",
     "//extensions/browser/api/document_scan",
+    "//extensions/browser/api/feedback_private",
     "//extensions/browser/api/file_handlers",
     "//extensions/browser/api/file_system",
     "//extensions/browser/api/hid",
diff --git a/extensions/browser/api/extensions_api_client.cc b/extensions/browser/api/extensions_api_client.cc
index 7f2c985..89a6b4ca 100644
--- a/extensions/browser/api/extensions_api_client.cc
+++ b/extensions/browser/api/extensions_api_client.cc
@@ -116,6 +116,10 @@
   return nullptr;
 }
 
+FeedbackPrivateDelegate* ExtensionsAPIClient::GetFeedbackPrivateDelegate() {
+  return nullptr;
+}
+
 #if defined(OS_CHROMEOS)
 NonNativeFileSystemDelegate*
 ExtensionsAPIClient::GetNonNativeFileSystemDelegate() {
diff --git a/extensions/browser/api/extensions_api_client.h b/extensions/browser/api/extensions_api_client.h
index 1bc0fdae..133a014 100644
--- a/extensions/browser/api/extensions_api_client.h
+++ b/extensions/browser/api/extensions_api_client.h
@@ -35,6 +35,7 @@
 class DevicePermissionsPrompt;
 class ExtensionOptionsGuest;
 class ExtensionOptionsGuestDelegate;
+class FeedbackPrivateDelegate;
 class FileSystemDelegate;
 class ManagementAPIDelegate;
 class MessagingDelegate;
@@ -145,6 +146,9 @@
   // Returns a delegate for embedder-specific extension messaging.
   virtual MessagingDelegate* GetMessagingDelegate();
 
+  // Returns a delegate for the chrome.feedbackPrivate API.
+  virtual FeedbackPrivateDelegate* GetFeedbackPrivateDelegate();
+
 #if defined(OS_CHROMEOS)
   // If supported by the embedder, returns a delegate for querying non-native
   // file systems.
diff --git a/extensions/browser/api/feedback_private/BUILD.gn b/extensions/browser/api/feedback_private/BUILD.gn
new file mode 100644
index 0000000..e35051bb
--- /dev/null
+++ b/extensions/browser/api/feedback_private/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//extensions/features/features.gni")
+
+assert(enable_extensions,
+       "Cannot depend on extensions because enable_extensions=false.")
+
+source_set("feedback_private") {
+  sources = [
+    "feedback_private_delegate.h",
+  ]
+}
diff --git a/extensions/browser/api/feedback_private/OWNERS b/extensions/browser/api/feedback_private/OWNERS
new file mode 100644
index 0000000..806a1ce
--- /dev/null
+++ b/extensions/browser/api/feedback_private/OWNERS
@@ -0,0 +1,4 @@
+afakhry@chromium.org
+rkc@chromium.org
+
+# COMPONENT: Platform>Apps>Feedback
diff --git a/extensions/browser/api/feedback_private/feedback_private_delegate.h b/extensions/browser/api/feedback_private/feedback_private_delegate.h
new file mode 100644
index 0000000..feb1f066
--- /dev/null
+++ b/extensions/browser/api/feedback_private/feedback_private_delegate.h
@@ -0,0 +1,36 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_BROWSER_API_FEEDBACK_PRIVATE_FEEDBACK_PRIVATE_DELEGATE_H_
+#define EXTENSIONS_BROWSER_API_FEEDBACK_PRIVATE_FEEDBACK_PRIVATE_DELEGATE_H_
+
+#include <memory>
+
+namespace base {
+class DictionaryValue;
+}  // namespace base
+
+namespace content {
+class BrowserContext;
+}  // namespace content
+
+namespace extensions {
+
+// Delegate class for embedder-specific chrome.feedbackPrivate behavior.
+class FeedbackPrivateDelegate {
+ public:
+  virtual ~FeedbackPrivateDelegate() = default;
+
+  // Returns a dictionary of localized strings for the feedback component
+  // extension.
+  // Set |from_crash| to customize strings when the feedback UI was initiated
+  // from a "sad tab" crash.
+  virtual std::unique_ptr<base::DictionaryValue> GetStrings(
+      content::BrowserContext* browser_context,
+      bool from_crash) const = 0;
+};
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_API_FEEDBACK_PRIVATE_FEEDBACK_PRIVATE_DELEGATE_H_
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index e993a1dc..b4f08d75 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1748,9 +1748,12 @@
 void GL_APIENTRY GLES2OverlayPromotionHintCHROMIUM(GLuint texture,
                                                    GLboolean promotion_hint,
                                                    GLint display_x,
-                                                   GLint display_y) {
-  gles2::GetGLContext()->OverlayPromotionHintCHROMIUM(texture, promotion_hint,
-                                                      display_x, display_y);
+                                                   GLint display_y,
+                                                   GLint display_width,
+                                                   GLint display_height) {
+  gles2::GetGLContext()->OverlayPromotionHintCHROMIUM(
+      texture, promotion_hint, display_x, display_y, display_width,
+      display_height);
 }
 void GL_APIENTRY GLES2SwapBuffersWithBoundsCHROMIUM(GLsizei count,
                                                     const GLint* rects) {
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index d01ff052..adf0baa 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -3225,11 +3225,14 @@
 void OverlayPromotionHintCHROMIUM(GLuint texture,
                                   GLboolean promotion_hint,
                                   GLint display_x,
-                                  GLint display_y) {
+                                  GLint display_y,
+                                  GLint display_width,
+                                  GLint display_height) {
   gles2::cmds::OverlayPromotionHintCHROMIUM* c =
       GetCmdSpace<gles2::cmds::OverlayPromotionHintCHROMIUM>();
   if (c) {
-    c->Init(texture, promotion_hint, display_x, display_y);
+    c->Init(texture, promotion_hint, display_x, display_y, display_width,
+            display_height);
   }
 }
 
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 83c311a1..220e26d 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -1225,7 +1225,9 @@
 void OverlayPromotionHintCHROMIUM(GLuint texture,
                                   GLboolean promotion_hint,
                                   GLint display_x,
-                                  GLint display_y) override;
+                                  GLint display_y,
+                                  GLint display_width,
+                                  GLint display_height) override;
 
 void SwapBuffersWithBoundsCHROMIUM(GLsizei count, const GLint* rects) override;
 
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index 2be26ed..055575a 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -3512,14 +3512,18 @@
 void GLES2Implementation::OverlayPromotionHintCHROMIUM(GLuint texture,
                                                        GLboolean promotion_hint,
                                                        GLint display_x,
-                                                       GLint display_y) {
+                                                       GLint display_y,
+                                                       GLint display_width,
+                                                       GLint display_height) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glOverlayPromotionHintCHROMIUM("
                      << texture << ", "
                      << GLES2Util::GetStringBool(promotion_hint) << ", "
-                     << display_x << ", " << display_y << ")");
+                     << display_x << ", " << display_y << ", " << display_width
+                     << ", " << display_height << ")");
   helper_->OverlayPromotionHintCHROMIUM(texture, promotion_hint, display_x,
-                                        display_y);
+                                        display_y, display_width,
+                                        display_height);
   CheckGLError();
 }
 
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index abb8788..6c2a551 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -909,7 +909,9 @@
 virtual void OverlayPromotionHintCHROMIUM(GLuint texture,
                                           GLboolean promotion_hint,
                                           GLint display_x,
-                                          GLint display_y) = 0;
+                                          GLint display_y,
+                                          GLint display_width,
+                                          GLint display_height) = 0;
 virtual void SwapBuffersWithBoundsCHROMIUM(GLsizei count,
                                            const GLint* rects) = 0;
 virtual void SetDrawRectangleCHROMIUM(GLint x,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 512aa16..dbe13d1 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -883,7 +883,9 @@
 void OverlayPromotionHintCHROMIUM(GLuint texture,
                                   GLboolean promotion_hint,
                                   GLint display_x,
-                                  GLint display_y) override;
+                                  GLint display_y,
+                                  GLint display_width,
+                                  GLint display_height) override;
 void SwapBuffersWithBoundsCHROMIUM(GLsizei count, const GLint* rects) override;
 void SetDrawRectangleCHROMIUM(GLint x,
                               GLint y,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index fc8d4f7..abdbd078 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -1188,7 +1188,9 @@
     GLuint /* texture */,
     GLboolean /* promotion_hint */,
     GLint /* display_x */,
-    GLint /* display_y */) {}
+    GLint /* display_y */,
+    GLint /* display_width */,
+    GLint /* display_height */) {}
 void GLES2InterfaceStub::SwapBuffersWithBoundsCHROMIUM(
     GLsizei /* count */,
     const GLint* /* rects */) {}
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index b529546..bdcc2ef 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -883,7 +883,9 @@
 void OverlayPromotionHintCHROMIUM(GLuint texture,
                                   GLboolean promotion_hint,
                                   GLint display_x,
-                                  GLint display_y) override;
+                                  GLint display_y,
+                                  GLint display_width,
+                                  GLint display_height) override;
 void SwapBuffersWithBoundsCHROMIUM(GLsizei count, const GLint* rects) override;
 void SetDrawRectangleCHROMIUM(GLint x,
                               GLint y,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index 12d3986..b0cf7a8b 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -2533,11 +2533,13 @@
     GLuint texture,
     GLboolean promotion_hint,
     GLint display_x,
-    GLint display_y) {
+    GLint display_y,
+    GLint display_width,
+    GLint display_height) {
   TRACE_EVENT_BINARY_EFFICIENT0("gpu",
                                 "GLES2Trace::OverlayPromotionHintCHROMIUM");
   gl_->OverlayPromotionHintCHROMIUM(texture, promotion_hint, display_x,
-                                    display_y);
+                                    display_y, display_width, display_height);
 }
 
 void GLES2TraceImplementation::SwapBuffersWithBoundsCHROMIUM(
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 56890d3..d285480d 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -364,7 +364,7 @@
 
 // Extension CHROMIUM_stream_texture_matrix
 GL_APICALL void         GL_APIENTRY glUniformMatrix4fvStreamTextureMatrixCHROMIUM (GLintUniformLocation location, GLbooleanFalseOnly transpose, const GLfloat* transform);
-GL_APICALL void         GL_APIENTRY glOverlayPromotionHintCHROMIUM (GLidBindTexture texture, GLboolean promotion_hint, GLint display_x, GLint display_y);
+GL_APICALL void         GL_APIENTRY glOverlayPromotionHintCHROMIUM (GLidBindTexture texture, GLboolean promotion_hint, GLint display_x, GLint display_y, GLint display_width, GLint display_height);
 
 GL_APICALL void         GL_APIENTRY glSwapBuffersWithBoundsCHROMIUM (GLsizei count, const GLint* rects);
 
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index b01d1fa..8ea10c5 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -15846,21 +15846,28 @@
   void Init(GLuint _texture,
             GLboolean _promotion_hint,
             GLint _display_x,
-            GLint _display_y) {
+            GLint _display_y,
+            GLint _display_width,
+            GLint _display_height) {
     SetHeader();
     texture = _texture;
     promotion_hint = _promotion_hint;
     display_x = _display_x;
     display_y = _display_y;
+    display_width = _display_width;
+    display_height = _display_height;
   }
 
   void* Set(void* cmd,
             GLuint _texture,
             GLboolean _promotion_hint,
             GLint _display_x,
-            GLint _display_y) {
+            GLint _display_y,
+            GLint _display_width,
+            GLint _display_height) {
     static_cast<ValueType*>(cmd)->Init(_texture, _promotion_hint, _display_x,
-                                       _display_y);
+                                       _display_y, _display_width,
+                                       _display_height);
     return NextCmdAddress<ValueType>(cmd);
   }
 
@@ -15869,10 +15876,12 @@
   uint32_t promotion_hint;
   int32_t display_x;
   int32_t display_y;
+  int32_t display_width;
+  int32_t display_height;
 };
 
-static_assert(sizeof(OverlayPromotionHintCHROMIUM) == 20,
-              "size of OverlayPromotionHintCHROMIUM should be 20");
+static_assert(sizeof(OverlayPromotionHintCHROMIUM) == 28,
+              "size of OverlayPromotionHintCHROMIUM should be 28");
 static_assert(offsetof(OverlayPromotionHintCHROMIUM, header) == 0,
               "offset of OverlayPromotionHintCHROMIUM header should be 0");
 static_assert(offsetof(OverlayPromotionHintCHROMIUM, texture) == 4,
@@ -15884,6 +15893,12 @@
               "offset of OverlayPromotionHintCHROMIUM display_x should be 12");
 static_assert(offsetof(OverlayPromotionHintCHROMIUM, display_y) == 16,
               "offset of OverlayPromotionHintCHROMIUM display_y should be 16");
+static_assert(
+    offsetof(OverlayPromotionHintCHROMIUM, display_width) == 20,
+    "offset of OverlayPromotionHintCHROMIUM display_width should be 20");
+static_assert(
+    offsetof(OverlayPromotionHintCHROMIUM, display_height) == 24,
+    "offset of OverlayPromotionHintCHROMIUM display_height should be 24");
 
 struct SwapBuffersWithBoundsCHROMIUMImmediate {
   typedef SwapBuffersWithBoundsCHROMIUMImmediate ValueType;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index 3a06ce1e..8e1d11c 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -5297,7 +5297,8 @@
       *GetBufferAs<cmds::OverlayPromotionHintCHROMIUM>();
   void* next_cmd =
       cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLboolean>(12),
-              static_cast<GLint>(13), static_cast<GLint>(14));
+              static_cast<GLint>(13), static_cast<GLint>(14),
+              static_cast<GLint>(15), static_cast<GLint>(16));
   EXPECT_EQ(static_cast<uint32_t>(cmds::OverlayPromotionHintCHROMIUM::kCmdId),
             cmd.header.command);
   EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
@@ -5305,6 +5306,8 @@
   EXPECT_EQ(static_cast<GLboolean>(12), cmd.promotion_hint);
   EXPECT_EQ(static_cast<GLint>(13), cmd.display_x);
   EXPECT_EQ(static_cast<GLint>(14), cmd.display_y);
+  EXPECT_EQ(static_cast<GLint>(15), cmd.display_width);
+  EXPECT_EQ(static_cast<GLint>(16), cmd.display_height);
   CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
 }
 
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
index 246090b1..b6a91d8 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -1915,6 +1915,18 @@
         0x8AF0, "GL_TEXTURE_FILTERING_HINT_CHROMIUM",
     },
     {
+        0x8AF1, "GL_COLOR_SPACE_UNSPECIFIED_CHROMIUM",
+    },
+    {
+        0x8AF2, "GL_COLOR_SPACE_SCRGB_LINEAR_CHROMIUM",
+    },
+    {
+        0x8AF3, "GL_COLOR_SPACE_SRGB_CHROMIUM",
+    },
+    {
+        0x8AF4, "GL_COLOR_SPACE_DISPLAY_P3_CHROMIUM",
+    },
+    {
         0x8B30, "GL_FRAGMENT_SHADER",
     },
     {
diff --git a/gpu/command_buffer/service/gl_stream_texture_image.h b/gpu/command_buffer/service/gl_stream_texture_image.h
index 5ab4f75..b040da8 100644
--- a/gpu/command_buffer/service/gl_stream_texture_image.h
+++ b/gpu/command_buffer/service/gl_stream_texture_image.h
@@ -27,7 +27,9 @@
 
   virtual void NotifyPromotionHint(bool promotion_hint,
                                    int display_x,
-                                   int display_y) {}
+                                   int display_y,
+                                   int display_width,
+                                   int display_height) {}
 
  protected:
   ~GLStreamTextureImage() override {}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 0df37b0..f525b24 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1711,7 +1711,9 @@
   void DoOverlayPromotionHintCHROMIUM(GLuint client_id,
                                       GLboolean promotion_hint,
                                       GLint display_x,
-                                      GLint display_y);
+                                      GLint display_y,
+                                      GLint display_width,
+                                      GLint display_height);
 
   // Wrapper for glSetDrawRectangleCHROMIUM
   void DoSetDrawRectangleCHROMIUM(GLint x, GLint y, GLint width, GLint height);
@@ -8825,7 +8827,9 @@
 void GLES2DecoderImpl::DoOverlayPromotionHintCHROMIUM(GLuint client_id,
                                                       GLboolean promotion_hint,
                                                       GLint display_x,
-                                                      GLint display_y) {
+                                                      GLint display_y,
+                                                      GLint display_width,
+                                                      GLint display_height) {
   if (client_id == 0)
     return;
 
@@ -8844,7 +8848,8 @@
     return;
   }
 
-  image->NotifyPromotionHint(promotion_hint != GL_FALSE, display_x, display_y);
+  image->NotifyPromotionHint(promotion_hint != GL_FALSE, display_x, display_y,
+                             display_width, display_height);
 }
 
 void GLES2DecoderImpl::DoSetDrawRectangleCHROMIUM(GLint x,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index fef99fa..8cd6cd21 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -5129,7 +5129,10 @@
   GLboolean promotion_hint = static_cast<GLboolean>(c.promotion_hint);
   GLint display_x = static_cast<GLint>(c.display_x);
   GLint display_y = static_cast<GLint>(c.display_y);
-  DoOverlayPromotionHintCHROMIUM(texture, promotion_hint, display_x, display_y);
+  GLint display_width = static_cast<GLint>(c.display_width);
+  GLint display_height = static_cast<GLint>(c.display_height);
+  DoOverlayPromotionHintCHROMIUM(texture, promotion_hint, display_x, display_y,
+                                 display_width, display_height);
   return error::kNoError;
 }
 
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
index 17d0a0a..9c4d670 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doer_prototypes.h
@@ -980,7 +980,9 @@
 error::Error DoOverlayPromotionHintCHROMIUM(GLuint texture,
                                             GLboolean promotion_hint,
                                             GLint display_x,
-                                            GLint display_y);
+                                            GLint display_y,
+                                            GLint display_width,
+                                            GLint display_height);
 error::Error DoSetDrawRectangleCHROMIUM(GLint x,
                                         GLint y,
                                         GLint width,
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
index e6994df..bd0656e 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_doers.cc
@@ -4216,7 +4216,9 @@
     GLuint texture,
     GLboolean promotion_hint,
     GLint display_x,
-    GLint display_y) {
+    GLint display_y,
+    GLint display_width,
+    GLint display_height) {
   NOTIMPLEMENTED();
   return error::kNoError;
 }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
index 8a2d17d..2256a806 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough_handlers_autogen.cc
@@ -4336,8 +4336,11 @@
   GLboolean promotion_hint = static_cast<GLboolean>(c.promotion_hint);
   GLint display_x = static_cast<GLint>(c.display_x);
   GLint display_y = static_cast<GLint>(c.display_y);
-  error::Error error = DoOverlayPromotionHintCHROMIUM(texture, promotion_hint,
-                                                      display_x, display_y);
+  GLint display_width = static_cast<GLint>(c.display_width);
+  GLint display_height = static_cast<GLint>(c.display_height);
+  error::Error error =
+      DoOverlayPromotionHintCHROMIUM(texture, promotion_hint, display_x,
+                                     display_y, display_width, display_height);
   if (error != error::kNoError) {
     return error;
   }
diff --git a/headless/BUILD.gn b/headless/BUILD.gn
index 0b15edd..b27bf3b 100644
--- a/headless/BUILD.gn
+++ b/headless/BUILD.gn
@@ -223,7 +223,7 @@
   extra_deps = [ ":gen_devtools_client_api" ]
 }
 
-if (headless_fontconfig_utils && !is_fuchsia) {
+if (headless_fontconfig_utils) {
   static_library("headless_fontconfig_utils") {
     sources = [
       "public/util/fontconfig.cc",
diff --git a/headless/public/util/generic_url_request_job.cc b/headless/public/util/generic_url_request_job.cc
index fbf5490..73162804 100644
--- a/headless/public/util/generic_url_request_job.cc
+++ b/headless/public/util/generic_url_request_job.cc
@@ -280,6 +280,13 @@
   return true;
 }
 
+namespace {
+void CompletionCallback(int* dest, base::Closure* quit_closure, int value) {
+  *dest = value;
+  quit_closure->Run();
+}
+}  // namespace
+
 std::string GenericURLRequestJob::GetPostData() const {
   if (!request_->has_upload())
     return "";
@@ -292,11 +299,80 @@
     return "";
 
   DCHECK_EQ(1u, stream->GetElementReaders()->size());
-  const net::UploadBytesElementReader* reader =
-      (*stream->GetElementReaders())[0]->AsBytesReader();
-  if (!reader)
-    return "";
-  return std::string(reader->bytes(), reader->length());
+  const std::unique_ptr<net::UploadElementReader>& reader =
+      (*stream->GetElementReaders())[0];
+  // If |reader| is actually an UploadBytesElementReader we can get the data
+  // directly (should be faster than the horrible stuff below).
+  const net::UploadBytesElementReader* bytes_reader = reader->AsBytesReader();
+  if (bytes_reader)
+    return std::string(bytes_reader->bytes(), bytes_reader->length());
+
+  // TODO(alexclarke): Consider changing the interface of
+  // GenericURLRequestJob::GetPostData to use a callback which would let us
+  // avoid the nested run loops below.
+
+  // Initialize the reader.
+  {
+    base::Closure quit_closure;
+    int init_result = reader->Init(
+        base::Bind(&CompletionCallback, &init_result, &quit_closure));
+    if (init_result == net::ERR_IO_PENDING) {
+      base::RunLoop nested_run_loop;
+      base::MessageLoop::ScopedNestableTaskAllower allow_nested(
+          base::MessageLoop::current());
+      quit_closure = nested_run_loop.QuitClosure();
+      nested_run_loop.Run();
+    }
+
+    if (init_result != net::OK)
+      return "";
+  }
+
+  // Read the POST bytes.
+  uint64_t content_length = reader->GetContentLength();
+  std::string post_data;
+  post_data.reserve(content_length);
+  const size_t block_size = 1024;
+  scoped_refptr<net::IOBuffer> read_buffer(new net::IOBuffer(block_size));
+  while (post_data.size() < content_length) {
+    base::Closure quit_closure;
+    int bytes_read = reader->Read(
+        read_buffer.get(), block_size,
+        base::Bind(&CompletionCallback, &bytes_read, &quit_closure));
+
+    if (bytes_read == net::ERR_IO_PENDING) {
+      base::MessageLoop::ScopedNestableTaskAllower allow_nested(
+          base::MessageLoop::current());
+      base::RunLoop nested_run_loop;
+      quit_closure = nested_run_loop.QuitClosure();
+      nested_run_loop.Run();
+    }
+
+    // Bail out if an error occured.
+    if (bytes_read < 0)
+      return "";
+
+    post_data.append(read_buffer->data(), bytes_read);
+  }
+
+  return post_data;
+}
+
+uint64_t GenericURLRequestJob::GetPostDataSize() const {
+  if (!request_->has_upload())
+    return 0;
+
+  const net::UploadDataStream* stream = request_->get_upload();
+  if (!stream->GetElementReaders())
+    return 0;
+
+  if (stream->GetElementReaders()->size() == 0)
+    return 0;
+
+  DCHECK_EQ(1u, stream->GetElementReaders()->size());
+  const std::unique_ptr<net::UploadElementReader>& reader =
+      (*stream->GetElementReaders())[0];
+  return reader->GetContentLength();
 }
 
 const Request* GenericURLRequestJob::GetRequest() const {
diff --git a/headless/public/util/generic_url_request_job.h b/headless/public/util/generic_url_request_job.h
index 3a66ca6..59be8b8 100644
--- a/headless/public/util/generic_url_request_job.h
+++ b/headless/public/util/generic_url_request_job.h
@@ -51,6 +51,9 @@
   // Gets the POST data, if any, from the net::URLRequest.
   virtual std::string GetPostData() const = 0;
 
+  // Returns the size of the POST data, if any, from the net::URLRequest.
+  virtual uint64_t GetPostDataSize() const = 0;
+
   enum class ResourceType {
     MAIN_FRAME = 0,
     SUB_FRAME = 1,
@@ -192,6 +195,7 @@
   int GetFrameTreeNodeId() const override;
   std::string GetDevToolsAgentHostId() const override;
   std::string GetPostData() const override;
+  uint64_t GetPostDataSize() const override;
   ResourceType GetResourceType() const override;
   bool IsAsync() const override;
 
diff --git a/headless/public/util/generic_url_request_job_test.cc b/headless/public/util/generic_url_request_job_test.cc
index d2d9879..e14a20d 100644
--- a/headless/public/util/generic_url_request_job_test.cc
+++ b/headless/public/util/generic_url_request_job_test.cc
@@ -664,16 +664,107 @@
       })";
 
   std::string post_data;
+  uint64_t post_data_size;
   job_delegate_.SetPolicy(base::Bind(
-      [](std::string* post_data, PendingRequest* pending_request) {
+      [](std::string* post_data, uint64_t* post_data_size,
+         PendingRequest* pending_request) {
         *post_data = pending_request->GetRequest()->GetPostData();
+        *post_data_size = pending_request->GetRequest()->GetPostDataSize();
         pending_request->AllowRequest();
       },
-      &post_data));
+      &post_data, &post_data_size));
 
   CreateAndCompletePostJob(GURL("https://example.com"), "payload", reply);
 
   EXPECT_EQ("payload", post_data);
+  EXPECT_EQ(post_data_size, post_data.size());
+}
+
+namespace {
+class ByteAtATimeUploadElementReader : public net::UploadElementReader {
+ public:
+  explicit ByteAtATimeUploadElementReader(const std::string& content)
+      : content_(content) {}
+
+  // net::UploadElementReader implementation:
+  int Init(const net::CompletionCallback& callback) override {
+    offset_ = 0;
+    return net::OK;
+  }
+
+  uint64_t GetContentLength() const override { return content_.size(); }
+
+  uint64_t BytesRemaining() const override { return content_.size() - offset_; }
+
+  bool IsInMemory() const override { return false; }
+
+  int Read(net::IOBuffer* buf,
+           int buf_length,
+           const net::CompletionCallback& callback) override {
+    if (!BytesRemaining())
+      return net::OK;
+
+    base::MessageLoop::current()->task_runner()->PostTask(
+        FROM_HERE, base::Bind(&ByteAtATimeUploadElementReader::ReadImpl,
+                              base::Unretained(this), make_scoped_refptr(buf),
+                              buf_length, callback));
+    return net::ERR_IO_PENDING;
+  }
+
+ private:
+  void ReadImpl(scoped_refptr<net::IOBuffer> buf,
+                int buf_length,
+                const net::CompletionCallback callback) {
+    if (BytesRemaining()) {
+      *buf->data() = content_[offset_++];
+      callback.Run(1u);
+    } else {
+      callback.Run(0u);
+    }
+  }
+
+  std::string content_;
+  uint64_t offset_ = 0;
+};
+}  // namespace
+
+TEST_F(GenericURLRequestJobTest, GetPostDataAsync) {
+  std::string json_reply = R"(
+      {
+        "url": "https://example.com",
+        "http_response_code": 200,
+        "data": "Reply",
+        "headers": {
+          "Content-Type": "text/html; charset=UTF-8"
+        }
+      })";
+
+  std::string post_data;
+  uint64_t post_data_size;
+  job_delegate_.SetPolicy(base::Bind(
+      [](std::string* post_data, uint64_t* post_data_size,
+         PendingRequest* pending_request) {
+        *post_data = pending_request->GetRequest()->GetPostData();
+        *post_data_size = pending_request->GetRequest()->GetPostDataSize();
+        pending_request->AllowRequest();
+      },
+      &post_data, &post_data_size));
+
+  GURL url("https://example.com");
+  std::unique_ptr<net::URLRequest> request(url_request_context_.CreateRequest(
+      url, net::DEFAULT_PRIORITY, &request_delegate_,
+      TRAFFIC_ANNOTATION_FOR_TESTS));
+  request->set_method("POST");
+
+  json_fetch_reply_map_[url.spec()] = json_reply;
+
+  request->set_upload(net::ElementsUploadDataStream::CreateWithReader(
+      base::MakeUnique<ByteAtATimeUploadElementReader>("payload"), 0));
+  request->Start();
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_EQ("payload", post_data);
+  EXPECT_EQ(post_data_size, post_data.size());
 }
 
 }  // namespace headless
diff --git a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
index 62ba5f74..876dbe43 100644
--- a/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
+++ b/ios/chrome/browser/ui/authentication/chrome_signin_view_controller.mm
@@ -65,9 +65,6 @@
   LAYOUT_COMPACT,
 };
 
-// Alpha threshold upon which a view is considered hidden.
-const CGFloat kHiddenAlphaThreshold = 0.1;
-
 // Minimum duration of the pending state in milliseconds.
 const int64_t kMinimunPendingStateDurationMs = 300;
 
@@ -109,20 +106,6 @@
   DONE_STATE,
 };
 
-// Fades in |button| on screen if not already visible.
-void ShowButton(UIButton* button) {
-  if (button.alpha > kHiddenAlphaThreshold)
-    return;
-  button.alpha = 1.0;
-}
-
-// Fades out |button| on screen if not already hidden.
-void HideButton(UIButton* button) {
-  if (button.alpha < kHiddenAlphaThreshold)
-    return;
-  button.alpha = 0.0;
-}
-
 }  // namespace
 
 @interface ChromeSigninViewController ()<
@@ -504,14 +487,22 @@
   [_secondaryButton setTitle:self.skipSigninButtonTitle
                     forState:UIControlStateNormal];
   [self.view setNeedsLayout];
-
-  HideButton(_primaryButton);
-  HideButton(_secondaryButton);
-  [UIView animateWithDuration:kAnimationDuration
-                   animations:^{
-                     ShowButton(_primaryButton);
-                     ShowButton(_secondaryButton);
-                   }];
+  _primaryButton.hidden = YES;
+  _secondaryButton.hidden = YES;
+  [UIView transitionWithView:_primaryButton
+                    duration:kAnimationDuration
+                     options:UIViewAnimationOptionTransitionCrossDissolve
+                  animations:^{
+                    _primaryButton.hidden = NO;
+                  }
+                  completion:nil];
+  [UIView transitionWithView:_secondaryButton
+                    duration:kAnimationDuration
+                     options:UIViewAnimationOptionTransitionCrossDissolve
+                  animations:^{
+                    _secondaryButton.hidden = NO;
+                  }
+                  completion:nil];
 }
 
 - (void)reloadIdentityPickerState {
@@ -522,10 +513,18 @@
 }
 
 - (void)leaveIdentityPickerState:(AuthenticationState)nextState {
-  [UIView animateWithDuration:kAnimationDuration
+  [UIView transitionWithView:_primaryButton
+                    duration:kAnimationDuration
+                     options:UIViewAnimationOptionTransitionCrossDissolve
+                  animations:^{
+                    _primaryButton.hidden = YES;
+                  }
+                  completion:nil];
+  [UIView transitionWithView:_secondaryButton
+      duration:kAnimationDuration
+      options:UIViewAnimationOptionTransitionCrossDissolve
       animations:^{
-        HideButton(_primaryButton);
-        HideButton(_secondaryButton);
+        _secondaryButton.hidden = YES;
       }
       completion:^(BOOL finished) {
         [_accountSelectorVC willMoveToParentViewController:nil];
@@ -544,7 +543,7 @@
   [self.view setNeedsLayout];
 
   _pendingStateTimer.reset(new base::ElapsedTimer());
-  ShowButton(_secondaryButton);
+  _secondaryButton.hidden = NO;
   [_activityIndicator startAnimating];
 
   [self signIntoIdentity:self.selectedIdentity];
@@ -621,15 +620,22 @@
   [_secondaryButton setTitle:secondaryButtonTitle
                     forState:UIControlStateNormal];
   [self.view setNeedsLayout];
-
-  HideButton(_primaryButton);
-  HideButton(_secondaryButton);
-  [UIView animateWithDuration:kAnimationDuration
-                   animations:^{
-                     ShowButton(_primaryButton);
-                     ShowButton(_secondaryButton);
-                   }
-                   completion:nil];
+  _primaryButton.hidden = YES;
+  _secondaryButton.hidden = YES;
+  [UIView transitionWithView:_primaryButton
+                    duration:kAnimationDuration
+                     options:UIViewAnimationOptionTransitionCrossDissolve
+                  animations:^{
+                    _primaryButton.hidden = NO;
+                  }
+                  completion:nil];
+  [UIView transitionWithView:_secondaryButton
+                    duration:kAnimationDuration
+                     options:UIViewAnimationOptionTransitionCrossDissolve
+                  animations:^{
+                    _secondaryButton.hidden = NO;
+                  }
+                  completion:nil];
 }
 
 - (void)reloadIdentitySelectedState {
@@ -648,8 +654,8 @@
   [_confirmationVC removeFromParentViewController];
   _confirmationVC = nil;
   [self setPrimaryButtonStyling:_primaryButton];
-  HideButton(_primaryButton);
-  HideButton(_secondaryButton);
+  _primaryButton.hidden = YES;
+  _secondaryButton.hidden = YES;
   [self undoSignIn];
   [self enterState:nextState];
 }
@@ -665,7 +671,7 @@
   [_primaryButton addTarget:self
                      action:@selector(onPrimaryButtonPressed:)
            forControlEvents:UIControlEventTouchUpInside];
-  HideButton(_primaryButton);
+  _primaryButton.hidden = YES;
   [self.view addSubview:_primaryButton];
 
   _secondaryButton = [[MDCFlatButton alloc] init];
@@ -674,7 +680,7 @@
                        action:@selector(onSecondaryButtonPressed:)
              forControlEvents:UIControlEventTouchUpInside];
   [_secondaryButton setAccessibilityIdentifier:@"ic_close"];
-  HideButton(_secondaryButton);
+  _secondaryButton.hidden = YES;
   [self.view addSubview:_secondaryButton];
 
   _activityIndicator = [[MDCActivityIndicator alloc] initWithFrame:CGRectZero];
diff --git a/ios/chrome/browser/ui/history/history_ui_egtest.mm b/ios/chrome/browser/ui/history/history_ui_egtest.mm
index 2723762a..51b4feed 100644
--- a/ios/chrome/browser/ui/history/history_ui_egtest.mm
+++ b/ios/chrome/browser/ui/history/history_ui_egtest.mm
@@ -133,36 +133,6 @@
 id<GREYMatcher> ConfirmClearBrowsingDataButton() {
   return ButtonWithAccessibilityLabelId(IDS_IOS_CONFIRM_CLEAR_BUTTON);
 }
-
-// Sign in with a mock identity.
-void MockSignIn() {
-  // Set up a mock identity.
-  ChromeIdentity* identity =
-      [FakeChromeIdentity identityWithEmail:@"foo@gmail.com"
-                                     gaiaID:@"fooID"
-                                       name:@"Fake Foo"];
-  ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
-      identity);
-
-  [ChromeEarlGreyUI openSettingsMenu];
-  [[EarlGrey
-      selectElementWithMatcher:grey_accessibilityID(kSettingsSignInCellId)]
-      performAction:grey_tap()];
-  [[EarlGrey
-      selectElementWithMatcher:chrome_test_util::ButtonWithAccessibilityLabel(
-                                   identity.userEmail)]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:
-                 chrome_test_util::ButtonWithAccessibilityLabelId(
-                     IDS_IOS_ACCOUNT_CONSISTENCY_SETUP_SIGNIN_BUTTON)]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:
-                 chrome_test_util::ButtonWithAccessibilityLabelId(
-                     IDS_IOS_ACCOUNT_CONSISTENCY_CONFIRMATION_OK_BUTTON)]
-      performAction:grey_tap()];
-  [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
-      performAction:grey_tap()];
-}
 }  // namespace
 
 // History UI tests.
@@ -276,12 +246,6 @@
 // in, and that tapping on the link in the message opens a new tab with the sync
 // help page.
 - (void)testHistoryEntriesStatusCell {
-  // TODO(crbug.com/747445): Re-enable this test on iOS 11 once the sign in UI
-  // is fixed.
-  if (base::ios::IsRunningOnIOS11OrLater()) {
-    EARL_GREY_TEST_DISABLED(@"Disabled on iOS 11.");
-  }
-
   [self loadTestURLs];
   [self openHistoryPanel];
   // Assert that no message is shown when the user is not signed in.
@@ -293,9 +257,21 @@
   [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
       performAction:grey_tap()];
 
-  // Sign in and assert that the page indicates what type of history entries
-  // are shown.
-  MockSignIn();
+  // Mock sign in and assert that the page indicates what type of history
+  // entries are shown.
+  ChromeIdentity* identity =
+      [FakeChromeIdentity identityWithEmail:@"foo@gmail.com"
+                                     gaiaID:@"fooID"
+                                       name:@"Fake Foo"];
+  ios::FakeChromeIdentityService::GetInstanceFromChromeProvider()->AddIdentity(
+      identity);
+  [ChromeEarlGreyUI openSettingsMenu];
+  [ChromeEarlGreyUI tapSettingsMenuButton:chrome_test_util::SignInMenuButton()];
+  [ChromeEarlGreyUI signInToIdentityByEmail:identity.userEmail];
+  [ChromeEarlGreyUI confirmSigninConfirmationDialog];
+  [[EarlGrey selectElementWithMatcher:NavigationBarDoneButton()]
+      performAction:grey_tap()];
+
   [self openHistoryPanel];
   // Assert that message about entries is shown. The "history is showing local
   // entries" message will be shown because sync is not set up for this test.
diff --git a/ios/chrome/browser/ui/ntp/ntp_tile.h b/ios/chrome/browser/ui/ntp/ntp_tile.h
index 4bd2784..b65e609 100644
--- a/ios/chrome/browser/ui/ntp/ntp_tile.h
+++ b/ios/chrome/browser/ui/ntp/ntp_tile.h
@@ -16,7 +16,7 @@
 // The most visited site's URL.
 @property(readonly, atomic) NSURL* URL;
 // The filename of the most visited site's favicon on disk, if it exists.
-@property(strong, atomic) NSString* faviconPath;
+@property(strong, atomic) NSString* faviconFileName;
 // The fallback text color for the most visited site, if it exists.
 @property(strong, atomic) UIColor* fallbackTextColor;
 // The fallback background color for the most visited site, if it exists.
@@ -24,18 +24,26 @@
 // Whether the fallback background color for the most visited site is the
 // default color.
 @property(assign, atomic) BOOL fallbackIsDefaultColor;
+// The monogram to use on the fallback icon.
+@property(strong, atomic) NSString* fallbackMonogram;
 // Whether the favicon has been fetched for the most visited site. This can be
 // YES with no fallback values or favicon path.
 @property(assign, atomic) BOOL faviconFetched;
+// Index of the site's position in the most visited list.
+@property(assign, atomic) NSUInteger position;
 
-- (instancetype)initWithTitle:(NSString*)title URL:(NSURL*)URL;
 - (instancetype)initWithTitle:(NSString*)title
                           URL:(NSURL*)URL
-                  faviconPath:(NSString*)faviconPath
+                     position:(NSUInteger)position;
+- (instancetype)initWithTitle:(NSString*)title
+                          URL:(NSURL*)URL
+              faviconFileName:(NSString*)faviconFileName
             fallbackTextColor:(UIColor*)fallbackTextColor
       fallbackBackgroundColor:(UIColor*)fallbackTextColor
        fallbackIsDefaultColor:(BOOL)fallbackIsDefaultColor
-               faviconFetched:(BOOL)faviconFetched;
+             fallbackMonogram:(NSString*)fallbackMonogram
+               faviconFetched:(BOOL)faviconFetched
+                     position:(NSUInteger)position;
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_NTP_NTP_TILE_H_
diff --git a/ios/chrome/browser/ui/ntp/ntp_tile.mm b/ios/chrome/browser/ui/ntp/ntp_tile.mm
index 2686e49..d319a1bc 100644
--- a/ios/chrome/browser/ui/ntp/ntp_tile.mm
+++ b/ios/chrome/browser/ui/ntp/ntp_tile.mm
@@ -7,48 +7,59 @@
 namespace {
 NSString* kTitleKey = @"title";
 NSString* kURLKey = @"URL";
-NSString* kFaviconPathKey = @"faviconPath";
+NSString* kfaviconFileNameKey = @"faviconFileName";
 NSString* kFallbackTextColorKey = @"fallbackTextColor";
 NSString* kFallbackBackgroundColorKey = @"fallbackBackgroundColor";
 NSString* kFallbackIsDefaultColorKey = @"fallbackIsDefaultColor";
+NSString* kFallbackMonogram = @"fallbackMonogram";
 NSString* kFaviconFetched = @"faviconFetched";
+NSString* kPosition = @"position";
 }
 
 @implementation NTPTile
 
 @synthesize title = _title;
 @synthesize URL = _URL;
-@synthesize faviconPath = _faviconPath;
+@synthesize faviconFileName = _faviconFileName;
 @synthesize fallbackTextColor = _fallbackTextColor;
 @synthesize fallbackBackgroundColor = _fallbackBackgroundColor;
 @synthesize fallbackIsDefaultColor = _fallbackIsDefaultColor;
+@synthesize fallbackMonogram = _fallbackMonogram;
 @synthesize faviconFetched = _faviconFetched;
+@synthesize position = _position;
 
-- (instancetype)initWithTitle:(NSString*)title URL:(NSURL*)URL {
+- (instancetype)initWithTitle:(NSString*)title
+                          URL:(NSURL*)URL
+                     position:(NSUInteger)position {
   self = [super init];
   if (self) {
     _title = title;
     _URL = URL;
+    _position = position;
   }
   return self;
 }
 
 - (instancetype)initWithTitle:(NSString*)title
                           URL:(NSURL*)URL
-                  faviconPath:(NSString*)faviconPath
+              faviconFileName:(NSString*)faviconFileName
             fallbackTextColor:(UIColor*)fallbackTextColor
       fallbackBackgroundColor:(UIColor*)fallbackBackgroundColor
        fallbackIsDefaultColor:(BOOL)fallbackIsDefaultColor
-               faviconFetched:(BOOL)faviconFetched {
+             fallbackMonogram:(NSString*)fallbackMonogram
+               faviconFetched:(BOOL)faviconFetched
+                     position:(NSUInteger)position {
   self = [super init];
   if (self) {
     _title = title;
     _URL = URL;
-    _faviconPath = faviconPath;
+    _faviconFileName = faviconFileName;
     _fallbackTextColor = fallbackTextColor;
     _fallbackBackgroundColor = fallbackBackgroundColor;
     _fallbackIsDefaultColor = fallbackIsDefaultColor;
+    _fallbackMonogram = fallbackMonogram;
     _faviconFetched = faviconFetched;
+    _position = position;
   }
   return self;
 }
@@ -56,26 +67,32 @@
 - (instancetype)initWithCoder:(NSCoder*)aDecoder {
   return [self initWithTitle:[aDecoder decodeObjectForKey:kTitleKey]
                           URL:[aDecoder decodeObjectForKey:kURLKey]
-                  faviconPath:[aDecoder decodeObjectForKey:kFaviconPathKey]
+              faviconFileName:[aDecoder decodeObjectForKey:kfaviconFileNameKey]
             fallbackTextColor:[aDecoder
                                   decodeObjectForKey:kFallbackTextColorKey]
       fallbackBackgroundColor:
           [aDecoder decodeObjectForKey:kFallbackBackgroundColorKey]
        fallbackIsDefaultColor:[aDecoder
                                   decodeBoolForKey:kFallbackIsDefaultColorKey]
-               faviconFetched:[aDecoder decodeBoolForKey:kFaviconFetched]];
+             fallbackMonogram:[aDecoder decodeObjectForKey:kFallbackMonogram]
+               faviconFetched:[aDecoder decodeBoolForKey:kFaviconFetched]
+                     position:[[aDecoder decodeObjectForKey:kPosition]
+                                  unsignedIntegerValue]];
 }
 
 - (void)encodeWithCoder:(NSCoder*)aCoder {
   [aCoder encodeObject:self.title forKey:kTitleKey];
   [aCoder encodeObject:self.URL forKey:kURLKey];
-  [aCoder encodeObject:self.faviconPath forKey:kFaviconPathKey];
+  [aCoder encodeObject:self.faviconFileName forKey:kfaviconFileNameKey];
   [aCoder encodeObject:self.fallbackTextColor forKey:kFallbackTextColorKey];
   [aCoder encodeObject:self.fallbackBackgroundColor
                 forKey:kFallbackBackgroundColorKey];
   [aCoder encodeBool:self.fallbackIsDefaultColor
               forKey:kFallbackIsDefaultColorKey];
+  [aCoder encodeObject:self.fallbackMonogram forKey:kFallbackMonogram];
   [aCoder encodeBool:self.faviconFetched forKey:kFaviconFetched];
+  [aCoder encodeObject:[NSNumber numberWithUnsignedInteger:self.position]
+                forKey:kPosition];
 }
 
 @end
diff --git a/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm b/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm
index 9d18aa87..37b88113 100644
--- a/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm
+++ b/ios/chrome/browser/ui/ntp/ntp_tile_saver.mm
@@ -6,6 +6,7 @@
 
 #include "base/md5.h"
 #include "base/strings/sys_string_conversions.h"
+#include "components/favicon/core/fallback_url_util.h"
 #include "components/ntp_tiles/ntp_tile.h"
 #import "ios/chrome/browser/ui/ntp/google_landing_data_source.h"
 #import "ios/chrome/browser/ui/ntp/ntp_tile.h"
@@ -52,6 +53,12 @@
 
   if ([[NSFileManager defaultManager]
           fileExistsAtPath:[TmpFaviconFolderPath() path]]) {
+    [[NSFileManager defaultManager]
+               createDirectoryAtURL:faviconsURL.URLByDeletingLastPathComponent
+        withIntermediateDirectories:YES
+                         attributes:nil
+                              error:nil];
+
     [[NSFileManager defaultManager] moveItemAtURL:TmpFaviconFolderPath()
                                             toURL:faviconsURL
                                             error:nil];
@@ -82,6 +89,7 @@
   if (faviconsURL == nil) {
     return;
   }
+
   NSMutableDictionary<NSURL*, NTPTile*>* tiles =
       [[NSMutableDictionary alloc] init];
 
@@ -100,14 +108,16 @@
   // WriteToDiskIfComplete after each callback execution.
   // All the sites are added first to the list so that the WriteToDiskIfComplete
   // command is not passed an incomplete list.
-  for (const ntp_tiles::NTPTile& ntpTile : mostVisitedData) {
+  for (size_t i = 0; i < mostVisitedData.size(); i++) {
+    const ntp_tiles::NTPTile& ntpTile = mostVisitedData[i];
     NTPTile* tile =
         [[NTPTile alloc] initWithTitle:base::SysUTF16ToNSString(ntpTile.title)
-                                   URL:net::NSURLWithGURL(ntpTile.url)];
+                                   URL:net::NSURLWithGURL(ntpTile.url)
+                              position:i];
     [tiles setObject:tile forKey:tile.URL];
   }
 
-  for (NTPTile* tile : [tiles objectEnumerator]) {
+  for (__block NTPTile* tile : [tiles objectEnumerator]) {
     const GURL& gurl = net::GURLWithNSURL(tile.URL);
     NSString* faviconFileName = GetFaviconFileName(gurl);
     NSURL* fileURL =
@@ -117,7 +127,7 @@
       tile.faviconFetched = YES;
       NSData* imageData = UIImagePNGRepresentation(favicon);
       if ([imageData writeToURL:fileURL atomically:YES]) {
-        tile.faviconPath = faviconFileName;
+        tile.faviconFileName = faviconFileName;
       }
       WriteToDiskIfComplete(tiles, faviconsURL);
     };
@@ -128,6 +138,8 @@
           tile.fallbackTextColor = textColor;
           tile.fallbackBackgroundColor = backgroundColor;
           tile.fallbackIsDefaultColor = isDefaultColor;
+          tile.fallbackMonogram = base::SysUTF16ToNSString(
+              favicon::GetFallbackIconText(net::GURLWithNSURL(tile.URL)));
           WriteToDiskIfComplete(tiles, faviconsURL);
         };
 
@@ -150,8 +162,7 @@
 
 void WriteSavedMostVisited(NSDictionary<NSURL*, NTPTile*>* mostVisitedSites) {
   NSData* data = [NSKeyedArchiver archivedDataWithRootObject:mostVisitedSites];
-  NSUserDefaults* sharedDefaults =
-      [[NSUserDefaults alloc] initWithSuiteName:app_group::ApplicationGroup()];
+  NSUserDefaults* sharedDefaults = app_group::GetGroupUserDefaults();
   [sharedDefaults setObject:data forKey:app_group::kSuggestedItems];
 
   // TODO(crbug.com/750673): Update the widget's visibility depending on
@@ -159,8 +170,7 @@
 }
 
 NSDictionary* ReadSavedMostVisited() {
-  NSUserDefaults* sharedDefaults =
-      [[NSUserDefaults alloc] initWithSuiteName:app_group::ApplicationGroup()];
+  NSUserDefaults* sharedDefaults = app_group::GetGroupUserDefaults();
 
   return [NSKeyedUnarchiver
       unarchiveObjectWithData:[sharedDefaults
@@ -181,20 +191,25 @@
   tile.fallbackTextColor = nil;
   tile.fallbackBackgroundColor = nil;
   tile.faviconFetched = NO;
-  NSString* faviconPath = tile.faviconPath;
-  tile.faviconPath = nil;
+  NSString* previousFaviconFileName = tile.faviconFileName;
+  tile.faviconFileName = nil;
 
   // Fetch favicon and update saved defaults.
   NSString* faviconFileName = GetFaviconFileName(siteURL);
   NSURL* fileURL = [faviconsURL URLByAppendingPathComponent:faviconFileName];
+  NSURL* previousFileURL =
+      previousFaviconFileName
+          ? [faviconsURL URLByAppendingPathComponent:previousFaviconFileName]
+          : nil;
+  NSString* monogram =
+      base::SysUTF16ToNSString(favicon::GetFallbackIconText(siteURL));
 
   void (^faviconImageBlock)(UIImage*) = ^(UIImage* favicon) {
     tile.faviconFetched = YES;
     NSData* imageData = UIImagePNGRepresentation(favicon);
+    [[NSFileManager defaultManager] removeItemAtURL:previousFileURL error:nil];
     if ([imageData writeToURL:fileURL atomically:YES]) {
-      tile.faviconPath = faviconFileName;
-    } else {
-      [[NSFileManager defaultManager] removeItemAtPath:faviconPath error:nil];
+      tile.faviconFileName = faviconFileName;
     }
     WriteSingleUpdatedTileToDisk(tile);
   };
@@ -205,7 +220,9 @@
         tile.fallbackTextColor = textColor;
         tile.fallbackBackgroundColor = backgroundColor;
         tile.fallbackIsDefaultColor = isDefaultColor;
-        [[NSFileManager defaultManager] removeItemAtPath:faviconPath error:nil];
+        tile.fallbackMonogram = monogram;
+        [[NSFileManager defaultManager] removeItemAtURL:previousFileURL
+                                                  error:nil];
         WriteSingleUpdatedTileToDisk(tile);
       };
 
diff --git a/ios/chrome/browser/ui/ntp/ntp_tile_saver_unittest.mm b/ios/chrome/browser/ui/ntp/ntp_tile_saver_unittest.mm
index 8e5ea62..4ba1ad7 100644
--- a/ios/chrome/browser/ui/ntp/ntp_tile_saver_unittest.mm
+++ b/ios/chrome/browser/ui/ntp/ntp_tile_saver_unittest.mm
@@ -79,12 +79,12 @@
     EXPECT_NSEQ(tile.title, expectedTitle);
     EXPECT_NSEQ(tile.URL, expectedURL);
     EXPECT_TRUE(tile.faviconFetched);
-    EXPECT_NSNE(tile.faviconPath, nil);
+    EXPECT_NSNE(tile.faviconFileName, nil);
     EXPECT_NSEQ(tile.fallbackTextColor, nil);
     EXPECT_NSEQ(tile.fallbackBackgroundColor, nil);
     EXPECT_TRUE([[NSFileManager defaultManager]
         fileExistsAtPath:[[testFaviconDirectory()
-                             URLByAppendingPathComponent:tile.faviconPath]
+                             URLByAppendingPathComponent:tile.faviconFileName]
                              path]]);
   }
 
@@ -95,7 +95,7 @@
     EXPECT_NSEQ(tile.title, expectedTitle);
     EXPECT_NSEQ(tile.URL, expectedURL);
     EXPECT_TRUE(tile.faviconFetched);
-    EXPECT_NSEQ(tile.faviconPath, nil);
+    EXPECT_NSEQ(tile.faviconFileName, nil);
     EXPECT_NSEQ(tile.fallbackTextColor, UIColor.whiteColor);
     EXPECT_NSEQ(tile.fallbackBackgroundColor, UIColor.blueColor);
     EXPECT_EQ(tile.fallbackIsDefaultColor, NO);
diff --git a/ios/chrome/browser/web/progress_indicator_egtest.mm b/ios/chrome/browser/web/progress_indicator_egtest.mm
index f3205a0..dc18070 100644
--- a/ios/chrome/browser/web/progress_indicator_egtest.mm
+++ b/ios/chrome/browser/web/progress_indicator_egtest.mm
@@ -4,7 +4,6 @@
 
 #import <EarlGrey/EarlGrey.h>
 
-#include "base/ios/ios_util.h"
 #include "base/mac/foundation_util.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
@@ -166,11 +165,6 @@
     EARL_GREY_TEST_SKIPPED(@"Skipped for iPad (no progress view in tablet)");
   }
 
-  // TODO(crbug.com/747442): Re-enable this test once the bug is fixed.
-  if (base::ios::IsRunningOnIOS11OrLater()) {
-    EARL_GREY_TEST_DISABLED(@"Disabled on iOS 11.");
-  }
-
   const GURL formURL = web::test::HttpServer::MakeUrl(kFormURL);
   const GURL infinitePendingURL =
       web::test::HttpServer::MakeUrl(kInfinitePendingPageURL);
@@ -206,11 +200,6 @@
     EARL_GREY_TEST_SKIPPED(@"Skipped for iPad (no progress view in tablet)");
   }
 
-  // TODO(crbug.com/747442): Re-enable this test once the bug is fixed.
-  if (base::ios::IsRunningOnIOS11OrLater()) {
-    EARL_GREY_TEST_DISABLED(@"Disabled on iOS 11.");
-  }
-
   const GURL formURL = web::test::HttpServer::MakeUrl(kFormURL);
   const GURL simplePageURL = web::test::HttpServer::MakeUrl(kSimplePageURL);
 
diff --git a/ios/chrome/content_widget_extension/content_widget_view.h b/ios/chrome/content_widget_extension/content_widget_view.h
index 450bdd35..f9de690 100644
--- a/ios/chrome/content_widget_extension/content_widget_view.h
+++ b/ios/chrome/content_widget_extension/content_widget_view.h
@@ -7,6 +7,18 @@
 
 #import <UIKit/UIKit.h>
 
+@class MostVisitedTileView;
+@class NTPTile;
+
+// Protocol to be implemented by targets for user actions coming from the
+// content widget view.
+@protocol ContentWidgetViewDelegate
+
+// Called when tapping a tile to open |URL|.
+- (void)openURL:(NSURL*)URL;
+
+@end
+
 // View for the content widget. Shows 1 (compact view) or 2 (full size view)
 // rows of 4 most visited tiles (favicon or fallback + title), if there are
 // enough tiles to show. If there are fewer than 4 tiles, always displays a
@@ -16,11 +28,12 @@
 // The height of the widget in expanded mode.
 @property(nonatomic, readonly) CGFloat widgetExpandedHeight;
 
-// Designated initializer, creates the widget view. |compactHeight| indicates
-// the size to use in compact display. |initiallyCompact| indicates which mode
-// to display on initialization.
-- (instancetype)initWithCompactHeight:(CGFloat)compactHeight
-                     initiallyCompact:(BOOL)compact NS_DESIGNATED_INITIALIZER;
+// Designated initializer, creates the widget view with a |delegate| for user
+// actions. |compactHeight| indicates the size to use in compact display.
+// |initiallyCompact| indicates which mode to display on initialization.
+- (instancetype)initWithDelegate:(id<ContentWidgetViewDelegate>)delegate
+                   compactHeight:(CGFloat)compactHeight
+                initiallyCompact:(BOOL)compact NS_DESIGNATED_INITIALIZER;
 - (instancetype)initWithFrame:(CGRect)frame NS_UNAVAILABLE;
 - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
@@ -31,6 +44,10 @@
 // within the |compactHeight| passed in the constructor.
 - (void)showMode:(BOOL)compact;
 
+// Updates the displayed sites. |sites| should contain NTPTiles with continuous
+// positions starting at 0.
+- (void)updateSites:(NSDictionary<NSURL*, NTPTile*>*)sites;
+
 @end
 
 #endif  // IOS_CHROME_CONTENT_WIDGET_EXTENSION_CONTENT_WIDGET_VIEW_H_
diff --git a/ios/chrome/content_widget_extension/content_widget_view.mm b/ios/chrome/content_widget_extension/content_widget_view.mm
index dab4fab6..ae7f9313 100644
--- a/ios/chrome/content_widget_extension/content_widget_view.mm
+++ b/ios/chrome/content_widget_extension/content_widget_view.mm
@@ -4,8 +4,11 @@
 
 #import "ios/chrome/content_widget_extension/content_widget_view.h"
 
+#include "base/logging.h"
 #import "ios/chrome/browser/ui/favicon/favicon_view.h"
+#import "ios/chrome/browser/ui/ntp/ntp_tile.h"
 #import "ios/chrome/browser/ui/util/constraints_ui_util.h"
+#include "ios/chrome/common/app_group/app_group_constants.h"
 #import "ios/chrome/content_widget_extension/most_visited_tile_view.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -19,6 +22,9 @@
 const CGFloat kTileHeight = 100;
 // Icons to show per row.
 const int kIconsPerRow = 4;
+// Number of rows in the widget. Note that modifying this value will not add
+// extra rows and will break functionality unless additional changes are made.
+const int kRows = 2;
 }
 
 @interface ContentWidgetView ()
@@ -37,13 +43,17 @@
 @property(nonatomic, readonly) BOOL shouldShowSecondRow;
 // The number of sites to display.
 @property(nonatomic, assign) int siteCount;
+// The most visited tile views; tiles remain in this array even when hidden.
+@property(nonatomic, strong) NSArray<MostVisitedTileView*>* mostVisitedTiles;
+// The delegate for actions in the view.
+@property(nonatomic, weak) id<ContentWidgetViewDelegate> delegate;
 
 // Sets up the widget UI for an expanded or compact appearance based on
 // |compact|.
 - (void)createUI:(BOOL)compact;
 
-// Creates the view for a row of 4 sites.
-- (UIView*)createRowOfSites;
+// Arranges |tiles| horizontally in a view and returns the view.
+- (UIView*)createRowFromTiles:(NSArray<MostVisitedTileView*>*)tiles;
 
 // Returns the height to use for the first row, depending on the display mode.
 - (CGFloat)firstRowHeight:(BOOL)compact;
@@ -52,6 +62,9 @@
 // be shown).
 - (CGFloat)secondRowHeight;
 
+// Opens the |mostVisitedTile|'s url, using the delegate.
+- (void)openURLFromMostVisited:(MostVisitedTileView*)mostVisitedTile;
+
 @end
 
 @implementation ContentWidgetView
@@ -61,11 +74,16 @@
 @synthesize compactHeight = _compactHeight;
 @synthesize firstRowHeightConstraint = _firstRowHeightConstraint;
 @synthesize siteCount = _siteCount;
+@synthesize mostVisitedTiles = _mostVisitedTiles;
+@synthesize delegate = _delegate;
 
-- (instancetype)initWithCompactHeight:(CGFloat)compactHeight
-                     initiallyCompact:(BOOL)compact {
+- (instancetype)initWithDelegate:(id<ContentWidgetViewDelegate>)delegate
+                   compactHeight:(CGFloat)compactHeight
+                initiallyCompact:(BOOL)compact {
   self = [super initWithFrame:CGRectZero];
   if (self) {
+    DCHECK(delegate);
+    _delegate = delegate;
     _compactHeight = compactHeight;
     [self createUI:compact];
   }
@@ -85,8 +103,18 @@
 #pragma mark - UI creation
 
 - (void)createUI:(BOOL)compact {
-  _firstRow = [self createRowOfSites];
-  _secondRow = [self createRowOfSites];
+  NSMutableArray* tiles = [[NSMutableArray alloc] init];
+  for (int i = 0; i < kIconsPerRow * kRows; i++) {
+    [tiles addObject:[[MostVisitedTileView alloc] init]];
+  }
+  _mostVisitedTiles = tiles;
+
+  _firstRow = [self
+      createRowFromTiles:[tiles
+                             subarrayWithRange:NSMakeRange(0, kIconsPerRow)]];
+  _secondRow = [self
+      createRowFromTiles:[tiles subarrayWithRange:NSMakeRange(kIconsPerRow,
+                                                              kIconsPerRow)]];
 
   [self addSubview:_firstRow];
   [self addSubview:_secondRow];
@@ -105,14 +133,8 @@
   ]];
 }
 
-- (UIView*)createRowOfSites {
-  NSMutableArray<MostVisitedTileView*>* cells = [[NSMutableArray alloc] init];
-  for (int i = 0; i < kIconsPerRow; i++) {
-    cells[i] = [[MostVisitedTileView alloc] init];
-    cells[i].translatesAutoresizingMaskIntoConstraints = NO;
-  }
-
-  UIStackView* stack = [[UIStackView alloc] initWithArrangedSubviews:cells];
+- (UIView*)createRowFromTiles:(NSArray<MostVisitedTileView*>*)tiles {
+  UIStackView* stack = [[UIStackView alloc] initWithArrangedSubviews:tiles];
   stack.translatesAutoresizingMaskIntoConstraints = NO;
   stack.axis = UILayoutConstraintAxisHorizontal;
   stack.alignment = UIStackViewAlignmentTop;
@@ -134,19 +156,73 @@
   return container;
 }
 
+- (void)updateSites:(NSDictionary<NSURL*, NTPTile*>*)sites {
+  for (NTPTile* site in sites.objectEnumerator) {
+    // If the site's position is > the # of tiles shown, there is no tile to
+    // update. Remember that sites is a dictionary and is not ordered by
+    // position.
+    if (static_cast<NSUInteger>(site.position) > self.mostVisitedTiles.count) {
+      continue;
+    }
+    MostVisitedTileView* tileView = self.mostVisitedTiles[site.position];
+    tileView.titleLabel.text = site.title;
+    tileView.URL = site.URL;
+
+    FaviconAttributes* attributes = nil;
+
+    if (site.faviconFileName) {
+      NSURL* filePath = [app_group::ContentWidgetFaviconsFolder()
+          URLByAppendingPathComponent:site.faviconFileName];
+      UIImage* faviconImage = [UIImage imageWithContentsOfFile:filePath.path];
+      if (faviconImage) {
+        attributes = [FaviconAttributes attributesWithImage:faviconImage];
+      }
+    } else {
+      attributes = [FaviconAttributes
+          attributesWithMonogram:site.fallbackMonogram
+                       textColor:site.fallbackTextColor
+                 backgroundColor:site.fallbackBackgroundColor
+          defaultBackgroundColor:site.fallbackIsDefaultColor];
+    }
+    [tileView.faviconView configureWithAttributes:attributes];
+    tileView.alpha = 1;
+    tileView.userInteractionEnabled = YES;
+    [tileView addTarget:self
+                  action:@selector(openURLFromMostVisited:)
+        forControlEvents:UIControlEventTouchUpInside];
+    tileView.accessibilityLabel = site.title;
+  }
+
+  self.siteCount = sites.count;
+  [self hideEmptyTiles];
+}
+
+- (void)openURLFromMostVisited:(MostVisitedTileView*)mostVisitedTile {
+  [self.delegate openURL:mostVisitedTile.URL];
+}
+
+- (void)hideEmptyTiles {
+  for (int i = self.siteCount; i < kRows * kIconsPerRow; i++) {
+    self.mostVisitedTiles[i].alpha = 0;
+    self.mostVisitedTiles[i].userInteractionEnabled = NO;
+  }
+}
+
 - (CGFloat)firstRowHeight:(BOOL)compact {
   if (compact) {
     return self.compactHeight;
   }
 
-  CGFloat firstRowHeight = kTileHeight + 2 * kTileSpacing;
+  CGFloat firstRowHeight = kTileHeight + kRows * kTileSpacing;
   CGFloat secondRowHeight = [self secondRowHeight];
   CGFloat totalHeight = firstRowHeight + secondRowHeight;
-  if (totalHeight >= self.compactHeight) {
+  if (totalHeight > self.compactHeight) {
     return firstRowHeight;
   }
 
-  return self.compactHeight - secondRowHeight;
+  // The expanded height should be strictly greater than compactHeight,
+  // otherwise iOS does not update the UI correctly.
+  return self.compactHeight - secondRowHeight + 1;
 }
 
 - (CGFloat)secondRowHeight {
diff --git a/ios/chrome/content_widget_extension/content_widget_view_controller.mm b/ios/chrome/content_widget_extension/content_widget_view_controller.mm
index f3de0bd..8e2557ed 100644
--- a/ios/chrome/content_widget_extension/content_widget_view_controller.mm
+++ b/ios/chrome/content_widget_extension/content_widget_view_controller.mm
@@ -13,6 +13,7 @@
 #import "ios/chrome/browser/ui/util/constraints_ui_util.h"
 #include "ios/chrome/common/app_group/app_group_constants.h"
 #include "ios/chrome/content_widget_extension/content_widget_view.h"
+#import "ios/chrome/content_widget_extension/most_visited_tile_view.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -27,7 +28,7 @@
 const CGFloat widgetCompactHeightIOS9 = 110;
 }  // namespace
 
-@interface ContentWidgetViewController ()
+@interface ContentWidgetViewController ()<ContentWidgetViewDelegate>
 @property(nonatomic, strong) NSDictionary<NSURL*, NTPTile*>* sites;
 @property(nonatomic, weak) ContentWidgetView* widgetView;
 @property(nonatomic, readonly) BOOL isCompact;
@@ -35,8 +36,8 @@
 // Updates the widget with latest data. Returns whether any visual updates
 // occurred.
 - (BOOL)updateWidget;
-// Opens the main application with the given |URL|.
-- (void)openAppWithURL:(NSString*)URL;
+// Expand the widget.
+- (void)setExpanded:(CGSize)maxSize;
 @end
 
 @implementation ContentWidgetViewController
@@ -47,8 +48,9 @@
 #pragma mark - properties
 
 - (BOOL)isCompact {
-  return [self.extensionContext widgetActiveDisplayMode] ==
-         NCWidgetDisplayModeCompact;
+  return base::ios::IsRunningOnIOS10OrLater() &&
+         [self.extensionContext widgetActiveDisplayMode] ==
+             NCWidgetDisplayModeCompact;
 }
 
 #pragma mark - UIViewController
@@ -57,7 +59,7 @@
   [super viewDidLoad];
 
   CGFloat height =
-      self.extensionContext
+      self.extensionContext && base::ios::IsRunningOnIOS10OrLater()
           ? [self.extensionContext
                 widgetMaximumSizeForDisplayMode:NCWidgetDisplayModeCompact]
                 .height
@@ -66,25 +68,23 @@
   // A local variable is necessary here as the property is declared weak and the
   // object would be deallocated before being retained by the addSubview call.
   ContentWidgetView* widgetView =
-      [[ContentWidgetView alloc] initWithCompactHeight:height
-                                      initiallyCompact:self.isCompact];
+      [[ContentWidgetView alloc] initWithDelegate:self
+                                    compactHeight:height
+                                 initiallyCompact:self.isCompact];
   self.widgetView = widgetView;
   [self.view addSubview:self.widgetView];
 
   if (base::ios::IsRunningOnIOS10OrLater()) {
     self.extensionContext.widgetLargestAvailableDisplayMode =
         NCWidgetDisplayModeExpanded;
+  } else {
+    [self setExpanded:[[UIScreen mainScreen] bounds].size];
   }
 
   self.widgetView.translatesAutoresizingMaskIntoConstraints = NO;
   AddSameConstraints(self.widgetView, self.view);
 }
 
-- (void)viewWillAppear:(BOOL)animated {
-  [super viewWillAppear:animated];
-  [self updateWidget];
-}
-
 - (void)widgetPerformUpdateWithCompletionHandler:
     (void (^)(NCUpdateResult))completionHandler {
   completionHandler([self updateWidget] ? NCUpdateResultNewData
@@ -113,8 +113,7 @@
       self.preferredContentSize = maxSize;
       break;
     case NCWidgetDisplayModeExpanded:
-      self.preferredContentSize =
-          CGSizeMake(maxSize.width, [self.widgetView widgetExpandedHeight]);
+      [self setExpanded:maxSize];
       break;
   }
 }
@@ -130,22 +129,30 @@
 
 #pragma mark - internal
 
+- (void)setExpanded:(CGSize)maxSize {
+  [self updateWidget];
+  self.preferredContentSize =
+      CGSizeMake(maxSize.width,
+                 MIN([self.widgetView widgetExpandedHeight], maxSize.height));
+}
+
 - (BOOL)updateWidget {
-  NSUserDefaults* sharedDefaults =
-      [[NSUserDefaults alloc] initWithSuiteName:app_group::ApplicationGroup()];
+  NSUserDefaults* sharedDefaults = app_group::GetGroupUserDefaults();
   NSDictionary<NSURL*, NTPTile*>* newSites = [NSKeyedUnarchiver
       unarchiveObjectWithData:[sharedDefaults
                                   objectForKey:app_group::kSuggestedItems]];
-  if (newSites == self.sites) {
+  if ([newSites isEqualToDictionary:self.sites]) {
     return NO;
   }
   self.sites = newSites;
+  [self.widgetView updateSites:self.sites];
   return YES;
 }
 
-- (void)openAppWithURL:(NSString*)URL {
-  NSUserDefaults* sharedDefaults =
-      [[NSUserDefaults alloc] initWithSuiteName:app_group::ApplicationGroup()];
+#pragma mark - ContentWidgetViewDelegate
+
+- (void)openURL:(NSURL*)URL {
+  NSUserDefaults* sharedDefaults = app_group::GetGroupUserDefaults();
   NSString* defaultsKey =
       base::SysUTF8ToNSString(app_group::kChromeAppGroupCommandPreference);
 
@@ -163,7 +170,7 @@
     appPrefKey : @"TodayExtension",
     commandPrefKey :
         base::SysUTF8ToNSString(app_group::kChromeAppGroupOpenURLCommand),
-    paramPrefKey : URL,
+    paramPrefKey : URL.absoluteString,
   };
 
   [sharedDefaults setObject:commandDict forKey:defaultsKey];
diff --git a/ios/chrome/content_widget_extension/most_visited_tile_view.h b/ios/chrome/content_widget_extension/most_visited_tile_view.h
index c68eabb..d93cd79 100644
--- a/ios/chrome/content_widget_extension/most_visited_tile_view.h
+++ b/ios/chrome/content_widget_extension/most_visited_tile_view.h
@@ -11,7 +11,7 @@
 
 // View to display a Most Visited tile based on the suggestion.
 // It displays the favicon for this Most Visited suggestion and its title.
-@interface MostVisitedTileView : UIView
+@interface MostVisitedTileView : UIButton
 
 // FaviconView displaying the favicon.
 @property(nonatomic, strong, readonly, nonnull) FaviconViewNew* faviconView;
@@ -19,6 +19,9 @@
 // Title of the Most Visited.
 @property(nonatomic, strong, readonly, nonnull) UILabel* titleLabel;
 
+// URL of the Most Visited.
+@property(nonatomic, strong, nullable) NSURL* URL;
+
 @end
 
 #endif  // IOS_CHROME_CONTENT_WIDGET_EXTENSION_MOST_VISITED_TILE_VIEW_H_
diff --git a/ios/chrome/content_widget_extension/most_visited_tile_view.mm b/ios/chrome/content_widget_extension/most_visited_tile_view.mm
index fd4d567..5ca4f0b 100644
--- a/ios/chrome/content_widget_extension/most_visited_tile_view.mm
+++ b/ios/chrome/content_widget_extension/most_visited_tile_view.mm
@@ -25,6 +25,7 @@
 
 @synthesize faviconView = _faviconView;
 @synthesize titleLabel = _titleLabel;
+@synthesize URL = _URL;
 
 #pragma mark - Public
 
@@ -50,6 +51,8 @@
     stack.spacing = kSpaceFaviconTitle;
     stack.alignment = UIStackViewAlignmentCenter;
     stack.translatesAutoresizingMaskIntoConstraints = NO;
+    stack.isAccessibilityElement = NO;
+    stack.userInteractionEnabled = NO;
     [self addSubview:stack];
     AddSameConstraints(self, stack);
 
@@ -58,6 +61,8 @@
       [_faviconView.widthAnchor constraintEqualToConstant:kFaviconSize],
       [_faviconView.heightAnchor constraintEqualToConstant:kFaviconSize],
     ]];
+
+    self.translatesAutoresizingMaskIntoConstraints = NO;
   }
   return self;
 }
diff --git a/ios/web/public/test/fakes/test_web_state.h b/ios/web/public/test/fakes/test_web_state.h
index 9bbe078..128f446 100644
--- a/ios/web/public/test/fakes/test_web_state.h
+++ b/ios/web/public/test/fakes/test_web_state.h
@@ -55,6 +55,7 @@
   const base::string16& GetTitle() const override;
   bool IsLoading() const override;
   double GetLoadingProgress() const override;
+  bool IsCrashed() const override;
   bool IsBeingDestroyed() const override;
   const GURL& GetVisibleURL() const override;
   const GURL& GetLastCommittedURL() const override;
diff --git a/ios/web/public/test/fakes/test_web_state.mm b/ios/web/public/test/fakes/test_web_state.mm
index 67da5e2..5d428df 100644
--- a/ios/web/public/test/fakes/test_web_state.mm
+++ b/ios/web/public/test/fakes/test_web_state.mm
@@ -176,6 +176,10 @@
   return 0.0;
 }
 
+bool TestWebState::IsCrashed() const {
+  return false;
+}
+
 bool TestWebState::IsBeingDestroyed() const {
   return false;
 }
diff --git a/ios/web/public/web_state/web_state.h b/ios/web/public/web_state/web_state.h
index 6478ad8..245f5b1 100644
--- a/ios/web/public/web_state/web_state.h
+++ b/ios/web/public/web_state/web_state.h
@@ -190,6 +190,10 @@
   // (nothing loaded) and 1.0 (fully loaded).
   virtual double GetLoadingProgress() const = 0;
 
+  // Returns true if the web process backing this WebState is believed to
+  // currently be crashed.
+  virtual bool IsCrashed() const = 0;
+
   // Whether this instance is in the process of being destroyed.
   virtual bool IsBeingDestroyed() const = 0;
 
diff --git a/ios/web/web_state/ui/crw_web_controller.h b/ios/web/web_state/ui/crw_web_controller.h
index b72d745a..bf4e1d8e53 100644
--- a/ios/web/web_state/ui/crw_web_controller.h
+++ b/ios/web/web_state/ui/crw_web_controller.h
@@ -105,6 +105,9 @@
 // |WebStateObserver::DidSuppressDialog| will be called.
 @property(nonatomic, assign) BOOL shouldSuppressDialogs;
 
+// YES if the web process backing WebView is believed to currently be crashed.
+@property(nonatomic, assign, getter=isWebProcessCrashed) BOOL webProcessCrashed;
+
 // Designated initializer. Initializes web controller with |webState|. The
 // calling code must retain the ownership of |webState|.
 - (instancetype)initWithWebState:(web::WebStateImpl*)webState;
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index b204af2..1befb1a8 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -359,8 +359,6 @@
   // Set to YES when a hashchange event is manually dispatched for same-document
   // history navigations.
   BOOL _dispatchingSameDocumentHashChangeEvent;
-  // YES if the web process backing _wkWebView is believed to currently be dead.
-  BOOL _webProcessIsDead;
 
   // Object for loading POST requests with body.
   base::scoped_nsobject<CRWJSPOSTRequestLoader> _POSTRequestLoader;
@@ -944,6 +942,7 @@
 @synthesize usePlaceholderOverlay = _usePlaceholderOverlay;
 @synthesize loadPhase = _loadPhase;
 @synthesize shouldSuppressDialogs = _shouldSuppressDialogs;
+@synthesize webProcessCrashed = _webProcessCrashed;
 
 - (instancetype)initWithWebState:(WebStateImpl*)webState {
   self = [super init];
@@ -1147,7 +1146,7 @@
 }
 
 - (BOOL)isViewAlive {
-  return !_webProcessIsDead && [_containerView isViewAlive];
+  return !_webProcessCrashed && [_containerView isViewAlive];
 }
 
 - (BOOL)contentIsHTML {
@@ -4101,7 +4100,7 @@
 }
 
 - (void)webViewWebProcessDidCrash {
-  _webProcessIsDead = YES;
+  _webProcessCrashed = YES;
   _webStateImpl->CancelDialogs();
   _webStateImpl->OnRenderProcessGone();
 }
@@ -4309,7 +4308,7 @@
     decidePolicyForNavigationAction:(WKNavigationAction*)action
                     decisionHandler:
                         (void (^)(WKNavigationActionPolicy))decisionHandler {
-  _webProcessIsDead = NO;
+  _webProcessCrashed = NO;
   if (_isBeingDestroyed) {
     decisionHandler(WKNavigationActionPolicyCancel);
     return;
@@ -4851,7 +4850,7 @@
 - (void)webViewTitleDidChange {
   // WKWebView's title becomes empty when the web process dies; ignore that
   // update.
-  if (_webProcessIsDead) {
+  if (_webProcessCrashed) {
     DCHECK_EQ([_webView title].length, 0U);
     return;
   }
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index f2f40c1..7e38171 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -948,6 +948,10 @@
 // Tests that WebStateDelegate::RenderProcessGone is called when WKWebView web
 // process has crashed.
 TEST_F(CRWWebControllerWebProcessTest, Crash) {
+  ASSERT_TRUE([web_controller() isViewAlive]);
+  ASSERT_FALSE([web_controller() isWebProcessCrashed]);
+  ASSERT_FALSE(web_state()->IsCrashed());
+
   web::TestWebStateObserver observer(web_state());
   web::TestWebStateObserver* observer_ptr = &observer;
   web::SimulateWKWebViewCrash(webView_);
@@ -956,6 +960,8 @@
   });
   EXPECT_EQ(web_state(), observer.render_process_gone_info()->web_state);
   EXPECT_FALSE([web_controller() isViewAlive]);
+  EXPECT_TRUE([web_controller() isWebProcessCrashed]);
+  EXPECT_TRUE(web_state()->IsCrashed());
 };
 
 }  // namespace
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index c357d9d9..22eb8adf 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -197,6 +197,7 @@
   const base::string16& GetTitle() const override;
   bool IsLoading() const override;
   double GetLoadingProgress() const override;
+  bool IsCrashed() const override;
   bool IsBeingDestroyed() const override;
   const GURL& GetVisibleURL() const override;
   const GURL& GetLastCommittedURL() const override;
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index c8ce61a..dd27c66 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -240,6 +240,10 @@
   return [web_controller_ loadingProgress];
 }
 
+bool WebStateImpl::IsCrashed() const {
+  return [web_controller_ isWebProcessCrashed];
+}
+
 bool WebStateImpl::IsBeingDestroyed() const {
   return is_being_destroyed_;
 }
diff --git a/media/base/audio_latency.cc b/media/base/audio_latency.cc
index ccc634b..e077fdbe 100644
--- a/media/base/audio_latency.cc
+++ b/media/base/audio_latency.cc
@@ -106,10 +106,10 @@
     return frames_per_buffer;
   }
 
-#if defined(OS_LINUX) || defined(OS_MACOSX)
-  // On Linux and MacOS, the low level IO implementations on the browser side
-  // supports all buffer size the clients want. We use the native peer
-  // connection buffer size (10ms) to achieve best possible performance.
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_FUCHSIA)
+  // On Linux, MacOS and Fuchsia, the low level IO implementations on the
+  // browser side supports all buffer size the clients want. We use the native
+  // peer connection buffer size (10ms) to achieve best possible performance.
   frames_per_buffer = sample_rate / 100;
 #elif defined(OS_ANDROID)
   // TODO(olka/henrika): This settings are very old, need to be revisited.
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc
index 2d8f866..db6fc06 100644
--- a/media/base/media_switches.cc
+++ b/media/base/media_switches.cc
@@ -201,7 +201,7 @@
                                             base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Use AndroidOverlay rather than ContentVideoView in clank?
-const base::Feature kUseAndroidOverlay{"use-android_overlay",
+const base::Feature kUseAndroidOverlay{"UseAndroidOverlay",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Let video track be unselected when video is playing in the background.
@@ -228,7 +228,7 @@
 
 // Support FLAC codec within ISOBMFF streams used with Media Source Extensions.
 const base::Feature kMseFlacInIsobmff{"MseFlacInIsobmff",
-                                      base::FEATURE_DISABLED_BY_DEFAULT};
+                                      base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Use the new Remote Playback / media flinging pipeline.
 const base::Feature kNewRemotePlaybackPipeline{
diff --git a/media/gpu/android/promotion_hint_aggregator.h b/media/gpu/android/promotion_hint_aggregator.h
index 44e5561..9fd1e43 100644
--- a/media/gpu/android/promotion_hint_aggregator.h
+++ b/media/gpu/android/promotion_hint_aggregator.h
@@ -22,6 +22,8 @@
   struct Hint {
     int x = 0;
     int y = 0;
+    int width = 0;
+    int height = 0;
     bool is_promotable = false;
   };
 
diff --git a/media/gpu/android_video_decode_accelerator.cc b/media/gpu/android_video_decode_accelerator.cc
index 62ba3bc..152a4ec 100644
--- a/media/gpu/android_video_decode_accelerator.cc
+++ b/media/gpu/android_video_decode_accelerator.cc
@@ -66,6 +66,11 @@
 // NotifyEndOfBitstreamBuffer() before getting output from the bitstream.
 enum { kMaxBitstreamsNotifiedInAdvance = 32 };
 
+// Number of frames to defer overlays for when entering fullscreen.  This lets
+// blink relayout settle down a bit.  If overlay positions were synchronous,
+// then we wouldn't need this.
+enum { kFrameDelayForFullscreenLayout = 15 };
+
 // MediaCodec is only guaranteed to support baseline, but some devices may
 // support others. Advertise support for all H264 profiles and let the
 // MediaCodec fail when decoding if it's not actually supported. It's assumed
@@ -1276,6 +1281,18 @@
 
   surface_chooser_state_.is_frame_hidden = overlay_info.is_frame_hidden;
 
+  if (overlay_info.is_fullscreen && !surface_chooser_state_.is_fullscreen) {
+    // It would be nice if we could just delay until we get a hint from an
+    // overlay that's "in fullscreen" in the sense that the CompositorFrame it
+    // came from had some flag set to indicate that the renderer was in
+    // fullscreen mode when it was generated.  However, even that's hard, since
+    // there's no real connection between "renderer finds out about fullscreen"
+    // and "blink has completed layouts for it".  The latter is what we really
+    // want to know.
+    surface_chooser_state_.is_expecting_relayout = true;
+    hints_until_clear_relayout_flag_ = kFrameDelayForFullscreenLayout;
+  }
+
   // Notify the chooser about the fullscreen state.
   surface_chooser_state_.is_fullscreen = overlay_info.is_fullscreen;
 
@@ -1563,10 +1580,29 @@
 
 void AndroidVideoDecodeAccelerator::NotifyPromotionHint(
     const PromotionHintAggregator::Hint& hint) {
+  bool update_state = false;
+
   promotion_hint_aggregator_->NotifyPromotionHint(hint);
+
+  // If we're expecting a full screen relayout, then also use this hint as a
+  // notification that another frame has happened.
+  if (hints_until_clear_relayout_flag_ > 0) {
+    hints_until_clear_relayout_flag_--;
+    if (hints_until_clear_relayout_flag_ == 0) {
+      surface_chooser_state_.is_expecting_relayout = false;
+      update_state = true;
+    }
+  }
+
+  surface_chooser_state_.initial_position =
+      gfx::Rect(hint.x, hint.y, hint.width, hint.height);
   bool promotable = promotion_hint_aggregator_->IsSafeToPromote();
   if (promotable != surface_chooser_state_.is_compositor_promotable) {
     surface_chooser_state_.is_compositor_promotable = promotable;
+    update_state = true;
+  }
+
+  if (update_state) {
     surface_chooser_->UpdateState(base::Optional<AndroidOverlayFactoryCB>(),
                                   surface_chooser_state_);
   }
diff --git a/media/gpu/android_video_decode_accelerator.h b/media/gpu/android_video_decode_accelerator.h
index b03473b..a36dd41 100644
--- a/media/gpu/android_video_decode_accelerator.h
+++ b/media/gpu/android_video_decode_accelerator.h
@@ -394,6 +394,13 @@
 
   AndroidVideoSurfaceChooser::State surface_chooser_state_;
 
+  // Number of promotion hints that we need to receive before clearing the
+  // "delay overlay promotion" flag in |surface_chooser_state_|.  We do this so
+  // that the transition looks better, since it gives blink time to stabilize.
+  // Since overlay positioning isn't synchronous, it's good to make sure that
+  // blink isn't moving the quad around too.
+  int hints_until_clear_relayout_flag_ = 0;
+
   // Optional factory to produce mojo AndroidOverlay instances.
   AndroidOverlayMojoFactoryCB overlay_factory_cb_;
 
diff --git a/media/gpu/android_video_surface_chooser.h b/media/gpu/android_video_surface_chooser.h
index 67051a3..aa0c57c 100644
--- a/media/gpu/android_video_surface_chooser.h
+++ b/media/gpu/android_video_surface_chooser.h
@@ -11,6 +11,7 @@
 #include "base/optional.h"
 #include "media/base/android/android_overlay.h"
 #include "media/gpu/media_gpu_export.h"
+#include "ui/gfx/geometry/rect.h"
 
 namespace media {
 
@@ -29,6 +30,12 @@
 
     // Is the compositor willing to promote this?
     bool is_compositor_promotable = false;
+
+    // Are we expecting a relayout soon?
+    bool is_expecting_relayout = false;
+
+    // Hint to use for the initial position when transitioning to an overlay.
+    gfx::Rect initial_position;
   };
 
   // Notify the client that |overlay| is ready for use.  The client may get
diff --git a/media/gpu/android_video_surface_chooser_impl.cc b/media/gpu/android_video_surface_chooser_impl.cc
index 3e66239..d2f6ae8c 100644
--- a/media/gpu/android_video_surface_chooser_impl.cc
+++ b/media/gpu/android_video_surface_chooser_impl.cc
@@ -110,6 +110,14 @@
   if (!current_state_.is_compositor_promotable)
     new_overlay_state = kUsingSurfaceTexture;
 
+  // If we're expecting a relayout, then don't transition to overlay if we're
+  // not already in one.  We don't want to transition out, though.  This lets us
+  // delay entering on a fullscreen transition until blink relayout is complete.
+  // TODO(liberato): Detect this more directly.
+  if (current_state_.is_expecting_relayout &&
+      client_overlay_state_ != kUsingOverlay)
+    new_overlay_state = kUsingSurfaceTexture;
+
   // If we need a secure surface, then we must choose an overlay.  The only way
   // we won't is if we don't have a factory or our request fails.  If the
   // compositor won't promote, then we still use the overlay, since hopefully
@@ -182,10 +190,7 @@
   config.failed_cb =
       base::Bind(&AndroidVideoSurfaceChooserImpl::OnOverlayFailed,
                  weak_factory_.GetWeakPtr());
-  // TODO(liberato): where do we get the initial size from?  For CVV, it's
-  // set via the natural size, and this is ignored anyway.  The client should
-  // provide this.
-  config.rect = gfx::Rect(0, 0, 1, 1);
+  config.rect = current_state_.initial_position;
   overlay_ = overlay_factory_.Run(std::move(config));
   if (!overlay_)
     SwitchToSurfaceTexture();
diff --git a/media/gpu/android_video_surface_chooser_impl_unittest.cc b/media/gpu/android_video_surface_chooser_impl_unittest.cc
index acf4bd4f..69e811d0 100644
--- a/media/gpu/android_video_surface_chooser_impl_unittest.cc
+++ b/media/gpu/android_video_surface_chooser_impl_unittest.cc
@@ -57,13 +57,15 @@
 enum class IsSecure { No, Yes };
 enum class IsFrameHidden { No, Yes };
 enum class IsCCPromotable { No, Yes };
+enum class IsExpectingRelayout { No, Yes };
 
 using TestParams = std::tuple<ShouldUseOverlay,
                               AllowDynamic,
                               IsFullscreen,
                               IsSecure,
                               IsFrameHidden,
-                              IsCCPromotable>;
+                              IsCCPromotable,
+                              IsExpectingRelayout>;
 
 // Useful macro for instantiating tests.
 #define Either(x) Values(x::No, x::Yes)
@@ -308,6 +310,7 @@
   chooser_state_.is_secure = IsYes(IsSecure, 3);
   chooser_state_.is_frame_hidden = IsYes(IsFrameHidden, 4);
   chooser_state_.is_compositor_promotable = IsYes(IsCCPromotable, 5);
+  chooser_state_.is_expecting_relayout = IsYes(IsExpectingRelayout, 6);
 
   if (should_use_overlay) {
     EXPECT_CALL(client_, UseSurfaceTexture()).Times(0);
@@ -332,8 +335,9 @@
                                 Either(AllowDynamic),
                                 Values(IsFullscreen::No),
                                 Values(IsSecure::No),
-                                Values(IsFrameHidden::No),
-                                Either(IsCCPromotable)));
+                                Either(IsFrameHidden),
+                                Either(IsCCPromotable),
+                                Either(IsExpectingRelayout)));
 INSTANTIATE_TEST_CASE_P(FullscreenUsesOverlay,
                         AndroidVideoSurfaceChooserImplTest,
                         Combine(Values(ShouldUseOverlay::Yes),
@@ -341,7 +345,8 @@
                                 Values(IsFullscreen::Yes),
                                 Values(IsSecure::No),
                                 Values(IsFrameHidden::No),
-                                Values(IsCCPromotable::Yes)));
+                                Values(IsCCPromotable::Yes),
+                                Values(IsExpectingRelayout::No)));
 INSTANTIATE_TEST_CASE_P(SecureUsesOverlay,
                         AndroidVideoSurfaceChooserImplTest,
                         Combine(Values(ShouldUseOverlay::Yes),
@@ -349,7 +354,8 @@
                                 Either(IsFullscreen),
                                 Values(IsSecure::Yes),
                                 Values(IsFrameHidden::No),
-                                Values(IsCCPromotable::Yes)));
+                                Values(IsCCPromotable::Yes),
+                                Either(IsExpectingRelayout)));
 
 INSTANTIATE_TEST_CASE_P(HiddenFramesUseSurfaceTexture,
                         AndroidVideoSurfaceChooserImplTest,
@@ -358,7 +364,8 @@
                                 Either(IsFullscreen),
                                 Either(IsSecure),
                                 Values(IsFrameHidden::Yes),
-                                Either(IsCCPromotable)));
+                                Either(IsCCPromotable),
+                                Either(IsExpectingRelayout)));
 // For all dynamic cases, we shouldn't use an overlay if the compositor won't
 // promote it.  For L1, it will fail either way until the CC supports "must
 // promote" overlays, so we ignore those cases.  Non-dynamic is excluded, since
@@ -371,6 +378,41 @@
                                 Either(IsFullscreen),
                                 Values(IsSecure::No),
                                 Values(IsFrameHidden::No),
-                                Values(IsCCPromotable::No)));
+                                Values(IsCCPromotable::No),
+                                Either(IsExpectingRelayout)));
+
+// If we're expecting a relayout, then we should never use an overlay unless
+// it's required for a secure output.
+INSTANTIATE_TEST_CASE_P(InsecureExpectingRelayoutUsesSurfaceTexture,
+                        AndroidVideoSurfaceChooserImplTest,
+                        Combine(Values(ShouldUseOverlay::No),
+                                Values(AllowDynamic::Yes),
+                                Either(IsFullscreen),
+                                Values(IsSecure::No),
+                                Either(IsFrameHidden),
+                                Either(IsCCPromotable),
+                                Values(IsExpectingRelayout::Yes)));
+
+// "is_fullscreen" should be enough to trigger an overlay pre-M.
+INSTANTIATE_TEST_CASE_P(NotDynamicInFullscreenUsesOverlay,
+                        AndroidVideoSurfaceChooserImplTest,
+                        Combine(Values(ShouldUseOverlay::Yes),
+                                Values(AllowDynamic::No),
+                                Values(IsFullscreen::Yes),
+                                Either(IsSecure),
+                                Either(IsFrameHidden),
+                                Either(IsCCPromotable),
+                                Either(IsExpectingRelayout)));
+
+// "is_secure" should be enough to trigger an overlay pre-M.
+INSTANTIATE_TEST_CASE_P(NotDynamicSecureUsesOverlay,
+                        AndroidVideoSurfaceChooserImplTest,
+                        Combine(Values(ShouldUseOverlay::Yes),
+                                Values(AllowDynamic::No),
+                                Either(IsFullscreen),
+                                Values(IsSecure::Yes),
+                                Either(IsFrameHidden),
+                                Either(IsCCPromotable),
+                                Either(IsExpectingRelayout)));
 
 }  // namespace media
diff --git a/media/gpu/avda_codec_image.cc b/media/gpu/avda_codec_image.cc
index 00db66b..6ba5e0f 100644
--- a/media/gpu/avda_codec_image.cc
+++ b/media/gpu/avda_codec_image.cc
@@ -234,11 +234,15 @@
 
 void AVDACodecImage::NotifyPromotionHint(bool promotion_hint,
                                          int display_x,
-                                         int display_y) {
+                                         int display_y,
+                                         int display_width,
+                                         int display_height) {
   // TODO(liberato): this should just be given to us.
   PromotionHintAggregator::Hint hint;
   hint.x = display_x;
   hint.y = display_y;
+  hint.width = display_width;
+  hint.height = display_height;
   hint.is_promotable = promotion_hint;
   shared_state_->GetPromotionHintCB().Run(hint);
 }
diff --git a/media/gpu/avda_codec_image.h b/media/gpu/avda_codec_image.h
index c8c8c26..3ee9822 100644
--- a/media/gpu/avda_codec_image.h
+++ b/media/gpu/avda_codec_image.h
@@ -50,7 +50,9 @@
   void GetTextureMatrix(float xform[16]) override;
   void NotifyPromotionHint(bool promotion_hint,
                            int display_x,
-                           int display_y) override;
+                           int display_y,
+                           int display_width,
+                           int display_height) override;
 
   enum class UpdateMode {
     // Discards the codec buffer, no UpdateTexImage().
diff --git a/media/media_options.gni b/media/media_options.gni
index 26217a65..e34f7f8 100644
--- a/media/media_options.gni
+++ b/media/media_options.gni
@@ -59,7 +59,7 @@
   # which are encoded using HEVC require |enable_hevc_demuxing| to be enabled.
   enable_dolby_vision_demuxing = proprietary_codecs && is_chromecast
 
-  enable_webrtc = !is_cast_audio_only && !is_fuchsia
+  enable_webrtc = !is_cast_audio_only
 
   # Enable HLS with SAMPLE-AES decryption.
   # Enabled by default on the cast desktop implementation to allow unit tests of
diff --git a/mojo/edk/system/watch.cc b/mojo/edk/system/watch.cc
index b629f90f..63d8beb5 100644
--- a/mojo/edk/system/watch.cc
+++ b/mojo/edk/system/watch.cc
@@ -25,12 +25,8 @@
                         bool allowed_to_call_callback) {
   AssertWatcherLockAcquired();
 
-  // TODO(crbug.com/740044): Remove this CHECK.
-  CHECK(this);
-
   // NOTE: This method must NEVER call into |dispatcher_| directly, because it
   // may be called while |dispatcher_| holds a lock.
-
   MojoResult rv = MOJO_RESULT_SHOULD_WAIT;
   RequestContext* const request_context = RequestContext::current();
   const bool notify_success =
@@ -59,9 +55,6 @@
 }
 
 void Watch::Cancel() {
-  // TODO(crbug.com/740044): Remove this CHECK.
-  CHECK(this);
-
   RequestContext::current()->AddWatchCancelFinalizer(this);
 }
 
@@ -71,13 +64,13 @@
   // We hold the lock through invocation to ensure that only one notification
   // callback runs for this context at any given time.
   base::AutoLock lock(notification_lock_);
-  if (result == MOJO_RESULT_CANCELLED) {
-    // Make sure cancellation is the last notification we dispatch.
-    DCHECK(!is_cancelled_);
-    is_cancelled_ = true;
-  } else if (is_cancelled_) {
+
+  // Ensure that no notifications are dispatched beyond cancellation.
+  if (is_cancelled_)
     return;
-  }
+
+  if (result == MOJO_RESULT_CANCELLED)
+    is_cancelled_ = true;
 
   // NOTE: This will acquire |watcher_|'s internal lock. It's safe because a
   // thread can only enter InvokeCallback() from within a RequestContext
diff --git a/mojo/edk/system/watcher_dispatcher.cc b/mojo/edk/system/watcher_dispatcher.cc
index 5fbaef34..db43843 100644
--- a/mojo/edk/system/watcher_dispatcher.cc
+++ b/mojo/edk/system/watcher_dispatcher.cc
@@ -47,9 +47,6 @@
 
     watch = std::move(it->second);
 
-    // TODO(crbug.com/740044): Remove this CHECK.
-    CHECK(watch);
-
     // Wipe out all state associated with the closed dispatcher.
     watches_.erase(watch->context());
     ready_watches_.erase(watch.get());
@@ -97,7 +94,8 @@
   std::map<uintptr_t, scoped_refptr<Watch>> watches;
   {
     base::AutoLock lock(lock_);
-    DCHECK(!closed_);
+    if (closed_)
+      return MOJO_RESULT_INVALID_ARGUMENT;
     closed_ = true;
     std::swap(watches, watches_);
     watched_handles_.clear();
@@ -122,9 +120,8 @@
   // after we've updated all our own relevant state and released |lock_|.
   {
     base::AutoLock lock(lock_);
-
-    // TODO(crbug.com/740044): Remove this CHECK.
-    CHECK(!closed_);
+    if (closed_)
+      return MOJO_RESULT_INVALID_ARGUMENT;
 
     if (watches_.count(context) || watched_handles_.count(dispatcher.get()))
       return MOJO_RESULT_ALREADY_EXISTS;
@@ -147,21 +144,17 @@
     return rv;
   }
 
-  // TODO(crbug.com/740044): Perhaps the crash is caused by a racy use of
-  // watchers, which - while incorrect - should not in fact be able to crash at
-  // this layer.
-  //
-  // Hypothesis is that two threads are racing with one adding a watch and one
-  // closing the watcher handle. If the watcher handle is closed immediately
-  // before the AddWatcherRef() call above, |dispatcher| can retain an invalid
-  // pointer to this WatcherDispatcher indefinitely, leading to an eventual UAF
-  // if and when it tries to dispatch a notification.
-  //
-  // If such a race is indeed the sole source of crashes, all subsequent crash
-  // reports which would have come from Watch::NotifyState etc should instead
-  // fail the CHECK below.
-  base::AutoLock lock(lock_);
-  CHECK(!closed_);
+  bool remove_now;
+  {
+    // If we've been closed already, there's a chance our closure raced with
+    // the call to AddWatcherRef() above. In that case we want to ensure we've
+    // removed our ref from |dispatcher|. Note that this may in turn race
+    // with normal removal, but that's fine.
+    base::AutoLock lock(lock_);
+    remove_now = closed_;
+  }
+  if (remove_now)
+    dispatcher->RemoveWatcherRef(this, context);
 
   return MOJO_RESULT_OK;
 }
@@ -172,6 +165,8 @@
   scoped_refptr<Watch> watch;
   {
     base::AutoLock lock(lock_);
+    if (closed_)
+      return MOJO_RESULT_INVALID_ARGUMENT;
     auto it = watches_.find(context);
     if (it == watches_.end())
       return MOJO_RESULT_NOT_FOUND;
@@ -179,11 +174,6 @@
     watches_.erase(it);
   }
 
-  // TODO(crbug.com/740044): Remove these CHECKs.
-  CHECK(watch);
-  CHECK(watch->dispatcher());
-  CHECK(this);
-
   // Mark the watch as cancelled so no further notifications get through.
   watch->Cancel();
 
@@ -218,6 +208,8 @@
       (!ready_contexts || !ready_results || !ready_signals_states)) {
     return MOJO_RESULT_INVALID_ARGUMENT;
   }
+  if (closed_)
+    return MOJO_RESULT_INVALID_ARGUMENT;
 
   if (watched_handles_.empty())
     return MOJO_RESULT_NOT_FOUND;
@@ -261,10 +253,7 @@
   return MOJO_RESULT_FAILED_PRECONDITION;
 }
 
-WatcherDispatcher::~WatcherDispatcher() {
-  // TODO(crbug.com/740044): Remove this.
-  CHECK(closed_);
-}
+WatcherDispatcher::~WatcherDispatcher() = default;
 
 }  // namespace edk
 }  // namespace mojo
diff --git a/mojo/edk/system/watcher_unittest.cc b/mojo/edk/system/watcher_unittest.cc
index 9987e483..92484c4 100644
--- a/mojo/edk/system/watcher_unittest.cc
+++ b/mojo/edk/system/watcher_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
+#include "base/rand_util.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
 #include "base/threading/simple_thread.h"
@@ -1722,6 +1723,126 @@
   EXPECT_EQ(MOJO_RESULT_OK, MojoClose(a));
 }
 
+base::Closure g_do_random_thing_callback;
+
+void ReadAllMessages(uintptr_t context,
+                     MojoResult result,
+                     MojoHandleSignalsState state,
+                     MojoWatcherNotificationFlags flags) {
+  if (result == MOJO_RESULT_OK) {
+    MojoHandle handle = static_cast<MojoHandle>(context);
+    MojoMessageHandle message;
+    while (MojoReadMessage(handle, &message, MOJO_READ_MESSAGE_FLAG_NONE) ==
+           MOJO_RESULT_OK) {
+      MojoDestroyMessage(message);
+    }
+  }
+
+  constexpr size_t kNumRandomThingsToDoOnNotify = 5;
+  for (size_t i = 0; i < kNumRandomThingsToDoOnNotify; ++i)
+    g_do_random_thing_callback.Run();
+}
+
+MojoHandle RandomHandle(MojoHandle* handles, size_t size) {
+  return handles[base::RandInt(0, static_cast<int>(size) - 1)];
+}
+
+void DoRandomThing(MojoHandle* watchers,
+                   size_t num_watchers,
+                   MojoHandle* watched_handles,
+                   size_t num_watched_handles) {
+  switch (base::RandInt(0, 10)) {
+    case 0:
+      MojoClose(RandomHandle(watchers, num_watchers));
+      break;
+    case 1:
+      MojoClose(RandomHandle(watched_handles, num_watched_handles));
+      break;
+    case 2:
+    case 3:
+    case 4: {
+      MojoMessageHandle message;
+      ASSERT_EQ(MOJO_RESULT_OK, MojoCreateMessage(&message));
+      ASSERT_EQ(MOJO_RESULT_OK,
+                MojoAttachMessageContext(message, 1, nullptr, nullptr));
+      MojoWriteMessage(RandomHandle(watched_handles, num_watched_handles),
+                       message, MOJO_WRITE_MESSAGE_FLAG_NONE);
+      break;
+    }
+    case 5:
+    case 6: {
+      MojoHandle w = RandomHandle(watchers, num_watchers);
+      MojoHandle h = RandomHandle(watched_handles, num_watched_handles);
+      MojoWatch(w, h, MOJO_HANDLE_SIGNAL_READABLE,
+                MOJO_WATCH_CONDITION_SATISFIED, static_cast<uintptr_t>(h));
+      break;
+    }
+    case 7:
+    case 8: {
+      uint32_t num_ready_contexts = 1;
+      uintptr_t ready_context;
+      MojoResult ready_result;
+      MojoHandleSignalsState ready_state;
+      if (MojoArmWatcher(RandomHandle(watchers, num_watchers),
+                         &num_ready_contexts, &ready_context, &ready_result,
+                         &ready_state) == MOJO_RESULT_FAILED_PRECONDITION &&
+          ready_result == MOJO_RESULT_OK) {
+        ReadAllMessages(ready_context, ready_result, ready_state, 0);
+      }
+      break;
+    }
+    case 9:
+    case 10: {
+      MojoHandle w = RandomHandle(watchers, num_watchers);
+      MojoHandle h = RandomHandle(watched_handles, num_watched_handles);
+      MojoCancelWatch(w, static_cast<uintptr_t>(h));
+      break;
+    }
+    default:
+      NOTREACHED();
+      break;
+  }
+}
+
+TEST_F(WatcherTest, ConcurrencyStressTest) {
+  // Regression test for https://crbug.com/740044. Exercises racy usage of the
+  // watcher API to weed out potential crashes.
+
+  constexpr size_t kNumWatchers = 50;
+  constexpr size_t kNumWatchedHandles = 50;
+  static_assert(kNumWatchedHandles % 2 == 0, "Invalid number of test handles.");
+
+  constexpr size_t kNumThreads = 10;
+  static constexpr size_t kNumOperationsPerThread = 400;
+
+  MojoHandle watchers[kNumWatchers];
+  MojoHandle watched_handles[kNumWatchedHandles];
+  g_do_random_thing_callback =
+      base::Bind(&DoRandomThing, watchers, kNumWatchers, watched_handles,
+                 kNumWatchedHandles);
+
+  for (size_t i = 0; i < kNumWatchers; ++i)
+    MojoCreateWatcher(&ReadAllMessages, &watchers[i]);
+  for (size_t i = 0; i < kNumWatchedHandles; i += 2)
+    CreateMessagePipe(&watched_handles[i], &watched_handles[i + 1]);
+
+  std::unique_ptr<ThreadedRunner> threads[kNumThreads];
+  auto runner_callback = base::Bind([]() {
+    for (size_t i = 0; i < kNumOperationsPerThread; ++i)
+      g_do_random_thing_callback.Run();
+  });
+  for (size_t i = 0; i < kNumThreads; ++i) {
+    threads[i] = base::MakeUnique<ThreadedRunner>(runner_callback);
+    threads[i]->Start();
+  }
+  for (size_t i = 0; i < kNumThreads; ++i)
+    threads[i]->Join();
+  for (size_t i = 0; i < kNumWatchers; ++i)
+    MojoClose(watchers[i]);
+  for (size_t i = 0; i < kNumWatchedHandles; ++i)
+    MojoClose(watched_handles[i]);
+}
+
 }  // namespace
 }  // namespace edk
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index f427466..067523a 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -67,7 +67,6 @@
     "lib/control_message_handler.h",
     "lib/control_message_proxy.cc",
     "lib/control_message_proxy.h",
-    "lib/debug_util.h",
     "lib/deque.h",
     "lib/filter_chain.cc",
     "lib/fixed_buffer.cc",
diff --git a/mojo/public/cpp/bindings/interface_endpoint_client.h b/mojo/public/cpp/bindings/interface_endpoint_client.h
index 25b815c..891039d 100644
--- a/mojo/public/cpp/bindings/interface_endpoint_client.h
+++ b/mojo/public/cpp/bindings/interface_endpoint_client.h
@@ -26,7 +26,6 @@
 #include "mojo/public/cpp/bindings/filter_chain.h"
 #include "mojo/public/cpp/bindings/lib/control_message_handler.h"
 #include "mojo/public/cpp/bindings/lib/control_message_proxy.h"
-#include "mojo/public/cpp/bindings/lib/debug_util.h"
 #include "mojo/public/cpp/bindings/message.h"
 #include "mojo/public/cpp/bindings/scoped_interface_endpoint_handle.h"
 
@@ -39,8 +38,7 @@
 // endpoint, either the implementation side or the client side.
 // It should only be accessed and destructed on the creating sequence.
 class MOJO_CPP_BINDINGS_EXPORT InterfaceEndpointClient
-    : NON_EXPORTED_BASE(public MessageReceiverWithResponder),
-      NON_EXPORTED_BASE(private internal::LifeTimeTrackerForDebugging) {
+    : NON_EXPORTED_BASE(public MessageReceiverWithResponder) {
  public:
   // |receiver| is okay to be null. If it is not null, it must outlive this
   // object.
diff --git a/mojo/public/cpp/bindings/lib/debug_util.h b/mojo/public/cpp/bindings/lib/debug_util.h
deleted file mode 100644
index 1783645..0000000
--- a/mojo/public/cpp/bindings/lib/debug_util.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2017 The Chromium 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 MOJO_PUBLIC_CPP_BINDINGS_LIB_DEBUG_UTIL_H_
-#define MOJO_PUBLIC_CPP_BINDINGS_LIB_DEBUG_UTIL_H_
-
-namespace mojo {
-namespace internal {
-
-// TODO(crbug.com/741047): Remove this after the bug is fixed.
-class LifeTimeTrackerForDebugging {
- public:
-  LifeTimeTrackerForDebugging() {}
-
-  ~LifeTimeTrackerForDebugging() { state_ = DESTROYED; }
-
-  void CheckObjectIsValid() {
-    CHECK(this);
-
-    // This adress has been used to construct a LifeTimeTrackerForDebugging.
-    CHECK(state_ == ALIVE || state_ == DESTROYED);
-
-    // If the previous check succeeds but this fails, it is likely to be
-    // use-after-free problem.
-    CHECK_EQ(ALIVE, state_);
-  }
-
- private:
-  enum MagicValue : uint64_t {
-    ALIVE = 0x1029384756afbecd,
-    DESTROYED = 0xdcebfa6574839201
-  };
-
-  uint64_t state_ = ALIVE;
-};
-
-}  // namespace internal
-}  // namespace mojo
-
-#endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_DEBUG_UTIL_H_
diff --git a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
index 0fe98c7e..bb59369 100644
--- a/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
+++ b/mojo/public/cpp/bindings/lib/interface_endpoint_client.cc
@@ -167,15 +167,8 @@
 
 InterfaceEndpointClient::~InterfaceEndpointClient() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  // TODO(crbug.com/741047): Remove these checks.
-  CheckObjectIsValid();
-  CHECK(task_runner_->RunsTasksInCurrentSequence());
-
-  if (controller_) {
-    CHECK(handle_.group_controller());
+  if (controller_)
     handle_.group_controller()->DetachEndpointClient(handle_);
-  }
 }
 
 AssociatedGroup* InterfaceEndpointClient::associated_group() {
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.cc b/mojo/public/cpp/bindings/lib/multiplex_router.cc
index f40c040..c98b7d4 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.cc
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.cc
@@ -504,16 +504,12 @@
 
 void MultiplexRouter::DetachEndpointClient(
     const ScopedInterfaceEndpointHandle& handle) {
-  // TODO(crbug.com/741047): Remove this check.
-  CheckObjectIsValid();
-
   const InterfaceId id = handle.id();
 
   DCHECK(IsValidInterfaceId(id));
 
   MayAutoLock locker(&lock_);
-  // TODO(crbug.com/741047): change this to DCEHCK.
-  CHECK(base::ContainsKey(endpoints_, id));
+  DCHECK(base::ContainsKey(endpoints_, id));
 
   InterfaceEndpoint* endpoint = endpoints_[id].get();
   endpoint->DetachClient();
@@ -670,9 +666,6 @@
 void MultiplexRouter::OnPipeConnectionError() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
-  // TODO(crbug.com/741047): Remove this check.
-  CheckObjectIsValid();
-
   scoped_refptr<MultiplexRouter> protector(this);
   MayAutoLock locker(&lock_);
 
diff --git a/mojo/public/cpp/bindings/lib/multiplex_router.h b/mojo/public/cpp/bindings/lib/multiplex_router.h
index 3061ce6..be6b2cc 100644
--- a/mojo/public/cpp/bindings/lib/multiplex_router.h
+++ b/mojo/public/cpp/bindings/lib/multiplex_router.h
@@ -25,7 +25,6 @@
 #include "mojo/public/cpp/bindings/connector.h"
 #include "mojo/public/cpp/bindings/filter_chain.h"
 #include "mojo/public/cpp/bindings/interface_id.h"
-#include "mojo/public/cpp/bindings/lib/debug_util.h"
 #include "mojo/public/cpp/bindings/lib/deque.h"
 #include "mojo/public/cpp/bindings/message_header_validator.h"
 #include "mojo/public/cpp/bindings/pipe_control_message_handler.h"
@@ -56,8 +55,7 @@
 class MOJO_CPP_BINDINGS_EXPORT MultiplexRouter
     : NON_EXPORTED_BASE(public MessageReceiver),
       public AssociatedGroupController,
-      NON_EXPORTED_BASE(public PipeControlMessageHandlerDelegate),
-      NON_EXPORTED_BASE(private LifeTimeTrackerForDebugging) {
+      NON_EXPORTED_BASE(public PipeControlMessageHandlerDelegate) {
  public:
   enum Config {
     // There is only the master interface running on this router. Please note
diff --git a/net/BUILD.gn b/net/BUILD.gn
index c6a1186..866a0f2 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1820,7 +1820,10 @@
         sources -= [ "cert/x509_certificate_ios.cc" ]
       }
       if (is_mac) {
-        sources -= [ "cert/x509_certificate_mac.cc" ]
+        sources -= [
+          "cert/x509_cert_types_mac.cc",
+          "cert/x509_certificate_mac.cc",
+        ]
       }
       if (use_nss_certs) {
         sources -= [ "cert/x509_certificate_nss.cc" ]
@@ -1829,7 +1832,10 @@
         sources -= [ "cert/x509_certificate_openssl.cc" ]
       }
       if (is_win) {
-        sources -= [ "cert/x509_certificate_win.cc" ]
+        sources -= [
+          "cert/x509_cert_types_win.cc",
+          "cert/x509_certificate_win.cc",
+        ]
       }
     } else {
       sources -= [ "cert/x509_certificate_bytes.cc" ]
diff --git a/net/cert/x509_cert_types.cc b/net/cert/x509_cert_types.cc
index d0e09b7d..221046cc 100644
--- a/net/cert/x509_cert_types.cc
+++ b/net/cert/x509_cert_types.cc
@@ -13,6 +13,11 @@
 #include "net/base/parse_number.h"
 #include "net/cert/x509_certificate.h"
 
+#if BUILDFLAG(USE_BYTE_CERTS)
+#include "net/cert/internal/parse_name.h"
+#include "net/der/input.h"
+#endif
+
 namespace net {
 
 namespace {
@@ -39,6 +44,64 @@
 CertPrincipal::~CertPrincipal() {
 }
 
+#if BUILDFLAG(USE_BYTE_CERTS)
+bool CertPrincipal::ParseDistinguishedName(const void* ber_name_data,
+                                           size_t length) {
+  RDNSequence rdns;
+  if (!ParseName(
+          der::Input(reinterpret_cast<const uint8_t*>(ber_name_data), length),
+          &rdns))
+    return false;
+
+  for (const RelativeDistinguishedName& rdn : rdns) {
+    for (const X509NameAttribute& name_attribute : rdn) {
+      if (name_attribute.type == TypeCommonNameOid()) {
+        if (common_name.empty() &&
+            !name_attribute.ValueAsString(&common_name)) {
+          return false;
+        }
+      } else if (name_attribute.type == TypeLocalityNameOid()) {
+        if (locality_name.empty() &&
+            !name_attribute.ValueAsString(&locality_name)) {
+          return false;
+        }
+      } else if (name_attribute.type == TypeStateOrProvinceNameOid()) {
+        if (state_or_province_name.empty() &&
+            !name_attribute.ValueAsString(&state_or_province_name)) {
+          return false;
+        }
+      } else if (name_attribute.type == TypeCountryNameOid()) {
+        if (country_name.empty() &&
+            !name_attribute.ValueAsString(&country_name)) {
+          return false;
+        }
+      } else if (name_attribute.type == TypeStreetAddressOid()) {
+        std::string s;
+        if (!name_attribute.ValueAsString(&s))
+          return false;
+        street_addresses.push_back(s);
+      } else if (name_attribute.type == TypeOrganizationNameOid()) {
+        std::string s;
+        if (!name_attribute.ValueAsString(&s))
+          return false;
+        organization_names.push_back(s);
+      } else if (name_attribute.type == TypeOrganizationUnitNameOid()) {
+        std::string s;
+        if (!name_attribute.ValueAsString(&s))
+          return false;
+        organization_unit_names.push_back(s);
+      } else if (name_attribute.type == TypeDomainComponentOid()) {
+        std::string s;
+        if (!name_attribute.ValueAsString(&s))
+          return false;
+        domain_components.push_back(s);
+      }
+    }
+  }
+  return true;
+}
+#endif
+
 std::string CertPrincipal::GetDisplayName() const {
   if (!common_name.empty())
     return common_name;
diff --git a/net/cert/x509_cert_types.h b/net/cert/x509_cert_types.h
index 0a38a6da..e8c28dd3 100644
--- a/net/cert/x509_cert_types.h
+++ b/net/cert/x509_cert_types.h
@@ -19,6 +19,7 @@
 #include "net/base/hash_value.h"
 #include "net/base/net_export.h"
 #include "net/cert/cert_status_flags.h"
+#include "net/net_features.h"
 
 #if defined(OS_MACOSX) && !defined(OS_IOS)
 #include <Security/x509defs.h>
@@ -36,8 +37,10 @@
   explicit CertPrincipal(const std::string& name);
   ~CertPrincipal();
 
-#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
+#if BUILDFLAG(USE_BYTE_CERTS) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
+    defined(OS_WIN)
   // Parses a BER-format DistinguishedName.
+  // TODO(mattm): change this to take a der::Input.
   bool ParseDistinguishedName(const void* ber_name_data, size_t length);
 #endif
 
diff --git a/net/cert/x509_cert_types_unittest.cc b/net/cert/x509_cert_types_unittest.cc
index 9882090cd..2ac7c57 100644
--- a/net/cert/x509_cert_types_unittest.cc
+++ b/net/cert/x509_cert_types_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
+#include "build/build_config.h"
 #include "net/test/test_certificate_data.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -13,7 +14,8 @@
 
 namespace {
 
-#if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN)
+#if BUILDFLAG(USE_BYTE_CERTS) || (defined(OS_MACOSX) && !defined(OS_IOS)) || \
+    defined(OS_WIN)
 TEST(X509TypesTest, ParseDNVerisign) {
   CertPrincipal verisign;
   EXPECT_TRUE(verisign.ParseDistinguishedName(VerisignDN, sizeof(VerisignDN)));
diff --git a/net/cert/x509_certificate_bytes.cc b/net/cert/x509_certificate_bytes.cc
index 96dcf3fb..17cd7f3 100644
--- a/net/cert/x509_certificate_bytes.cc
+++ b/net/cert/x509_certificate_bytes.cc
@@ -12,7 +12,6 @@
 #include "net/cert/asn1_util.h"
 #include "net/cert/internal/cert_errors.h"
 #include "net/cert/internal/name_constraints.h"
-#include "net/cert/internal/parse_name.h"
 #include "net/cert/internal/parsed_certificate.h"
 #include "net/cert/internal/signature_algorithm.h"
 #include "net/cert/internal/verify_name_match.h"
@@ -83,62 +82,6 @@
   return NormalizeName(issuer_value, out_normalized_issuer, &errors);
 }
 
-// Fills |principal| from the DER encoded |name_tlv|, returning true on success
-// or false if parsing failed or some of the values could not be converted to
-// UTF-8.
-bool ParsePrincipal(const der::Input& name_tlv, CertPrincipal* principal) {
-  RDNSequence rdns;
-  if (!ParseName(name_tlv, &rdns))
-    return false;
-
-  for (const RelativeDistinguishedName& rdn : rdns) {
-    for (const X509NameAttribute& name_attribute : rdn) {
-      if (name_attribute.type == TypeCommonNameOid()) {
-        if (principal->common_name.empty() &&
-            !name_attribute.ValueAsString(&principal->common_name)) {
-          return false;
-        }
-      } else if (name_attribute.type == TypeLocalityNameOid()) {
-        if (principal->locality_name.empty() &&
-            !name_attribute.ValueAsString(&principal->locality_name)) {
-          return false;
-        }
-      } else if (name_attribute.type == TypeStateOrProvinceNameOid()) {
-        if (principal->state_or_province_name.empty() &&
-            !name_attribute.ValueAsString(&principal->state_or_province_name)) {
-          return false;
-        }
-      } else if (name_attribute.type == TypeCountryNameOid()) {
-        if (principal->country_name.empty() &&
-            !name_attribute.ValueAsString(&principal->country_name)) {
-          return false;
-        }
-      } else if (name_attribute.type == TypeStreetAddressOid()) {
-        std::string s;
-        if (!name_attribute.ValueAsString(&s))
-          return false;
-        principal->street_addresses.push_back(s);
-      } else if (name_attribute.type == TypeOrganizationNameOid()) {
-        std::string s;
-        if (!name_attribute.ValueAsString(&s))
-          return false;
-        principal->organization_names.push_back(s);
-      } else if (name_attribute.type == TypeOrganizationUnitNameOid()) {
-        std::string s;
-        if (!name_attribute.ValueAsString(&s))
-          return false;
-        principal->organization_unit_names.push_back(s);
-      } else if (name_attribute.type == TypeDomainComponentOid()) {
-        std::string s;
-        if (!name_attribute.ValueAsString(&s))
-          return false;
-        principal->domain_components.push_back(s);
-      }
-    }
-  }
-  return true;
-}
-
 // Parses certificates from a PKCS#7 SignedData structure, appending them to
 // |handles|.
 void CreateOSCertHandlesFromPKCS7Bytes(
@@ -182,8 +125,10 @@
                            DefaultParseCertificateOptions(), &tbs, nullptr))
     return false;
 
-  if (!ParsePrincipal(tbs.subject_tlv, &subject_) ||
-      !ParsePrincipal(tbs.issuer_tlv, &issuer_)) {
+  if (!subject_.ParseDistinguishedName(tbs.subject_tlv.UnsafeData(),
+                                       tbs.subject_tlv.Length()) ||
+      !issuer_.ParseDistinguishedName(tbs.issuer_tlv.UnsafeData(),
+                                      tbs.issuer_tlv.Length())) {
     return false;
   }
 
diff --git a/net/spdy/core/http2_frame_decoder_adapter.cc b/net/spdy/core/http2_frame_decoder_adapter.cc
index cb1e745..2f86bb1 100644
--- a/net/spdy/core/http2_frame_decoder_adapter.cc
+++ b/net/spdy/core/http2_frame_decoder_adapter.cc
@@ -15,9 +15,7 @@
 #include <cstring>
 #include <utility>
 
-#include "base/format_macros.h"
 #include "base/logging.h"
-#include "base/optional.h"
 #include "base/sys_byteorder.h"
 #include "build/build_config.h"
 #include "net/http2/decoder/decode_buffer.h"
@@ -32,6 +30,7 @@
 #include "net/spdy/core/spdy_alt_svc_wire_format.h"
 #include "net/spdy/core/spdy_bug_tracker.h"
 #include "net/spdy/core/spdy_frame_builder.h"
+#include "net/spdy/core/spdy_framer.h"
 #include "net/spdy/core/spdy_header_block.h"
 #include "net/spdy/core/spdy_headers_handler_interface.h"
 #include "net/spdy/core/spdy_protocol.h"
@@ -39,18 +38,12 @@
 #include "net/spdy/platform/api/spdy_ptr_util.h"
 #include "net/spdy/platform/api/spdy_string_utils.h"
 
-#if defined(COMPILER_GCC)
-#define PRETTY_THIS SpdyStringPrintf("%s@%p ", __PRETTY_FUNCTION__, this)
-#elif defined(COMPILER_MSVC)
-#define PRETTY_THIS SpdyStringPrintf("%s@%p ", __FUNCSIG__, this)
-#else
-#define PRETTY_THIS SpdyStringPrintf("%s@%p ", __func__, this)
-#endif
-
 namespace net {
-
 namespace {
 
+using SpdyFramerError = SpdyFramer::SpdyFramerError;
+using SpdyState = SpdyFramer::SpdyState;
+
 const bool kHasPriorityFields = true;
 const bool kNotHasPriorityFields = false;
 
@@ -87,951 +80,858 @@
 #endif
 }
 
-class Http2DecoderAdapter : public SpdyFramerDecoderAdapter,
-                            public Http2FrameDecoderListener {
-  typedef SpdyFramer::SpdyState SpdyState;
-  typedef SpdyFramer::SpdyFramerError SpdyFramerError;
+}  // namespace
 
- public:
-  Http2DecoderAdapter() : SpdyFramerDecoderAdapter() {
-    DVLOG(1) << "Http2DecoderAdapter ctor";
-    ResetInternal();
-  }
-  ~Http2DecoderAdapter() override {}
+Http2DecoderAdapter::Http2DecoderAdapter() {
+  DVLOG(1) << "Http2DecoderAdapter ctor";
+  ResetInternal();
+}
 
-  // ===========================================================================
-  // Implementations of the pure virtual methods from SpdyFramerDecoderAdapter;
-  // the other virtual methods of SpdyFramerDecoderAdapter have satsifactory
-  // default implementations.
+Http2DecoderAdapter::~Http2DecoderAdapter() {}
 
-  void set_extension_visitor(ExtensionVisitorInterface* visitor) override {
-    extension_ = visitor;
-  }
+void Http2DecoderAdapter::set_visitor(SpdyFramerVisitorInterface* visitor) {
+  visitor_ = visitor;
+}
 
-  // Passes the call on to the HPACK decoder.
-  void SetDecoderHeaderTableDebugVisitor(
-      std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor)
-      override {
-    GetHpackDecoder()->SetHeaderTableDebugVisitor(std::move(visitor));
-  }
+void Http2DecoderAdapter::set_debug_visitor(
+    SpdyFramerDebugVisitorInterface* debug_visitor) {
+  debug_visitor_ = debug_visitor;
+}
 
-  size_t ProcessInput(const char* data, size_t len) override {
-    size_t limit = recv_frame_size_limit_;
-    frame_decoder_->set_maximum_payload_size(limit);
+void Http2DecoderAdapter::set_process_single_input_frame(bool v) {
+  process_single_input_frame_ = v;
+}
 
-    size_t total_processed = 0;
-    while (len > 0 && spdy_state_ != SpdyFramer::SPDY_ERROR) {
-      // Process one at a time so that we update the adapter's internal
-      // state appropriately.
-      const size_t processed = ProcessInputFrame(data, len);
+void Http2DecoderAdapter::set_extension_visitor(
+    ExtensionVisitorInterface* visitor) {
+  extension_ = visitor;
+}
 
-      // We had some data, and weren't in an error state, so should have
-      // processed/consumed at least one byte of it, even if we then ended up
-      // in an error state.
-      DCHECK(processed > 0) << "processed=" << processed
-                            << "   spdy_state_=" << spdy_state_
-                            << "   spdy_framer_error_=" << spdy_framer_error_;
+// Passes the call on to the HPACK decoder.
+void Http2DecoderAdapter::SetDecoderHeaderTableDebugVisitor(
+    std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) {
+  GetHpackDecoder()->SetHeaderTableDebugVisitor(std::move(visitor));
+}
 
-      data += processed;
-      len -= processed;
-      total_processed += processed;
-      if (process_single_input_frame() || processed == 0) {
-        break;
-      }
+size_t Http2DecoderAdapter::ProcessInput(const char* data, size_t len) {
+  size_t limit = recv_frame_size_limit_;
+  frame_decoder_->set_maximum_payload_size(limit);
+
+  size_t total_processed = 0;
+  while (len > 0 && spdy_state_ != SpdyFramer::SPDY_ERROR) {
+    // Process one at a time so that we update the adapter's internal
+    // state appropriately.
+    const size_t processed = ProcessInputFrame(data, len);
+
+    // We had some data, and weren't in an error state, so should have
+    // processed/consumed at least one byte of it, even if we then ended up
+    // in an error state.
+    DCHECK(processed > 0) << "processed=" << processed
+                          << "   spdy_state_=" << spdy_state_
+                          << "   spdy_framer_error_=" << spdy_framer_error_;
+
+    data += processed;
+    len -= processed;
+    total_processed += processed;
+    if (process_single_input_frame() || processed == 0) {
+      break;
     }
-    return total_processed;
   }
+  return total_processed;
+}
 
-  void Reset() override { ResetInternal(); }
+void Http2DecoderAdapter::Reset() {
+  ResetInternal();
+}
 
-  SpdyState state() const override { return spdy_state_; }
+SpdyState Http2DecoderAdapter::state() const {
+  return spdy_state_;
+}
 
-  SpdyFramerError spdy_framer_error() const override {
-    return spdy_framer_error_;
+SpdyFramerError Http2DecoderAdapter::spdy_framer_error() const {
+  return spdy_framer_error_;
+}
+
+bool Http2DecoderAdapter::probable_http_response() const {
+  return latched_probable_http_response_;
+}
+
+size_t Http2DecoderAdapter::EstimateMemoryUsage() const {
+  // Skip |frame_decoder_|, |frame_header_| and |hpack_first_frame_header_| as
+  // they don't allocate.
+  return SpdyEstimateMemoryUsage(alt_svc_origin_) +
+         SpdyEstimateMemoryUsage(alt_svc_value_);
+}
+
+// ===========================================================================
+// Implementations of the methods declared by Http2FrameDecoderListener.
+
+// Called once the common frame header has been decoded for any frame.
+// This function is largely based on SpdyFramer::ValidateFrameHeader
+// and some parts of SpdyFramer::ProcessCommonHeader.
+bool Http2DecoderAdapter::OnFrameHeader(const Http2FrameHeader& header) {
+  DVLOG(1) << "OnFrameHeader: " << header;
+  decoded_frame_header_ = true;
+  if (!latched_probable_http_response_) {
+    latched_probable_http_response_ = header.IsProbableHttpResponse();
   }
-
-  bool probable_http_response() const override {
-    return latched_probable_http_response_;
+  const uint8_t raw_frame_type = static_cast<uint8_t>(header.type);
+  visitor()->OnCommonHeader(header.stream_id, header.payload_length,
+                            raw_frame_type, header.flags);
+  if (has_expected_frame_type_ && header.type != expected_frame_type_) {
+    // Report an unexpected frame error and close the connection if we
+    // expect a known frame type (probably CONTINUATION) and receive an
+    // unknown frame.
+    VLOG(1) << "The framer was expecting to receive a " << expected_frame_type_
+            << " frame, but instead received an unknown frame of type "
+            << header.type;
+    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME);
+    return false;
   }
-
-  size_t EstimateMemoryUsage() const override {
-    // Skip |frame_decoder_|, |frame_header_| and |hpack_first_frame_header_| as
-    // they don't allocate.
-    return SpdyEstimateMemoryUsage(alt_svc_origin_) +
-           SpdyEstimateMemoryUsage(alt_svc_value_);
-  }
-  // ===========================================================================
-  // Implementations of the methods declared by Http2FrameDecoderListener.
-
-  // Called once the common frame header has been decoded for any frame.
-  // This function is largely based on SpdyFramer::ValidateFrameHeader
-  // and some parts of SpdyFramer::ProcessCommonHeader.
-  bool OnFrameHeader(const Http2FrameHeader& header) override {
-    DVLOG(1) << "OnFrameHeader: " << header;
-    decoded_frame_header_ = true;
-    if (!latched_probable_http_response_) {
-      latched_probable_http_response_ = header.IsProbableHttpResponse();
+  if (!IsSupportedHttp2FrameType(header.type)) {
+    if (extension_ != nullptr) {
+      // Unknown frames will be passed to the registered extension.
+      return true;
     }
-    const uint8_t raw_frame_type = static_cast<uint8_t>(header.type);
-    visitor()->OnCommonHeader(header.stream_id, header.payload_length,
-                              raw_frame_type, header.flags);
-    if (has_expected_frame_type_ && header.type != expected_frame_type_) {
-      // Report an unexpected frame error and close the connection if we
-      // expect a known frame type (probably CONTINUATION) and receive an
-      // unknown frame.
-      VLOG(1) << "The framer was expecting to receive a "
-              << expected_frame_type_
-              << " frame, but instead received an unknown frame of type "
-              << header.type;
-      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME);
+    // In HTTP2 we ignore unknown frame types for extensibility, as long as
+    // the rest of the control frame header is valid.
+    // We rely on the visitor to check validity of stream_id.
+    bool valid_stream =
+        visitor()->OnUnknownFrame(header.stream_id, raw_frame_type);
+    if (!valid_stream) {
+      // Report an invalid frame error if the stream_id is not valid.
+      VLOG(1) << "Unknown control frame type " << header.type
+              << " received on invalid stream " << header.stream_id;
+      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME);
+      return false;
+    } else {
+      DVLOG(1) << "Ignoring unknown frame type " << header.type;
+      return true;
+    }
+  }
+
+  SpdyFrameType frame_type = ToSpdyFrameType(header.type);
+  if (!IsValidHTTP2FrameStreamId(header.stream_id, frame_type)) {
+    VLOG(1) << "The framer received an invalid streamID of " << header.stream_id
+            << " for a frame of type " << header.type;
+    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID);
+    return false;
+  }
+
+  if (has_expected_frame_type_ && header.type != expected_frame_type_) {
+    VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not "
+            << header.type;
+    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME);
+    return false;
+  }
+
+  if (!has_expected_frame_type_ &&
+      header.type == Http2FrameType::CONTINUATION) {
+    VLOG(1) << "Got CONTINUATION frame when not expected.";
+    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME);
+    return false;
+  }
+
+  if (header.type == Http2FrameType::DATA) {
+    // For some reason SpdyFramer still rejects invalid DATA frame flags.
+    uint8_t valid_flags = Http2FrameFlag::PADDED | Http2FrameFlag::END_STREAM;
+    if (header.HasAnyFlags(~valid_flags)) {
+      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_DATA_FRAME_FLAGS);
       return false;
     }
-    if (!IsSupportedHttp2FrameType(header.type)) {
-      if (extension_ != nullptr) {
-        // Unknown frames will be passed to the registered extension.
-        return true;
-      }
-      // In HTTP2 we ignore unknown frame types for extensibility, as long as
-      // the rest of the control frame header is valid.
-      // We rely on the visitor to check validity of stream_id.
-      bool valid_stream =
-          visitor()->OnUnknownFrame(header.stream_id, raw_frame_type);
-      if (!valid_stream) {
-        // Report an invalid frame error if the stream_id is not valid.
-        VLOG(1) << "Unknown control frame type " << header.type
-                << " received on invalid stream " << header.stream_id;
-        SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME);
-        return false;
-      } else {
-        DVLOG(1) << "Ignoring unknown frame type " << header.type;
-        return true;
-      }
-    }
-
-    SpdyFrameType frame_type = ToSpdyFrameType(header.type);
-    if (!IsValidHTTP2FrameStreamId(header.stream_id, frame_type)) {
-      VLOG(1) << "The framer received an invalid streamID of "
-              << header.stream_id << " for a frame of type " << header.type;
-      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID);
-      return false;
-    }
-
-    if (has_expected_frame_type_ && header.type != expected_frame_type_) {
-      VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not "
-              << header.type;
-      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME);
-      return false;
-    }
-
-    if (!has_expected_frame_type_ &&
-        header.type == Http2FrameType::CONTINUATION) {
-      VLOG(1) << "Got CONTINUATION frame when not expected.";
-      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME);
-      return false;
-    }
-
-    if (header.type == Http2FrameType::DATA) {
-      // For some reason SpdyFramer still rejects invalid DATA frame flags.
-      uint8_t valid_flags = Http2FrameFlag::PADDED | Http2FrameFlag::END_STREAM;
-      if (header.HasAnyFlags(~valid_flags)) {
-        SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_DATA_FRAME_FLAGS);
-        return false;
-      }
-    }
-
-    return true;
   }
 
-  void OnDataStart(const Http2FrameHeader& header) override {
-    DVLOG(1) << "OnDataStart: " << header;
+  return true;
+}
 
-    if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
-      frame_header_ = header;
-      has_frame_header_ = true;
-      visitor()->OnDataFrameHeader(header.stream_id, header.payload_length,
-                                   header.IsEndStream());
+void Http2DecoderAdapter::OnDataStart(const Http2FrameHeader& header) {
+  DVLOG(1) << "OnDataStart: " << header;
+
+  if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
+    frame_header_ = header;
+    has_frame_header_ = true;
+    visitor()->OnDataFrameHeader(header.stream_id, header.payload_length,
+                                 header.IsEndStream());
+  }
+}
+
+void Http2DecoderAdapter::OnDataPayload(const char* data, size_t len) {
+  DVLOG(1) << "OnDataPayload: len=" << len;
+  DCHECK(has_frame_header_);
+  DCHECK_EQ(frame_header_.type, Http2FrameType::DATA);
+  visitor()->OnStreamFrameData(frame_header().stream_id, data, len);
+}
+
+void Http2DecoderAdapter::OnDataEnd() {
+  DVLOG(1) << "OnDataEnd";
+  DCHECK(has_frame_header_);
+  DCHECK_EQ(frame_header_.type, Http2FrameType::DATA);
+  if (frame_header().IsEndStream()) {
+    visitor()->OnStreamEnd(frame_header().stream_id);
+  }
+  opt_pad_length_.reset();
+}
+
+void Http2DecoderAdapter::OnHeadersStart(const Http2FrameHeader& header) {
+  DVLOG(1) << "OnHeadersStart: " << header;
+  if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
+    frame_header_ = header;
+    has_frame_header_ = true;
+    if (header.HasPriority()) {
+      // Once we've got the priority fields, then we can report the arrival
+      // of this HEADERS frame.
+      on_headers_called_ = false;
+      return;
     }
-  }
-
-  void OnDataPayload(const char* data, size_t len) override {
-    DVLOG(1) << "OnDataPayload: len=" << len;
-    DCHECK(has_frame_header_);
-    DCHECK_EQ(frame_header_.type, Http2FrameType::DATA);
-    visitor()->OnStreamFrameData(frame_header().stream_id, data, len);
-  }
-
-  void OnDataEnd() override {
-    DVLOG(1) << "OnDataEnd";
-    DCHECK(has_frame_header_);
-    DCHECK_EQ(frame_header_.type, Http2FrameType::DATA);
-    if (frame_header().IsEndStream()) {
-      visitor()->OnStreamEnd(frame_header().stream_id);
-    }
-    opt_pad_length_.reset();
-  }
-
-  void OnHeadersStart(const Http2FrameHeader& header) override {
-    DVLOG(1) << "OnHeadersStart: " << header;
-    if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
-      frame_header_ = header;
-      has_frame_header_ = true;
-      if (header.HasPriority()) {
-        // Once we've got the priority fields, then we can report the arrival
-        // of this HEADERS frame.
-        on_headers_called_ = false;
-        return;
-      }
-      on_headers_called_ = true;
-      ReportReceiveCompressedFrame(header);
-      visitor()->OnHeaders(header.stream_id, kNotHasPriorityFields,
-                           0,      // priority
-                           0,      // parent_stream_id
-                           false,  // exclusive
-                           header.IsEndStream(), header.IsEndHeaders());
-      CommonStartHpackBlock();
-    }
-  }
-
-  void OnHeadersPriority(const Http2PriorityFields& priority) override {
-    DVLOG(1) << "OnHeadersPriority: " << priority;
-    DCHECK(has_frame_header_);
-    DCHECK_EQ(frame_type(), Http2FrameType::HEADERS) << frame_header_;
-    DCHECK(frame_header_.HasPriority());
-    DCHECK(!on_headers_called_);
     on_headers_called_ = true;
-    ReportReceiveCompressedFrame(frame_header_);
-    visitor()->OnHeaders(frame_header_.stream_id, kHasPriorityFields,
-                         priority.weight, priority.stream_dependency,
-                         priority.is_exclusive, frame_header_.IsEndStream(),
-                         frame_header_.IsEndHeaders());
+    ReportReceiveCompressedFrame(header);
+    visitor()->OnHeaders(header.stream_id, kNotHasPriorityFields,
+                         0,      // priority
+                         0,      // parent_stream_id
+                         false,  // exclusive
+                         header.IsEndStream(), header.IsEndHeaders());
     CommonStartHpackBlock();
   }
+}
 
-  void OnHpackFragment(const char* data, size_t len) override {
-    DVLOG(1) << "OnHpackFragment: len=" << len;
-    on_hpack_fragment_called_ = true;
-    if (!GetHpackDecoder()->HandleControlFrameHeadersData(data, len)) {
-      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE);
-      return;
-    }
+void Http2DecoderAdapter::OnHeadersPriority(
+    const Http2PriorityFields& priority) {
+  DVLOG(1) << "OnHeadersPriority: " << priority;
+  DCHECK(has_frame_header_);
+  DCHECK_EQ(frame_type(), Http2FrameType::HEADERS) << frame_header_;
+  DCHECK(frame_header_.HasPriority());
+  DCHECK(!on_headers_called_);
+  on_headers_called_ = true;
+  ReportReceiveCompressedFrame(frame_header_);
+  visitor()->OnHeaders(frame_header_.stream_id, kHasPriorityFields,
+                       priority.weight, priority.stream_dependency,
+                       priority.is_exclusive, frame_header_.IsEndStream(),
+                       frame_header_.IsEndHeaders());
+  CommonStartHpackBlock();
+}
+
+void Http2DecoderAdapter::OnHpackFragment(const char* data, size_t len) {
+  DVLOG(1) << "OnHpackFragment: len=" << len;
+  on_hpack_fragment_called_ = true;
+  if (!GetHpackDecoder()->HandleControlFrameHeadersData(data, len)) {
+    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE);
+    return;
   }
+}
 
-  void OnHeadersEnd() override {
-    DVLOG(1) << "OnHeadersEnd";
-    CommonHpackFragmentEnd();
-    opt_pad_length_.reset();
+void Http2DecoderAdapter::OnHeadersEnd() {
+  DVLOG(1) << "OnHeadersEnd";
+  CommonHpackFragmentEnd();
+  opt_pad_length_.reset();
+}
+
+void Http2DecoderAdapter::OnPriorityFrame(const Http2FrameHeader& header,
+                                          const Http2PriorityFields& priority) {
+  DVLOG(1) << "OnPriorityFrame: " << header << "; priority: " << priority;
+  if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
+    visitor()->OnPriority(header.stream_id, priority.stream_dependency,
+                          priority.weight, priority.is_exclusive);
   }
+}
 
-  void OnPriorityFrame(const Http2FrameHeader& header,
-                       const Http2PriorityFields& priority) override {
-    DVLOG(1) << "OnPriorityFrame: " << header << "; priority: " << priority;
-    if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
-      visitor()->OnPriority(header.stream_id, priority.stream_dependency,
-                            priority.weight, priority.is_exclusive);
-    }
-  }
-
-  void OnContinuationStart(const Http2FrameHeader& header) override {
-    DVLOG(1) << "OnContinuationStart: " << header;
-    if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
-      DCHECK(has_hpack_first_frame_header_);
-      if (header.stream_id != hpack_first_frame_header_.stream_id) {
-        SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME);
-        return;
-      }
-      frame_header_ = header;
-      has_frame_header_ = true;
-      ReportReceiveCompressedFrame(header);
-      visitor()->OnContinuation(header.stream_id, header.IsEndHeaders());
-    }
-  }
-
-  void OnContinuationEnd() override {
-    DVLOG(1) << "OnContinuationEnd";
-    CommonHpackFragmentEnd();
-  }
-
-  void OnPadLength(size_t trailing_length) override {
-    DVLOG(1) << "OnPadLength: " << trailing_length;
-    opt_pad_length_ = trailing_length;
-    if (frame_header_.type == Http2FrameType::DATA) {
-      visitor()->OnStreamPadding(stream_id(), 1);
-    } else if (frame_header_.type == Http2FrameType::HEADERS) {
-      CHECK_LT(trailing_length, 256u);
-    }
-  }
-
-  void OnPadding(const char* padding, size_t skipped_length) override {
-    DVLOG(1) << "OnPadding: " << skipped_length;
-    if (frame_header_.type == Http2FrameType::DATA) {
-      visitor()->OnStreamPadding(stream_id(), skipped_length);
-    } else {
-      MaybeAnnounceEmptyFirstHpackFragment();
-    }
-  }
-
-  void OnRstStream(const Http2FrameHeader& header,
-                   Http2ErrorCode http2_error_code) override {
-    DVLOG(1) << "OnRstStream: " << header << "; code=" << http2_error_code;
-    if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
-      SpdyErrorCode error_code =
-          ParseErrorCode(static_cast<uint32_t>(http2_error_code));
-      visitor()->OnRstStream(header.stream_id, error_code);
-    }
-  }
-
-  void OnSettingsStart(const Http2FrameHeader& header) override {
-    DVLOG(1) << "OnSettingsStart: " << header;
-    if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) {
-      frame_header_ = header;
-      has_frame_header_ = true;
-      visitor()->OnSettings();
-    }
-  }
-
-  void OnSetting(const Http2SettingFields& setting_fields) override {
-    DVLOG(1) << "OnSetting: " << setting_fields;
-    const uint16_t parameter = static_cast<uint16_t>(setting_fields.parameter);
-    SpdySettingsIds setting_id;
-    if (!ParseSettingsId(parameter, &setting_id)) {
-      if (extension_ == nullptr) {
-        DVLOG(1) << "Ignoring unknown setting id: " << setting_fields;
-      } else {
-        extension_->OnSetting(parameter, setting_fields.value);
-      }
-      return;
-    }
-    visitor()->OnSetting(setting_id, setting_fields.value);
-  }
-
-  void OnSettingsEnd() override {
-    DVLOG(1) << "OnSettingsEnd";
-    visitor()->OnSettingsEnd();
-  }
-
-  void OnSettingsAck(const Http2FrameHeader& header) override {
-    DVLOG(1) << "OnSettingsAck: " << header;
-    if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) {
-      visitor()->OnSettingsAck();
-    }
-  }
-
-  void OnPushPromiseStart(const Http2FrameHeader& header,
-                          const Http2PushPromiseFields& promise,
-                          size_t total_padding_length) override {
-    DVLOG(1) << "OnPushPromiseStart: " << header << "; promise: " << promise
-             << "; total_padding_length: " << total_padding_length;
-    if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
-      if (promise.promised_stream_id == 0) {
-        SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME);
-        return;
-      }
-      frame_header_ = header;
-      has_frame_header_ = true;
-      ReportReceiveCompressedFrame(header);
-      visitor()->OnPushPromise(header.stream_id, promise.promised_stream_id,
-                               header.IsEndHeaders());
-      CommonStartHpackBlock();
-    }
-  }
-
-  void OnPushPromiseEnd() override {
-    DVLOG(1) << "OnPushPromiseEnd";
-    CommonHpackFragmentEnd();
-    opt_pad_length_.reset();
-  }
-
-  void OnPing(const Http2FrameHeader& header,
-              const Http2PingFields& ping) override {
-    DVLOG(1) << "OnPing: " << header << "; ping: " << ping;
-    if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) {
-      visitor()->OnPing(ToSpdyPingId(ping), false);
-    }
-  }
-
-  void OnPingAck(const Http2FrameHeader& header,
-                 const Http2PingFields& ping) override {
-    DVLOG(1) << "OnPingAck: " << header << "; ping: " << ping;
-    if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) {
-      visitor()->OnPing(ToSpdyPingId(ping), true);
-    }
-  }
-
-  void OnGoAwayStart(const Http2FrameHeader& header,
-                     const Http2GoAwayFields& goaway) override {
-    DVLOG(1) << "OnGoAwayStart: " << header << "; goaway: " << goaway;
-    if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) {
-      frame_header_ = header;
-      has_frame_header_ = true;
-      SpdyErrorCode error_code =
-          ParseErrorCode(static_cast<uint32_t>(goaway.error_code));
-      visitor()->OnGoAway(goaway.last_stream_id, error_code);
-    }
-  }
-
-  void OnGoAwayOpaqueData(const char* data, size_t len) override {
-    DVLOG(1) << "OnGoAwayOpaqueData: len=" << len;
-    visitor()->OnGoAwayFrameData(data, len);
-  }
-
-  void OnGoAwayEnd() override {
-    DVLOG(1) << "OnGoAwayEnd";
-    visitor()->OnGoAwayFrameData(nullptr, 0);
-  }
-
-  void OnWindowUpdate(const Http2FrameHeader& header,
-                      uint32_t increment) override {
-    DVLOG(1) << "OnWindowUpdate: " << header << "; increment=" << increment;
-    if (IsOkToStartFrame(header)) {
-      visitor()->OnWindowUpdate(header.stream_id, increment);
-    }
-  }
-
-  // Per RFC7838, an ALTSVC frame on stream 0 with origin_length == 0, or one on
-  // a stream other than stream 0 with origin_length != 0 MUST be ignored.  All
-  // frames are decoded by Http2DecoderAdapter, and it is left to the consumer
-  // (listener) to implement this behavior.
-  void OnAltSvcStart(const Http2FrameHeader& header,
-                     size_t origin_length,
-                     size_t value_length) override {
-    DVLOG(1) << "OnAltSvcStart: " << header
-             << "; origin_length: " << origin_length
-             << "; value_length: " << value_length;
-    if (!IsOkToStartFrame(header)) {
+void Http2DecoderAdapter::OnContinuationStart(const Http2FrameHeader& header) {
+  DVLOG(1) << "OnContinuationStart: " << header;
+  if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
+    DCHECK(has_hpack_first_frame_header_);
+    if (header.stream_id != hpack_first_frame_header_.stream_id) {
+      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME);
       return;
     }
     frame_header_ = header;
     has_frame_header_ = true;
-    alt_svc_origin_.clear();
-    alt_svc_value_.clear();
+    ReportReceiveCompressedFrame(header);
+    visitor()->OnContinuation(header.stream_id, header.IsEndHeaders());
   }
+}
 
-  void OnAltSvcOriginData(const char* data, size_t len) override {
-    DVLOG(1) << "OnAltSvcOriginData: len=" << len;
-    alt_svc_origin_.append(data, len);
+void Http2DecoderAdapter::OnContinuationEnd() {
+  DVLOG(1) << "OnContinuationEnd";
+  CommonHpackFragmentEnd();
+}
+
+void Http2DecoderAdapter::OnPadLength(size_t trailing_length) {
+  DVLOG(1) << "OnPadLength: " << trailing_length;
+  opt_pad_length_ = trailing_length;
+  if (frame_header_.type == Http2FrameType::DATA) {
+    visitor()->OnStreamPadding(stream_id(), 1);
+  } else if (frame_header_.type == Http2FrameType::HEADERS) {
+    CHECK_LT(trailing_length, 256u);
   }
+}
 
-  // Called when decoding the Alt-Svc-Field-Value of an ALTSVC;
-  // the field is uninterpreted.
-  void OnAltSvcValueData(const char* data, size_t len) override {
-    DVLOG(1) << "OnAltSvcValueData: len=" << len;
-    alt_svc_value_.append(data, len);
+void Http2DecoderAdapter::OnPadding(const char* padding,
+                                    size_t skipped_length) {
+  DVLOG(1) << "OnPadding: " << skipped_length;
+  if (frame_header_.type == Http2FrameType::DATA) {
+    visitor()->OnStreamPadding(stream_id(), skipped_length);
+  } else {
+    MaybeAnnounceEmptyFirstHpackFragment();
   }
+}
 
-  void OnAltSvcEnd() override {
-    DVLOG(1) << "OnAltSvcEnd: origin.size(): " << alt_svc_origin_.size()
-             << "; value.size(): " << alt_svc_value_.size();
-    SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
-    if (!SpdyAltSvcWireFormat::ParseHeaderFieldValue(alt_svc_value_,
-                                                     &altsvc_vector)) {
-      DLOG(ERROR) << "SpdyAltSvcWireFormat::ParseHeaderFieldValue failed.";
+void Http2DecoderAdapter::OnRstStream(const Http2FrameHeader& header,
+                                      Http2ErrorCode http2_error_code) {
+  DVLOG(1) << "OnRstStream: " << header << "; code=" << http2_error_code;
+  if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
+    SpdyErrorCode error_code =
+        ParseErrorCode(static_cast<uint32_t>(http2_error_code));
+    visitor()->OnRstStream(header.stream_id, error_code);
+  }
+}
+
+void Http2DecoderAdapter::OnSettingsStart(const Http2FrameHeader& header) {
+  DVLOG(1) << "OnSettingsStart: " << header;
+  if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) {
+    frame_header_ = header;
+    has_frame_header_ = true;
+    visitor()->OnSettings();
+  }
+}
+
+void Http2DecoderAdapter::OnSetting(const Http2SettingFields& setting_fields) {
+  DVLOG(1) << "OnSetting: " << setting_fields;
+  const uint16_t parameter = static_cast<uint16_t>(setting_fields.parameter);
+  SpdySettingsIds setting_id;
+  if (!ParseSettingsId(parameter, &setting_id)) {
+    if (extension_ == nullptr) {
+      DVLOG(1) << "Ignoring unknown setting id: " << setting_fields;
+    } else {
+      extension_->OnSetting(parameter, setting_fields.value);
+    }
+    return;
+  }
+  visitor()->OnSetting(setting_id, setting_fields.value);
+}
+
+void Http2DecoderAdapter::OnSettingsEnd() {
+  DVLOG(1) << "OnSettingsEnd";
+  visitor()->OnSettingsEnd();
+}
+
+void Http2DecoderAdapter::OnSettingsAck(const Http2FrameHeader& header) {
+  DVLOG(1) << "OnSettingsAck: " << header;
+  if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) {
+    visitor()->OnSettingsAck();
+  }
+}
+
+void Http2DecoderAdapter::OnPushPromiseStart(
+    const Http2FrameHeader& header,
+    const Http2PushPromiseFields& promise,
+    size_t total_padding_length) {
+  DVLOG(1) << "OnPushPromiseStart: " << header << "; promise: " << promise
+           << "; total_padding_length: " << total_padding_length;
+  if (IsOkToStartFrame(header) && HasRequiredStreamId(header)) {
+    if (promise.promised_stream_id == 0) {
       SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME);
       return;
     }
-    visitor()->OnAltSvc(frame_header_.stream_id, alt_svc_origin_,
-                        altsvc_vector);
-    // We assume that ALTSVC frames are rare, so get rid of the storage.
-    alt_svc_origin_.clear();
-    alt_svc_origin_.shrink_to_fit();
-    alt_svc_value_.clear();
-    alt_svc_value_.shrink_to_fit();
+    frame_header_ = header;
+    has_frame_header_ = true;
+    ReportReceiveCompressedFrame(header);
+    visitor()->OnPushPromise(header.stream_id, promise.promised_stream_id,
+                             header.IsEndHeaders());
+    CommonStartHpackBlock();
   }
+}
 
-  // Except for BLOCKED frames, all other unknown frames are either dropped or
-  // passed to a registered extension.
-  void OnUnknownStart(const Http2FrameHeader& header) override {
-    DVLOG(1) << "OnUnknownStart: " << header;
-    if (IsOkToStartFrame(header)) {
-      if (extension_ != nullptr) {
-        const uint8_t type = static_cast<uint8_t>(header.type);
-        const uint8_t flags = static_cast<uint8_t>(header.flags);
-        handling_extension_payload_ = extension_->OnFrameHeader(
-            header.stream_id, header.payload_length, type, flags);
-      }
+void Http2DecoderAdapter::OnPushPromiseEnd() {
+  DVLOG(1) << "OnPushPromiseEnd";
+  CommonHpackFragmentEnd();
+  opt_pad_length_.reset();
+}
+
+void Http2DecoderAdapter::OnPing(const Http2FrameHeader& header,
+                                 const Http2PingFields& ping) {
+  DVLOG(1) << "OnPing: " << header << "; ping: " << ping;
+  if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) {
+    visitor()->OnPing(ToSpdyPingId(ping), false);
+  }
+}
+
+void Http2DecoderAdapter::OnPingAck(const Http2FrameHeader& header,
+                                    const Http2PingFields& ping) {
+  DVLOG(1) << "OnPingAck: " << header << "; ping: " << ping;
+  if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) {
+    visitor()->OnPing(ToSpdyPingId(ping), true);
+  }
+}
+
+void Http2DecoderAdapter::OnGoAwayStart(const Http2FrameHeader& header,
+                                        const Http2GoAwayFields& goaway) {
+  DVLOG(1) << "OnGoAwayStart: " << header << "; goaway: " << goaway;
+  if (IsOkToStartFrame(header) && HasRequiredStreamIdZero(header)) {
+    frame_header_ = header;
+    has_frame_header_ = true;
+    SpdyErrorCode error_code =
+        ParseErrorCode(static_cast<uint32_t>(goaway.error_code));
+    visitor()->OnGoAway(goaway.last_stream_id, error_code);
+  }
+}
+
+void Http2DecoderAdapter::OnGoAwayOpaqueData(const char* data, size_t len) {
+  DVLOG(1) << "OnGoAwayOpaqueData: len=" << len;
+  visitor()->OnGoAwayFrameData(data, len);
+}
+
+void Http2DecoderAdapter::OnGoAwayEnd() {
+  DVLOG(1) << "OnGoAwayEnd";
+  visitor()->OnGoAwayFrameData(nullptr, 0);
+}
+
+void Http2DecoderAdapter::OnWindowUpdate(const Http2FrameHeader& header,
+                                         uint32_t increment) {
+  DVLOG(1) << "OnWindowUpdate: " << header << "; increment=" << increment;
+  if (IsOkToStartFrame(header)) {
+    visitor()->OnWindowUpdate(header.stream_id, increment);
+  }
+}
+
+// Per RFC7838, an ALTSVC frame on stream 0 with origin_length == 0, or one on
+// a stream other than stream 0 with origin_length != 0 MUST be ignored.  All
+// frames are decoded by Http2DecoderAdapter, and it is left to the consumer
+// (listener) to implement this behavior.
+void Http2DecoderAdapter::OnAltSvcStart(const Http2FrameHeader& header,
+                                        size_t origin_length,
+                                        size_t value_length) {
+  DVLOG(1) << "OnAltSvcStart: " << header
+           << "; origin_length: " << origin_length
+           << "; value_length: " << value_length;
+  if (!IsOkToStartFrame(header)) {
+    return;
+  }
+  frame_header_ = header;
+  has_frame_header_ = true;
+  alt_svc_origin_.clear();
+  alt_svc_value_.clear();
+}
+
+void Http2DecoderAdapter::OnAltSvcOriginData(const char* data, size_t len) {
+  DVLOG(1) << "OnAltSvcOriginData: len=" << len;
+  alt_svc_origin_.append(data, len);
+}
+
+// Called when decoding the Alt-Svc-Field-Value of an ALTSVC;
+// the field is uninterpreted.
+void Http2DecoderAdapter::OnAltSvcValueData(const char* data, size_t len) {
+  DVLOG(1) << "OnAltSvcValueData: len=" << len;
+  alt_svc_value_.append(data, len);
+}
+
+void Http2DecoderAdapter::OnAltSvcEnd() {
+  DVLOG(1) << "OnAltSvcEnd: origin.size(): " << alt_svc_origin_.size()
+           << "; value.size(): " << alt_svc_value_.size();
+  SpdyAltSvcWireFormat::AlternativeServiceVector altsvc_vector;
+  if (!SpdyAltSvcWireFormat::ParseHeaderFieldValue(alt_svc_value_,
+                                                   &altsvc_vector)) {
+    DLOG(ERROR) << "SpdyAltSvcWireFormat::ParseHeaderFieldValue failed.";
+    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME);
+    return;
+  }
+  visitor()->OnAltSvc(frame_header_.stream_id, alt_svc_origin_, altsvc_vector);
+  // We assume that ALTSVC frames are rare, so get rid of the storage.
+  alt_svc_origin_.clear();
+  alt_svc_origin_.shrink_to_fit();
+  alt_svc_value_.clear();
+  alt_svc_value_.shrink_to_fit();
+}
+
+// Except for BLOCKED frames, all other unknown frames are either dropped or
+// passed to a registered extension.
+void Http2DecoderAdapter::OnUnknownStart(const Http2FrameHeader& header) {
+  DVLOG(1) << "OnUnknownStart: " << header;
+  if (IsOkToStartFrame(header)) {
+    if (extension_ != nullptr) {
+      const uint8_t type = static_cast<uint8_t>(header.type);
+      const uint8_t flags = static_cast<uint8_t>(header.flags);
+      handling_extension_payload_ = extension_->OnFrameHeader(
+          header.stream_id, header.payload_length, type, flags);
     }
   }
+}
 
-  void OnUnknownPayload(const char* data, size_t len) override {
-    if (handling_extension_payload_) {
-      extension_->OnFramePayload(data, len);
-    } else {
-      DVLOG(1) << "OnUnknownPayload: len=" << len;
-    }
+void Http2DecoderAdapter::OnUnknownPayload(const char* data, size_t len) {
+  if (handling_extension_payload_) {
+    extension_->OnFramePayload(data, len);
+  } else {
+    DVLOG(1) << "OnUnknownPayload: len=" << len;
   }
+}
 
-  void OnUnknownEnd() override {
-    DVLOG(1) << "OnUnknownEnd";
-    handling_extension_payload_ = false;
-  }
+void Http2DecoderAdapter::OnUnknownEnd() {
+  DVLOG(1) << "OnUnknownEnd";
+  handling_extension_payload_ = false;
+}
 
-  void OnPaddingTooLong(const Http2FrameHeader& header,
-                        size_t missing_length) override {
-    DVLOG(1) << "OnPaddingTooLong: " << header
-             << "; missing_length: " << missing_length;
-    if (header.type == Http2FrameType::DATA) {
-      if (header.payload_length == 0) {
-        DCHECK_EQ(1u, missing_length);
-        SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_DATA_FRAME_FLAGS);
-        return;
-      }
-      visitor()->OnStreamPadding(header.stream_id, 1);
-    }
-    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_PADDING);
-  }
-
-  void OnFrameSizeError(const Http2FrameHeader& header) override {
-    DVLOG(1) << "OnFrameSizeError: " << header;
-    size_t recv_limit = recv_frame_size_limit_;
-    if (header.payload_length > recv_limit) {
-      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_OVERSIZED_PAYLOAD);
+void Http2DecoderAdapter::OnPaddingTooLong(const Http2FrameHeader& header,
+                                           size_t missing_length) {
+  DVLOG(1) << "OnPaddingTooLong: " << header
+           << "; missing_length: " << missing_length;
+  if (header.type == Http2FrameType::DATA) {
+    if (header.payload_length == 0) {
+      DCHECK_EQ(1u, missing_length);
+      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_DATA_FRAME_FLAGS);
       return;
     }
-    if (header.type != Http2FrameType::DATA &&
-        header.payload_length > recv_limit) {
-      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_CONTROL_PAYLOAD_TOO_LARGE);
-      return;
-    }
-    switch (header.type) {
-      case Http2FrameType::GOAWAY:
-      case Http2FrameType::ALTSVC:
-        SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME);
-        break;
-      default:
-        SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME_SIZE);
-    }
+    visitor()->OnStreamPadding(header.stream_id, 1);
   }
+  SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_PADDING);
+}
 
- private:
-  // Decodes the input up to the next frame boundary (i.e. at most one frame),
-  // stopping early if an error is detected.
-  size_t ProcessInputFrame(const char* data, size_t len) {
-    DCHECK_NE(spdy_state_, SpdyState::SPDY_ERROR);
-    DecodeBuffer db(data, len);
-    DecodeStatus status = frame_decoder_->DecodeFrame(&db);
-    if (spdy_state_ != SpdyFramer::SPDY_ERROR) {
-      DetermineSpdyState(status);
-    } else {
-      VLOG(1) << "ProcessInputFrame spdy_framer_error_="
-              << SpdyFramer::SpdyFramerErrorToString(spdy_framer_error_);
-      if (spdy_framer_error_ == SpdyFramerError::SPDY_INVALID_PADDING &&
-          has_frame_header_ && frame_type() != Http2FrameType::DATA) {
-        // spdy_framer_test checks that all of the available frame payload
-        // has been consumed, so do that.
-        size_t total = remaining_total_payload();
-        if (total <= frame_header().payload_length) {
-          size_t avail = db.MinLengthRemaining(total);
-          VLOG(1) << "Skipping past " << avail << " bytes, of " << total
-                  << " total remaining in the frame's payload.";
-          db.AdvanceCursor(avail);
-        } else {
-          SPDY_BUG << "Total remaining (" << total
-                   << ") should not be greater than the payload length; "
-                   << frame_header();
-        }
+void Http2DecoderAdapter::OnFrameSizeError(const Http2FrameHeader& header) {
+  DVLOG(1) << "OnFrameSizeError: " << header;
+  size_t recv_limit = recv_frame_size_limit_;
+  if (header.payload_length > recv_limit) {
+    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_OVERSIZED_PAYLOAD);
+    return;
+  }
+  if (header.type != Http2FrameType::DATA &&
+      header.payload_length > recv_limit) {
+    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_CONTROL_PAYLOAD_TOO_LARGE);
+    return;
+  }
+  switch (header.type) {
+    case Http2FrameType::GOAWAY:
+    case Http2FrameType::ALTSVC:
+      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME);
+      break;
+    default:
+      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_CONTROL_FRAME_SIZE);
+  }
+}
+
+// Decodes the input up to the next frame boundary (i.e. at most one frame),
+// stopping early if an error is detected.
+size_t Http2DecoderAdapter::ProcessInputFrame(const char* data, size_t len) {
+  DCHECK_NE(spdy_state_, SpdyState::SPDY_ERROR);
+  DecodeBuffer db(data, len);
+  DecodeStatus status = frame_decoder_->DecodeFrame(&db);
+  if (spdy_state_ != SpdyState::SPDY_ERROR) {
+    DetermineSpdyState(status);
+  } else {
+    VLOG(1) << "ProcessInputFrame spdy_framer_error_="
+            << SpdyFramer::SpdyFramerErrorToString(spdy_framer_error_);
+    if (spdy_framer_error_ == SpdyFramerError::SPDY_INVALID_PADDING &&
+        has_frame_header_ && frame_type() != Http2FrameType::DATA) {
+      // spdy_framer_test checks that all of the available frame payload
+      // has been consumed, so do that.
+      size_t total = remaining_total_payload();
+      if (total <= frame_header().payload_length) {
+        size_t avail = db.MinLengthRemaining(total);
+        VLOG(1) << "Skipping past " << avail << " bytes, of " << total
+                << " total remaining in the frame's payload.";
+        db.AdvanceCursor(avail);
+      } else {
+        SPDY_BUG << "Total remaining (" << total
+                 << ") should not be greater than the payload length; "
+                 << frame_header();
       }
     }
-    return db.Offset();
   }
+  return db.Offset();
+}
 
-  // After decoding, determine the next SpdyState. Only called if the current
-  // state is NOT SpdyState::SPDY_ERROR (i.e. if none of the callback methods
-  // detected an error condition), because otherwise we assume that the callback
-  // method has set spdy_framer_error_ appropriately.
-  void DetermineSpdyState(DecodeStatus status) {
-    DCHECK_EQ(spdy_framer_error_, SpdyFramer::SPDY_NO_ERROR);
-    DCHECK(!HasError()) << spdy_framer_error_;
-    switch (status) {
-      case DecodeStatus::kDecodeDone:
-        DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeDone";
-        ResetBetweenFrames();
-        break;
-      case DecodeStatus::kDecodeInProgress:
-        DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeInProgress";
-        if (decoded_frame_header_) {
-          if (IsDiscardingPayload()) {
-            set_spdy_state(SpdyState::SPDY_IGNORE_REMAINING_PAYLOAD);
-          } else if (has_frame_header_ &&
-                     frame_type() == Http2FrameType::DATA) {
-            if (IsReadingPaddingLength()) {
-              set_spdy_state(SpdyState::SPDY_READ_DATA_FRAME_PADDING_LENGTH);
-            } else if (IsSkippingPadding()) {
-              set_spdy_state(SpdyState::SPDY_CONSUME_PADDING);
-            } else {
-              set_spdy_state(SpdyState::SPDY_FORWARD_STREAM_FRAME);
-            }
-          } else {
-            set_spdy_state(SpdyState::SPDY_CONTROL_FRAME_PAYLOAD);
-          }
-        } else {
-          set_spdy_state(SpdyState::SPDY_READING_COMMON_HEADER);
-        }
-        break;
-      case DecodeStatus::kDecodeError:
-        VLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeError";
+// After decoding, determine the next SpdyState. Only called if the current
+// state is NOT SpdyState::SPDY_ERROR (i.e. if none of the callback methods
+// detected an error condition), because otherwise we assume that the callback
+// method has set spdy_framer_error_ appropriately.
+void Http2DecoderAdapter::DetermineSpdyState(DecodeStatus status) {
+  DCHECK_EQ(spdy_framer_error_, SpdyFramer::SPDY_NO_ERROR);
+  DCHECK(!HasError()) << spdy_framer_error_;
+  switch (status) {
+    case DecodeStatus::kDecodeDone:
+      DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeDone";
+      ResetBetweenFrames();
+      break;
+    case DecodeStatus::kDecodeInProgress:
+      DVLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeInProgress";
+      if (decoded_frame_header_) {
         if (IsDiscardingPayload()) {
-          if (remaining_total_payload() == 0) {
-            // Push the Http2FrameDecoder out of state kDiscardPayload now
-            // since doing so requires no input.
-            DecodeBuffer tmp("", 0);
-            DecodeStatus status = frame_decoder_->DecodeFrame(&tmp);
-            if (status != DecodeStatus::kDecodeDone) {
-              SPDY_BUG << "Expected to be done decoding the frame, not "
-                       << status;
-              SetSpdyErrorAndNotify(SpdyFramer::SPDY_INTERNAL_FRAMER_ERROR);
-            } else if (spdy_framer_error_ != SpdyFramer::SPDY_NO_ERROR) {
-              SPDY_BUG << "Expected to have no error, not "
-                       << SpdyFramer::SpdyFramerErrorToString(
-                              spdy_framer_error_);
-            } else {
-              ResetBetweenFrames();
-            }
+          set_spdy_state(SpdyState::SPDY_IGNORE_REMAINING_PAYLOAD);
+        } else if (has_frame_header_ && frame_type() == Http2FrameType::DATA) {
+          if (IsReadingPaddingLength()) {
+            set_spdy_state(SpdyState::SPDY_READ_DATA_FRAME_PADDING_LENGTH);
+          } else if (IsSkippingPadding()) {
+            set_spdy_state(SpdyState::SPDY_CONSUME_PADDING);
           } else {
-            set_spdy_state(SpdyState::SPDY_IGNORE_REMAINING_PAYLOAD);
+            set_spdy_state(SpdyState::SPDY_FORWARD_STREAM_FRAME);
           }
         } else {
-          SetSpdyErrorAndNotify(SpdyFramer::SPDY_INVALID_CONTROL_FRAME);
+          set_spdy_state(SpdyState::SPDY_CONTROL_FRAME_PAYLOAD);
         }
-        break;
-    }
+      } else {
+        set_spdy_state(SpdyState::SPDY_READING_COMMON_HEADER);
+      }
+      break;
+    case DecodeStatus::kDecodeError:
+      VLOG(1) << "ProcessInputFrame -> DecodeStatus::kDecodeError";
+      if (IsDiscardingPayload()) {
+        if (remaining_total_payload() == 0) {
+          // Push the Http2FrameDecoder out of state kDiscardPayload now
+          // since doing so requires no input.
+          DecodeBuffer tmp("", 0);
+          DecodeStatus status = frame_decoder_->DecodeFrame(&tmp);
+          if (status != DecodeStatus::kDecodeDone) {
+            SPDY_BUG << "Expected to be done decoding the frame, not "
+                     << status;
+            SetSpdyErrorAndNotify(SpdyFramer::SPDY_INTERNAL_FRAMER_ERROR);
+          } else if (spdy_framer_error_ != SpdyFramer::SPDY_NO_ERROR) {
+            SPDY_BUG << "Expected to have no error, not "
+                     << SpdyFramer::SpdyFramerErrorToString(spdy_framer_error_);
+          } else {
+            ResetBetweenFrames();
+          }
+        } else {
+          set_spdy_state(SpdyState::SPDY_IGNORE_REMAINING_PAYLOAD);
+        }
+      } else {
+        SetSpdyErrorAndNotify(SpdyFramer::SPDY_INVALID_CONTROL_FRAME);
+      }
+      break;
+  }
+}
+
+void Http2DecoderAdapter::ResetBetweenFrames() {
+  CorruptFrameHeader(&frame_header_);
+  decoded_frame_header_ = false;
+  has_frame_header_ = false;
+  set_spdy_state(SpdyState::SPDY_READY_FOR_FRAME);
+}
+
+// ResetInternal is called from the constructor, and during tests, but not
+// otherwise (i.e. not between every frame).
+void Http2DecoderAdapter::ResetInternal() {
+  set_spdy_state(SpdyState::SPDY_READY_FOR_FRAME);
+  spdy_framer_error_ = SpdyFramerError::SPDY_NO_ERROR;
+
+  decoded_frame_header_ = false;
+  has_frame_header_ = false;
+  on_headers_called_ = false;
+  on_hpack_fragment_called_ = false;
+  latched_probable_http_response_ = false;
+  has_expected_frame_type_ = false;
+
+  CorruptFrameHeader(&frame_header_);
+  CorruptFrameHeader(&hpack_first_frame_header_);
+
+  frame_decoder_.reset(new Http2FrameDecoder(this));
+  hpack_decoder_ = nullptr;
+}
+
+void Http2DecoderAdapter::set_spdy_state(SpdyState v) {
+  DVLOG(2) << "set_spdy_state(" << SpdyFramer::StateToString(v) << ")";
+  spdy_state_ = v;
+}
+
+void Http2DecoderAdapter::SetSpdyErrorAndNotify(SpdyFramerError error) {
+  if (HasError()) {
+    DCHECK_EQ(spdy_state_, SpdyState::SPDY_ERROR);
+  } else {
+    VLOG(2) << "SetSpdyErrorAndNotify("
+            << SpdyFramer::SpdyFramerErrorToString(error) << ")";
+    DCHECK_NE(error, SpdyFramerError::SPDY_NO_ERROR);
+    spdy_framer_error_ = error;
+    set_spdy_state(SpdyState::SPDY_ERROR);
+    frame_decoder_->set_listener(&no_op_listener_);
+    visitor()->OnError(error);
+  }
+}
+
+bool Http2DecoderAdapter::HasError() const {
+  if (spdy_state_ == SpdyState::SPDY_ERROR) {
+    DCHECK_NE(spdy_framer_error(), SpdyFramerError::SPDY_NO_ERROR);
+    return true;
+  } else {
+    DCHECK_EQ(spdy_framer_error(), SpdyFramerError::SPDY_NO_ERROR);
+    return false;
+  }
+}
+
+const Http2FrameHeader& Http2DecoderAdapter::frame_header() const {
+  DCHECK(has_frame_header_);
+  return frame_header_;
+}
+
+uint32_t Http2DecoderAdapter::stream_id() const {
+  return frame_header().stream_id;
+}
+
+Http2FrameType Http2DecoderAdapter::frame_type() const {
+  return frame_header().type;
+}
+
+size_t Http2DecoderAdapter::remaining_total_payload() const {
+  DCHECK(has_frame_header_);
+  size_t remaining = frame_decoder_->remaining_payload();
+  if (IsPaddable(frame_type()) && frame_header_.IsPadded()) {
+    remaining += frame_decoder_->remaining_padding();
+  }
+  return remaining;
+}
+
+bool Http2DecoderAdapter::IsReadingPaddingLength() {
+  bool result = frame_header_.IsPadded() && !opt_pad_length_;
+  DVLOG(2) << "Http2DecoderAdapter::IsReadingPaddingLength: " << result;
+  return result;
+}
+bool Http2DecoderAdapter::IsSkippingPadding() {
+  bool result = frame_header_.IsPadded() && opt_pad_length_ &&
+                frame_decoder_->remaining_payload() == 0 &&
+                frame_decoder_->remaining_padding() > 0;
+  DVLOG(2) << "Http2DecoderAdapter::IsSkippingPadding: " << result;
+  return result;
+}
+bool Http2DecoderAdapter::IsDiscardingPayload() {
+  bool result = decoded_frame_header_ && frame_decoder_->IsDiscardingPayload();
+  DVLOG(2) << "Http2DecoderAdapter::IsDiscardingPayload: " << result;
+  return result;
+}
+// Called from OnXyz or OnXyzStart methods to decide whether it is OK to
+// handle the callback.
+bool Http2DecoderAdapter::IsOkToStartFrame(const Http2FrameHeader& header) {
+  DVLOG(3) << "IsOkToStartFrame";
+  if (HasError()) {
+    VLOG(2) << "HasError()";
+    return false;
+  }
+  DCHECK(!has_frame_header_);
+  if (has_expected_frame_type_ && header.type != expected_frame_type_) {
+    VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not "
+            << header.type;
+    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME);
+    return false;
   }
 
-  void ResetBetweenFrames() {
-    CorruptFrameHeader(&frame_header_);
-    decoded_frame_header_ = false;
-    has_frame_header_ = false;
-    set_spdy_state(SpdyState::SPDY_READY_FOR_FRAME);
+  return true;
+}
+
+bool Http2DecoderAdapter::HasRequiredStreamId(uint32_t stream_id) {
+  DVLOG(3) << "HasRequiredStreamId: " << stream_id;
+  if (HasError()) {
+    VLOG(2) << "HasError()";
+    return false;
   }
-
-  // ResetInternal is called from the constructor, and during tests, but not
-  // otherwise (i.e. not between every frame).
-  void ResetInternal() {
-    set_spdy_state(SpdyState::SPDY_READY_FOR_FRAME);
-    spdy_framer_error_ = SpdyFramerError::SPDY_NO_ERROR;
-
-    decoded_frame_header_ = false;
-    has_frame_header_ = false;
-    on_headers_called_ = false;
-    on_hpack_fragment_called_ = false;
-    latched_probable_http_response_ = false;
-    has_expected_frame_type_ = false;
-
-    CorruptFrameHeader(&frame_header_);
-    CorruptFrameHeader(&hpack_first_frame_header_);
-
-    frame_decoder_.reset(new Http2FrameDecoder(this));
-    hpack_decoder_ = nullptr;
-  }
-
-  void set_spdy_state(SpdyState v) {
-    DVLOG(2) << "set_spdy_state(" << SpdyFramer::StateToString(v) << ")";
-    spdy_state_ = v;
-  }
-
-  void SetSpdyErrorAndNotify(SpdyFramerError error) {
-    if (HasError()) {
-      DCHECK_EQ(spdy_state_, SpdyState::SPDY_ERROR);
-    } else {
-      VLOG(2) << "SetSpdyErrorAndNotify("
-              << SpdyFramer::SpdyFramerErrorToString(error) << ")";
-      DCHECK_NE(error, SpdyFramerError::SPDY_NO_ERROR);
-      spdy_framer_error_ = error;
-      set_spdy_state(SpdyState::SPDY_ERROR);
-      frame_decoder_->set_listener(&no_op_listener_);
-      visitor()->OnError(error);
-    }
-  }
-
-  bool HasError() const {
-    if (spdy_state_ == SpdyState::SPDY_ERROR) {
-      DCHECK_NE(spdy_framer_error(), SpdyFramerError::SPDY_NO_ERROR);
-      return true;
-    } else {
-      DCHECK_EQ(spdy_framer_error(), SpdyFramerError::SPDY_NO_ERROR);
-      return false;
-    }
-  }
-
-  const Http2FrameHeader& frame_header() const {
-    DCHECK(has_frame_header_);
-    return frame_header_;
-  }
-
-  uint32_t stream_id() const { return frame_header().stream_id; }
-
-  Http2FrameType frame_type() const { return frame_header().type; }
-
-  size_t remaining_total_payload() const {
-    DCHECK(has_frame_header_);
-    size_t remaining = frame_decoder_->remaining_payload();
-    if (IsPaddable(frame_type()) && frame_header_.IsPadded()) {
-      remaining += frame_decoder_->remaining_padding();
-    }
-    return remaining;
-  }
-
-  bool IsReadingPaddingLength() {
-    bool result = frame_header_.IsPadded() && !opt_pad_length_;
-    DVLOG(2) << "Http2DecoderAdapter::IsReadingPaddingLength: " << result;
-    return result;
-  }
-  bool IsSkippingPadding() {
-    bool result = frame_header_.IsPadded() && opt_pad_length_ &&
-                  frame_decoder_->remaining_payload() == 0 &&
-                  frame_decoder_->remaining_padding() > 0;
-    DVLOG(2) << "Http2DecoderAdapter::IsSkippingPadding: " << result;
-    return result;
-  }
-  bool IsDiscardingPayload() {
-    bool result =
-        decoded_frame_header_ && frame_decoder_->IsDiscardingPayload();
-    DVLOG(2) << "Http2DecoderAdapter::IsDiscardingPayload: " << result;
-    return result;
-  }
-  // Called from OnXyz or OnXyzStart methods to decide whether it is OK to
-  // handle the callback.
-  bool IsOkToStartFrame(const Http2FrameHeader& header) {
-    DVLOG(3) << "IsOkToStartFrame";
-    if (HasError()) {
-      VLOG(2) << "HasError()";
-      return false;
-    }
-    DCHECK(!has_frame_header_);
-    if (has_expected_frame_type_ && header.type != expected_frame_type_) {
-      VLOG(1) << "Expected frame type " << expected_frame_type_ << ", not "
-              << header.type;
-      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_UNEXPECTED_FRAME);
-      return false;
-    }
-
+  if (stream_id != 0) {
     return true;
   }
+  VLOG(1) << "Stream Id is required, but zero provided";
+  SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID);
+  return false;
+}
 
-  bool HasRequiredStreamId(uint32_t stream_id) {
-    DVLOG(3) << "HasRequiredStreamId: " << stream_id;
-    if (HasError()) {
-      VLOG(2) << "HasError()";
-      return false;
-    }
-    if (stream_id != 0) {
-      return true;
-    }
-    VLOG(1) << "Stream Id is required, but zero provided";
-    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID);
+bool Http2DecoderAdapter::HasRequiredStreamId(const Http2FrameHeader& header) {
+  return HasRequiredStreamId(header.stream_id);
+}
+
+bool Http2DecoderAdapter::HasRequiredStreamIdZero(uint32_t stream_id) {
+  DVLOG(3) << "HasRequiredStreamIdZero: " << stream_id;
+  if (HasError()) {
+    VLOG(2) << "HasError()";
     return false;
   }
-
-  bool HasRequiredStreamId(const Http2FrameHeader& header) {
-    return HasRequiredStreamId(header.stream_id);
+  if (stream_id == 0) {
+    return true;
   }
+  VLOG(1) << "Stream Id was not zero, as required: " << stream_id;
+  SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID);
+  return false;
+}
 
-  bool HasRequiredStreamIdZero(uint32_t stream_id) {
-    DVLOG(3) << "HasRequiredStreamIdZero: " << stream_id;
-    if (HasError()) {
-      VLOG(2) << "HasError()";
-      return false;
-    }
-    if (stream_id == 0) {
-      return true;
-    }
-    VLOG(1) << "Stream Id was not zero, as required: " << stream_id;
-    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INVALID_STREAM_ID);
-    return false;
+bool Http2DecoderAdapter::HasRequiredStreamIdZero(
+    const Http2FrameHeader& header) {
+  return HasRequiredStreamIdZero(header.stream_id);
+}
+
+void Http2DecoderAdapter::ReportReceiveCompressedFrame(
+    const Http2FrameHeader& header) {
+  if (debug_visitor() != nullptr) {
+    size_t total = header.payload_length + Http2FrameHeader::EncodedSize();
+    debug_visitor()->OnReceiveCompressedFrame(
+        header.stream_id, ToSpdyFrameType(header.type), total);
   }
+}
 
-  bool HasRequiredStreamIdZero(const Http2FrameHeader& header) {
-    return HasRequiredStreamIdZero(header.stream_id);
+HpackDecoderAdapter* Http2DecoderAdapter::GetHpackDecoder() {
+  if (hpack_decoder_ == nullptr) {
+    hpack_decoder_ = SpdyMakeUnique<HpackDecoderAdapter>();
   }
+  return hpack_decoder_.get();
+}
 
-  void ReportReceiveCompressedFrame(const Http2FrameHeader& header) {
-    if (debug_visitor() != nullptr) {
-      size_t total = header.payload_length + Http2FrameHeader::EncodedSize();
-      debug_visitor()->OnReceiveCompressedFrame(
-          header.stream_id, ToSpdyFrameType(header.type), total);
-    }
+void Http2DecoderAdapter::CommonStartHpackBlock() {
+  DVLOG(1) << "CommonStartHpackBlock";
+  DCHECK(!has_hpack_first_frame_header_);
+  if (!frame_header_.IsEndHeaders()) {
+    hpack_first_frame_header_ = frame_header_;
+    has_hpack_first_frame_header_ = true;
+  } else {
+    CorruptFrameHeader(&hpack_first_frame_header_);
   }
-
-  HpackDecoderAdapter* GetHpackDecoder() override {
-    if (hpack_decoder_ == nullptr) {
-      hpack_decoder_ = SpdyMakeUnique<HpackDecoderAdapter>();
-    }
-    return hpack_decoder_.get();
+  on_hpack_fragment_called_ = false;
+  SpdyHeadersHandlerInterface* handler =
+      visitor()->OnHeaderFrameStart(stream_id());
+  if (handler == nullptr) {
+    SPDY_BUG << "visitor_->OnHeaderFrameStart returned nullptr";
+    SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INTERNAL_FRAMER_ERROR);
+    return;
   }
+  GetHpackDecoder()->HandleControlFrameHeadersStart(handler);
+}
 
-  void CommonStartHpackBlock() {
-    DVLOG(1) << "CommonStartHpackBlock";
-    DCHECK(!has_hpack_first_frame_header_);
-    if (!frame_header_.IsEndHeaders()) {
-      hpack_first_frame_header_ = frame_header_;
-      has_hpack_first_frame_header_ = true;
+// SpdyFramer calls HandleControlFrameHeadersData even if there are zero
+// fragment bytes in the first frame, so do the same.
+void Http2DecoderAdapter::MaybeAnnounceEmptyFirstHpackFragment() {
+  if (!on_hpack_fragment_called_) {
+    OnHpackFragment(nullptr, 0);
+    DCHECK(on_hpack_fragment_called_);
+  }
+}
+
+void Http2DecoderAdapter::CommonHpackFragmentEnd() {
+  DVLOG(1) << "CommonHpackFragmentEnd: stream_id=" << stream_id();
+  if (HasError()) {
+    VLOG(1) << "HasError(), returning";
+    return;
+  }
+  DCHECK(has_frame_header_);
+  MaybeAnnounceEmptyFirstHpackFragment();
+  if (frame_header_.IsEndHeaders()) {
+    DCHECK_EQ(has_hpack_first_frame_header_,
+              frame_type() == Http2FrameType::CONTINUATION)
+        << frame_header();
+    has_expected_frame_type_ = false;
+    if (GetHpackDecoder()->HandleControlFrameHeadersComplete(nullptr)) {
+      visitor()->OnHeaderFrameEnd(stream_id());
     } else {
-      CorruptFrameHeader(&hpack_first_frame_header_);
-    }
-    on_hpack_fragment_called_ = false;
-    SpdyHeadersHandlerInterface* handler =
-        visitor()->OnHeaderFrameStart(stream_id());
-    if (handler == nullptr) {
-      SPDY_BUG << "visitor_->OnHeaderFrameStart returned nullptr";
-      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_INTERNAL_FRAMER_ERROR);
+      SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE);
       return;
     }
-    GetHpackDecoder()->HandleControlFrameHeadersStart(handler);
-  }
-
-  // SpdyFramer calls HandleControlFrameHeadersData even if there are zero
-  // fragment bytes in the first frame, so do the same.
-  void MaybeAnnounceEmptyFirstHpackFragment() {
-    if (!on_hpack_fragment_called_) {
-      OnHpackFragment(nullptr, 0);
-      DCHECK(on_hpack_fragment_called_);
+    const Http2FrameHeader& first = frame_type() == Http2FrameType::CONTINUATION
+                                        ? hpack_first_frame_header_
+                                        : frame_header_;
+    if (first.type == Http2FrameType::HEADERS && first.IsEndStream()) {
+      visitor()->OnStreamEnd(first.stream_id);
     }
+    has_hpack_first_frame_header_ = false;
+    CorruptFrameHeader(&hpack_first_frame_header_);
+  } else {
+    DCHECK(has_hpack_first_frame_header_);
+    has_expected_frame_type_ = true;
+    expected_frame_type_ = Http2FrameType::CONTINUATION;
   }
-
-  void CommonHpackFragmentEnd() {
-    DVLOG(1) << "CommonHpackFragmentEnd: stream_id=" << stream_id();
-    if (HasError()) {
-      VLOG(1) << "HasError(), returning";
-      return;
-    }
-    DCHECK(has_frame_header_);
-    MaybeAnnounceEmptyFirstHpackFragment();
-    if (frame_header_.IsEndHeaders()) {
-      DCHECK_EQ(has_hpack_first_frame_header_,
-                frame_type() == Http2FrameType::CONTINUATION)
-          << frame_header();
-      has_expected_frame_type_ = false;
-      if (GetHpackDecoder()->HandleControlFrameHeadersComplete(nullptr)) {
-        visitor()->OnHeaderFrameEnd(stream_id());
-      } else {
-        SetSpdyErrorAndNotify(SpdyFramerError::SPDY_DECOMPRESS_FAILURE);
-        return;
-      }
-      const Http2FrameHeader& first =
-          frame_type() == Http2FrameType::CONTINUATION
-              ? hpack_first_frame_header_
-              : frame_header_;
-      if (first.type == Http2FrameType::HEADERS && first.IsEndStream()) {
-        visitor()->OnStreamEnd(first.stream_id);
-      }
-      has_hpack_first_frame_header_ = false;
-      CorruptFrameHeader(&hpack_first_frame_header_);
-    } else {
-      DCHECK(has_hpack_first_frame_header_);
-      has_expected_frame_type_ = true;
-      expected_frame_type_ = Http2FrameType::CONTINUATION;
-    }
-  }
-
-  // If non-null, unknown frames and settings are passed to the extension.
-  ExtensionVisitorInterface* extension_ = nullptr;
-
-  // The HPACK decoder to be used for this adapter. User is responsible for
-  // clearing if the adapter is to be used for another connection.
-  std::unique_ptr<HpackDecoderAdapter> hpack_decoder_ = nullptr;
-
-  // The HTTP/2 frame decoder. Accessed via a unique_ptr to allow replacement
-  // (e.g. in tests) when Reset() is called.
-  std::unique_ptr<Http2FrameDecoder> frame_decoder_;
-
-  // The most recently decoded frame header; invalid after we reached the end
-  // of that frame.
-  Http2FrameHeader frame_header_;
-
-  // If decoding an HPACK block that is split across multiple frames, this holds
-  // the frame header of the HEADERS or PUSH_PROMISE that started the block.
-  Http2FrameHeader hpack_first_frame_header_;
-
-  // Amount of trailing padding. Currently used just as an indicator of whether
-  // OnPadLength has been called.
-  base::Optional<size_t> opt_pad_length_;
-
-  // Temporary buffers for the AltSvc fields.
-  Http2String alt_svc_origin_;
-  Http2String alt_svc_value_;
-
-  // Listener used if we transition to an error state; the listener ignores all
-  // the callbacks.
-  Http2FrameDecoderNoOpListener no_op_listener_;
-
-  // Next frame type expected. Currently only used for CONTINUATION frames,
-  // but could be used for detecting whether the first frame is a SETTINGS
-  // frame.
-  // TODO(jamessyng): Provide means to indicate that decoder should require
-  // SETTINGS frame as the first frame.
-  Http2FrameType expected_frame_type_;
-
-  // Attempt to duplicate the SpdyState and SpdyFramerError values that
-  // SpdyFramer sets. Values determined by getting tests to pass.
-  SpdyState spdy_state_;
-  SpdyFramerError spdy_framer_error_;
-
-  // The limit on the size of received HTTP/2 payloads as specified in the
-  // SETTINGS_MAX_FRAME_SIZE advertised to peer.
-  size_t recv_frame_size_limit_ = kSpdyInitialFrameSizeLimit;
-
-  // Has OnFrameHeader been called?
-  bool decoded_frame_header_ = false;
-
-  // Have we recorded an Http2FrameHeader for the current frame?
-  // We only do so if the decoder will make multiple callbacks for
-  // the frame; for example, for PING frames we don't make record
-  // the frame header, but for ALTSVC we do.
-  bool has_frame_header_ = false;
-
-  // Have we recorded an Http2FrameHeader for the current HPACK block?
-  // True only for multi-frame HPACK blocks.
-  bool has_hpack_first_frame_header_ = false;
-
-  // Has OnHeaders() already been called for current HEADERS block? Only
-  // meaningful between OnHeadersStart and OnHeadersPriority.
-  bool on_headers_called_;
-
-  // Has OnHpackFragment() already been called for current HPACK block?
-  // SpdyFramer will pass an empty buffer to the HPACK decoder if a HEADERS
-  // or PUSH_PROMISE has no HPACK data in it (e.g. a HEADERS frame with only
-  // padding). Detect that condition and replicate the behavior using this
-  // field.
-  bool on_hpack_fragment_called_;
-
-  // Have we seen a frame header that appears to be an HTTP/1 response?
-  bool latched_probable_http_response_ = false;
-
-  // Is expected_frame_type_ set?
-  bool has_expected_frame_type_ = false;
-
-  // Is the current frame payload destined for |extension_|?
-  bool handling_extension_payload_ = false;
-};
-
-}  // namespace
+}
 
 bool SpdyFramerVisitorInterface::OnGoAwayFrameData(const char* goaway_data,
                                                    size_t len) {
   return true;
 }
 
-SpdyFramerDecoderAdapter::SpdyFramerDecoderAdapter() {
-  DVLOG(1) << PRETTY_THIS;
-}
-
-SpdyFramerDecoderAdapter::~SpdyFramerDecoderAdapter() {
-  DVLOG(1) << PRETTY_THIS;
-}
-
-void SpdyFramerDecoderAdapter::set_visitor(
-    SpdyFramerVisitorInterface* visitor) {
-  visitor_ = visitor;
-}
-
-void SpdyFramerDecoderAdapter::set_debug_visitor(
-    SpdyFramerDebugVisitorInterface* debug_visitor) {
-  debug_visitor_ = debug_visitor;
-}
-
-void SpdyFramerDecoderAdapter::set_process_single_input_frame(bool v) {
-  process_single_input_frame_ = v;
-}
-
-std::unique_ptr<SpdyFramerDecoderAdapter> CreateHttp2FrameDecoderAdapter() {
+std::unique_ptr<Http2DecoderAdapter> CreateHttp2FrameDecoderAdapter() {
   return SpdyMakeUnique<Http2DecoderAdapter>();
 }
 
diff --git a/net/spdy/core/http2_frame_decoder_adapter.h b/net/spdy/core/http2_frame_decoder_adapter.h
index a1ea8b7c..db463e2 100644
--- a/net/spdy/core/http2_frame_decoder_adapter.h
+++ b/net/spdy/core/http2_frame_decoder_adapter.h
@@ -5,15 +5,13 @@
 #ifndef NET_SPDY_CORE_HTTP2_FRAME_DECODER_ADAPTER_H_
 #define NET_SPDY_CORE_HTTP2_FRAME_DECODER_ADAPTER_H_
 
-// Provides a SpdyFramerDecoderAdapter that uses Http2FrameDecoder for decoding
-// HTTP/2 frames. The adapter does not directly decode HPACK, but instead calls
-// SpdyFramer::GetHpackDecoderAdapter() to get the decoder to be used.
-
 #include <stddef.h>
 
 #include <cstdint>
 #include <memory>
 
+#include "base/optional.h"
+#include "net/http2/decoder/http2_frame_decoder.h"
 #include "net/spdy/core/hpack/hpack_header_table.h"
 #include "net/spdy/core/spdy_alt_svc_wire_format.h"
 #include "net/spdy/core/spdy_framer.h"
@@ -23,7 +21,7 @@
 
 namespace net {
 
-// SpdyFramerDecoderAdapter will use the given visitor implementing this
+// Http2DecoderAdapter will use the given visitor implementing this
 // interface to deliver event callbacks as frames are decoded.
 //
 // Control frames that contain HTTP2 header blocks (HEADER, and PUSH_PROMISE)
@@ -182,42 +180,42 @@
   virtual bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) = 0;
 };
 
-// Abstract base class for an HTTP/2 decoder to be called from SpdyFramer.
-class SpdyFramerDecoderAdapter {
+// Adapts SpdyFramer interface to use Http2FrameDecoder.
+class SPDY_EXPORT_PRIVATE Http2DecoderAdapter
+    : public Http2FrameDecoderListener {
  public:
-  SpdyFramerDecoderAdapter();
-  virtual ~SpdyFramerDecoderAdapter();
+  Http2DecoderAdapter();
+  ~Http2DecoderAdapter() override;
 
   // Set callbacks to be called from the framer.  A visitor must be set, or
   // else the framer will likely crash.  It is acceptable for the visitor
   // to do nothing.  If this is called multiple times, only the last visitor
   // will be used.
-  virtual void set_visitor(SpdyFramerVisitorInterface* visitor);
+  void set_visitor(SpdyFramerVisitorInterface* visitor);
   SpdyFramerVisitorInterface* visitor() const { return visitor_; }
 
   // Set extension callbacks to be called from the framer or decoder. Optional.
   // If called multiple times, only the last visitor will be used.
-  virtual void set_extension_visitor(ExtensionVisitorInterface* visitor) = 0;
+  void set_extension_visitor(ExtensionVisitorInterface* visitor);
 
   // Set debug callbacks to be called from the framer. The debug visitor is
   // completely optional and need not be set in order for normal operation.
   // If this is called multiple times, only the last visitor will be used.
-  virtual void set_debug_visitor(
-      SpdyFramerDebugVisitorInterface* debug_visitor);
+  void set_debug_visitor(SpdyFramerDebugVisitorInterface* debug_visitor);
   SpdyFramerDebugVisitorInterface* debug_visitor() const {
     return debug_visitor_;
   }
 
   // Set debug callbacks to be called from the HPACK decoder.
-  virtual void SetDecoderHeaderTableDebugVisitor(
-      std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor) = 0;
+  void SetDecoderHeaderTableDebugVisitor(
+      std::unique_ptr<HpackHeaderTable::DebugVisitorInterface> visitor);
 
   // Sets whether or not ProcessInput returns after finishing a frame, or
   // continues processing additional frames. Normally ProcessInput processes
   // all input, but this method enables the caller (and visitor) to work with
   // a single frame at a time (or that portion of the frame which is provided
   // as input). Reset() does not change the value of this flag.
-  virtual void set_process_single_input_frame(bool v);
+  void set_process_single_input_frame(bool v);
   bool process_single_input_frame() const {
     return process_single_input_frame_;
   }
@@ -226,35 +224,206 @@
   // the number of bytes consumed. It is safe to pass more bytes in than
   // may be consumed. Should process (or otherwise buffer) as much as
   // available, unless process_single_input_frame is true.
-  virtual size_t ProcessInput(const char* data, size_t len) = 0;
+  size_t ProcessInput(const char* data, size_t len);
 
   // Reset the decoder (used just for tests at this time).
-  virtual void Reset() = 0;
+  void Reset();
 
   // Current state of the decoder.
-  virtual SpdyFramer::SpdyState state() const = 0;
+  SpdyFramer::SpdyState state() const;
 
   // Current error code (NO_ERROR if state != ERROR).
-  virtual SpdyFramer::SpdyFramerError spdy_framer_error() const = 0;
+  SpdyFramer::SpdyFramerError spdy_framer_error() const;
 
   // Has any frame header looked like the start of an HTTP/1.1 (or earlier)
   // response? Used to detect if a backend/server that we sent a request to
   // has responded with an HTTP/1.1 (or earlier) response.
-  virtual bool probable_http_response() const = 0;
+  bool probable_http_response() const;
 
   // Returns the estimate of dynamically allocated memory in bytes.
-  virtual size_t EstimateMemoryUsage() const = 0;
+  size_t EstimateMemoryUsage() const;
 
-  // Get (and lazily initialize) the HPACK decoder state.
-  virtual HpackDecoderAdapter* GetHpackDecoder() = 0;
+  HpackDecoderAdapter* GetHpackDecoder();
 
  private:
+  bool OnFrameHeader(const Http2FrameHeader& header) override;
+  void OnDataStart(const Http2FrameHeader& header) override;
+  void OnDataPayload(const char* data, size_t len) override;
+  void OnDataEnd() override;
+  void OnHeadersStart(const Http2FrameHeader& header) override;
+  void OnHeadersPriority(const Http2PriorityFields& priority) override;
+  void OnHpackFragment(const char* data, size_t len) override;
+  void OnHeadersEnd() override;
+  void OnPriorityFrame(const Http2FrameHeader& header,
+                       const Http2PriorityFields& priority) override;
+  void OnContinuationStart(const Http2FrameHeader& header) override;
+  void OnContinuationEnd() override;
+  void OnPadLength(size_t trailing_length) override;
+  void OnPadding(const char* padding, size_t skipped_length) override;
+  void OnRstStream(const Http2FrameHeader& header,
+                   Http2ErrorCode http2_error_code) override;
+  void OnSettingsStart(const Http2FrameHeader& header) override;
+  void OnSetting(const Http2SettingFields& setting_fields) override;
+  void OnSettingsEnd() override;
+  void OnSettingsAck(const Http2FrameHeader& header) override;
+  void OnPushPromiseStart(const Http2FrameHeader& header,
+                          const Http2PushPromiseFields& promise,
+                          size_t total_padding_length) override;
+  void OnPushPromiseEnd() override;
+  void OnPing(const Http2FrameHeader& header,
+              const Http2PingFields& ping) override;
+  void OnPingAck(const Http2FrameHeader& header,
+                 const Http2PingFields& ping) override;
+  void OnGoAwayStart(const Http2FrameHeader& header,
+                     const Http2GoAwayFields& goaway) override;
+  void OnGoAwayOpaqueData(const char* data, size_t len) override;
+  void OnGoAwayEnd() override;
+  void OnWindowUpdate(const Http2FrameHeader& header,
+                      uint32_t increment) override;
+  void OnAltSvcStart(const Http2FrameHeader& header,
+                     size_t origin_length,
+                     size_t value_length) override;
+  void OnAltSvcOriginData(const char* data, size_t len) override;
+  void OnAltSvcValueData(const char* data, size_t len) override;
+  void OnAltSvcEnd() override;
+  void OnUnknownStart(const Http2FrameHeader& header) override;
+  void OnUnknownPayload(const char* data, size_t len) override;
+  void OnUnknownEnd() override;
+  void OnPaddingTooLong(const Http2FrameHeader& header,
+                        size_t missing_length) override;
+  void OnFrameSizeError(const Http2FrameHeader& header) override;
+
+  size_t ProcessInputFrame(const char* data, size_t len);
+
+  void DetermineSpdyState(DecodeStatus status);
+  void ResetBetweenFrames();
+
+  // ResetInternal is called from the constructor, and during tests, but not
+  // otherwise (i.e. not between every frame).
+  void ResetInternal();
+
+  void set_spdy_state(SpdyFramer::SpdyState v);
+
+  void SetSpdyErrorAndNotify(SpdyFramer::SpdyFramerError error);
+
+  bool HasError() const;
+  const Http2FrameHeader& frame_header() const;
+
+  uint32_t stream_id() const;
+  Http2FrameType frame_type() const;
+
+  size_t remaining_total_payload() const;
+
+  bool IsReadingPaddingLength();
+  bool IsSkippingPadding();
+  bool IsDiscardingPayload();
+  // Called from OnXyz or OnXyzStart methods to decide whether it is OK to
+  // handle the callback.
+  bool IsOkToStartFrame(const Http2FrameHeader& header);
+  bool HasRequiredStreamId(uint32_t stream_id);
+
+  bool HasRequiredStreamId(const Http2FrameHeader& header);
+
+  bool HasRequiredStreamIdZero(uint32_t stream_id);
+
+  bool HasRequiredStreamIdZero(const Http2FrameHeader& header);
+
+  void ReportReceiveCompressedFrame(const Http2FrameHeader& header);
+
+  void CommonStartHpackBlock();
+
+  // SpdyFramer calls HandleControlFrameHeadersData even if there are zero
+  // fragment bytes in the first frame, so do the same.
+  void MaybeAnnounceEmptyFirstHpackFragment();
+  void CommonHpackFragmentEnd();
+
+  // The most recently decoded frame header; invalid after we reached the end
+  // of that frame.
+  Http2FrameHeader frame_header_;
+
+  // If decoding an HPACK block that is split across multiple frames, this holds
+  // the frame header of the HEADERS or PUSH_PROMISE that started the block.
+  Http2FrameHeader hpack_first_frame_header_;
+
+  // Amount of trailing padding. Currently used just as an indicator of whether
+  // OnPadLength has been called.
+  base::Optional<size_t> opt_pad_length_;
+
+  // Temporary buffers for the AltSvc fields.
+  Http2String alt_svc_origin_;
+  Http2String alt_svc_value_;
+
+  // Listener used if we transition to an error state; the listener ignores all
+  // the callbacks.
+  Http2FrameDecoderNoOpListener no_op_listener_;
+
   SpdyFramerVisitorInterface* visitor_ = nullptr;
   SpdyFramerDebugVisitorInterface* debug_visitor_ = nullptr;
+
+  // If non-null, unknown frames and settings are passed to the extension.
+  ExtensionVisitorInterface* extension_ = nullptr;
+
+  // The HPACK decoder to be used for this adapter. User is responsible for
+  // clearing if the adapter is to be used for another connection.
+  std::unique_ptr<HpackDecoderAdapter> hpack_decoder_ = nullptr;
+
+  // The HTTP/2 frame decoder. Accessed via a unique_ptr to allow replacement
+  // (e.g. in tests) when Reset() is called.
+  std::unique_ptr<Http2FrameDecoder> frame_decoder_;
+
+  // Next frame type expected. Currently only used for CONTINUATION frames,
+  // but could be used for detecting whether the first frame is a SETTINGS
+  // frame.
+  // TODO(jamessyng): Provide means to indicate that decoder should require
+  // SETTINGS frame as the first frame.
+  Http2FrameType expected_frame_type_;
+
+  // Attempt to duplicate the SpdyState and SpdyFramerError values that
+  // SpdyFramer sets. Values determined by getting tests to pass.
+  SpdyFramer::SpdyState spdy_state_;
+  SpdyFramer::SpdyFramerError spdy_framer_error_;
+
+  // The limit on the size of received HTTP/2 payloads as specified in the
+  // SETTINGS_MAX_FRAME_SIZE advertised to peer.
+  size_t recv_frame_size_limit_ = kSpdyInitialFrameSizeLimit;
+
+  // Has OnFrameHeader been called?
+  bool decoded_frame_header_ = false;
+
+  // Have we recorded an Http2FrameHeader for the current frame?
+  // We only do so if the decoder will make multiple callbacks for
+  // the frame; for example, for PING frames we don't make record
+  // the frame header, but for ALTSVC we do.
+  bool has_frame_header_ = false;
+
+  // Have we recorded an Http2FrameHeader for the current HPACK block?
+  // True only for multi-frame HPACK blocks.
+  bool has_hpack_first_frame_header_ = false;
+
+  // Has OnHeaders() already been called for current HEADERS block? Only
+  // meaningful between OnHeadersStart and OnHeadersPriority.
+  bool on_headers_called_;
+
+  // Has OnHpackFragment() already been called for current HPACK block?
+  // SpdyFramer will pass an empty buffer to the HPACK decoder if a HEADERS
+  // or PUSH_PROMISE has no HPACK data in it (e.g. a HEADERS frame with only
+  // padding). Detect that condition and replicate the behavior using this
+  // field.
+  bool on_hpack_fragment_called_;
+
+  // Have we seen a frame header that appears to be an HTTP/1 response?
+  bool latched_probable_http_response_ = false;
+
+  // Is expected_frame_type_ set?
+  bool has_expected_frame_type_ = false;
+
+  // Is the current frame payload destined for |extension_|?
+  bool handling_extension_payload_ = false;
+
   bool process_single_input_frame_ = false;
 };
 
-std::unique_ptr<SpdyFramerDecoderAdapter> CreateHttp2FrameDecoderAdapter();
+std::unique_ptr<Http2DecoderAdapter> CreateHttp2FrameDecoderAdapter();
 
 }  // namespace net
 
diff --git a/net/spdy/core/spdy_framer.h b/net/spdy/core/spdy_framer.h
index cfa1a42..69439482 100644
--- a/net/spdy/core/spdy_framer.h
+++ b/net/spdy/core/spdy_framer.h
@@ -26,20 +26,19 @@
 
 namespace net {
 
-class HttpProxyClientSocketPoolTest;
+class Http2DecoderAdapter;
 class HttpNetworkLayer;
 class HttpNetworkTransactionTest;
+class HttpProxyClientSocketPoolTest;
+class SpdyFrameBuilder;
+class SpdyFramer;
+class SpdyFramerVisitorInterface;
 class SpdyHttpStreamTest;
 class SpdyNetworkTransactionTest;
 class SpdyProxyClientSocketTest;
 class SpdySessionTest;
 class SpdyStreamTest;
 
-class SpdyFramer;
-class SpdyFrameBuilder;
-class SpdyFramerDecoderAdapter;
-class SpdyFramerVisitorInterface;
-
 namespace test {
 
 class TestSpdyVisitor;
@@ -638,7 +637,7 @@
   SpdyHeadersHandlerInterface* header_handler_;
 
   // Decoder to use instead of this instance.
-  std::unique_ptr<SpdyFramerDecoderAdapter> decoder_adapter_;
+  std::unique_ptr<Http2DecoderAdapter> decoder_adapter_;
 
   // Determines whether HPACK compression is used.
   const CompressionOption compression_option_;
diff --git a/pdf/pdfium/fuzzers/BUILD.gn b/pdf/pdfium/fuzzers/BUILD.gn
index 118e9cc..41ef2d0 100644
--- a/pdf/pdfium/fuzzers/BUILD.gn
+++ b/pdf/pdfium/fuzzers/BUILD.gn
@@ -216,6 +216,6 @@
       "//v8:external_startup_data",
     ]
     dict = "dicts/pdf.dict"
-    seed_corpus = "src/third_party/pdfium/test"
+    seed_corpus = "//third_party/pdfium/test"
   }
 }
diff --git a/pdf/pdfium/fuzzers/corpora/pdf_codec_bmp/not_kitty.bmp b/pdf/pdfium/fuzzers/corpora/pdf_codec_bmp/not_kitty.bmp
new file mode 100644
index 0000000..0309c928
--- /dev/null
+++ b/pdf/pdfium/fuzzers/corpora/pdf_codec_bmp/not_kitty.bmp
Binary files differ
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 53f12786..2c33892 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -1707,16 +1707,6 @@
   FORM_DoDocumentAAction(form_, FPDFDOC_AACTION_DP);
 }
 
-PDFiumPage::Area PDFiumEngine::GetCharIndex(const pp::MouseInputEvent& event,
-                                            int* page_index,
-                                            int* char_index,
-                                            int* form_type,
-                                            PDFiumPage::LinkTarget* target) {
-  // First figure out which page this is in.
-  pp::Point mouse_point = event.GetPosition();
-  return GetCharIndex(mouse_point, page_index, char_index, form_type, target);
-}
-
 PDFiumPage::Area PDFiumEngine::GetCharIndex(const pp::Point& point,
                                             int* page_index,
                                             int* char_index,
@@ -1779,8 +1769,9 @@
   int char_index = -1;
   int form_type = FPDF_FORMFIELD_UNKNOWN;
   PDFiumPage::LinkTarget target;
+  pp::Point point = event.GetPosition();
   PDFiumPage::Area area =
-      GetCharIndex(event, &page_index, &char_index, &form_type, &target);
+      GetCharIndex(point, &page_index, &char_index, &form_type, &target);
   mouse_down_state_.Set(area, target);
 
   // Decide whether to open link or not based on user action in mouse up and
@@ -1794,8 +1785,8 @@
 
   if (page_index != -1) {
     last_page_mouse_down_ = page_index;
-    double page_x, page_y;
-    pp::Point point = event.GetPosition();
+    double page_x;
+    double page_y;
     DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);
 
     FORM_OnLButtonDown(form_, pages_[page_index]->GetPage(), 0, page_x, page_y);
@@ -1895,8 +1886,9 @@
   int char_index = -1;
   int form_type = FPDF_FORMFIELD_UNKNOWN;
   PDFiumPage::LinkTarget target;
+  pp::Point point = event.GetPosition();
   PDFiumPage::Area area =
-      GetCharIndex(event, &page_index, &char_index, &form_type, &target);
+      GetCharIndex(point, &page_index, &char_index, &form_type, &target);
 
   // Open link on mouse up for same link for which mouse down happened earlier.
   if (mouse_down_state_.Matches(area, target)) {
@@ -1928,8 +1920,8 @@
     return false;
 
   if (page_index != -1) {
-    double page_x, page_y;
-    pp::Point point = event.GetPosition();
+    double page_x;
+    double page_y;
     DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);
     FORM_OnLButtonUp(form_, pages_[page_index]->GetPage(), 0, page_x, page_y);
   }
@@ -1946,8 +1938,9 @@
   int char_index = -1;
   int form_type = FPDF_FORMFIELD_UNKNOWN;
   PDFiumPage::LinkTarget target;
+  pp::Point point = event.GetPosition();
   PDFiumPage::Area area =
-      GetCharIndex(event, &page_index, &char_index, &form_type, &target);
+      GetCharIndex(point, &page_index, &char_index, &form_type, &target);
 
   // Clear |mouse_down_state_| if mouse moves away from where the mouse down
   // happened.
@@ -1986,8 +1979,8 @@
     }
 
     if (page_index != -1) {
-      double page_x, page_y;
-      pp::Point point = event.GetPosition();
+      double page_x;
+      double page_y;
       DeviceToPage(page_index, point.x(), point.y(), &page_x, &page_y);
       FORM_OnMouseMove(form_, pages_[page_index]->GetPage(), 0, page_x, page_y);
     }
diff --git a/pdf/pdfium/pdfium_engine.h b/pdf/pdfium/pdfium_engine.h
index 37d30d8f..7dd2cee 100644
--- a/pdf/pdfium/pdfium_engine.h
+++ b/pdf/pdfium/pdfium_engine.h
@@ -339,13 +339,8 @@
   // the plugin's text selection.
   void SetFormSelectedText(FPDF_FORMHANDLE form_handle, FPDF_PAGE page);
 
-  // Given a mouse event, returns which page and character location it's closest
-  // to.
-  PDFiumPage::Area GetCharIndex(const pp::MouseInputEvent& event,
-                                int* page_index,
-                                int* char_index,
-                                int* form_type,
-                                PDFiumPage::LinkTarget* target);
+  // Given |point|, returns which page and character location it's closest to,
+  // as well as extra information about objects at that point.
   PDFiumPage::Area GetCharIndex(const pp::Point& point,
                                 int* page_index,
                                 int* char_index,
diff --git a/ppapi/features/features.gni b/ppapi/features/features.gni
index 560d1ec..ac17e1f 100644
--- a/ppapi/features/features.gni
+++ b/ppapi/features/features.gni
@@ -7,5 +7,5 @@
 import("//build/config/features.gni")
 
 declare_args() {
-  enable_plugins = !is_android && !is_ios && !is_chromecast && !is_fuchsia
+  enable_plugins = !is_android && !is_ios && !is_chromecast
 }
diff --git a/printing/features/features.gni b/printing/features/features.gni
index b3d6967..a41202a2 100644
--- a/printing/features/features.gni
+++ b/printing/features/features.gni
@@ -7,11 +7,11 @@
 
 declare_args() {
   # Enable basic printing support and UI.
-  enable_basic_printing = !is_chromecast && !is_ios && !is_fuchsia
+  enable_basic_printing = !is_chromecast && !is_ios
 
   # Enable printing with print preview. It does not imply
   # enable_basic_printing. It's possible to build Chrome with preview only.
-  enable_print_preview = !is_android && !is_chromecast && !is_ios && !is_fuchsia
+  enable_print_preview = !is_android && !is_chromecast && !is_ios
 
-  use_cups = (is_desktop_linux || is_mac) && !is_chromecast && !is_fuchsia
+  use_cups = (is_desktop_linux || is_mac) && !is_chromecast
 }
diff --git a/remoting/host/BUILD.gn b/remoting/host/BUILD.gn
index 59ee750..1bcad96 100644
--- a/remoting/host/BUILD.gn
+++ b/remoting/host/BUILD.gn
@@ -137,6 +137,8 @@
     "dns_blackhole_checker.h",
     "evaluate_capability.cc",
     "evaluate_capability.h",
+    "file_transfer_message_handler.cc",
+    "file_transfer_message_handler.h",
     "file_transfer_message_handler_factory.cc",
     "file_transfer_message_handler_factory.h",
     "forward_process_stats_agent.cc",
diff --git a/remoting/host/file_transfer_message_handler.cc b/remoting/host/file_transfer_message_handler.cc
new file mode 100644
index 0000000..1f7fad01
--- /dev/null
+++ b/remoting/host/file_transfer_message_handler.cc
@@ -0,0 +1,31 @@
+// Copyright 2017 The Chromium 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 "remoting/host/file_transfer_message_handler.h"
+
+#include "remoting/base/compound_buffer.h"
+
+namespace remoting {
+
+FileTransferMessageHandler::FileTransferMessageHandler(
+    const std::string& name,
+    std::unique_ptr<protocol::MessagePipe> pipe)
+    : protocol::NamedMessagePipeHandler(name, std::move(pipe)) {}
+
+FileTransferMessageHandler::~FileTransferMessageHandler() = default;
+
+void FileTransferMessageHandler::OnConnected() {
+  // TODO(jarhar): Implement open logic.
+}
+
+void FileTransferMessageHandler::OnIncomingMessage(
+    std::unique_ptr<CompoundBuffer> message) {
+  // TODO(jarhar): Implement message received logic.
+}
+
+void FileTransferMessageHandler::OnDisconnecting() {
+  // TODO(jarhar): Implement close logic.
+}
+
+}  // namespace remoting
diff --git a/remoting/host/file_transfer_message_handler.h b/remoting/host/file_transfer_message_handler.h
new file mode 100644
index 0000000..dca3315
--- /dev/null
+++ b/remoting/host/file_transfer_message_handler.h
@@ -0,0 +1,26 @@
+// Copyright 2017 The Chromium 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 REMOTING_HOST_FILE_TRANSFER_MESSAGE_HANDLER_H_
+#define REMOTING_HOST_FILE_TRANSFER_MESSAGE_HANDLER_H_
+
+#include "remoting/protocol/named_message_pipe_handler.h"
+
+namespace remoting {
+
+class FileTransferMessageHandler : public protocol::NamedMessagePipeHandler {
+ public:
+  FileTransferMessageHandler(const std::string& name,
+                             std::unique_ptr<protocol::MessagePipe> pipe);
+  ~FileTransferMessageHandler() override;
+
+  // protocol::NamedMessagePipeHandler implementation.
+  void OnConnected() override;
+  void OnIncomingMessage(std::unique_ptr<CompoundBuffer> message) override;
+  void OnDisconnecting() override;
+};
+
+}  // namespace remoting
+
+#endif  // REMOTING_HOST_FILE_TRANSFER_MESSAGE_HANDLER_H_
diff --git a/remoting/host/file_transfer_message_handler_factory.cc b/remoting/host/file_transfer_message_handler_factory.cc
index c14ccabe..e9ec036 100644
--- a/remoting/host/file_transfer_message_handler_factory.cc
+++ b/remoting/host/file_transfer_message_handler_factory.cc
@@ -4,6 +4,8 @@
 
 #include "remoting/host/file_transfer_message_handler_factory.h"
 
+#include "remoting/host/file_transfer_message_handler.h"
+
 namespace remoting {
 
 FileTransferMessageHandlerFactory::FileTransferMessageHandlerFactory() =
@@ -14,7 +16,10 @@
 void FileTransferMessageHandlerFactory::CreateDataChannelHandler(
     const std::string& channel_name,
     std::unique_ptr<protocol::MessagePipe> pipe) {
-  // TODO(jarhar): Implement FileTransferMessageHandler and pass pipe to it.
+  // FileTransferMessageHandler manages its own lifetime and is tied to the
+  // lifetime of |pipe|. Once |pipe| is closed, this instance will be cleaned
+  // up.
+  new FileTransferMessageHandler(channel_name, std::move(pipe));
 }
 
 }  // namespace remoting
diff --git a/remoting/host/win/unprivileged_process_delegate.cc b/remoting/host/win/unprivileged_process_delegate.cc
index dfff10c..c70589f 100644
--- a/remoting/host/win/unprivileged_process_delegate.cc
+++ b/remoting/host/win/unprivileged_process_delegate.cc
@@ -155,8 +155,7 @@
 
   // Generate a unique window station name.
   std::string window_station_name = base::StringPrintf(
-      "chromoting-%d-%d",
-      base::GetCurrentProcId(),
+      "chromoting-%" CrPRIdPid "-%d", base::GetCurrentProcId(),
       base::RandInt(1, std::numeric_limits<int>::max()));
 
   // Make sure that a new window station will be created instead of opening
diff --git a/services/ui/service.cc b/services/ui/service.cc
index e1efc27..e8f02c9 100644
--- a/services/ui/service.cc
+++ b/services/ui/service.cc
@@ -272,7 +272,7 @@
   // so keep this line below both of those.
   input_device_server_.RegisterAsObserver();
 
-  window_server_.reset(new ws::WindowServer(this));
+  window_server_ = base::MakeUnique<ws::WindowServer>(this);
   std::unique_ptr<ws::GpuHost> gpu_host =
       base::MakeUnique<ws::DefaultGpuHost>(window_server_.get());
   std::unique_ptr<ws::FrameSinkManagerClientBinding> frame_sink_manager =
diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc
index 1d99e171..d137da0e 100644
--- a/services/ui/ws/event_dispatcher.cc
+++ b/services/ui/ws/event_dispatcher.cc
@@ -339,8 +339,9 @@
   LocationTarget updated_target = location_target;
   updated_target.deepest_window.in_non_client_area = true;
   updated_target.deepest_window.window =
-      (fallback_to_root_ && location_target.deepest_window.window)
-          ? location_target.deepest_window.window->GetRoot()
+      location_target.deepest_window.window
+          ? delegate_->GetFallbackTargetForEventBlockedByModal(
+                location_target.deepest_window.window->GetRoot())
           : nullptr;
   return updated_target;
 }
diff --git a/services/ui/ws/event_dispatcher.h b/services/ui/ws/event_dispatcher.h
index f5256e5..d8936e3 100644
--- a/services/ui/ws/event_dispatcher.h
+++ b/services/ui/ws/event_dispatcher.h
@@ -59,8 +59,6 @@
   explicit EventDispatcher(EventDispatcherDelegate* delegate);
   ~EventDispatcher() override;
 
-  void set_fallback_to_root(bool value) { fallback_to_root_ = value; }
-
   ModalWindowController* modal_window_controller() {
     return &modal_window_controller_;
   }
@@ -353,13 +351,6 @@
       AcceleratorMatchPhase::ANY;
 #endif
 
-  // Used to determine behavior when the target of an event is blocked by a
-  // modal window.
-  // . If true, the target becomes the root window.
-  // . If false, no target is used, which means the window-manager does not
-  //   see the event.
-  bool fallback_to_root_ = false;
-
   DISALLOW_COPY_AND_ASSIGN(EventDispatcher);
 };
 
diff --git a/services/ui/ws/event_dispatcher_delegate.h b/services/ui/ws/event_dispatcher_delegate.h
index fbf1b72..2a8f3060 100644
--- a/services/ui/ws/event_dispatcher_delegate.h
+++ b/services/ui/ws/event_dispatcher_delegate.h
@@ -97,6 +97,13 @@
   virtual void OnEventTargetNotFound(const ui::Event& event,
                                      int64_t display_id) = 0;
 
+  // If an event is blocked by a modal window this function is used to determine
+  // which window the event should be dispatched to. Return null to indicate no
+  // window. |window| is the window the event would be targetted at if there was
+  // no modal window open.
+  virtual ServerWindow* GetFallbackTargetForEventBlockedByModal(
+      ServerWindow* window) = 0;
+
   // Called when an event occurs that targets a window that should be blocked
   // by a modal window. |modal_window| is the modal window that blocked the
   // event.
diff --git a/services/ui/ws/event_dispatcher_unittest.cc b/services/ui/ws/event_dispatcher_unittest.cc
index 7fea2747..a86e3d49 100644
--- a/services/ui/ws/event_dispatcher_unittest.cc
+++ b/services/ui/ws/event_dispatcher_unittest.cc
@@ -66,6 +66,8 @@
         last_accelerator_(0) {}
   ~TestEventDispatcherDelegate() override {}
 
+  void EnableFallbackToRoot() { fallback_to_root_ = true; }
+
   ui::Event* last_event_target_not_found() {
     return last_event_target_not_found_.get();
   }
@@ -175,6 +177,10 @@
                              int64_t display_id) override {
     last_event_target_not_found_ = ui::Event::Clone(event);
   }
+  ServerWindow* GetFallbackTargetForEventBlockedByModal(
+      ServerWindow* window) override {
+    return fallback_to_root_ ? root_ : nullptr;
+  }
   void OnEventOccurredOutsideOfModalWindow(
       ServerWindow* modal_transient) override {
     window_that_blocked_event_ = modal_transient;
@@ -191,6 +197,9 @@
   base::Optional<bool> last_cursor_visibility_;
   ServerWindow* window_that_blocked_event_ = nullptr;
 
+  // If true events blocked by a modal window are sent to |root_|.
+  bool fallback_to_root_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(TestEventDispatcherDelegate);
 };
 
@@ -1641,7 +1650,7 @@
 // enabled.
 TEST_P(EventDispatcherTest,
        ModalWindowEventOnDescendantOfModalParentWithFallback) {
-  event_dispatcher()->set_fallback_to_root(true);
+  test_event_dispatcher_delegate()->EnableFallbackToRoot();
 
   std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
   std::unique_ptr<ServerWindow> w11 =
@@ -1727,9 +1736,9 @@
 }
 
 // Variant of ModalWindowEventOutsideSystemModal with
-// set_fallback_to_root(true).
+// EnableFallbackToRoot().
 TEST_P(EventDispatcherTest, ModalWindowEventOutsideSystemModalWithFallback) {
-  event_dispatcher()->set_fallback_to_root(true);
+  test_event_dispatcher_delegate()->EnableFallbackToRoot();
 
   std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
 
diff --git a/services/ui/ws/frame_generator.cc b/services/ui/ws/frame_generator.cc
index 4f379d8f..d3f48ee 100644
--- a/services/ui/ws/frame_generator.cc
+++ b/services/ui/ws/frame_generator.cc
@@ -36,7 +36,8 @@
   SetNeedsBeginFrame(true);
 }
 
-void FrameGenerator::OnSurfaceCreated(const viz::SurfaceInfo& surface_info) {
+void FrameGenerator::OnFirstSurfaceActivation(
+    const viz::SurfaceInfo& surface_info) {
   DCHECK(surface_info.is_valid());
 
   // Only handle embedded surfaces changing here. The display root surface
diff --git a/services/ui/ws/frame_generator.h b/services/ui/ws/frame_generator.h
index 43c4685a..adbc2766 100644
--- a/services/ui/ws/frame_generator.h
+++ b/services/ui/ws/frame_generator.h
@@ -34,7 +34,7 @@
   void SetHighContrastMode(bool enabled);
 
   // Updates the WindowManager's SurfaceInfo.
-  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info);
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info);
 
   // Swaps the |window_manager_surface_info_| with that of |other|.
   void SwapSurfaceWith(FrameGenerator* other);
diff --git a/services/ui/ws/frame_generator_unittest.cc b/services/ui/ws/frame_generator_unittest.cc
index 0411dc9..356d550 100644
--- a/services/ui/ws/frame_generator_unittest.cc
+++ b/services/ui/ws/frame_generator_unittest.cc
@@ -135,7 +135,7 @@
   // |frame_generator_|. After InitWithSurfaceInfo finishes, |frame_generator_|
   // has a valid SurfaceInfo and does not request BeginFrames.
   void InitWithSurfaceInfo() {
-    frame_generator_->OnSurfaceCreated(kArbitrarySurfaceInfo);
+    frame_generator_->OnFirstSurfaceActivation(kArbitrarySurfaceInfo);
 
     // Issue a BeginFrame so that frame_generator_ stops requesting BeginFrames
     // after submitting a CompositorFrame.
@@ -187,7 +187,7 @@
   EXPECT_EQ(viz::BeginFrameAck(), LastBeginFrameAck());
 }
 
-TEST_F(FrameGeneratorTest, OnSurfaceCreated) {
+TEST_F(FrameGeneratorTest, OnFirstSurfaceActivation) {
   InitWithSurfaceInfo();
 
   // Verify that the CompositorFrame refers to the window manager's surface via
diff --git a/services/ui/ws/server_window_compositor_frame_sink_manager.h b/services/ui/ws/server_window_compositor_frame_sink_manager.h
index aadecca..7256b1b 100644
--- a/services/ui/ws/server_window_compositor_frame_sink_manager.h
+++ b/services/ui/ws/server_window_compositor_frame_sink_manager.h
@@ -6,12 +6,12 @@
 #define SERVICES_UI_WS_SERVER_WINDOW_COMPOSITOR_FRAME_SINK_MANAGER_H_
 
 #include "base/macros.h"
-#include "cc/ipc/compositor_frame.mojom.h"
 #include "components/viz/common/gpu/context_provider.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "services/ui/public/interfaces/window_tree.mojom.h"
 #include "services/viz/compositing/privileged/interfaces/frame_sink_manager.mojom.h"
+#include "services/viz/public/interfaces/compositing/compositor_frame.mojom.h"
 
 namespace ui {
 namespace ws {
diff --git a/services/ui/ws/window_manager_state.cc b/services/ui/ws/window_manager_state.cc
index a0d3263..6b5c44e6a 100644
--- a/services/ui/ws/window_manager_state.cc
+++ b/services/ui/ws/window_manager_state.cc
@@ -810,6 +810,13 @@
     UpdateNativeCursorFromDispatcher();
 }
 
+ServerWindow* WindowManagerState::GetFallbackTargetForEventBlockedByModal(
+    ServerWindow* window) {
+  DCHECK(window);
+  // TODO(sky): reevaluate when http://crbug.com/646998 is fixed.
+  return GetWindowManagerRootForDisplayRoot(window);
+}
+
 void WindowManagerState::OnEventOccurredOutsideOfModalWindow(
     ServerWindow* modal_window) {
   window_tree_->OnEventOccurredOutsideOfModalWindow(modal_window);
diff --git a/services/ui/ws/window_manager_state.h b/services/ui/ws/window_manager_state.h
index b05d06f1..31eddae 100644
--- a/services/ui/ws/window_manager_state.h
+++ b/services/ui/ws/window_manager_state.h
@@ -285,6 +285,8 @@
   ServerWindow* GetRootWindowContaining(gfx::Point* location_in_display,
                                         int64_t* display_id) override;
   void OnEventTargetNotFound(const Event& event, int64_t display_id) override;
+  ServerWindow* GetFallbackTargetForEventBlockedByModal(
+      ServerWindow* window) override;
   void OnEventOccurredOutsideOfModalWindow(ServerWindow* modal_window) override;
 
   // ServerWindowObserver:
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc
index 7b7d26c1..137a2f1 100644
--- a/services/ui/ws/window_server.cc
+++ b/services/ui/ws/window_server.cc
@@ -913,7 +913,8 @@
   delegate_->StartDisplayInit();
 }
 
-void WindowServer::OnSurfaceCreated(const viz::SurfaceInfo& surface_info) {
+void WindowServer::OnFirstSurfaceActivation(
+    const viz::SurfaceInfo& surface_info) {
   WindowId window_id(
       WindowIdFromTransportId(surface_info.id().frame_sink_id().client_id()));
   ServerWindow* window = GetWindow(window_id);
@@ -935,7 +936,7 @@
     // special case because ServerWindows created by the WindowServer are not
     // part of a WindowTree. Send the SurfaceId directly to FrameGenerator and
     // claim the temporary reference for the display root.
-    display->platform_display()->GetFrameGenerator()->OnSurfaceCreated(
+    display->platform_display()->GetFrameGenerator()->OnFirstSurfaceActivation(
         surface_info);
     display->root_window()
         ->GetOrCreateCompositorFrameSinkManager()
diff --git a/services/ui/ws/window_server.h b/services/ui/ws/window_server.h
index ec6a69e7..20e2b46 100644
--- a/services/ui/ws/window_server.h
+++ b/services/ui/ws/window_server.h
@@ -372,7 +372,7 @@
   void OnGpuServiceInitialized() override;
 
   // viz::mojom::FrameSinkManagerClient:
-  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
   void OnClientConnectionClosed(const viz::FrameSinkId& frame_sink_id) override;
   void OnAggregatedHitTestRegionListUpdated(
       const viz::FrameSinkId& frame_sink_id,
diff --git a/services/viz/compositing/privileged/interfaces/frame_sink_manager.mojom b/services/viz/compositing/privileged/interfaces/frame_sink_manager.mojom
index 72ccbc21..a499709 100644
--- a/services/viz/compositing/privileged/interfaces/frame_sink_manager.mojom
+++ b/services/viz/compositing/privileged/interfaces/frame_sink_manager.mojom
@@ -95,9 +95,9 @@
 // compositor. The frame sink manager host is either the browser process in
 // Chrome or the window server process.
 interface FrameSinkManagerClient {
-  // Called by the frame sink manager immediately upon receiving a
-  // CompositorFrame with a new SurfaceId for the first time.
-  OnSurfaceCreated(cc.mojom.SurfaceInfo surface_info);
+  // Called by the frame sink manager when a CompositorFrame with a new
+  // SurfaceId activates for the first time.
+  OnFirstSurfaceActivation(cc.mojom.SurfaceInfo surface_info);
 
   // The CompositorFrameSink pipe for |frame_sink_id| was closed. The client
   // cannot submit any CompositorFrames to viz after this occurs.
diff --git a/services/viz/public/cpp/compositing/BUILD.gn b/services/viz/public/cpp/compositing/BUILD.gn
index 07d4324..8ac67f5 100644
--- a/services/viz/public/cpp/compositing/BUILD.gn
+++ b/services/viz/public/cpp/compositing/BUILD.gn
@@ -12,6 +12,7 @@
   deps = [
     "//base/test:test_support",
     "//components/viz/common:common",
+    "//components/viz/test:test_support",
     "//media/capture/mojo:capture_types",
     "//services/service_manager/public/cpp",
     "//services/service_manager/public/cpp:service_test_support",
diff --git a/services/viz/public/cpp/compositing/DEPS b/services/viz/public/cpp/compositing/DEPS
index 4debd219..d1586ba 100644
--- a/services/viz/public/cpp/compositing/DEPS
+++ b/services/viz/public/cpp/compositing/DEPS
@@ -1,3 +1,9 @@
 include_rules = [
+  "+ui/gfx/ipc",
   "+ui/gfx/mojo",
+  "+ui/gfx/geometry/mojo",
+  "+cc",
+  "+gpu/ipc",
+  "+skia/public/interfaces",
+  "+ui/latency/mojo",
 ]
diff --git a/services/viz/public/cpp/compositing/compositor_frame.typemap b/services/viz/public/cpp/compositing/compositor_frame.typemap
new file mode 100644
index 0000000..353a7af
--- /dev/null
+++ b/services/viz/public/cpp/compositing/compositor_frame.typemap
@@ -0,0 +1,15 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//services/viz/public/interfaces/compositing/compositor_frame.mojom"
+public_headers = [ "//cc/output/compositor_frame.h" ]
+traits_headers =
+    [ "//services/viz/public/cpp/compositing/compositor_frame_struct_traits.h" ]
+sources = [
+  "//services/viz/public/cpp/compositing/compositor_frame_struct_traits.cc",
+]
+deps = [
+  "//cc",
+]
+type_mappings = [ "viz.mojom.CompositorFrame=cc::CompositorFrame[move_only]" ]
diff --git a/cc/ipc/compositor_frame_for_blink.typemap b/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
similarity index 81%
rename from cc/ipc/compositor_frame_for_blink.typemap
rename to services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
index 9fbd8a9..256c13f 100644
--- a/cc/ipc/compositor_frame_for_blink.typemap
+++ b/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
@@ -2,11 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-mojom = "//cc/ipc/compositor_frame.mojom"
+mojom = "//services/viz/public/interfaces/compositing/compositor_frame.mojom"
 public_headers = [ "//cc/output/compositor_frame.h" ]
 traits_headers = [
   "//cc/ipc/compositor_frame_metadata_struct_traits.h",
-  "//cc/ipc/compositor_frame_struct_traits.h",
   "//cc/ipc/filter_operation_struct_traits.h",
   "//cc/ipc/filter_operations_struct_traits.h",
   "//cc/ipc/render_pass_struct_traits.h",
@@ -19,6 +18,7 @@
   "//gpu/ipc/common/sync_token_struct_traits.h",
   "//ipc/ipc_message_utils.h",
   "//mojo/common/common_custom_types_struct_traits.h",
+  "//services/viz/public/cpp/compositing/compositor_frame_struct_traits.h",
   "//skia/public/interfaces/image_filter_struct_traits.h",
   "//ui/gfx/mojo/selection_bound_struct_traits.h",
   "//ui/gfx/mojo/transform_struct_traits.h",
@@ -29,9 +29,10 @@
   "//cc/ipc:interfaces",
   "//gpu/ipc/common:interfaces",
   "//mojo/common:common_custom_types",
+  "//services/viz/public/interfaces/compositing",
   "//skia/public/interfaces",
   "//ui/gfx/geometry/mojo",
   "//ui/gfx/mojo",
   "//ui/latency/mojo:interfaces",
 ]
-type_mappings = [ "cc.mojom.CompositorFrame=cc::CompositorFrame[move_only]" ]
+type_mappings = [ "viz.mojom.CompositorFrame=cc::CompositorFrame[move_only]" ]
diff --git a/cc/ipc/compositor_frame_struct_traits.cc b/services/viz/public/cpp/compositing/compositor_frame_struct_traits.cc
similarity index 64%
rename from cc/ipc/compositor_frame_struct_traits.cc
rename to services/viz/public/cpp/compositing/compositor_frame_struct_traits.cc
index f06f370..c9bfd12 100644
--- a/cc/ipc/compositor_frame_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/compositor_frame_struct_traits.cc
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/ipc/compositor_frame_struct_traits.h"
+#include "services/viz/public/cpp/compositing/compositor_frame_struct_traits.h"
+
 #include "cc/ipc/compositor_frame_metadata_struct_traits.h"
 #include "cc/ipc/render_pass_struct_traits.h"
 #include "cc/ipc/transferable_resource_struct_traits.h"
@@ -10,10 +11,8 @@
 namespace mojo {
 
 // static
-bool StructTraits<cc::mojom::CompositorFrameDataView,
-                  cc::CompositorFrame>::Read(cc::mojom::CompositorFrameDataView
-                                                 data,
-                                             cc::CompositorFrame* out) {
+bool StructTraits<viz::mojom::CompositorFrameDataView, cc::CompositorFrame>::
+    Read(viz::mojom::CompositorFrameDataView data, cc::CompositorFrame* out) {
   return data.ReadPasses(&out->render_pass_list) &&
          !out->render_pass_list.empty() && data.ReadMetadata(&out->metadata) &&
          data.ReadResources(&out->resource_list);
diff --git a/services/viz/public/cpp/compositing/compositor_frame_struct_traits.h b/services/viz/public/cpp/compositing/compositor_frame_struct_traits.h
new file mode 100644
index 0000000..c85ce80
--- /dev/null
+++ b/services/viz/public/cpp/compositing/compositor_frame_struct_traits.h
@@ -0,0 +1,37 @@
+// Copyright 2016 The Chromium 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 SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COMPOSITOR_FRAME_STRUCT_TRAITS_H_
+#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COMPOSITOR_FRAME_STRUCT_TRAITS_H_
+
+#include <vector>
+
+#include "cc/output/compositor_frame.h"
+#include "services/viz/public/interfaces/compositing/compositor_frame.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<viz::mojom::CompositorFrameDataView, cc::CompositorFrame> {
+  static const cc::CompositorFrameMetadata& metadata(
+      const cc::CompositorFrame& input) {
+    return input.metadata;
+  }
+
+  static const std::vector<viz::TransferableResource>& resources(
+      const cc::CompositorFrame& input) {
+    return input.resource_list;
+  }
+
+  static const cc::RenderPassList& passes(const cc::CompositorFrame& input) {
+    return input.render_pass_list;
+  }
+
+  static bool Read(viz::mojom::CompositorFrameDataView data,
+                   cc::CompositorFrame* out);
+};
+
+}  // namespace mojo
+
+#endif  // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COMPOSITOR_FRAME_STRUCT_TRAITS_H_
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index 8b9eb28..a989f48 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -5,10 +5,51 @@
 #include <utility>
 
 #include "base/message_loop/message_loop.h"
+#include "cc/ipc/begin_frame_args_struct_traits.h"
+#include "cc/ipc/compositor_frame_metadata_struct_traits.h"
+#include "cc/ipc/copy_output_request_struct_traits.h"
+#include "cc/ipc/copy_output_result_struct_traits.h"
+#include "cc/ipc/filter_operation_struct_traits.h"
+#include "cc/ipc/filter_operations_struct_traits.h"
+#include "cc/ipc/frame_sink_id_struct_traits.h"
+#include "cc/ipc/local_surface_id_struct_traits.h"
+#include "cc/ipc/quads_struct_traits.h"
+#include "cc/ipc/render_pass_struct_traits.h"
+#include "cc/ipc/returned_resource_struct_traits.h"
+#include "cc/ipc/selection_struct_traits.h"
+#include "cc/ipc/shared_quad_state_struct_traits.h"
+#include "cc/ipc/surface_id_struct_traits.h"
+#include "cc/ipc/surface_sequence_struct_traits.h"
+#include "cc/ipc/texture_mailbox_struct_traits.h"
+#include "cc/ipc/transferable_resource_struct_traits.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/quads/debug_border_draw_quad.h"
+#include "cc/quads/render_pass.h"
+#include "cc/quads/solid_color_draw_quad.h"
+#include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/quads/resource_format.h"
 #include "components/viz/common/resources/resource_settings.h"
+#include "components/viz/common/resources/transferable_resource.h"
+#include "components/viz/test/begin_frame_args_test.h"
+#include "gpu/ipc/common/mailbox_holder_struct_traits.h"
+#include "gpu/ipc/common/mailbox_struct_traits.h"
+#include "gpu/ipc/common/sync_token_struct_traits.h"
+#include "ipc/ipc_message_utils.h"
+#include "mojo/common/common_custom_types_struct_traits.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/viz/public/cpp/compositing/compositor_frame_struct_traits.h"
 #include "services/viz/public/cpp/compositing/resource_settings_struct_traits.h"
+#include "services/viz/public/interfaces/compositing/compositor_frame.mojom.h"
+#include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
+#include "skia/public/interfaces/blur_image_filter_tile_mode_struct_traits.h"
+#include "skia/public/interfaces/image_filter_struct_traits.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+#include "ui/gfx/ipc/color/gfx_param_traits.h"
+#include "ui/gfx/mojo/buffer_types_struct_traits.h"
+#include "ui/gfx/mojo/selection_bound_struct_traits.h"
+#include "ui/gfx/mojo/transform_struct_traits.h"
+#include "ui/latency/mojo/latency_info_struct_traits.h"
 
 namespace viz {
 
@@ -36,6 +77,129 @@
             output.buffer_to_texture_target_map);
 }
 
+// Note that this is a fairly trivial test of CompositorFrame serialization as
+// most of the heavy lifting has already been done by CompositorFrameMetadata,
+// RenderPass, and QuadListBasic unit tests.
+TEST_F(StructTraitsTest, CompositorFrame) {
+  std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create();
+  render_pass->SetNew(1, gfx::Rect(5, 6), gfx::Rect(2, 3), gfx::Transform());
+
+  // SharedQuadState.
+  const gfx::Transform sqs_quad_to_target_transform(
+      1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f, 11.f, 12.f, 13.f, 14.f,
+      15.f, 16.f);
+  const gfx::Rect sqs_layer_rect(1234, 5678);
+  const gfx::Rect sqs_visible_layer_rect(12, 34, 56, 78);
+  const gfx::Rect sqs_clip_rect(123, 456, 789, 101112);
+  const bool sqs_is_clipped = true;
+  const float sqs_opacity = 0.9f;
+  const SkBlendMode sqs_blend_mode = SkBlendMode::kSrcOver;
+  const int sqs_sorting_context_id = 1337;
+  cc::SharedQuadState* sqs = render_pass->CreateAndAppendSharedQuadState();
+  sqs->SetAll(sqs_quad_to_target_transform, sqs_layer_rect,
+              sqs_visible_layer_rect, sqs_clip_rect, sqs_is_clipped,
+              sqs_opacity, sqs_blend_mode, sqs_sorting_context_id);
+
+  // DebugBorderDrawQuad.
+  const gfx::Rect rect1(1234, 4321, 1357, 7531);
+  const SkColor color1 = SK_ColorRED;
+  const int32_t width1 = 1337;
+  cc::DebugBorderDrawQuad* debug_quad =
+      render_pass->CreateAndAppendDrawQuad<cc::DebugBorderDrawQuad>();
+  debug_quad->SetNew(sqs, rect1, rect1, color1, width1);
+
+  // SolidColorDrawQuad.
+  const gfx::Rect rect2(2468, 8642, 4321, 1234);
+  const uint32_t color2 = 0xffffffff;
+  const bool force_anti_aliasing_off = true;
+  cc::SolidColorDrawQuad* solid_quad =
+      render_pass->CreateAndAppendDrawQuad<cc::SolidColorDrawQuad>();
+  solid_quad->SetNew(sqs, rect2, rect2, color2, force_anti_aliasing_off);
+
+  // TransferableResource constants.
+  const uint32_t tr_id = 1337;
+  const ResourceFormat tr_format = ALPHA_8;
+  const gfx::BufferFormat tr_buffer_format = gfx::BufferFormat::R_8;
+  const uint32_t tr_filter = 1234;
+  const gfx::Size tr_size(1234, 5678);
+  TransferableResource resource;
+  resource.id = tr_id;
+  resource.format = tr_format;
+  resource.buffer_format = tr_buffer_format;
+  resource.filter = tr_filter;
+  resource.size = tr_size;
+
+  // CompositorFrameMetadata constants.
+  const float device_scale_factor = 2.6f;
+  const gfx::Vector2dF root_scroll_offset(1234.5f, 6789.1f);
+  const float page_scale_factor = 1337.5f;
+  const gfx::SizeF scrollable_viewport_size(1337.7f, 1234.5f);
+  const uint32_t content_source_id = 3;
+  const BeginFrameAck begin_frame_ack(5, 10, false);
+
+  cc::CompositorFrame input;
+  input.metadata.device_scale_factor = device_scale_factor;
+  input.metadata.root_scroll_offset = root_scroll_offset;
+  input.metadata.page_scale_factor = page_scale_factor;
+  input.metadata.scrollable_viewport_size = scrollable_viewport_size;
+  input.render_pass_list.push_back(std::move(render_pass));
+  input.resource_list.push_back(resource);
+  input.metadata.content_source_id = content_source_id;
+  input.metadata.begin_frame_ack = begin_frame_ack;
+
+  cc::CompositorFrame output;
+  mojom::CompositorFrame::Deserialize(mojom::CompositorFrame::Serialize(&input),
+                                      &output);
+
+  EXPECT_EQ(device_scale_factor, output.metadata.device_scale_factor);
+  EXPECT_EQ(root_scroll_offset, output.metadata.root_scroll_offset);
+  EXPECT_EQ(page_scale_factor, output.metadata.page_scale_factor);
+  EXPECT_EQ(scrollable_viewport_size, output.metadata.scrollable_viewport_size);
+  EXPECT_EQ(content_source_id, output.metadata.content_source_id);
+  EXPECT_EQ(begin_frame_ack, output.metadata.begin_frame_ack);
+
+  ASSERT_EQ(1u, output.resource_list.size());
+  TransferableResource out_resource = output.resource_list[0];
+  EXPECT_EQ(tr_id, out_resource.id);
+  EXPECT_EQ(tr_format, out_resource.format);
+  EXPECT_EQ(tr_buffer_format, out_resource.buffer_format);
+  EXPECT_EQ(tr_filter, out_resource.filter);
+  EXPECT_EQ(tr_size, out_resource.size);
+
+  EXPECT_EQ(1u, output.render_pass_list.size());
+  const cc::RenderPass* out_render_pass = output.render_pass_list[0].get();
+  ASSERT_EQ(2u, out_render_pass->quad_list.size());
+  ASSERT_EQ(1u, out_render_pass->shared_quad_state_list.size());
+
+  const cc::SharedQuadState* out_sqs =
+      out_render_pass->shared_quad_state_list.ElementAt(0);
+  EXPECT_EQ(sqs_quad_to_target_transform, out_sqs->quad_to_target_transform);
+  EXPECT_EQ(sqs_layer_rect, out_sqs->quad_layer_rect);
+  EXPECT_EQ(sqs_visible_layer_rect, out_sqs->visible_quad_layer_rect);
+  EXPECT_EQ(sqs_clip_rect, out_sqs->clip_rect);
+  EXPECT_EQ(sqs_is_clipped, out_sqs->is_clipped);
+  EXPECT_EQ(sqs_opacity, out_sqs->opacity);
+  EXPECT_EQ(sqs_blend_mode, out_sqs->blend_mode);
+  EXPECT_EQ(sqs_sorting_context_id, out_sqs->sorting_context_id);
+
+  const cc::DebugBorderDrawQuad* out_debug_border_draw_quad =
+      cc::DebugBorderDrawQuad::MaterialCast(
+          out_render_pass->quad_list.ElementAt(0));
+  EXPECT_EQ(rect1, out_debug_border_draw_quad->rect);
+  EXPECT_EQ(rect1, out_debug_border_draw_quad->visible_rect);
+  EXPECT_EQ(color1, out_debug_border_draw_quad->color);
+  EXPECT_EQ(width1, out_debug_border_draw_quad->width);
+
+  const cc::SolidColorDrawQuad* out_solid_color_draw_quad =
+      cc::SolidColorDrawQuad::MaterialCast(
+          out_render_pass->quad_list.ElementAt(1));
+  EXPECT_EQ(rect2, out_solid_color_draw_quad->rect);
+  EXPECT_EQ(rect2, out_solid_color_draw_quad->visible_rect);
+  EXPECT_EQ(color2, out_solid_color_draw_quad->color);
+  EXPECT_EQ(force_anti_aliasing_off,
+            out_solid_color_draw_quad->force_anti_aliasing_off);
+}
+
 }  // namespace
 
 }  // namespace viz
diff --git a/services/viz/public/cpp/compositing/typemaps.gni b/services/viz/public/cpp/compositing/typemaps.gni
index 56c999e..7af5e5c 100644
--- a/services/viz/public/cpp/compositing/typemaps.gni
+++ b/services/viz/public/cpp/compositing/typemaps.gni
@@ -2,4 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-typemaps = [ "//services/viz/public/cpp/compositing/resource_settings.typemap" ]
+typemaps = [
+  "//services/viz/public/cpp/compositing/compositor_frame.typemap",
+  "//services/viz/public/cpp/compositing/resource_settings.typemap",
+]
diff --git a/services/viz/public/interfaces/compositing/BUILD.gn b/services/viz/public/interfaces/compositing/BUILD.gn
index 781f7b7..c0bc16cb 100644
--- a/services/viz/public/interfaces/compositing/BUILD.gn
+++ b/services/viz/public/interfaces/compositing/BUILD.gn
@@ -6,6 +6,7 @@
 
 mojom("compositing") {
   sources = [
+    "compositor_frame.mojom",
     "compositor_frame_sink.mojom",
     "resource_settings.mojom",
   ]
diff --git a/cc/ipc/compositor_frame.mojom b/services/viz/public/interfaces/compositing/compositor_frame.mojom
similarity index 96%
rename from cc/ipc/compositor_frame.mojom
rename to services/viz/public/interfaces/compositing/compositor_frame.mojom
index e32e1ef1a..ad7d6bb6 100644
--- a/cc/ipc/compositor_frame.mojom
+++ b/services/viz/public/interfaces/compositing/compositor_frame.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module cc.mojom;
+module viz.mojom;
 
 import "cc/ipc/compositor_frame_metadata.mojom";
 import "cc/ipc/render_pass.mojom";
diff --git a/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom b/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
index 6ba6cf3d..3f93e56 100644
--- a/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
+++ b/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
@@ -5,7 +5,6 @@
 module viz.mojom;
 
 import "cc/ipc/begin_frame_args.mojom";
-import "cc/ipc/compositor_frame.mojom";
 import "cc/ipc/copy_output_request.mojom";
 import "cc/ipc/frame_sink_id.mojom";
 import "cc/ipc/local_surface_id.mojom";
@@ -13,6 +12,7 @@
 import "cc/ipc/returned_resource.mojom";
 import "cc/ipc/surface_sequence.mojom";
 import "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom";
+import "services/viz/public/interfaces/compositing/compositor_frame.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
 // A CompositorFrameSink is an interface for receiving CompositorFrame
@@ -34,7 +34,7 @@
   // DidReceiveCompositorFrameAck() asynchronously when the frame has been
   // processed in order to unthrottle the next frame.
   SubmitCompositorFrame(cc.mojom.LocalSurfaceId local_surface_id,
-                        cc.mojom.CompositorFrame frame,
+                        viz.mojom.CompositorFrame frame,
                         viz.mojom.HitTestRegionList? hit_test_region_list);
 
   // Notifies the frame sink that a BeginFrame was completed, but that no
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index c9ec6dd..ca68c80 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -10473,7 +10473,6 @@
   "Fuchsia": {
     "additional_compile_targets": [
       "gl_unittests",
-      "media_unittests",
       "net_unittests"
     ],
     "gtest_tests": [
@@ -10502,6 +10501,15 @@
         "test": "ipc_tests"
       },
       {
+        "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.media_unittests.filter"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false
+        },
+        "test": "media_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": false
         },
@@ -10586,6 +10594,15 @@
         "test": "ipc_tests"
       },
       {
+        "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/fuchsia.media_unittests.filter"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": false
+        },
+        "test": "media_unittests"
+      },
+      {
         "swarming": {
           "can_use_on_swarming_builders": false
         },
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index a8f92d2..61020f5 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -2644,6 +2644,67 @@
       },
       {
         "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build48-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build48-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -3132,6 +3193,67 @@
       },
       {
         "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build13-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build13-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_filters_cases",
           "-v",
           "--upload-results",
@@ -3193,6 +3315,67 @@
       },
       {
         "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build48-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build48-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_path_rendering_cases",
           "-v",
           "--upload-results",
@@ -3559,6 +3742,128 @@
       },
       {
         "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build48-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build48-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build13-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build13-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "start_with_url.cold.startup_pages",
           "-v",
           "--upload-results",
@@ -7356,6 +7661,67 @@
       },
       {
         "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build75-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build75-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -7844,6 +8210,67 @@
       },
       {
         "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build73-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build73-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_filters_cases",
           "-v",
           "--upload-results",
@@ -7905,6 +8332,67 @@
       },
       {
         "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build75-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build75-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_path_rendering_cases",
           "-v",
           "--upload-results",
@@ -8271,6 +8759,128 @@
       },
       {
         "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build75-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build75-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build73-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build73-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "start_with_url.cold.startup_pages",
           "-v",
           "--upload-results",
@@ -10818,6 +11428,37 @@
       },
       {
         "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "smoothness.key_desktop_move_cases",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build165-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -11066,6 +11707,37 @@
       },
       {
         "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "smoothness.tough_animation_cases",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build164-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_filters_cases",
           "-v",
           "--upload-results",
@@ -11097,6 +11769,37 @@
       },
       {
         "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "smoothness.tough_image_decode_cases",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build165-b1--device1",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_path_rendering_cases",
           "-v",
           "--upload-results",
@@ -11283,6 +11986,68 @@
       },
       {
         "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "start_with_ext.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build166-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "start_with_ext.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build164-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "start_with_url.cold.startup_pages",
           "-v",
           "--upload-results",
@@ -14541,6 +15306,67 @@
       },
       {
         "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build45-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build45-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -15029,6 +15855,67 @@
       },
       {
         "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build15-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build15-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_filters_cases",
           "-v",
           "--upload-results",
@@ -15090,6 +15977,67 @@
       },
       {
         "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build45-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build45-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_path_rendering_cases",
           "-v",
           "--upload-results",
@@ -15456,6 +16404,128 @@
       },
       {
         "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build45-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build45-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build15-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build15-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "start_with_url.cold.startup_pages",
           "-v",
           "--upload-results",
@@ -18034,6 +19104,37 @@
       },
       {
         "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "smoothness.key_desktop_move_cases",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build113-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -18282,6 +19383,37 @@
       },
       {
         "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "smoothness.tough_animation_cases",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build112-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_filters_cases",
           "-v",
           "--upload-results",
@@ -18313,6 +19445,37 @@
       },
       {
         "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "smoothness.tough_image_decode_cases",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build113-b1--device1",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_path_rendering_cases",
           "-v",
           "--upload-results",
@@ -18499,6 +19662,68 @@
       },
       {
         "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "start_with_ext.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build114-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-webview",
+          "--webview-embedder-apk=../../out/Release/apks/SystemWebViewShell.apk"
+        ],
+        "isolate_name": "telemetry_perf_webview_tests",
+        "name": "start_with_ext.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_webview_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build112-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "start_with_url.cold.startup_pages",
           "-v",
           "--upload-results",
@@ -21757,6 +22982,67 @@
       },
       {
         "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build49-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build49-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -22245,6 +23531,67 @@
       },
       {
         "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build9-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build9-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_filters_cases",
           "-v",
           "--upload-results",
@@ -22306,6 +23653,67 @@
       },
       {
         "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build49-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build49-b1--device5",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_path_rendering_cases",
           "-v",
           "--upload-results",
@@ -22672,6 +24080,128 @@
       },
       {
         "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build49-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build49-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build9-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build9-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "start_with_url.cold.startup_pages",
           "-v",
           "--upload-results",
@@ -26347,6 +27877,67 @@
       },
       {
         "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build47-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.key_desktop_move_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.key_desktop_move_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build47-b1--device3",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.key_mobile_sites_smooth",
           "-v",
           "--upload-results",
@@ -26835,6 +28426,67 @@
       },
       {
         "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build17-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_animation_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_animation_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build17-b1--device6",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_filters_cases",
           "-v",
           "--upload-results",
@@ -26896,6 +28548,67 @@
       },
       {
         "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build47-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "smoothness.tough_image_decode_cases",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "smoothness.tough_image_decode_cases.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build47-b1--device2",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "smoothness.tough_path_rendering_cases",
           "-v",
           "--upload-results",
@@ -27262,6 +28975,128 @@
       },
       {
         "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build47-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.cold.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.cold.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build47-b1--device4",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=android-chromium"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build17-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": false,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
+          "start_with_ext.warm.blank_page",
+          "-v",
+          "--upload-results",
+          "--output-format=chartjson",
+          "--browser=reference",
+          "--output-trace-tag=_ref"
+        ],
+        "isolate_name": "telemetry_perf_tests",
+        "name": "start_with_ext.warm.blank_page.reference",
+        "override_compile_targets": [
+          "telemetry_perf_tests"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "android_devices": "1",
+              "id": "build17-b1--device7",
+              "os": "Android",
+              "pool": "Chrome-perf"
+            }
+          ],
+          "expiration": 36000,
+          "hard_timeout": 10800,
+          "ignore_task_failure": true,
+          "io_timeout": 3600,
+          "upload_test_results": false
+        }
+      },
+      {
+        "args": [
           "start_with_url.cold.startup_pages",
           "-v",
           "--upload-results",
diff --git a/testing/buildbot/filters/fuchsia.media_unittests.filter b/testing/buildbot/filters/fuchsia.media_unittests.filter
new file mode 100644
index 0000000..236c722
--- /dev/null
+++ b/testing/buildbot/filters/fuchsia.media_unittests.filter
@@ -0,0 +1,11 @@
+# TODO(fuchsia): Fix these tests and remove the filter. crbug.com/731302 .
+
+# Mojo hasn't been ported yet. crbug.com/740791
+-Mojo*
+
+# These tests are slow and may flake under qemu. crbug.com/745094
+-Pipeline*
+
+# These tests depend on base::CancelableSyncSocket, which is currently
+# broken, see https://crbug.com/741783
+-*Audio*DeviceTest.*CreateStream*
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index 704e628..03517aa2 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -1,7 +1,6 @@
 # These tests currently fail when run with --enable-network-service
 # See https://crbug.com/729849
 
-Bug(none) accessibility/table-cell-for-column-and-row-crash.html [ Timeout ]
 Bug(none) battery-status/api-defined.html [ Timeout ]
 Bug(none) battery-status/multiple-promises-after-resolve.html [ Timeout ]
 Bug(none) battery-status/multiple-promises.html [ Timeout ]
@@ -101,28 +100,12 @@
 Bug(none) bluetooth/service/getCharacteristics/gen-get-same-object-with-uuid.html [ Timeout ]
 Bug(none) bluetooth/service/getCharacteristics/gen-get-same-object.html [ Timeout ]
 Bug(none) bluetooth/service/getCharacteristics/gen-invalid-characteristic-name.html [ Timeout ]
-Bug(none) compositing/color-matching/image-color-matching.html [ Failure ]
-Bug(none) compositing/geometry/video-fixed-scrolling.html [ Failure ]
-Bug(none) compositing/geometry/video-opacity-overlay.html [ Failure ]
-Bug(none) compositing/iframes/iframe-in-composited-layer.html [ Failure ]
-Bug(none) compositing/layers-inside-overflow-scroll.html [ Failure Timeout ]
-Bug(none) compositing/overflow/overflow-compositing-descendant.html [ Failure ]
-Bug(none) compositing/overflow/scroll-ancestor-update.html [ Failure ]
-Bug(none) compositing/reflections/load-video-in-reflection.html [ Failure ]
-Bug(none) compositing/self-painting-layers.html [ Failure ]
-Bug(none) compositing/self-painting-layers2.html [ Timeout ]
 Bug(none) compositing/video-frame-size-change.html [ Timeout ]
-Bug(none) compositing/video/video-reflection.html [ Timeout ]
-Bug(none) compositing/visibility/visibility-simple-video-layer.html [ Failure ]
-Bug(none) crypto/gc.html [ Timeout ]
 Bug(none) css-parser/color3.html [ Failure ]
 Bug(none) css-parser/color3_hsl.html [ Failure ]
 Bug(none) css-parser/color3_hsla_1.html [ Failure ]
 Bug(none) css-parser/color3_hsla_2.html [ Failure ]
 Bug(none) css-parser/color3_keywords.html [ Failure ]
-Bug(none) css2.1/t040304-c64-uri-00-a-g.html [ Failure ]
-Bug(none) css3/filters/effect-reference-removed-while-pending-resources.html [ Timeout ]
-Bug(none) dom/attr/access-after-element-destruction.html [ Timeout ]
 Bug(none) dom/legacy_dom_conformance/svg/level3/xpath/Attribute_Nodes.svg [ Failure ]
 Bug(none) dom/legacy_dom_conformance/svg/level3/xpath/Attribute_Nodes_xmlns.svg [ Failure ]
 Bug(none) dom/legacy_dom_conformance/svg/level3/xpath/Comment_Nodes.svg [ Failure ]
@@ -183,32 +166,13 @@
 Bug(none) dom/legacy_dom_conformance/svg/level3/xpath/XPathResult_snapshotLength_ORDERED_NODE_SNAPSHOT_TYPE.svg [ Failure ]
 Bug(none) dom/legacy_dom_conformance/svg/level3/xpath/XPathResult_snapshotLength_UNORDERED_NODE_SNAPSHOT_TYPE.svg [ Failure ]
 Bug(none) dom/legacy_dom_conformance/svg/level3/xpath/XPathResult_stringValue.svg [ Failure ]
-Bug(none) editing/input/drag_in_unselectable.html [ Failure ]
-Bug(none) editing/input/text-input-controller-leak-document.html [ Timeout ]
-Bug(none) editing/inserting/delete-insignificant-text-crash.html [ Timeout ]
-Bug(none) editing/inserting/insert-html-crash.html [ Timeout ]
-Bug(none) editing/style/apply-style-join-child-text-nodes-crash.html [ Timeout ]
 Bug(none) external/wpt/2dcontext/imagebitmap/createImageBitmap-drawImage.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/clear-site-data/storage.https.html [ Failure ]
 Bug(none) external/wpt/fetch/api/abort/serviceworker-intercepted.https.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/FileAPI/historical.https.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/FileAPI/url/url_xmlhttprequest.html [ Crash Failure Timeout ]
-Bug(none) external/wpt/IndexedDB [ Failure Timeout ]
-Bug(none) external/wpt/WebIDL/ecmascript-binding/es-exceptions/exceptions.html [ Failure Timeout ]
-Bug(none) external/wpt/WebIDL/ecmascript-binding/has-instance.html [ Failure Timeout ]
 Bug(none) external/wpt/XMLHttpRequest [ Crash Failure Timeout ]
 Bug(none) external/wpt/background-fetch/interfaces-worker.https.html [ Crash Failure Timeout ]
-Bug(none) external/wpt/battery-status/battery-discharging-manual.https.html [ Failure Timeout ]
-Bug(none) external/wpt/battery-status/battery-full-manual.https.html [ Failure Timeout ]
-Bug(none) external/wpt/battery-status/battery-iframe.https.html [ Failure Timeout ]
-Bug(none) external/wpt/battery-status/battery-interface-idlharness.https.html [ Failure Timeout ]
-Bug(none) external/wpt/battery-status/battery-promise-window.https.html [ Failure Timeout ]
-Bug(none) external/wpt/battery-status/battery-promise.https.html [ Failure Timeout ]
-Bug(none) external/wpt/beacon/headers/header-content-type.html [ Failure Timeout ]
-Bug(none) external/wpt/beacon/headers/header-referrer-no-referrer-when-downgrade.https.html [ Failure Timeout ]
-Bug(none) external/wpt/beacon/headers/header-referrer-strict-origin-when-cross-origin.https.html [ Failure Timeout ]
-Bug(none) external/wpt/beacon/headers/header-referrer-strict-origin.https.html [ Failure Timeout ]
-Bug(none) external/wpt/beacon/headers/header-referrer-unsafe-url.https.html [ Failure Timeout ]
 Bug(none) external/wpt/clear-site-data/navigation.https.html [ Timeout ]
 Bug(none) external/wpt/content-security-policy/child-src/child-src-about-blank-allowed-by-default.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/content-security-policy/child-src/child-src-about-blank-allowed-by-scheme.sub.html [ Failure Timeout ]
@@ -253,46 +217,25 @@
 Bug(none) external/wpt/content-security-policy/script-src/script-src-report-only-policy-works-with-hash-policy.html [ Failure ]
 Bug(none) external/wpt/content-security-policy/style-src/style-src-multiple-policies-multiple-hashing-algorithms.html [ Failure ]
 Bug(none) external/wpt/content-security-policy/script-src/script-src-report-only-policy-works-with-external-hash-policy.html [ Failure ]
-Bug(none) external/wpt/content-security-policy/securitypolicyviolation/img-src-redirect-upgrade-reporting.https.html [ Failure Timeout ]
 Bug(none) external/wpt/content-security-policy/securitypolicyviolation/inside-service-worker.https.html [ Crash Failure Timeout ]
-Bug(none) external/wpt/content-security-policy/securitypolicyviolation/upgrade-insecure-requests-reporting.https.html [ Failure Timeout ]
 Bug(none) external/wpt/content-security-policy/svg/svg-inline.sub.html [ Failure Timeout ]
-Bug(none) external/wpt/content-security-policy/worker-src/dedicated-child.sub.html [ Failure Timeout ]
-Bug(none) external/wpt/content-security-policy/worker-src/dedicated-fallback.sub.html [ Failure Timeout Failure ]
-Bug(none) external/wpt/content-security-policy/worker-src/dedicated-list.sub.html [ Failure Timeout ]
-Bug(none) external/wpt/content-security-policy/worker-src/dedicated-self.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/content-security-policy/worker-src/service-child.https.sub.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/content-security-policy/worker-src/service-fallback.https.sub.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/content-security-policy/worker-src/service-list.https.sub.html [ Crash Failure Timeout ]
-Bug(none) external/wpt/content-security-policy/worker-src/service-none.https.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/content-security-policy/worker-src/service-self.https.sub.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/content-security-policy/worker-src/shared-child.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/content-security-policy/worker-src/shared-fallback.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/content-security-policy/worker-src/shared-list.sub.html [ Failure Timeout ]
-Bug(none) external/wpt/content-security-policy/worker-src/shared-self.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/cookies/secure/set-from-dom.https.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/cookies/secure/set-from-http.https.sub.html [ Failure Timeout ]
-Bug(none) external/wpt/cookies/secure/set-from-ws.https.sub.html [ Failure Timeout ]
-Bug(none) external/wpt/cookies/secure/set-from-wss.https.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/cors/allow-headers.htm [ Failure Timeout ]
-Bug(none) external/wpt/cors/basic.htm [ Failure Timeout ]
 Bug(none) external/wpt/cors/origin.htm [ Failure Timeout ]
 Bug(none) external/wpt/cors/preflight-cache.htm [ Failure Timeout ]
 Bug(none) external/wpt/cors/request-headers.htm [ Failure Timeout ]
 Bug(none) external/wpt/cors/response-headers.htm [ Failure Timeout ]
 Bug(none) external/wpt/cors/simple-requests.htm [ Failure Timeout ]
-Bug(none) external/wpt/css-font-display/font-display.html [ Failure Timeout ]
-Bug(none) external/wpt/css/CSS2/floats-clear/floats-015.xht [ Failure Timeout ]
-Bug(none) external/wpt/css/css-grid-1/alignment/grid-content-distribution-018.html [ Failure Timeout ]
-Bug(none) external/wpt/css/css-shapes-1/shape-outside/shape-box/shape-outside-box-003.html [ Failure Timeout ]
-Bug(none) external/wpt/css/css-shapes-1/shape-outside/values/shape-outside-ellipse-004.html [ Failure Timeout ]
 Bug(none) external/wpt/cssom-view/scrolling-quirks-vs-nonquirks.html [ Failure Timeout ]
 Bug(none) external/wpt/cssom-view/scrollingElement.html [ Failure Timeout ]
-Bug(none) external/wpt/custom-elements/custom-element-registry/per-global.html [ Failure Timeout ]
-Bug(none) external/wpt/dom/nodes/Document-URL.sub.html [ Failure Timeout ]
-Bug(none) external/wpt/dom/nodes/Document-characterSet-normalization.html [ Crash Failure Timeout ]
-Bug(none) external/wpt/dom/nodes/Document-createElement-namespace.html [ Failure Timeout ]
-Bug(none) external/wpt/dom/nodes/Element-remove.html [ Failure Timeout ]
 Bug(none) external/wpt/domxpath/xml_xpath_runner.html [ Failure Timeout ]
 Bug(none) external/wpt/eventsource/dedicated-worker/eventsource-onopen.htm [ Failure Timeout ]
 Bug(none) external/wpt/fetch/api/basic/accept-header.any.html [ Failure ]
@@ -308,36 +251,10 @@
 Bug(none) external/wpt/fetch/api/policies/referrer-origin-when-cross-origin-service-worker.https.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/fetch/api/policies/referrer-unsafe-url-service-worker.https.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/fetch/api/response/response-cancel-stream.html [ Timeout ]
-Bug(none) external/wpt/fullscreen/api/document-exit-fullscreen-active-document.html [ Failure Timeout ]
-Bug(none) external/wpt/fullscreen/api/document-fullscreen-enabled-active-document.html [ Failure Timeout ]
-Bug(none) external/wpt/fullscreen/api/element-request-fullscreen-active-document.html [ Failure Timeout ]
-Bug(none) external/wpt/hr-time/test_cross_frame_start.html [ Failure Timeout ]
-Bug(none) external/wpt/hr-time/window-worker-time-origin.html [ Timeout ]
 Bug(none) external/wpt/html/browsers/browsing-the-web/navigating-across-documents/012.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/browsing-the-web/read-media/pageload-video.html [ Crash Pass Failure Timeout ]
-Bug(none) external/wpt/html/browsers/browsing-the-web/unloading-documents/005.html [ Crash ]
-Bug(none) external/wpt/html/browsers/history/the-location-interface/location-pathname-setter-question-mark.html [ Failure Timeout ]
 Bug(none) external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken-weird.html [ Failure Timeout Failure ]
-Bug(none) external/wpt/html/browsers/history/the-location-interface/location-protocol-setter-non-broken.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/history/the-location-interface/location-prototype-setting-cross-origin.sub.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/history/the-location-interface/location-prototype-setting-goes-cross-origin-domain.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/html/browsers/offline/appcache/workers/appcache-worker.html [ Timeout ]
-Bug(none) external/wpt/html/browsers/offline/application-cache-api/api_status_idle.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/the-window-object/Window-document.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/the-window-object/apis-for-creating-and-navigating-browsing-contexts-by-name/creating_browsing_context_test_01.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/the-windowproxy-exotic-object/windowproxy-prototype-setting-cross-origin.sub.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/the-windowproxy-exotic-object/windowproxy-prototype-setting-goes-cross-origin-domain.sub.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/windows/browsing-context-names/choose-_blank-002.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/windows/browsing-context-names/choose-default-001.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/windows/nested-browsing-contexts/window-parent-null.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/windows/nested-browsing-contexts/window-parent.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/windows/nested-browsing-contexts/window-top-null.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/windows/nested-browsing-contexts/window-top.html [ Failure Timeout ]
-Bug(none) external/wpt/html/browsers/windows/noreferrer-null-opener.html [ Failure Timeout ]
-Bug(none) external/wpt/html/dom/self-origin.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/html/infrastructure/safe-passing-of-structured-data/shared-array-buffers/window-serviceworker-failure.https.html [ Crash Failure Timeout ]
-Bug(none) external/wpt/html/infrastructure/urls/terminology-0/document-base-url.html [ Failure Timeout ]
-Bug(none) external/wpt/html/rendering/non-replaced-elements/the-page/iframe-marginwidth-marginheight.html [ Failure Timeout ]
 Bug(none) external/wpt/html/semantics/embedded-content/media-elements/playing-the-media-resource/playbackRate.html [ Failure Timeout ]
 Bug(none) external/wpt/html/semantics/embedded-content/media-elements/ready-states/autoplay-with-slow-text-tracks.html [ Failure Timeout ]
 Bug(none) external/wpt/html/semantics/embedded-content/media-elements/video_008.htm [ Failure Timeout ]
@@ -354,15 +271,12 @@
 Bug(none) external/wpt/html/webappapis/scripting/processing-model-2/integration-with-the-javascript-agent-formalism/canblock-serviceworker.https.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/html/webappapis/scripting/processing-model-2/unhandled-promise-rejections/promise-rejection-events.serviceworker.https.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/html/webappapis/the-windoworworkerglobalscope-mixin/Worker_Self_Origin.html [ Failure Timeout ]
-Bug(none) external/wpt/media-source/mediasource-config-change-webm-a-bitrate.html [ Failure Timeout ]
 Bug(none) external/wpt/mixed-content/allowed/http-csp/same-host-wss/websocket-request/top-level/keep-scheme-redirect/websocket-allowed.https.html [ Failure Timeout ]
 Bug(none) external/wpt/mixed-content/allowed/http-csp/same-host-wss/websocket-request/top-level/no-redirect/websocket-allowed.https.html [ Failure Timeout ]
 Bug(none) external/wpt/navigation-timing/nav2_test_attributes_values.html [ Failure Timeout ]
 Bug(none) external/wpt/navigation-timing/nav2_test_unloadEvents_previous_document_cross_origin.sub.html [ Failure Timeout ]
 Bug(none) external/wpt/notifications/shownotification-resolve-manual.https.html [ Failure Timeout ]
 Bug(none) external/wpt/offscreen-canvas [ Crash Failure Timeout ]
-Bug(none) external/wpt/orientation-sensor/idlharness.https.html [ Failure Timeout ]
-Bug(none) external/wpt/pointerevents/pointerevent_touch-action-table-test_touch-manual.html [ Failure Timeout ]
 Bug(none) external/wpt/preload/fetch-destination.https.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/preload/single-download-preload.html [ Failure Timeout ]
 Bug(none) external/wpt/resource-timing/resource_TAO_match_origin.htm [ Failure Timeout ]
@@ -371,20 +285,7 @@
 Bug(none) external/wpt/resource-timing/resource_cached.htm [ Failure Timeout ]
 Bug(none) external/wpt/resource-timing/resource_connection_reuse.html [ Failure Timeout ]
 Bug(none) external/wpt/resource-timing/test_resource_timing.html [ Failure Timeout ]
-Bug(none) external/wpt/secure-contexts/basic-popup-and-iframe-tests.html [ Failure Timeout ]
 Bug(none) external/wpt/service-workers [ Crash Failure Timeout ]
-Bug(none) external/wpt/storage/estimate-indexeddb-worker.https.html [ Failure Timeout ]
-Bug(none) external/wpt/storage/estimate-indexeddb.https.html [ Failure Timeout ]
-Bug(none) external/wpt/storage/interfaces.https.html [ Failure Timeout ]
-Bug(none) external/wpt/storage/opaque-origin.https.html [ Failure Timeout ]
-Bug(none) external/wpt/storage/persist-permission-manual.https.html [ Failure Timeout ]
-Bug(none) external/wpt/storage/persisted-worker.https.html [ Failure Timeout ]
-Bug(none) external/wpt/storage/persisted.https.html [ Failure Timeout ]
-Bug(none) external/wpt/storage/storagemanager-estimate.https.html [ Failure Timeout ]
-Bug(none) external/wpt/storage/storagemanager-persist-worker.https.html [ Failure Timeout ]
-Bug(none) external/wpt/storage/storagemanager-persist.https.html [ Failure Timeout ]
-Bug(none) external/wpt/storage/storagemanager-persisted-worker.https.html [ Failure Timeout ]
-Bug(none) external/wpt/storage/storagemanager-persisted.https.html [ Failure Timeout ]
 Bug(none) external/wpt/streams/byte-length-queuing-strategy.serviceworker.https.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/streams/count-queuing-strategy.serviceworker.https.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/streams/piping/close-propagation-backward.serviceworker.https.html [ Crash Failure Timeout ]
@@ -430,23 +331,9 @@
 Bug(none) external/wpt/streams/writable-streams/start.serviceworker.https.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/streams/writable-streams/write.serviceworker.https.html [ Crash Failure Timeout ]
 Bug(none) external/wpt/html/syntax/parsing/html5lib_tests1.html?run_type=uri [ Timeout ]
-Bug(none) external/wpt/url/failure.html [ Failure Timeout ]
 Bug(none) external/wpt/wasm/wasm_service_worker_test.https.html [ Crash Timeout ]
-Bug(none) external/wpt/web-animations/interfaces/AnimationTimeline/document-timeline.html [ Failure ]
-Bug(none) external/wpt/web-share/idlharness.https.html [ Failure Timeout ]
-Bug(none) external/wpt/web-share/share-url-invalid.https.html [ Failure Timeout ]
-Bug(none) external/wpt/web-share/share-without-user-gesture.https.html [ Failure Timeout ]
-Bug(none) external/wpt/webaudio/the-audio-api/the-audiobuffer-interface/idl-test.html [ Failure Timeout ]
-Bug(none) external/wpt/webaudio/the-audio-api/the-audiodestinationnode-interface/idl-test.html [ Failure Timeout ]
-Bug(none) external/wpt/webaudio/the-audio-api/the-audioparam-interface/idl-test.html [ Failure Timeout ]
-Bug(none) external/wpt/webaudio/the-audio-api/the-constantsourcenode-interface/test-constantsourcenode.html [ Failure Timeout ]
-Bug(none) external/wpt/webaudio/the-audio-api/the-delaynode-interface/idl-test.html [ Failure Timeout ]
-Bug(none) external/wpt/webaudio/the-audio-api/the-gainnode-interface/idl-test.html [ Failure Timeout ]
-Bug(none) external/wpt/webaudio/the-audio-api/the-iirfilternode-interface/test-iirfilternode.html [ Failure Timeout ]
 Bug(none) external/wpt/websockets/cookies/003.html [ Failure ]
-Bug(none) external/wpt/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/class_object/class_timestamp_future.html [ Failure Timeout ]
 Bug(none) external/wpt/workers/SharedWorker_blobUrl.html [ Failure Timeout ]
-Bug(none) external/wpt/workers/name-property.html [ Failure Timeout ]
 Bug(none) fast/canvas/canvas-createImageBitmap-drawImage.html [ Crash Failure ]
 Bug(none) fast/canvas/webgl/texImage-imageBitmap-from-imageBitmap-from-blob.html [ Crash Failure ]
 Bug(none) fast/canvas/canvas-createImageBitmap-invalid-blob-in-workers.html [ Crash ]
@@ -456,120 +343,20 @@
 Bug(none) fast/canvas/canvas-createImageBitmap-invalid-args.html [ Crash ]
 Bug(none) fast/canvas/canvas-createImageBitmap-size-tooBig.html [ Crash ]
 Bug(none) fast/canvas/webgl/texImage-imageBitmap-from-blob-resize.html [ Crash Failure ]
-Bug(none) fast/css/counters/counter-traverse-table-cell.html [ Failure ]
-Bug(none) fast/css/font-face-attribute-remove.html [ Timeout ]
-Bug(none) fast/css/object-fit-grow-landscape.html [ Failure ]
-Bug(none) fast/css/object-fit-grow-portrait.html [ Failure ]
-Bug(none) fast/dnd/file-drag-drop-on-page.html [ Failure ]
-Bug(none) fast/dom/Document/xml-document-focus.xml [ Failure ]
-Bug(none) fast/dom/Element/offsetLeft-offsetTop-body-quirk.html [ Failure ]
-Bug(none) fast/dom/Element/offsetLeft-offsetTop-html.html [ Failure ]
-Bug(none) fast/dom/HTMLAnchorElement/anchor-download-unset.html [ Timeout ]
-Bug(none) fast/dom/HTMLAnchorElement/anchor-nodownload.html [ Timeout ]
-Bug(none) fast/dom/HTMLLinkElement/prefetch.html [ Failure ]
-Bug(none) fast/dom/HTMLLinkElement/subresource.html [ Failure ]
-Bug(none) fast/dom/HTMLObjectElement/update-data.html [ Timeout ]
-Bug(none) fast/dom/NodeList/nodelist-reachable.html [ Timeout ]
 Bug(none) fast/dom/Range/surround-contents-font-face-crash.svg [ Timeout ]
-Bug(none) fast/dom/StyleSheet/gc-parent-rule.html [ Timeout ]
-Bug(none) fast/dom/StyleSheet/gc-rule-children-wrappers.html [ Timeout ]
-Bug(none) fast/dom/StyleSheet/gc-styleheet-wrapper.xhtml [ Failure Timeout ]
-Bug(none) fast/dom/Window/customized-property-survives-gc.html [ Timeout ]
-Bug(none) fast/dom/Window/property-access-on-cached-properties-after-frame-navigated.html [ Timeout ]
-Bug(none) fast/dom/Window/property-access-on-cached-window-after-frame-navigated.html [ Timeout ]
-Bug(none) fast/dom/Window/property-access-on-cached-window-after-frame-removed-and-gced.html [ Timeout ]
-Bug(none) fast/dom/child-insertion-notify-crash.html [ Timeout ]
-Bug(none) fast/dom/css-delete-doc.html [ Timeout ]
-Bug(none) fast/dom/document-navigation-error-no-crash.html [ Timeout ]
-Bug(none) fast/dom/gc-dom-tree-lifetime.html [ Timeout ]
-Bug(none) fast/dom/gc-image-element-2.html [ Timeout ]
-Bug(none) fast/dom/node-filter-gc.html [ Timeout ]
 Bug(none) fast/dom/split-cdata.xml [ Timeout ]
-Bug(none) fast/encoding/char-encoding.html [ Timeout ]
-Bug(none) fast/events/attribute-listener-cloned-from-frameless-doc-context-2.html [ Timeout ]
 Bug(none) fast/events/attribute-listener-cloned-from-frameless-doc.xhtml [ Timeout ]
-Bug(none) fast/events/attribute-listener-extracted-from-frameless-doc-context-2.html [ Timeout ]
-Bug(none) fast/events/before-unload-adopt-within-subframes.html [ Timeout ]
-Bug(none) fast/events/before-unload-remove-and-add-subframe.html [ Timeout ]
-Bug(none) fast/events/click-after-mousedown-cancel.html [ Timeout ]
-Bug(none) fast/events/crash-on-querying-event-path.html [ Timeout ]
-Bug(none) fast/events/drag-and-drop-autoscroll-inner-frame.html [ Failure ]
 Bug(none) fast/events/event-on-xhr-document.html [ Failure ]
-Bug(none) fast/events/event-properties-gc.html [ Timeout ]
-Bug(none) fast/events/media-focus-in-standalone-media-document.html [ Crash Timeout ]
-Bug(none) fast/events/message-port-gc-closed-cloned.html [ Timeout ]
-Bug(none) fast/events/message-port-gc-closed.html [ Timeout ]
 Bug(none) fast/events/message-port-transferables.html [ Timeout ]
-Bug(none) fast/events/resize-subframe.html [ Failure ]
-Bug(none) fast/events/touch/gesture/long-press-focuses-frame.html [ Failure ]
-Bug(none) fast/events/wheel/mouse-wheel-scroll-latching.html [ Timeout Pass ]
-Bug(none) fast/events/wheel/wheel-scroll-latching-on-scrollbar.html [ Crash Timeout Pass ]
-Bug(none) fast/files/apply-blob-url-to-img.html [ Timeout ]
 Bug(none) fast/files/apply-blob-url-to-xhr.html [ Crash Timeout ]
 Bug(none) fast/files/workers/worker-apply-blob-url-to-xhr.html [ Crash Failure Timeout ]
-Bug(none) fast/files/workers/worker-read-file-async.html [ Failure ]
-Bug(none) fast/files/workers/worker-read-file-constructor-async.html [ Timeout ]
-Bug(none) fast/files/workers/worker-read-file-sync.html [ Failure ]
 Bug(none) fast/files/xhr-response-blob.html [ Crash Failure ]
-Bug(none) fast/filesystem/file-writer-truncate-extend.html [ Failure ]
-Bug(none) fast/filesystem/file-writer-write-overlapped.html [ Failure ]
-Bug(none) fast/filesystem/filesystem-reference.html [ Timeout ]
-Bug(none) fast/filesystem/form-reading-from-file.html [ Failure ]
-Bug(none) fast/filesystem/snapshot-file-with-gc.html [ Failure ]
-Bug(none) fast/filesystem/workers/file-writer-sync-truncate-extend.html [ Failure ]
-Bug(none) fast/filesystem/workers/file-writer-sync-write-overlapped.html [ Failure ]
-Bug(none) fast/filesystem/workers/file-writer-truncate-extend.html [ Failure ]
-Bug(none) fast/filesystem/workers/file-writer-write-overlapped.html [ Failure ]
-Bug(none) fast/forms/file/recover-file-input-in-unposted-form.html [ Crash Pass Timeout ]
-Bug(none) fast/forms/select/input-select-after-resize.html [ Failure ]
-Bug(none) fast/forms/select/option-add-crash.html [ Timeout ]
-Bug(none) fast/forms/select/select-set-length-with-mutation-remove.html [ Timeout ]
-Bug(none) fast/frames/content-opacity-1.html [ Failure ]
-Bug(none) fast/frames/frame-navigation.html [ Failure ]
-Bug(none) fast/frames/frame-src-attribute.html [ Timeout ]
-Bug(none) fast/frames/frameset-style-recalc.html [ Failure ]
-Bug(none) fast/frames/negative-remaining-length-crash.html [ Failure ]
-Bug(none) fast/frames/sandboxed-iframe-plugins.html [ Failure ]
-Bug(none) fast/frames/set-parent-src-synchronously-xhtml.xhtml [ Crash ]
-Bug(none) fast/harness/internals-observe-gc.html [ Timeout ]
-Bug(none) fast/harness/perftests/measure-time.html [ Timeout ]
-Bug(none) fast/harness/perftests/runs-per-second-iterations.html [ Timeout ]
-Bug(none) fast/harness/perftests/runs-per-second-log.html [ Timeout ]
 Bug(none) fast/history/history-back-twice-with-subframes-assert.html [ Timeout ]
-Bug(none) fast/html/imports/import-expando-gc.html [ Timeout ]
-Bug(none) fast/js/nested-object-gc.html [ Timeout ]
-Bug(none) fast/js/with-scope-gc.html [ Timeout ]
-Bug(none) fast/loader/document-destruction-within-unload.html [ Crash ]
 Bug(none) fast/loader/local-svg-parsed-as-svg.svg [ Timeout ]
-Bug(none) fast/loader/main-document-url-for-non-http-loads.html [ Failure ]
 Bug(none) fast/loader/object-with-rejected-resource.html [ Failure ]
-Bug(none) fast/loader/reload-zero-byte-plugin.html [ Timeout ]
-Bug(none) fast/loader/sandboxed-plugin-crash.html [ Crash ]
-Bug(none) fast/loader/simultaneous-reloads-assert.html [ Failure ]
-Bug(none) fast/loader/stateobjects/pushstate-in-data-url-denied.html [ Failure ]
-Bug(none) fast/loader/url-strip-cr-lf-tab.html [ Failure ]
-Bug(none) fast/media/mq-color-gamut-picture.html [ Failure ]
-Bug(none) fast/mediastream/MediaStreamTrack-clone.html [ Timeout ]
-Bug(none) fast/mediastream/MediaStreamTrack-contentHint.html [ Timeout ]
 Bug(none) fast/parser/compatMode-in-xhtml.xhtml [ Timeout ]
 Bug(none) fast/parser/external-entities-in-xslt.xml [ Failure ]
-Bug(none) fast/parser/xhtml-close-while-parsing.xhtml [ Crash ]
-Bug(none) fast/parser/xhtml-document-with-html-object.xhtml [ Timeout ]
-Bug(none) fast/parser/xhtml-dom-character-data-modified-crash.html [ Crash ]
-Bug(none) fast/parser/xhtml-synchronous-detach-crash.html [ Crash ]
-Bug(none) fast/peerconnection/RTCPeerConnection-lifetime.html [ Timeout ]
-Bug(none) fast/replaced/frame-removed-during-resize-smaller.html [ Timeout ]
-Bug(none) fast/replaced/frame-removed-during-resize.html [ Timeout ]
 Bug(none) fast/serviceworker/access-container-on-local-file.html [ Failure ]
-Bug(none) fast/spatial-navigation/snav-hidden-iframe-zero-size.html [ Failure ]
-Bug(none) fast/spatial-navigation/snav-hidden-iframe.html [ Failure ]
-Bug(none) fast/spatial-navigation/snav-iframe-nested.html [ Failure ]
-Bug(none) fast/spatial-navigation/snav-iframe-no-focusable-content.html [ Failure ]
-Bug(none) fast/spatial-navigation/snav-iframe-no-scrollable-content.html [ Failure ]
-Bug(none) fast/spatial-navigation/snav-iframe-recursive-offset-parent.html [ Failure ]
-Bug(none) fast/spatial-navigation/snav-iframe-with-offscreen-focusable-element.html [ Failure ]
-Bug(none) fast/spatial-navigation/snav-media-elements.html [ Timeout ]
-Bug(none) fast/tokenizer/image-empty-crash.html [ Timeout ]
 Bug(none) fast/workers/shared-worker-console-log.html [ Timeout ]
 Bug(none) fast/workers/close-context-messageport-crash.html [ Timeout ]
 Bug(none) fast/xmlhttprequest/xmlhttprequest-bad-mimetype.html [ Failure ]
@@ -589,15 +376,6 @@
 Bug(none) fast/xsl/xslt-processor.html [ Failure ]
 Bug(none) fast/xsl/xslt-relative-path.xml [ Failure ]
 Bug(none) fast/xsl/xslt-second-level-import.xml [ Skip ]
-Bug(none) fullscreen/full-screen-iframe-allowed-video.html [ Timeout ]
-Bug(none) fullscreen/full-screen-iframe-legacy.html [ Timeout ]
-Bug(none) fullscreen/full-screen-iframe-without-allow-attribute-allowed-from-parent.html [ Failure ]
-Bug(none) fullscreen/video-controls-timeline.html [ Timeout ]
-Bug(none) fullscreen/video-specified-size.html [ Timeout ]
-Bug(none) harness-tests/mojo-helpers.html [ Timeout ]
-Bug(none) html/document_metadata/head-check.html [ Timeout ]
-Bug(none) html/marquee/marquee-clone-crash.html [ Timeout ]
-Bug(none) html5lib/generated/run-tests1-data.html [ Timeout ]
 Bug(none) http/tests/appcache/404-manifest.html [ Failure ]
 Bug(none) http/tests/appcache/abort-cache-ondownloading-manifest-404.html [ Timeout ]
 Bug(none) http/tests/appcache/access-via-redirect.php [ Timeout ]
@@ -989,77 +767,8 @@
 Bug(none) http/tests/local/formdata/send-form-data.html [ Failure ]
 Bug(none) http/tests/local/formdata/upload-events.html [ Failure ]
 Bug(none) http/tests/local/serviceworker/fetch-request-body-file.html [ Crash Timeout ]
-Bug(none) http/tests/media/audio-seekable-contains-zero-without-ranges.html [ Timeout ]
-Bug(none) http/tests/media/audio-timeline-seek-outside-seekable.html [ Timeout ]
-Bug(none) http/tests/media/autoplay-crossorigin.html [ Timeout ]
-Bug(none) http/tests/media/controls/controls-list-add-hide.html [ Timeout ]
-Bug(none) http/tests/media/controls/controls-list-remove-show.html [ Timeout ]
-Bug(none) http/tests/media/controls/video-controls-overflow-menu-correct-ordering.html [ Timeout ]
-Bug(none) http/tests/media/controls/video-controls-overflow-menu-updates-appropriately.html [ Timeout ]
-Bug(none) http/tests/media/encrypted-media/encrypted-media-encrypted-event-same-origin.html [ Timeout ]
-Bug(none) http/tests/media/gc-while-network-loading.html [ Timeout ]
-Bug(none) http/tests/media/media-document.html [ Crash ]
-Bug(none) http/tests/media/media-source/mediasource-addsourcebuffer.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-append-buffer.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-appendwindow.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-avtracks.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-buffered.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-config-change-webm-a-bitrate.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-config-change-webm-av-audio-bitrate.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-config-change-webm-av-framesize.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-config-change-webm-av-video-bitrate.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-detach.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-duration-boundaryconditions.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-duration.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-errors.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-getvideoplaybackquality.html [ Failure Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-initsegmentreceived-alg.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-play-then-seek-back.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-play.html [ Failure Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-precise-duration.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-redundant-seek.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-remove.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-removesourcebuffer.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-seek-beyond-duration.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-seek-during-pending-seek.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-seekable.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-sequencemode-append-buffer.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-sequencemode-crbug-616565.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-sourcebuffer-mode.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-sourcebuffer-trackdefaults.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-sourcebufferlist.html [ Timeout ]
-Bug(none) http/tests/media/media-source/mediasource-timestamp-offset.html [ Timeout ]
-Bug(none) http/tests/media/media-source/stream_memory_tests/mediasource-appendbuffer-quota-exceeded-default-buffers.html [ Timeout ]
-Bug(none) http/tests/media/mixed-range-response.html [ Timeout ]
-Bug(none) http/tests/media/preload-conditions.html [ Timeout ]
-Bug(none) http/tests/media/progress-events-generated-correctly.html [ Timeout ]
-Bug(none) http/tests/media/reload-after-dialog.html [ Timeout ]
-Bug(none) http/tests/media/remove-while-loading.html [ Timeout ]
-Bug(none) http/tests/media/video-buffered-range-contains-currentTime.html [ Timeout ]
 Bug(none) http/tests/media/video-buffered.html [ Timeout ]
-Bug(none) http/tests/media/video-cancel-load.html [ Timeout ]
-Bug(none) http/tests/media/video-controls-download-button-displayed.html [ Timeout ]
-Bug(none) http/tests/media/video-controls-download-button-not-displayed-hide-download-ui.html [ Timeout ]
-Bug(none) http/tests/media/video-controls-download-button-not-displayed-mediastream.html [ Timeout ]
-Bug(none) http/tests/media/video-controls-download-button-saves-media.html [ Timeout ]
-Bug(none) http/tests/media/video-controls-overflow-menu-download-button.html [ Timeout ]
-Bug(none) http/tests/media/video-cookie.html [ Timeout ]
-Bug(none) http/tests/media/video-error-abort.html [ Timeout ]
 Bug(none) http/tests/media/video-in-iframe-crash.html [ Crash Timeout ]
-Bug(none) http/tests/media/video-load-metadata-decode-error.html [ Timeout ]
-Bug(none) http/tests/media/video-load-suspend.html [ Timeout ]
-Bug(none) http/tests/media/video-load-twice.html [ Timeout ]
-Bug(none) http/tests/media/video-load-with-userpass.html [ Timeout ]
-Bug(none) http/tests/media/video-play-progress.html [ Timeout ]
-Bug(none) http/tests/media/video-play-stall-before-meta-data.html [ Timeout ]
-Bug(none) http/tests/media/video-preload-metadata.html [ Timeout ]
-Bug(none) http/tests/media/video-query-url.html [ Timeout ]
-Bug(none) http/tests/media/video-referer.html [ Timeout ]
-Bug(none) http/tests/media/video-seek-to-duration.html [ Timeout ]
-Bug(none) http/tests/media/video-seek-to-middle.html [ Timeout ]
-Bug(none) http/tests/media/video-served-as-text.html [ Timeout ]
-Bug(none) http/tests/media/video-throttled-load-metadata.html [ Timeout ]
-Bug(none) http/tests/media/video-useragent.html [ Timeout ]
 Bug(none) http/tests/misc/adopt-iframe-src-attr-after-remove.html [ Timeout ]
 Bug(none) http/tests/misc/createElementNamespace1.xml [ Failure ]
 Bug(none) http/tests/misc/detach-and-location-change-in-onload.html [ Timeout ]
@@ -1372,17 +1081,6 @@
 Bug(none) http/tests/workers/shared-worker-secure-context.https.html [ Timeout ]
 Bug(none) http/tests/workers/text-encoding.html [ Failure ]
 Bug(none) http/tests/xmlhttprequest [ Crash Failure Timeout ]
-Bug(none) imagecapture/MediaStreamTrack-applyConstraints-getSettings.html [ Timeout ]
-Bug(none) imagecapture/MediaStreamTrack-applyConstraints-reject.html [ Timeout ]
-Bug(none) imagecapture/MediaStreamTrack-applyConstraints.html [ Timeout ]
-Bug(none) imagecapture/MediaStreamTrack-getCapabilities.html [ Timeout ]
-Bug(none) imagecapture/MediaStreamTrack-getSettings.html [ Timeout ]
-Bug(none) imagecapture/getPhotoCapabilities.html [ Timeout ]
-Bug(none) imagecapture/getPhotoSettings.html [ Timeout ]
-Bug(none) imagecapture/setOptions-reject.html [ Timeout ]
-Bug(none) imagecapture/setOptions.html [ Timeout ]
-Bug(none) imagecapture/takePhoto-with-PhotoSettings.html [ Timeout ]
-Bug(none) imagecapture/takePhoto.html [ Timeout ]
 Bug(none) inspector-enabled/console/console-uncaught-promise-no-inspector.html [ Timeout ]
 Bug(none) inspector-protocol/accessibility/accessibility-nameSources-buttons.js [ Timeout ]
 Bug(none) inspector-protocol/css/css-get-background-colors.js [ Timeout ]
@@ -1559,343 +1257,6 @@
 Bug(none) installedapp/getinstalledrelatedapps-empty.html [ Timeout ]
 Bug(none) installedapp/getinstalledrelatedapps.html [ Timeout ]
 Bug(none) loader/iframe-src-change-onload-crash.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_canplay.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_canplay_manual.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_canplaythrough.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_canplaythrough_manual.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_loadeddata.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_loadeddata_manual.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_loadedmetadata.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_loadedmetadata_manual.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_loadstart.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_loadstart_manual.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_order_canplay_canplaythrough.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_order_canplay_playing.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_order_loadedmetadata_loadeddata.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_order_loadstart_progress.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_pause_manual.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_play.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_play_manual.html [ Failure Timeout ]
-Bug(none) media/W3C/audio/events/event_playing.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_playing_manual.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_progress.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_progress_manual.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_timeupdate.html [ Timeout ]
-Bug(none) media/W3C/audio/events/event_timeupdate_manual.html [ Timeout ]
-Bug(none) media/W3C/audio/networkState/networkState_during_loadstart.html [ Timeout ]
-Bug(none) media/W3C/audio/paused/paused_false_during_play.html [ Timeout ]
-Bug(none) media/W3C/audio/paused/paused_true_during_pause.html [ Timeout ]
-Bug(none) media/W3C/audio/readyState/readyState_during_canplay.html [ Timeout ]
-Bug(none) media/W3C/audio/readyState/readyState_during_canplaythrough.html [ Timeout ]
-Bug(none) media/W3C/audio/readyState/readyState_during_loadeddata.html [ Timeout ]
-Bug(none) media/W3C/audio/readyState/readyState_during_loadedmetadata.html [ Timeout ]
-Bug(none) media/W3C/audio/readyState/readyState_during_playing.html [ Timeout ]
-Bug(none) media/W3C/audio/src/src_removal_does_not_trigger_loadstart.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_canplay.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_canplay_manual.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_canplaythrough.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_canplaythrough_manual.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_loadeddata.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_loadeddata_manual.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_loadedmetadata.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_loadedmetadata_manual.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_loadstart.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_loadstart_manual.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_order_canplay_canplaythrough.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_order_canplay_playing.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_order_loadedmetadata_loadeddata.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_order_loadstart_progress.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_pause_manual.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_play.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_play_manual.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_playing.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_playing_manual.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_progress.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_progress_manual.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_timeupdate.html [ Timeout ]
-Bug(none) media/W3C/video/events/event_timeupdate_manual.html [ Timeout ]
-Bug(none) media/W3C/video/networkState/networkState_during_loadstart.html [ Timeout ]
-Bug(none) media/W3C/video/networkState/networkState_during_progress.html [ Timeout ]
-Bug(none) media/W3C/video/paused/paused_false_during_play.html [ Timeout ]
-Bug(none) media/W3C/video/paused/paused_true_during_pause.html [ Timeout ]
-Bug(none) media/W3C/video/readyState/readyState_during_canplay.html [ Timeout ]
-Bug(none) media/W3C/video/readyState/readyState_during_canplaythrough.html [ Timeout ]
-Bug(none) media/W3C/video/readyState/readyState_during_loadeddata.html [ Timeout ]
-Bug(none) media/W3C/video/readyState/readyState_during_loadedmetadata.html [ Timeout ]
-Bug(none) media/W3C/video/readyState/readyState_during_playing.html [ Timeout ]
-Bug(none) media/W3C/video/src/src_removal_does_not_trigger_loadstart.html [ Timeout ]
-Bug(none) media/audio-concurrent-supported.html [ Timeout ]
-Bug(none) media/audio-constructor-preload.html [ Timeout ]
-Bug(none) media/audio-constructor-src.html [ Timeout ]
-Bug(none) media/audio-constructor.html [ Timeout ]
-Bug(none) media/audio-controls-captions.html [ Timeout ]
-Bug(none) media/audio-controls-do-not-fade-out.html [ Timeout ]
-Bug(none) media/audio-controls-rendering.html [ Timeout ]
-Bug(none) media/audio-data-url.html [ Timeout ]
-Bug(none) media/audio-delete-while-slider-thumb-clicked.html [ Timeout ]
-Bug(none) media/audio-garbage-collect.html [ Timeout ]
-Bug(none) media/audio-only-video-intrinsic-size.html [ Timeout ]
-Bug(none) media/audio-play-event.html [ Timeout ]
-Bug(none) media/auto-play-in-sandbox-with-allow-scripts.html [ Timeout ]
-Bug(none) media/autoplay-clears-autoplaying-flag.html [ Timeout ]
-Bug(none) media/autoplay-document-move.html [ Timeout ]
-Bug(none) media/autoplay-from-mediastream-to-src.html [ Timeout ]
-Bug(none) media/autoplay-muted-conditions.html [ Timeout ]
-Bug(none) media/autoplay-muted-datasaver-off.html [ Timeout ]
-Bug(none) media/autoplay-muted-datasaver-on.html [ Timeout ]
-Bug(none) media/autoplay-muted.html [ Timeout ]
-Bug(none) media/autoplay-never-visible.html [ Timeout ]
-Bug(none) media/autoplay-non-whitelisted-scope.html [ Timeout ]
-Bug(none) media/autoplay-unmute-offscreen.html [ Timeout ]
-Bug(none) media/autoplay-when-visible-multiple-times.html [ Timeout ]
-Bug(none) media/autoplay-when-visible.html [ Timeout ]
-Bug(none) media/autoplay-whitelisted-scope.html [ Timeout ]
-Bug(none) media/autoplay-with-preload-none.html [ Timeout ]
-Bug(none) media/autoplay.html [ Timeout ]
-Bug(none) media/avtrack/addtrack.html [ Timeout ]
-Bug(none) media/avtrack/audio-track-enabled.html [ Timeout ]
-Bug(none) media/avtrack/audio-track-properties.html [ Timeout ]
-Bug(none) media/avtrack/forget-on-load.html [ Timeout ]
-Bug(none) media/avtrack/gc.html [ Timeout ]
-Bug(none) media/avtrack/getTrackById.html [ Timeout ]
-Bug(none) media/avtrack/track-switching.html [ Timeout ]
-Bug(none) media/avtrack/video-track-properties.html [ Timeout ]
-Bug(none) media/avtrack/video-track-selected.html [ Timeout ]
-Bug(none) media/color-profile-munsell-bt601-smpte-to-srgb.html [ Failure ]
-Bug(none) media/color-profile-munsell-bt709-to-srgb.html [ Failure ]
-Bug(none) media/color-profile-video-poster-image.html [ Failure ]
-Bug(none) media/color-profile-video-seek-filter.html [ Timeout ]
-Bug(none) media/color-profile-video-seek-object-fit.html [ Timeout ]
-Bug(none) media/color-profile-video-seek.html [ Timeout ]
-Bug(none) media/color-profile-video.html [ Timeout ]
-Bug(none) media/controls-after-reload.html [ Timeout ]
-Bug(none) media/controls-drag-timebar-rendering.html [ Timeout ]
-Bug(none) media/controls-drag-timebar.html [ Timeout ]
-Bug(none) media/controls-right-click-on-timebar.html [ Timeout ]
-Bug(none) media/controls-strict.html [ Timeout ]
-Bug(none) media/controls-styling-strict.html [ Timeout ]
-Bug(none) media/controls-styling.html [ Timeout ]
-Bug(none) media/controls-timeline.html [ Timeout ]
-Bug(none) media/controls-volume-slider-keynav.html [ Timeout ]
-Bug(none) media/controls-volume-slider.html [ Timeout ]
-Bug(none) media/controls-without-preload.html [ Timeout ]
-Bug(none) media/controls/buttons-after-reset.html [ Timeout ]
-Bug(none) media/controls/closed-captions-switch-track.html [ Timeout ]
-Bug(none) media/controls/controls-cast-button-narrow.html [ Timeout ]
-Bug(none) media/controls/controls-cast-button.html [ Timeout ]
-Bug(none) media/controls/controls-cast-do-not-fade-out.html [ Timeout ]
-Bug(none) media/controls/controls-cast-overlay-slow-fade.html [ Timeout ]
-Bug(none) media/controls/controls-overlay-cast-button.html [ Timeout ]
-Bug(none) media/controls/overflow-fully-hidden.html [ Timeout ]
-Bug(none) media/controls/overlay-play-button-document-move.html [ Timeout ]
-Bug(none) media/controls/overlay-play-button-narrow.html [ Timeout ]
-Bug(none) media/controls/settings-disable-controls.html [ Timeout ]
-Bug(none) media/controls/time-update-after-unload.html [ Timeout ]
-Bug(none) media/controls/video-controls-overflow-menu-hide-on-click-outside.html [ Timeout ]
-Bug(none) media/controls/video-controls-overflow-menu-hide-on-click-panel.html [ Timeout ]
-Bug(none) media/controls/video-controls-overflow-menu-hide-on-click.html [ Timeout ]
-Bug(none) media/controls/video-controls-overflow-menu-hide-on-resize.html [ Timeout ]
-Bug(none) media/controls/video-controls-overflow-menu-text.html [ Timeout ]
-Bug(none) media/controls/video-controls-overflow-menu-visibility.html [ Timeout ]
-Bug(none) media/controls/video-controls-with-cast-rendering.html [ Timeout ]
-Bug(none) media/controls/video-enter-exit-fullscreen-while-hovering-shows-controls.html [ Timeout ]
-Bug(none) media/controls/video-overlay-cast-covering.html [ Timeout ]
-Bug(none) media/controls/video-overlay-cast-dark-rendering.html [ Timeout ]
-Bug(none) media/controls/video-overlay-cast-light-rendering.html [ Failure ]
-Bug(none) media/controls/video-overlay-play-button.html [ Timeout ]
-Bug(none) media/controls/volumechange-muted-attribute.html [ Timeout ]
-Bug(none) media/controls/volumechange-stopimmediatepropagation.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-async-creation-with-gc.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-async-setcert-with-gc.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-lifetime-mediakeys-with-session.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-lifetime-mediakeys.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-lifetime-mediakeysession-reference.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-lifetime-mediakeysession-release-noreference.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-lifetime-mediakeysession-release.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-lifetime-multiple-mediakeys.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-lifetime-reload.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-onencrypted.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-playback-encrypted-and-clear-sources.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-playback-multiple-sessions.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-playback-setmediakeys-after-src.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-playback-setmediakeys-before-src.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-playback-two-videos.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-reset-src-after-setmediakeys.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-reset-src-during-setmediakeys.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-setmediakeys-again-after-playback.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-setmediakeys-again-after-resetting-src.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-setmediakeys-at-same-time.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-setmediakeys-multiple-times-with-different-mediakeys.html [ Timeout ]
-Bug(none) media/encrypted-media/encrypted-media-waiting-for-a-key.html [ Timeout ]
-Bug(none) media/event-attributes.html [ Timeout ]
-Bug(none) media/fullscreen-controls-visible-last.html [ Timeout ]
-Bug(none) media/gc-while-playing.html [ Timeout ]
-Bug(none) media/gc-while-seeking.html [ Timeout ]
-Bug(none) media/media-can-load-when-hidden.html [ Timeout ]
-Bug(none) media/media-captions-no-controls.html [ Timeout ]
-Bug(none) media/media-continues-playing-after-replace-source.html [ Timeout ]
-Bug(none) media/media-controls-hide-menu-stoppropagation-iframe.html [ Timeout ]
-Bug(none) media/media-controls-hide-menu-stoppropagation.html [ Timeout ]
-Bug(none) media/media-controls-invalid-url.html [ Timeout ]
-Bug(none) media/media-controls-overflow-hidden.html [ Timeout ]
-Bug(none) media/media-controls-overflow-visible.html [ Timeout ]
-Bug(none) media/media-controls-tap-show-controls-without-activating.html [ Timeout ]
-Bug(none) media/media-document-audio-repaint.html [ Crash Timeout ]
-Bug(none) media/media-document-audio-size.html [ Crash Timeout ]
-Bug(none) media/media-element-play-after-eos.html [ Timeout ]
-Bug(none) media/media-ended.html [ Timeout ]
-Bug(none) media/media-extension-with-fragment.html [ Timeout ]
-Bug(none) media/media-load-event.html [ Timeout ]
-Bug(none) media/media-play-promise.html [ Timeout ]
-Bug(none) media/media-source-append-multiple.html [ Timeout ]
-Bug(none) media/mediasession/mojo/callback-alive-after-gc.html [ Timeout ]
-Bug(none) media/mediasession/mojo/file-image-removed.html [ Timeout ]
-Bug(none) media/mediasession/mojo/media-control-action-reaches-client.html [ Timeout ]
-Bug(none) media/mediasession/mojo/media-control-set-handler-notifies-service.html [ Timeout ]
-Bug(none) media/mediasession/mojo/metadata-async.html [ Timeout ]
-Bug(none) media/mediasession/mojo/metadata-propagated-twice.html [ Timeout ]
-Bug(none) media/mediasession/mojo/metadata-propagated.html [ Timeout ]
-Bug(none) media/mediasession/mojo/metadata-session-link.html [ Timeout ]
-Bug(none) media/mediasession/mojo/playback-state-propagated.html [ Timeout ]
-Bug(none) media/mediasession/mojo/set-null-metadata.html [ Timeout ]
-Bug(none) media/no-autoplay-with-user-gesture-requirement.html [ Timeout ]
-Bug(none) media/play-promise-crash.html [ Timeout ]
-Bug(none) media/remove-from-document.html [ Timeout ]
-Bug(none) media/seek-to-currentTime.html [ Timeout ]
-Bug(none) media/sources-fallback-codecs.html [ Timeout ]
-Bug(none) media/track [ Failure Timeout ]
-Bug(none) media/video-append-source.html [ Timeout ]
-Bug(none) media/video-aspect-ratio.html [ Timeout ]
-Bug(none) media/video-autoplay.html [ Timeout ]
-Bug(none) media/video-black-bg-in-media-document.html [ Crash ]
-Bug(none) media/video-buffered-unknown-duration.html [ Timeout ]
-Bug(none) media/video-buffered.html [ Timeout ]
-Bug(none) media/video-canvas-alpha.html [ Timeout ]
-Bug(none) media/video-canvas-draw.html [ Timeout ]
-Bug(none) media/video-colorspace-yuv420.html [ Failure ]
-Bug(none) media/video-colorspace-yuv422.html [ Failure ]
-Bug(none) media/video-controls-always-visible-when-control-hovered.html [ Timeout ]
-Bug(none) media/video-controls-attribute-fullscreen.html [ Timeout ]
-Bug(none) media/video-controls-auto-hide-after-play-by-touch.html [ Timeout ]
-Bug(none) media/video-controls-dont-show-on-focus-when-disabled.html [ Timeout ]
-Bug(none) media/video-controls-download-button-not-displayed-local.html [ Timeout ]
-Bug(none) media/video-controls-focus-movement-on-hide.html [ Timeout ]
-Bug(none) media/video-controls-fullscreen-iframe-allowed.html [ Timeout ]
-Bug(none) media/video-controls-fullscreen-iframe-not-allowed.html [ Timeout ]
-Bug(none) media/video-controls-fullscreen-not-supported.html [ Timeout ]
-Bug(none) media/video-controls-fullscreen.html [ Timeout ]
-Bug(none) media/video-controls-hidden-audio.html [ Timeout ]
-Bug(none) media/video-controls-hide-after-touch-on-control.html [ Timeout ]
-Bug(none) media/video-controls-hide-on-move-outside-controls.html [ Timeout ]
-Bug(none) media/video-controls-in-media-document.html [ Crash Timeout ]
-Bug(none) media/video-controls-mouse-events-captured.html [ Timeout ]
-Bug(none) media/video-controls-muted-video-can-unmute.html [ Timeout ]
-Bug(none) media/video-controls-overflow-menu-closed-captions-button.html [ Timeout ]
-Bug(none) media/video-controls-overflow-menu-closed-captions-list-hide-on-click-outside.html [ Timeout ]
-Bug(none) media/video-controls-overflow-menu-fullscreen-button.html [ Timeout ]
-Bug(none) media/video-controls-overflow-menu-last-button-visible.html [ Timeout ]
-Bug(none) media/video-controls-overflow-menu-mute-button.html [ Timeout ]
-Bug(none) media/video-controls-overflow-menu-play-button.html [ Timeout ]
-Bug(none) media/video-controls-rendering.html [ Timeout ]
-Bug(none) media/video-controls-show-on-focus.html [ Timeout ]
-Bug(none) media/video-controls-toggling.html [ Timeout ]
-Bug(none) media/video-controls-touch-events-captured.html [ Timeout ]
-Bug(none) media/video-controls-track-selection-menu.html [ Timeout ]
-Bug(none) media/video-controls-transformed.html [ Timeout ]
-Bug(none) media/video-controls-visibility-multimodal-mouse-after-touch.html [ Timeout ]
-Bug(none) media/video-controls-visibility-multimodal-touch-after-mouse.html [ Timeout ]
-Bug(none) media/video-controls-visible-audio-only.html [ Timeout ]
-Bug(none) media/video-controls-zoomed.html [ Timeout ]
-Bug(none) media/video-controls.html [ Timeout ]
-Bug(none) media/video-currentTime-before-have-metadata-media-fragment-uri.html [ Timeout ]
-Bug(none) media/video-currentTime-before-have-metadata.html [ Timeout ]
-Bug(none) media/video-currentTime-delay.html [ Timeout ]
-Bug(none) media/video-currentTime-set.html [ Timeout ]
-Bug(none) media/video-currentTime-set2.html [ Timeout ]
-Bug(none) media/video-currentTime.html [ Timeout ]
-Bug(none) media/video-defaultmuted.html [ Timeout ]
-Bug(none) media/video-delay-load-event.html [ Timeout Failure ]
-Bug(none) media/video-display-aspect-ratio.html [ Timeout ]
-Bug(none) media/video-display-none-crash.html [ Timeout ]
-Bug(none) media/video-display-toggle.html [ Timeout ]
-Bug(none) media/video-dom-autoplay.html [ Timeout ]
-Bug(none) media/video-dom-src.html [ Timeout ]
-Bug(none) media/video-double-seek-currentTime.html [ Timeout ]
-Bug(none) media/video-duration-known-after-eos.html [ Timeout ]
-Bug(none) media/video-enter-fullscreen-without-user-gesture.html [ Timeout ]
-Bug(none) media/video-force-preload-none-to-metadata-on-load.html [ Timeout ]
-Bug(none) media/video-force-preload-none-to-metadata-on-play.html [ Timeout ]
-Bug(none) media/video-frame-accurate-seek.html [ Timeout ]
-Bug(none) media/video-layer-crash.html [ Timeout ]
-Bug(none) media/video-load-networkState.html [ Timeout ]
-Bug(none) media/video-load-preload-none.html [ Timeout ]
-Bug(none) media/video-load-readyState.html [ Timeout ]
-Bug(none) media/video-loop-from-ended.html [ Timeout ]
-Bug(none) media/video-loop.html [ Timeout ]
-Bug(none) media/video-move-to-new-document-crash.html [ Timeout ]
-Bug(none) media/video-move-to-new-document.html [ Timeout ]
-Bug(none) media/video-muted.html [ Timeout ]
-Bug(none) media/video-no-autoplay.html [ Timeout ]
-Bug(none) media/video-no-controls-events-not-absorbed.html [ Timeout ]
-Bug(none) media/video-no-timeupdate-before-playback.html [ Timeout ]
-Bug(none) media/video-not-paused-while-looping.html [ Timeout ]
-Bug(none) media/video-object-fit-change.html [ Timeout ]
-Bug(none) media/video-object-fit.html [ Timeout ]
-Bug(none) media/video-pause-empty-events.html [ Timeout ]
-Bug(none) media/video-pause-immediately.html [ Failure Pass Timeout ]
-Bug(none) media/video-persistence.html [ Timeout ]
-Bug(none) media/video-play-empty-events.html [ Timeout ]
-Bug(none) media/video-play-pause-events.html [ Timeout ]
-Bug(none) media/video-play-require-user-gesture.html [ Timeout ]
-Bug(none) media/video-playbackrate.html [ Timeout ]
-Bug(none) media/video-played-collapse.html [ Timeout ]
-Bug(none) media/video-played-ranges-1.html [ Timeout ]
-Bug(none) media/video-played-reset.html [ Failure Pass Timeout ]
-Bug(none) media/video-playing-and-pause.html [ Timeout ]
-Bug(none) media/video-plays-past-end-of-test.html [ Timeout ]
-Bug(none) media/video-poster-delayed.html [ Timeout ]
-Bug(none) media/video-prefixed-fullscreen.html [ Timeout ]
-Bug(none) media/video-preload-none-to-metadata-after-load-crash.html [ Timeout ]
-Bug(none) media/video-preload.html [ Timeout ]
-Bug(none) media/video-remove-insert-repaints.html [ Timeout ]
-Bug(none) media/video-replaces-poster.html [ Timeout ]
-Bug(none) media/video-scales-in-media-document.html [ Crash ]
-Bug(none) media/video-seek-by-small-increment.html [ Timeout ]
-Bug(none) media/video-seek-past-end-paused.html [ Timeout ]
-Bug(none) media/video-seek-past-end-playing.html [ Timeout ]
-Bug(none) media/video-seek-to-duration-with-playbackrate-zero.html [ Timeout ]
-Bug(none) media/video-seekable.html [ Timeout ]
-Bug(none) media/video-seeking.html [ Timeout ]
-Bug(none) media/video-set-rate-from-pause.html [ Timeout ]
-Bug(none) media/video-single-valid-source.html [ Timeout ]
-Bug(none) media/video-size.html [ Timeout ]
-Bug(none) media/video-source-add-after-remove.html [ Timeout ]
-Bug(none) media/video-source-error.html [ Timeout ]
-Bug(none) media/video-source-load.html [ Timeout ]
-Bug(none) media/video-source-type-params.html [ Timeout ]
-Bug(none) media/video-source-type.html [ Timeout ]
-Bug(none) media/video-source.html [ Timeout ]
-Bug(none) media/video-src-blob.html [ Failure ]
-Bug(none) media/video-src-change.html [ Timeout ]
-Bug(none) media/video-src-empty.html [ Timeout ]
-Bug(none) media/video-src-remove.html [ Timeout ]
-Bug(none) media/video-src-set.html [ Timeout ]
-Bug(none) media/video-src-source.html [ Timeout ]
-Bug(none) media/video-src.html [ Timeout ]
-Bug(none) media/video-srcobject-mediastream-src-file.html [ Timeout ]
-Bug(none) media/video-timeupdate-during-playback.html [ Timeout ]
-Bug(none) media/video-transformed.html [ Timeout ]
-Bug(none) media/video-volume.html [ Timeout ]
-Bug(none) media/video-webkit-appearance.html [ Timeout ]
-Bug(none) media/video-zoom-controls.html [ Failure Timeout ]
-Bug(none) media/video-zoom.html [ Failure Timeout ]
-Bug(none) media/viewport-in-standalone-media-document.html [ Crash ]
-Bug(none) mhtml/invalid-bad-boundary.mht [ Timeout ]
-Bug(none) netinfo/gc-frame-listeners.html [ Timeout ]
-Bug(none) nfc/mock-nfc.html [ Timeout ]
-Bug(none) nfc/nfc-block-iframe.html [ Timeout ]
-Bug(none) nfc/push.html [ Timeout ]
-Bug(none) nfc/watch.html [ Timeout ]
 Bug(none) paint/invalidation/media-audio-no-spurious-repaints.html [ Timeout ]
 Bug(none) paint/invalidation/svg/relative-sized-image.xhtml [ Failure ]
 Bug(none) paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem.html [ Failure ]
@@ -1925,153 +1286,9 @@
 Bug(none) presentation/presentationconnectionavailableevent-ctor-mock.html [ Timeout ]
 Bug(none) printing/subframes-percentage-height.html [ Failure ]
 Bug(none) scrollbars/listbox-scrollbar-combinations.html [ Failure ]
-Bug(none) sensor/accelerometer.html [ Timeout ]
-Bug(none) sensor/ambient-light-sensor.html [ Timeout ]
-Bug(none) sensor/gyroscope.html [ Timeout ]
-Bug(none) sensor/magnetometer.html [ Timeout ]
-Bug(none) sensor/mock-sensor.html [ Timeout ]
-Bug(none) sensor/orientation-sensor.html [ Timeout ]
-Bug(none) shapedetection/detection-HTMLCanvasElement.html [ Timeout ]
-Bug(none) shapedetection/detection-HTMLImageElement.html [ Timeout ]
-Bug(none) shapedetection/detection-HTMLVideoElement.html [ Timeout ]
-Bug(none) shapedetection/detection-ImageBitmap.html [ Timeout ]
-Bug(none) shapedetection/detection-ImageData.html [ Timeout ]
-Bug(none) shapedetection/detection-on-worker.html [ Timeout ]
-Bug(none) shapedetection/detection-options.html [ Timeout ]
-Bug(none) shapedetection/detection-security-test.html [ Timeout ]
-Bug(none) shapedetection/detector-same-object.html [ Timeout ]
 Bug(none) storage/domstorage/events/basic.html [ Failure Timeout ]
-Bug(none) storage/indexeddb/cursor-request-cycle.html [ Timeout ]
-Bug(none) storage/indexeddb/cursor-value.html [ Timeout ]
-Bug(none) storage/indexeddb/empty-crash.html [ Timeout ]
-Bug(none) storage/indexeddb/key-cursor-request-cycle.html [ Timeout ]
-Bug(none) storage/indexeddb/key-generator.html [ Timeout ]
-Bug(none) storage/indexeddb/structured-clone.html [ Failure ]
-Bug(none) storage/indexeddb/versionchangerequest-activedomobject.html [ Timeout ]
-Bug(none) storage/websql/change-version.html [ Timeout ]
-Bug(none) storage/websql/database-removed-context-crash.html [ Timeout ]
-Bug(none) storage/websql/multiple-transactions.html [ Timeout ]
-Bug(none) storage/websql/transaction-error-callback-isolated-world.html [ Timeout ]
-Bug(none) storage/websql/transaction-success-callback-isolated-world.html [ Timeout ]
-Bug(none) svg/W3C-SVG-1.1-SE/filters-image-03-f.svg [ Failure ]
-Bug(none) svg/W3C-SVG-1.1-SE/filters-image-05-f.svg [ Failure ]
-Bug(none) svg/W3C-SVG-1.1/render-groups-01-b.svg [ Failure ]
-Bug(none) svg/W3C-SVG-1.1/render-groups-03-t.svg [ Failure ]
-Bug(none) svg/W3C-SVG-1.1/struct-image-06-t.svg [ Failure ]
-Bug(none) svg/W3C-SVG-1.1/struct-use-01-t.svg [ Failure ]
-Bug(none) svg/animations/mpath-remove-from-dependents-on-delete-crash.html [ Timeout ]
-Bug(none) svg/animations/target-condition-crash.html [ Timeout ]
-Bug(none) svg/as-border-image/svg-as-border-image.html [ Failure ]
-Bug(none) svg/as-image/image-preserveAspectRatio-all.svg [ Failure ]
-Bug(none) svg/custom/g-outside-svg.html [ Failure ]
-Bug(none) svg/custom/group-opacity.svg [ Failure ]
-Bug(none) svg/dom/SVGAnimatedListPropertyTearOff-crash.html [ Timeout ]
-Bug(none) svg/dom/SVGMatrixTearOff-crash.html [ Timeout ]
-Bug(none) svg/dom/getScreenCTM-ancestor-transform.html [ Failure ]
-Bug(none) svg/filters/feImage-preserveAspectRatio-all.svg [ Failure ]
-Bug(none) svg/filters/feImage-preserveAspectratio.svg [ Failure ]
-Bug(none) svg/filters/filter-source-position.svg [ Failure ]
-Bug(none) svg/filters/filteredImage.svg [ Failure ]
-Bug(none) svg/zoom/page/zoom-svg-through-object-with-absolute-size-2.xhtml [ Failure ]
-Bug(none) svg/zoom/page/zoom-svg-through-object-with-absolute-size.xhtml [ Failure ]
-Bug(none) svg/zoom/page/zoom-svg-through-object-with-percentage-size.xhtml [ Failure ]
 Bug(none) tables/mozilla/core/col_widths_fix_autoFixPer.html [ Timeout ]
 Bug(none) tables/mozilla_expected_failures/marvin/backgr_fixed-bg.html [ Failure ]
 Bug(none) traversal/node-iterator-009.html [ Failure ]
 Bug(none) traversal/tree-walker-006.html [ Failure ]
-Bug(none) vibration/vibration-iframe.html [ Timeout ]
-Bug(none) vibration/vibration.html [ Timeout ]
-Bug(none) virtual [ Crash Failure Timeout ]
-Bug(none) vr/events_vrdisplayactivate.html [ Timeout ]
-Bug(none) vr/events_vrdisplayconnect.html [ Timeout ]
-Bug(none) vr/events_vrdisplaypresentchange.html [ Timeout ]
-Bug(none) vr/exitPresent_reject_notpresenting.html [ Timeout ]
-Bug(none) vr/exitPresent_resolve.html [ Timeout ]
-Bug(none) vr/getEyeParameters_match.html [ Timeout ]
-Bug(none) vr/getFrameData_noupdate.html [ Timeout ]
-Bug(none) vr/getFrameData_oneframeupdate.html [ Timeout ]
-Bug(none) vr/getFrameData_samewithinframe.html [ Failure Timeout ]
-Bug(none) vr/getLayers_notpresenting.html [ Timeout ]
-Bug(none) vr/getLayers_presenting.html [ Timeout ]
-Bug(none) vr/getLayers_presenting_nondefaultbounds.html [ Timeout ]
-Bug(none) vr/getLayers_update.html [ Timeout ]
-Bug(none) vr/getVRDisplays_one_display.html [ Timeout ]
-Bug(none) vr/getVRDisplays_two_display.html [ Timeout ]
-Bug(none) vr/getVRDisplays_zero_display.html [ Timeout ]
-Bug(none) vr/multiple_requestAnimationFrame_called.html [ Timeout ]
-Bug(none) vr/requestAnimationFrame_called.html [ Timeout ]
-Bug(none) vr/requestAnimationFrame_consistentTimestamps.html [ Timeout ]
-Bug(none) vr/requestAnimationFrame_handoff.html [ Timeout ]
-Bug(none) vr/requestAnimationFrame_invalidhandle.html [ Timeout ]
-Bug(none) vr/requestAnimationFrame_submitFrame_combinations.html [ Timeout ]
-Bug(none) vr/requestAnimationFrame_unregister.html [ Timeout ]
-Bug(none) vr/requestPresent_reject_badleftbounds.html [ Timeout ]
-Bug(none) vr/requestPresent_reject_NaN_bounds.html [ Timeout ]
-Bug(none) vr/requestPresent_reject_badrightbounds.html [ Timeout ]
-Bug(none) vr/requestPresent_reject_nogesture.html [ Timeout ]
-Bug(none) vr/requestPresent_reject_nolayers.html [ Timeout ]
-Bug(none) vr/requestPresent_reject_nosource.html [ Timeout ]
-Bug(none) vr/requestPresent_reject_notsupported.html [ Timeout ]
-Bug(none) vr/requestPresent_reject_nowebgl.html [ Timeout ]
-Bug(none) vr/requestPresent_reject_nullsource.html [ Timeout ]
-Bug(none) vr/requestPresent_reject_toomanylayers.html [ Timeout ]
-Bug(none) vr/requestPresent_resolve.html [ Timeout ]
-Bug(none) vr/requestPresent_resolve_repeatwithgesture.html [ Timeout ]
-Bug(none) vr/requestPresent_resolve_repeatwithoutgesture.html [ Timeout ]
-Bug(none) vr/requestPresent_resolve_then_reject.html [ Timeout ]
-Bug(none) vr/requestPresent_resolve_webgl2.html [ Timeout ]
-Bug(none) vr/stageParameters_match.html [ Timeout ]
-Bug(none) webaudio/Analyser/realtimeanalyser-basic.html [ Timeout ]
-Bug(none) webaudio/Analyser/realtimeanalyser-fft-scaling.html [ Timeout ]
-Bug(none) webaudio/Analyser/realtimeanalyser-fft-sizing.html [ Timeout ]
-Bug(none) webaudio/Analyser/realtimeanalyser-float-data.html [ Timeout ]
-Bug(none) webaudio/Analyser/realtimeanalyser-freq-data.html [ Timeout ]
-Bug(none) webaudio/AudioBuffer/audiobuffer-copy-channel.html [ Timeout ]
-Bug(none) webaudio/AudioBuffer/audiobuffer-getChannelData.html [ Timeout ]
-Bug(none) webaudio/AudioBuffer/audiobuffer.html [ Timeout ]
-Bug(none) webaudio/AudioBufferSource/audiobuffersource-channels.html [ Timeout ]
-Bug(none) webaudio/AudioContext/audiocontext-close-basic.html [ Timeout ]
-Bug(none) webaudio/AudioContext/audiocontext-getoutputtimestamp.html [ Timeout ]
-Bug(none) webaudio/AudioContext/audiocontext-listener-should-not-crash.html [ Timeout ]
-Bug(none) webaudio/AudioContext/audiocontext-max-contexts.html [ Timeout ]
-Bug(none) webaudio/AudioContext/audiocontext-suspend-resume.html [ Timeout ]
-Bug(none) webaudio/AudioContext/audiocontextoptions.html [ Timeout ]
-Bug(none) webaudio/AudioNode/audionode-connect-method-chaining.html [ Timeout ]
-Bug(none) webaudio/AudioNode/audionode-disconnect-audioparam.html [ Timeout ]
-Bug(none) webaudio/AudioNode/audionode.html [ Timeout ]
-Bug(none) webaudio/AudioParam/audioparam-exceptional-values.html [ Timeout ]
-Bug(none) webaudio/AudioParam/audioparam-method-chaining.html [ Timeout ]
-Bug(none) webaudio/BiquadFilter/biquad-automation.html [ Timeout ]
-Bug(none) webaudio/BiquadFilter/biquad-getFrequencyResponse.html [ Timeout ]
-Bug(none) webaudio/BiquadFilter/biquadfilternode-basic.html [ Timeout ]
-Bug(none) webaudio/ConstantSource/constant-source-basic.html [ Timeout ]
-Bug(none) webaudio/Convolver/convolver-setBuffer-null.html [ Timeout ]
-Bug(none) webaudio/DynamicsCompressor/dynamicscompressor-basic.html [ Timeout ]
-Bug(none) webaudio/Gain/gain-basic.html [ Timeout ]
-Bug(none) webaudio/IIRFilter/iir-tail-time.html [ Timeout ]
-Bug(none) webaudio/IIRFilter/iirfilter.html [ Timeout ]
-Bug(none) webaudio/MediaElementAudioSource/mediaelementaudiosourcenode.html [ Timeout ]
-Bug(none) webaudio/MediaStreamAudioDestination/mediastreamaudiodestinationnode.html [ Timeout ]
-Bug(none) webaudio/MediaStreamAudioSource/mediastreamaudiosourcenode.html [ Timeout ]
-Bug(none) webaudio/Panner/pannernode-basic.html [ Timeout ]
-Bug(none) webaudio/PeriodicWave/periodicwave-lengths.html [ Timeout ]
-Bug(none) webaudio/StereoPanner/stereopannernode-basic.html [ Timeout ]
-Bug(none) webaudio/audio-scheduled-source-basic.html [ Timeout ]
-Bug(none) webaudio/codec-tests/webm/webm-decode.html [ Timeout ]
-Bug(none) webaudio/constructor/mediastreamaudiodestination.html [ Timeout ]
-Bug(none) webaudio/constructor/mediastreamaudiosource.html [ Timeout ]
-Bug(none) webaudio/decodeAudioData/decode-audio-data-basic.html [ Failure Pass Timeout ]
-Bug(none) webaudio/dom-exceptions.html [ Timeout ]
-Bug(none) webaudio/internals/audiocontext-close.html [ Timeout ]
-Bug(none) webaudio/internals/audiocontext-lock-threading-race.html [ Timeout ]
-Bug(none) webaudio/internals/audiosource-premature-gc.html [ Timeout ]
-Bug(none) webaudio/internals/audiosummingjunction-crash.html [ Timeout ]
-Bug(none) webaudio/internals/mediaelementaudiosourcenode-wrapper.html [ Timeout ]
-Bug(none) webaudio/test-basic.html [ Timeout ]
-Bug(none) webaudio/unit-tests/audit.html [ Timeout ]
-Bug(none) webshare/share-arity.html [ Timeout ]
-Bug(none) webshare/share-error.html [ Timeout ]
-Bug(none) webshare/share-nonutf8-encoding.html [ Timeout ]
-Bug(none) webshare/share-success.html [ Timeout ]
-Bug(none) webshare/share-types.html [ Timeout ]
-Bug(none) webshare/share-url-relative.html [ Timeout ]
+Bug(none) virtual [ Crash Failure Timeout ]
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/OWNERS
new file mode 100644
index 0000000..2c3d32a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-transforms-2/OWNERS
@@ -0,0 +1,2 @@
+# TEAM: paint-dev@chromium.org
+# COMPONENT: Blink>Transforms
diff --git a/third_party/WebKit/LayoutTests/external/wpt/images/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/images/OWNERS
new file mode 100644
index 0000000..990a4f1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/images/OWNERS
@@ -0,0 +1,2 @@
+# TEAM: paint-dev@chromium.org
+# COMPONENT: Blink>Image
diff --git a/third_party/WebKit/LayoutTests/external/wpt/svg/OWNERS b/third_party/WebKit/LayoutTests/external/wpt/svg/OWNERS
index 212e449..9e4d106 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/svg/OWNERS
+++ b/third_party/WebKit/LayoutTests/external/wpt/svg/OWNERS
@@ -1 +1,2 @@
-foolip@chromium.org
+# TEAM: paint-dev@chromium.org
+# COMPONENT: Blink>SVG
diff --git a/third_party/WebKit/Source/core/css/StyleSheetContentsFuzzer.cpp b/third_party/WebKit/Source/core/css/StyleSheetContentsFuzzer.cpp
index a2a3c73..f23bc97a 100644
--- a/third_party/WebKit/Source/core/css/StyleSheetContentsFuzzer.cpp
+++ b/third_party/WebKit/Source/core/css/StyleSheetContentsFuzzer.cpp
@@ -14,8 +14,17 @@
       blink::CSSParserContext::Create(blink::kHTMLStandardMode);
   blink::StyleSheetContents* styleSheet =
       blink::StyleSheetContents::Create(context);
+
   styleSheet->ParseString(String::FromUTF8WithLatin1Fallback(
       reinterpret_cast<const char*>(data), size));
+
+#if defined(ADDRESS_SANITIZER)
+  // LSAN needs unreachable objects to be released to avoid reporting them
+  // incorrectly as a memory leak.
+  blink::ThreadState* currentThreadState = blink::ThreadState::Current();
+  currentThreadState->CollectAllGarbage();
+#endif
+
   return 0;
 }
 
diff --git a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp
index ce88a75..c46a77ca 100644
--- a/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp
+++ b/third_party/WebKit/Source/core/exported/WebPluginContainerImpl.cpp
@@ -833,32 +833,45 @@
 
   if (web_event.GetType() == WebInputEvent::kRawKeyDown ||
       web_event.GetType() == WebInputEvent::kKeyDown) {
-    if ((web_event.GetModifiers() & WebInputEvent::kInputModifiers) ==
-            kEditingModifier &&
-        // Only copy/cut if there's a selection, so that we only ever do
-        // this for Pepper plugins that support copying/cutting.
-        // Windowless NPAPI plugins will get the event as before.
-        web_plugin_->HasSelection()) {
-      if (web_event.windows_key_code == VKEY_C ||
-          web_event.windows_key_code == VKEY_INSERT) {
-        Copy();
-        event->SetDefaultHandled();
-        return;
+    int input_modifiers =
+        web_event.GetModifiers() & WebInputEvent::kInputModifiers;
+    if (input_modifiers == kEditingModifier) {
+      // Only copy/cut if there's a selection, so that we only ever do
+      // this for Pepper plugins that support copying/cutting.
+      // Windowless NPAPI plugins will get the event as before.
+      if (web_plugin_->HasSelection()) {
+        if (web_event.windows_key_code == VKEY_C ||
+            web_event.windows_key_code == VKEY_INSERT) {
+          Copy();
+          event->SetDefaultHandled();
+          return;
+        }
+        if (web_event.windows_key_code == VKEY_X &&
+            ExecuteEditCommand("Cut", "")) {
+          event->SetDefaultHandled();
+          return;
+        }
       }
-      // Ask the plugin if it can cut text before executing "Cut".
-      if (web_event.windows_key_code == VKEY_X &&
-          ExecuteEditCommand("Cut", "")) {
+      // Ask the plugin if it can edit text before executing "Paste".
+      if (web_event.windows_key_code == VKEY_V && web_plugin_->CanEditText() &&
+          ExecuteEditCommand("Paste", "")) {
         event->SetDefaultHandled();
         return;
       }
     }
-    // Alternate shortcut for "Cut" is Shift + Delete.
-    if ((web_event.GetModifiers() & WebInputEvent::kInputModifiers) ==
-            WebInputEvent::kShiftKey &&
-        web_event.windows_key_code == VKEY_DELETE &&
-        web_plugin_->HasSelection() && ExecuteEditCommand("Cut", "")) {
-      event->SetDefaultHandled();
-      return;
+    // Alternate shortcuts for "Cut" and "Paste" are Shift + Delete and Shift +
+    // Insert, respectively.
+    else if (input_modifiers == WebInputEvent::kShiftKey) {
+      if (web_event.windows_key_code == VKEY_DELETE &&
+          web_plugin_->HasSelection() && ExecuteEditCommand("Cut", "")) {
+        event->SetDefaultHandled();
+        return;
+      }
+      if (web_event.windows_key_code == VKEY_INSERT &&
+          web_plugin_->CanEditText() && ExecuteEditCommand("Paste", "")) {
+        event->SetDefaultHandled();
+        return;
+      }
     }
   }
 
diff --git a/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp b/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp
index c9056f7e..189dce59 100644
--- a/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp
+++ b/third_party/WebKit/Source/core/exported/WebPluginContainerTest.cpp
@@ -138,12 +138,12 @@
   TestPluginWebFrameClient* const test_client_;
 };
 
-// Subclass of FakeWebPlugin used for testing the Cut edit command, so
-// HasSelection() and CanEditText() return true by default.
+// Subclass of FakeWebPlugin used for testing edit commands, so HasSelection()
+// and CanEditText() return true by default.
 class TestPluginWithEditableText : public FakeWebPlugin {
  public:
   explicit TestPluginWithEditableText(const WebPluginParams& params)
-      : FakeWebPlugin(params), cut_called_(false) {}
+      : FakeWebPlugin(params), cut_called_(false), paste_called_(false) {}
 
   bool HasSelection() const override { return true; }
   bool CanEditText() const override { return true; }
@@ -153,16 +153,25 @@
       cut_called_ = true;
       return true;
     }
+    if (name == "Paste") {
+      paste_called_ = true;
+      return true;
+    }
     return false;
   }
 
   bool IsCutCalled() const { return cut_called_; }
-  void ResetCutStatus() { cut_called_ = false; }
+  bool IsPasteCalled() const { return paste_called_; }
+  void ResetEditCommandState() {
+    cut_called_ = false;
+    paste_called_ = false;
+  }
 
  private:
   ~TestPluginWithEditableText() override {}
 
   bool cut_called_;
+  bool paste_called_;
 };
 
 class TestPluginWebFrameClient : public FrameTestHelpers::TestWebFrameClient {
@@ -532,7 +541,7 @@
   EXPECT_TRUE(test_plugin->IsCutCalled());
 
   // Reset Cut status for next time.
-  test_plugin->ResetCutStatus();
+  test_plugin->ResetEditCommandState();
 
   modifier_key = static_cast<WebInputEvent::Modifiers>(
       WebInputEvent::kShiftKey | WebInputEvent::kNumLockOn |
@@ -545,6 +554,59 @@
   EXPECT_TRUE(test_plugin->IsCutCalled());
 }
 
+// Verifies |Ctrl-V| and |Shift-Insert| keyboard events, results in the "Paste"
+// command being invoked.
+TEST_F(WebPluginContainerTest, PasteInsertKeyboardEventsTest) {
+  RegisterMockedURL("plugin_container.html");
+  // Must outlive |web_view_helper|.
+  TestPluginWebFrameClient plugin_web_frame_client;
+  FrameTestHelpers::WebViewHelper web_view_helper;
+
+  // Use TestPluginWithEditableText for testing "Paste".
+  plugin_web_frame_client.SetHasEditableText(true);
+
+  WebViewBase* web_view = web_view_helper.InitializeAndLoad(
+      base_url_ + "plugin_container.html", &plugin_web_frame_client);
+  EnablePlugins(web_view, WebSize(300, 300));
+
+  WebElement plugin_container_one_element =
+      web_view->MainFrameImpl()->GetDocument().GetElementById(
+          WebString::FromUTF8("translated-plugin"));
+
+  WebPlugin* plugin =
+      ToWebPluginContainerImpl(plugin_container_one_element.PluginContainer())
+          ->Plugin();
+  TestPluginWithEditableText* test_plugin =
+      static_cast<TestPluginWithEditableText*>(plugin);
+
+  WebInputEvent::Modifiers modifier_key = static_cast<WebInputEvent::Modifiers>(
+      WebInputEvent::kControlKey | WebInputEvent::kNumLockOn |
+      WebInputEvent::kIsLeft);
+#if defined(OS_MACOSX)
+  modifier_key = static_cast<WebInputEvent::Modifiers>(
+      WebInputEvent::kMetaKey | WebInputEvent::kNumLockOn |
+      WebInputEvent::kIsLeft);
+#endif
+  CreateAndHandleKeyboardEvent(&plugin_container_one_element, modifier_key,
+                               VKEY_V);
+
+  // Check that "Paste" command is invoked.
+  EXPECT_TRUE(test_plugin->IsPasteCalled());
+
+  // Reset Paste status for next time.
+  test_plugin->ResetEditCommandState();
+
+  modifier_key = static_cast<WebInputEvent::Modifiers>(
+      WebInputEvent::kShiftKey | WebInputEvent::kNumLockOn |
+      WebInputEvent::kIsLeft);
+
+  CreateAndHandleKeyboardEvent(&plugin_container_one_element, modifier_key,
+                               VKEY_INSERT);
+
+  // Check that "Paste" command is invoked.
+  EXPECT_TRUE(test_plugin->IsPasteCalled());
+}
+
 // A class to facilitate testing that events are correctly received by plugins.
 class EventTestPlugin : public FakeWebPlugin {
  public:
diff --git a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
index bd1285dc..c0685815 100644
--- a/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/RootScrollerController.cpp
@@ -200,12 +200,20 @@
   DCHECK(document_->GetFrame());
   DCHECK(document_->GetFrame()->View());
 
-  LocalFrameView* view =
+  LocalFrameView* child_view =
       ToLocalFrameView(frame_owner.OwnedEmbeddedContentView());
-  view->UpdateGeometry();
+
+  // We can get here as a result of the "post layout resize" on the main frame.
+  // That happens from inside LocalFrameView::PerformLayout. Calling
+  // UpdateGeometry on the iframe causes it to layout which calls
+  // Document::UpdateStyleAndLayout. That tries to recurse up the hierarchy,
+  // reentering Layout on this Document. Thus, we avoid calling this here if
+  // we're in layout; it'll get called when this Document finishes laying out.
+  if (!document_->GetFrame()->View()->IsInPerformLayout())
+    child_view->UpdateGeometry();
 
   if (&EffectiveRootScroller() == frame_owner)
-    view->SetLayoutSize(document_->GetFrame()->View()->GetLayoutSize());
+    child_view->SetLayoutSize(document_->GetFrame()->View()->GetLayoutSize());
 }
 
 PaintLayer* RootScrollerController::RootScrollerPaintLayer() const {
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index 43ccd2a..3923d54ba 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -90,7 +90,7 @@
   DCHECK(!RuntimeEnabledFeatures::RootLayerScrollingEnabled());
   auto element_id = CompositorElementIdFromLayoutObjectId(
       frame_view.GetLayoutView()->UniqueId(),
-      CompositorElementIdNamespace::kScrollTranslation);
+      CompositorElementIdNamespace::kScroll);
   if (auto* existing_scroll = frame_view.ScrollNode()) {
     auto existing_reasons = existing_scroll->GetMainThreadScrollingReasons();
     existing_scroll->Update(
@@ -1019,7 +1019,7 @@
       }
 
       auto element_id = CompositorElementIdFromLayoutObjectId(
-          object.UniqueId(), CompositorElementIdNamespace::kScrollTranslation);
+          object.UniqueId(), CompositorElementIdNamespace::kScroll);
 
       // TODO(pdr): Set the correct compositing reasons here.
       auto result = properties.UpdateScroll(
diff --git a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
index 26731351..6fd3de4 100644
--- a/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
+++ b/third_party/WebKit/Source/modules/vr/VRDisplay.cpp
@@ -644,10 +644,6 @@
     return;
   }
 
-  TRACE_EVENT_BEGIN0("gpu", "VRDisplay::Flush_1");
-  context_gl_->Flush();
-  TRACE_EVENT_END0("gpu", "VRDisplay::Flush_1");
-
   // Check if the canvas got resized, if yes send a bounds update.
   int current_width = rendering_context_->drawingBufferWidth();
   int current_height = rendering_context_->drawingBufferHeight();
@@ -679,18 +675,26 @@
     }
   }
 
-  TRACE_EVENT_BEGIN0("gpu", "VRDisplay::GetImage");
-  RefPtr<Image> image_ref = rendering_context_->GetImage(
-      kPreferAcceleration, kSnapshotReasonCreateImageBitmap);
-  TRACE_EVENT_END0("gpu", "VRDisplay::GetImage");
+  TRACE_EVENT_BEGIN0("gpu", "VRDisplay::GetStaticBitmapImage");
+  RefPtr<Image> image_ref = rendering_context_->GetStaticBitmapImage();
+  TRACE_EVENT_END0("gpu", "VRDisplay::GetStaticBitmapImage");
 
   // Hardware-accelerated rendering should always be texture backed,
   // as implemented by AcceleratedStaticBitmapImage. Ensure this is
   // the case, don't attempt to render if using an unexpected drawing
   // path.
   if (!image_ref.Get() || !image_ref->IsTextureBacked()) {
-    NOTREACHED() << "WebVR requires hardware-accelerated rendering to texture";
-    return;
+    TRACE_EVENT0("gpu", "VRDisplay::GetImage_SlowFallback");
+    // We get a non-texture-backed image when running layout tests
+    // on desktop builds. Add a slow fallback so that these continue
+    // working.
+    image_ref = rendering_context_->GetImage(kPreferAcceleration,
+                                             kSnapshotReasonCreateImageBitmap);
+    if (!image_ref.Get() || !image_ref->IsTextureBacked()) {
+      NOTREACHED()
+          << "WebVR requires hardware-accelerated rendering to texture";
+      return;
+    }
   }
 
   // The AcceleratedStaticBitmapImage must be kept alive until the
@@ -712,11 +716,6 @@
   TRACE_EVENT_BEGIN0("gpu", "VRDisplay::GetMailbox");
   auto mailbox = static_image->GetMailbox();
   TRACE_EVENT_END0("gpu", "VRDisplay::GetMailbox");
-  // Flush to avoid black screen flashes which appear to be related to
-  // "fence sync must be flushed before generating sync token" GL errors.
-  TRACE_EVENT_BEGIN0("gpu", "VRDisplay::Flush_2");
-  context_gl_->Flush();
-  TRACE_EVENT_END0("gpu", "VRDisplay::Flush_2");
   auto sync_token = static_image->GetSyncToken();
 
   // Wait for the previous render to finish, to avoid losing frames in the
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index e8b8cc1..bdb0c063 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -726,16 +726,7 @@
                           exception_state);
   }
 
-  RefPtr<StaticBitmapImage> image;
-  if (CreationAttributes().preserveDrawingBuffer()) {
-    SkImageInfo image_info =
-        SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
-                          CreationAttributes().alpha() ? kPremul_SkAlphaType
-                                                       : kOpaque_SkAlphaType);
-    image = MakeImageSnapshot(image_info);
-  } else {
-    image = GetDrawingBuffer()->TransferToStaticBitmapImage();
-  }
+  RefPtr<StaticBitmapImage> image = GetStaticBitmapImage();
 
   return host()->Commit(
       std::move(image), SkIRect::MakeWH(width, height),
@@ -743,6 +734,23 @@
       script_state, exception_state);
 }
 
+PassRefPtr<StaticBitmapImage>
+WebGLRenderingContextBase::GetStaticBitmapImage() {
+  if (!GetDrawingBuffer())
+    return nullptr;
+
+  if (CreationAttributes().preserveDrawingBuffer()) {
+    int width = GetDrawingBuffer()->Size().Width();
+    int height = GetDrawingBuffer()->Size().Height();
+    SkImageInfo image_info =
+        SkImageInfo::Make(width, height, kRGBA_8888_SkColorType,
+                          CreationAttributes().alpha() ? kPremul_SkAlphaType
+                                                       : kOpaque_SkAlphaType);
+    return MakeImageSnapshot(image_info);
+  }
+  return GetDrawingBuffer()->TransferToStaticBitmapImage();
+}
+
 RefPtr<StaticBitmapImage> WebGLRenderingContextBase::GetImage(
     AccelerationHint hint,
     SnapshotReason reason) const {
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index 0bfea30..5e0b7952 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -598,6 +598,10 @@
   // This clears the backbuffer if preserveDrawingBuffer is false.
   void MarkCompositedAndClearBackbufferIfNeeded();
 
+  // For use by WebVR, commits the current canvas content similar
+  // to the "commit" JS API.
+  PassRefPtr<StaticBitmapImage> GetStaticBitmapImage();
+
  protected:
   friend class EXTDisjointTimerQuery;
   friend class EXTDisjointTimerQueryWebGL2;
diff --git a/third_party/WebKit/Source/platform/graphics/CompositorElementId.cpp b/third_party/WebKit/Source/platform/graphics/CompositorElementId.cpp
index 0464e68..967f4807 100644
--- a/third_party/WebKit/Source/platform/graphics/CompositorElementId.cpp
+++ b/third_party/WebKit/Source/platform/graphics/CompositorElementId.cpp
@@ -29,8 +29,7 @@
   DCHECK(namespace_id == CompositorElementIdNamespace::kPrimary ||
          namespace_id == CompositorElementIdNamespace::kScroll ||
          namespace_id == CompositorElementIdNamespace::kEffectFilter ||
-         namespace_id == CompositorElementIdNamespace::kEffectMask ||
-         namespace_id == CompositorElementIdNamespace::kScrollTranslation);
+         namespace_id == CompositorElementIdNamespace::kEffectMask);
   return CreateCompositorElementId(id, namespace_id);
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/CompositorElementId.h b/third_party/WebKit/Source/platform/graphics/CompositorElementId.h
index 1908877f..2ada044 100644
--- a/third_party/WebKit/Source/platform/graphics/CompositorElementId.h
+++ b/third_party/WebKit/Source/platform/graphics/CompositorElementId.h
@@ -27,7 +27,6 @@
   kEffectFilter,
   kEffectMask,
   kEffectRoot,
-  kScrollTranslation,
   // A sentinel to indicate the maximum representable namespace id
   // (the maximum is one less than this value).
   kMaxRepresentableNamespaceId = 1 << kCompositorNamespaceBitCount
diff --git a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp
index cd297127e..8e1f8e92 100644
--- a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.cpp
@@ -103,7 +103,7 @@
   GraphicsLayer::RegisterContentsLayer(web_layer_.get());
 }
 
-void SurfaceLayerBridge::OnSurfaceCreated(
+void SurfaceLayerBridge::OnFirstSurfaceActivation(
     const viz::SurfaceInfo& surface_info) {
   if (!current_surface_id_.is_valid() && surface_info.is_valid()) {
     // First time a SurfaceId is received
diff --git a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h
index 9647aff..0541816a 100644
--- a/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/SurfaceLayerBridge.h
@@ -47,7 +47,7 @@
   void CreateSolidColorLayer();
 
   // Implementation of blink::mojom::blink::OffscreenCanvasSurfaceClient
-  void OnSurfaceCreated(const viz::SurfaceInfo&) override;
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo&) override;
   void SatisfyCallback(const viz::SurfaceSequence&);
   void RequireCallback(const viz::SurfaceId&, const viz::SurfaceSequence&);
 
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
index cbcc572..5e7afc1 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositorTest.cpp
@@ -149,6 +149,11 @@
         .get();
   }
 
+  CompositorElementId ScrollElementId(unsigned id) {
+    return CompositorElementIdFromLayoutObjectId(
+        id, CompositorElementIdNamespace::kScroll);
+  }
+
   void AddSimpleRectChunk(TestPaintArtifact& artifact) {
     artifact
         .Chunk(TransformPaintPropertyNode::Root(),
@@ -729,7 +734,7 @@
 TEST_F(PaintArtifactCompositorTestWithPropertyTrees, OneScrollNode) {
   FakeScrollClient scroll_client;
 
-  CompositorElementId expected_compositor_element_id = CompositorElementId(2);
+  CompositorElementId expected_compositor_element_id = ScrollElementId(2);
   RefPtr<ScrollPaintPropertyNode> scroll = ScrollPaintPropertyNode::Create(
       ScrollPaintPropertyNode::Root(), IntPoint(), IntSize(11, 13),
       IntSize(27, 31), true, false, 0 /* mainThreadScrollingReasons */,
@@ -838,7 +843,7 @@
   RefPtr<EffectPaintPropertyNode> effect =
       CreateOpacityOnlyEffect(EffectPaintPropertyNode::Root(), 0.5);
 
-  CompositorElementId expected_compositor_element_id_a = CompositorElementId(2);
+  CompositorElementId expected_compositor_element_id_a = ScrollElementId(2);
   RefPtr<ScrollPaintPropertyNode> scroll_a = ScrollPaintPropertyNode::Create(
       ScrollPaintPropertyNode::Root(), IntPoint(), IntSize(2, 3), IntSize(5, 7),
       false, true,
@@ -851,7 +856,7 @@
           kCompositingReasonLayerForScrollingContents, CompositorElementId(),
           scroll_a);
 
-  CompositorElementId expected_compositor_element_id_b = CompositorElementId(3);
+  CompositorElementId expected_compositor_element_id_b = ScrollElementId(3);
   RefPtr<ScrollPaintPropertyNode> scroll_b = ScrollPaintPropertyNode::Create(
       scroll_translation_a->ScrollNode(), IntPoint(), IntSize(19, 23),
       IntSize(29, 31), true, false, 0 /* mainThreadScrollingReasons */,
diff --git a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
index b13eb8b..e09e370 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/ScrollPaintPropertyNode.h
@@ -82,6 +82,7 @@
     user_scrollable_vertical_ = user_scrollable_vertical;
     main_thread_scrolling_reasons_ = main_thread_scrolling_reasons;
     compositor_element_id_ = compositor_element_id;
+    DCHECK(ElementIdNamespaceIsForScrolling());
     scroll_client_ = scroll_client;
     return true;
   }
@@ -171,7 +172,15 @@
         user_scrollable_vertical_(user_scrollable_vertical),
         main_thread_scrolling_reasons_(main_thread_scrolling_reasons),
         compositor_element_id_(compositor_element_id),
-        scroll_client_(scroll_client) {}
+        scroll_client_(scroll_client) {
+    DCHECK(ElementIdNamespaceIsForScrolling());
+  }
+
+  bool ElementIdNamespaceIsForScrolling() const {
+    return !compositor_element_id_ ||
+           NamespaceFromCompositorElementId(compositor_element_id_) ==
+               CompositorElementIdNamespace::kScroll;
+  }
 
   IntPoint bounds_offset_;
   IntSize container_bounds_;
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py
index 7238111..648e19dd 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git.py
@@ -27,7 +27,6 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-import datetime
 import logging
 import re
 
@@ -120,12 +119,6 @@
         return executive.run_command(
             [cls.executable_name, 'config', '--get-all', key], error_handler=Executive.ignore_error, cwd=cwd).rstrip('\n')
 
-    def _discard_local_commits(self):
-        self.run(['reset', '--hard', self._remote_branch_ref()])
-
-    def _rebase_in_progress(self):
-        return self._filesystem.exists(self.absolute_path(self._filesystem.join('.git', 'rebase-apply')))
-
     def has_working_directory_changes(self, pathspec=None):
         """Checks whether there are uncommitted changes."""
         command = ['diff', 'HEAD', '--no-renames', '--name-only']
@@ -133,13 +126,6 @@
             command.extend(['--', pathspec])
         return self.run(command) != ''
 
-    def _discard_working_directory_changes(self):
-        # TODO(qyearsley): Could run git clean here too; this wasn't done
-        # before in order to match svn, but this is no longer a concern.
-        self.run(['reset', 'HEAD', '--hard'])
-        if self._rebase_in_progress():
-            self.run(['rebase', '--abort'])
-
     def unstaged_changes(self):
         """Lists files with unstaged changes, including untracked files.
 
@@ -185,14 +171,6 @@
             return ''
         return self._branch_from_ref(ref)
 
-    def current_branch_or_ref(self):
-        """Returns the name of the current branch, or the commit hash if HEAD is detached."""
-        branch_name = self.current_branch()
-        if not branch_name:
-            # HEAD is detached; use commit SHA instead.
-            return self.run(['rev-parse', 'HEAD']).strip()
-        return branch_name
-
     def _upstream_branch(self):
         current_branch = self.current_branch()
         return self._branch_from_ref(self.read_git_config(
@@ -234,7 +212,6 @@
             match = re.search(status_regexp, line)
             if not match:
                 continue
-            # status = match.group('status')
             filename = match.group('filename')
             filenames.append(filename)
         return filenames
@@ -267,7 +244,7 @@
         return self._commit_position_from_git_log(git_log)
 
     def create_patch(self, git_commit=None, changed_files=None):
-        """Returns a byte array (str()) representing the patch file.
+        """Returns a byte array (str) representing the patch file.
 
         Patch files are effectively binary since they may contain
         files of multiple different encodings.
@@ -282,7 +259,6 @@
             '--no-renames',
             '--src-prefix=a/',
             '--dst-prefix=b/',
-
         ]
         if order:
             command.append(order)
@@ -305,20 +281,9 @@
         git_log = self.git_commit_detail(git_commit)
         return self._commit_position_from_git_log(git_log)
 
-    def checkout_branch(self, name):
-        self.run(['checkout', '-q', name])
-
-    def create_clean_branch(self, name):
-        self.run(['checkout', '-q', '-b', name, self._remote_branch_ref()])
-
-    # Git-specific methods:
     def _branch_ref_exists(self, branch_ref):
         return self.run(['show-ref', '--quiet', '--verify', branch_ref], return_exit_code=True) == 0
 
-    def delete_branch(self, branch_name):
-        if self._branch_ref_exists('refs/heads/' + branch_name):
-            self.run(['branch', '-D', branch_name])
-
     def _remote_merge_base(self):
         return self.run(['merge-base', self._remote_branch_ref(), 'HEAD']).strip()
 
@@ -344,7 +309,3 @@
         if format:
             args.append('--format=' + format)
         return self.run(args)
-
-    def affected_files(self, commit):
-        output = self.run(['log', '-1', '--format=', '--name-only', commit])
-        return output.strip().split('\n')
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_mock.py
index 1a84e98..c7208a0 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_mock.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/git_mock.py
@@ -33,18 +33,6 @@
     def current_branch(self):
         return 'mock-branch-name'
 
-    def current_branch_or_ref(self):
-        return 'mock-branch-name'
-
-    def checkout_branch(self, name):
-        pass
-
-    def create_clean_branch(self, name):
-        pass
-
-    def delete_branch(self, name):
-        pass
-
     def exists(self, path):
         # TestRealMain.test_real_main (and several other rebaseline tests) are sensitive to this return value.
         # We should make those tests more robust, but for now we just return True always (since no test needs otherwise).
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive.py
index 2936d44..ad4d8808d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive.py
@@ -207,19 +207,6 @@
 
         return sorted(running_pids)
 
-    def process_dump(self):
-        ps_process = None
-        if sys.platform in 'win32':
-            ps_process = self.popen(
-                ['wmic', 'process', 'get',
-                 'ProcessId,ParentProcessId,CommandLine'],
-                stdout=self.PIPE, stderr=self.PIPE)
-        else:
-            ps_process = self.popen(['ps', 'aux'], stdout=self.PIPE, stderr=self.PIPE)
-
-        stdout, _ = ps_process.communicate()
-        return [line.strip() for line in stdout.splitlines()]
-
     def wait_limited(self, pid, limit_in_seconds=None, check_frequency_in_seconds=None):
         seconds_left = limit_in_seconds or 10
         sleep_length = check_frequency_in_seconds or 1
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py
index d366254..efb7e35 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/system/executive_mock.py
@@ -201,9 +201,6 @@
     def map(self, thunk, arglist, processes=None):
         return map(thunk, arglist)
 
-    def process_dump(self):
-        return []
-
     @property
     def calls(self):
         # TODO(crbug.com/718456): Make self.full_calls always be an array of
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
index bac31dc8..c786b93 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
@@ -281,11 +281,6 @@
         """
         return self._is_http_test(test_file) or self._is_perf_test(test_file)
 
-    def _test_is_expected_missing(self, test_file):
-        expectations = self._expectations.model().get_expectations(test_file)
-        return (test_expectations.MISSING in expectations or
-                test_expectations.NEEDS_MANUAL_REBASELINE in expectations)
-
     def _test_is_slow(self, test_file):
         expectations = self._expectations.model().get_expectations(test_file)
         return (test_expectations.SLOW in expectations or
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_results.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_results.py
index 30f2e55..3918b10 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_results.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_results.py
@@ -67,11 +67,5 @@
     def __ne__(self, other):
         return not (self == other)
 
-    def has_failure_matching_types(self, *failure_classes):
-        for failure in self.failures:
-            if type(failure) in failure_classes:
-                return True
-        return False
-
     def dumps(self):
         return cPickle.dumps(self)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
index 2876324..11fae00 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -234,10 +234,6 @@
             return 1
         return max_locked_shards
 
-    def baseline_platform_dir(self):
-        """Returns the absolute path to the default (version-independent) platform-specific results."""
-        return self._filesystem.join(self.layout_tests_dir(), 'platform', self.port_name)
-
     def baseline_version_dir(self):
         """Returns the absolute path to the platform-and-version-specific results."""
         baseline_search_paths = self.baseline_search_path()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
index 40774ab3..65bbde0 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/test.py
@@ -427,9 +427,6 @@
             'linux': ['precise', 'trusty']
         }
 
-    def buildbot_archives_baselines(self):
-        return self._name != 'test-win-win7'
-
     def _path_to_driver(self):
         # This routine shouldn't normally be called, but it is called by
         # the mock_drt Driver. We return something, but make sure it's useless.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
index 745c179..0afdf8d 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/wpt_manifest.py
@@ -54,19 +54,6 @@
                         urls.update([item[0] for item in records])
         return urls
 
-    @memoized
-    def all_wpt_tests(self):
-        # TODO(qyearsley): Rename this method to indicate that it
-        # returns wpt test file paths, which may not be "test names".
-        if 'items' not in self.raw_dict:
-            return []
-
-        all_tests = []
-        for test_type in self.test_types:
-            for path_in_wpt in self.raw_dict['items'][test_type]:
-                all_tests.append(path_in_wpt)
-        return all_tests
-
     def is_test_file(self, path_in_wpt):
         return self._items_for_path(path_in_wpt) is not None
 
diff --git a/third_party/WebKit/public/blink_typemaps.gni b/third_party/WebKit/public/blink_typemaps.gni
index 26ee3c642..68996104 100644
--- a/third_party/WebKit/public/blink_typemaps.gni
+++ b/third_party/WebKit/public/blink_typemaps.gni
@@ -4,7 +4,7 @@
 
 typemaps = [
   "//cc/ipc/begin_frame_args_for_blink.typemap",
-  "//cc/ipc/compositor_frame_for_blink.typemap",
+  "//services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap",
   "//cc/ipc/frame_sink_id.typemap",
   "//cc/ipc/local_surface_id.typemap",
   "//cc/ipc/returned_resource.typemap",
diff --git a/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom b/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
index 92b7852f4..966de20 100644
--- a/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
+++ b/third_party/WebKit/public/platform/modules/offscreencanvas/offscreen_canvas_surface.mojom
@@ -17,7 +17,7 @@
 };
 
 interface OffscreenCanvasSurfaceClient {
-  OnSurfaceCreated(cc.mojom.SurfaceInfo surface_info);
+  OnFirstSurfaceActivation(cc.mojom.SurfaceInfo surface_info);
 };
 
 // Creates OffscreenCanvasSurface and CompositorFrameSink instances for use
@@ -35,4 +35,4 @@
   CreateCompositorFrameSink(cc.mojom.FrameSinkId frame_sink_id,
                             viz.mojom.CompositorFrameSinkClient client,
                             viz.mojom.CompositorFrameSink& sink);
-};
\ No newline at end of file
+};
diff --git a/third_party/zlib/google.patch b/third_party/zlib/0000-build.patch
similarity index 100%
rename from third_party/zlib/google.patch
rename to third_party/zlib/0000-build.patch
diff --git a/third_party/zlib/simd.patch b/third_party/zlib/0001-simd.patch
similarity index 100%
rename from third_party/zlib/simd.patch
rename to third_party/zlib/0001-simd.patch
diff --git a/third_party/zlib/0002-uninitializedcheck.patch b/third_party/zlib/0002-uninitializedcheck.patch
new file mode 100644
index 0000000..0713c00
--- /dev/null
+++ b/third_party/zlib/0002-uninitializedcheck.patch
@@ -0,0 +1,12 @@
+diff --git a/inflate.c b/inflate.c
+index ac333e8c2eda..69b769a871b8 100644
+--- a/third_party/zlib/inflate.c
++++ b/third_party/zlib/inflate.c
+@@ -228,6 +228,7 @@ int stream_size;
+     state->strm = strm;
+     state->window = Z_NULL;
+     state->mode = HEAD;     /* to pass state test in inflateReset2() */
++    state->check = adler32(0L, Z_NULL, 0);
+     ret = inflateReset2(strm, windowBits);
+     if (ret != Z_OK) {
+         ZFREE(strm, state);
diff --git a/third_party/zlib/README.chromium b/third_party/zlib/README.chromium
index fe6bc10..8658580 100644
--- a/third_party/zlib/README.chromium
+++ b/third_party/zlib/README.chromium
@@ -22,7 +22,9 @@
    imported.
  - The contents of the google directory are original Chromium-specific
    additions.
- - google.patch contains changes from the upstream version, mostly related to
-   the build.
- - Intel SIMD optimisations from https://github.com/jtkukunas/zlib/ have been
-   integrated. These changes are reflected in simd.patch.
+ - 0000-build.patch: changes from the upstream version, mostly related to the
+   build.
+ - 0001-simd.patch: integrate Intel SIMD optimisations from
+   https://github.com/jtkukunas/zlib/
+ - 0002-uninitializedcheck.patch: default-initialize state->check, see
+   crbug.com/697481
diff --git a/third_party/zlib/inflate.c b/third_party/zlib/inflate.c
index ac333e8..69b769a8 100644
--- a/third_party/zlib/inflate.c
+++ b/third_party/zlib/inflate.c
@@ -228,6 +228,7 @@
     state->strm = strm;
     state->window = Z_NULL;
     state->mode = HEAD;     /* to pass state test in inflateReset2() */
+    state->check = adler32(0L, Z_NULL, 0);
     ret = inflateReset2(strm, windowBits);
     if (ret != Z_OK) {
         ZFREE(strm, state);
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 9af988a6..b0021aa 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -1131,6 +1131,11 @@
   <int value="5" label="Second packaged app installed without showing"/>
 </enum>
 
+<enum name="AppListFolderOpened">
+  <int value="0" label="Original Folder Design"/>
+  <int value="1" label="Peeking App List Folder Design"/>
+</enum>
+
 <enum name="AppListPage">
   <int value="0" label="APPS"/>
   <int value="1" label="SEARCH_RESULTS"/>
@@ -1138,6 +1143,13 @@
   <int value="3" label="CUSTOM_LAUNCHER_PAGE"/>
 </enum>
 
+<enum name="AppListPeekingToFullscreenSource">
+  <int value="0" label="Swiped Up On Launcher"/>
+  <int value="1" label="Clicked Expand Arrow"/>
+  <int value="2" label="Scrolled With Mousepad"/>
+  <int value="3" label="Scrolled With Mouse"/>
+</enum>
+
 <enum name="AppListSearchResult">
   <int value="0" label="OMNIBOX"/>
   <int value="1" label="APP"/>
@@ -1157,6 +1169,12 @@
   <int value="3" label="RECOMMENDATION"/>
 </enum>
 
+<enum name="AppListShowSource">
+  <int value="0" label="Search Key"/>
+  <int value="1" label="Shelf Button"/>
+  <int value="2" label="Swipe Up From Shelf"/>
+</enum>
+
 <enum name="AppLoadedInTabSource">
   <int value="0" label="SOURCE_APP"/>
   <int value="1" label="SOURCE_BACKGROUND_PAGE"/>
@@ -34873,9 +34891,10 @@
   <int value="2" label="Nothing found"/>
   <int value="3" label="Already prompted"/>
   <int value="4" label="Cleaner download failed"/>
-  <int value="5" label="Browser not available"/>
+  <int value="5" label="Browser not available (deprecated)"/>
   <int value="6" label="Not on idle state"/>
   <int value="7" label="IPC connection broken"/>
+  <int value="8" label="Waiting for browser"/>
 </enum>
 
 <enum name="SoftwareReporterPromptDialogResponse">
@@ -34886,6 +34905,12 @@
   <int value="4" label="Closed without user interaction"/>
 </enum>
 
+<enum name="SoftwareReporterPromptShownWithType">
+  <int value="0" label="Legacy prompt shown"/>
+  <int value="1" label="On transition to infected state"/>
+  <int value="2" label="On browser window available"/>
+</enum>
+
 <enum name="SpareWebContentsStatus">
   <int value="0" label="Created"/>
   <int value="1" label="Used"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index d689d635..17c509d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -1617,6 +1617,14 @@
   </summary>
 </histogram>
 
+<histogram name="Apps.AppListFolderOpened" enum="AppListFolderOpened">
+  <owner>newcomer@chromium.org</owner>
+  <summary>
+    The number of times folders are opened in the app list. This is logged when
+    the folder is clicked.
+  </summary>
+</histogram>
+
 <histogram name="Apps.AppListHowEnabled" enum="AppListEnableSource">
   <owner>tapted@chromium.org</owner>
   <summary>
@@ -1635,6 +1643,15 @@
   </summary>
 </histogram>
 
+<histogram name="Apps.AppListPeekingToFullscreenSource"
+    enum="AppListPeekingToFullscreenSource">
+  <owner>newcomer@chromium.org</owner>
+  <summary>
+    The source which transitions the app list from Peeking to Fullscreen. This
+    is logged when the transition method is used.
+  </summary>
+</histogram>
+
 <histogram name="Apps.AppListSearchCommenced" units="searches">
   <owner>tapted@chromium.org</owner>
   <summary>
@@ -1676,6 +1693,14 @@
   </summary>
 </histogram>
 
+<histogram name="Apps.AppListShowSource" enum="AppListShowSource">
+  <owner>newcomer@chromium.org</owner>
+  <summary>
+    The number of times the different sources for showing the app list are used.
+    This is logged when the app list is shown.
+  </summary>
+</histogram>
+
 <histogram name="Apps.AppListTimeToDiscover" units="ms">
   <owner>tapted@chromium.org</owner>
   <summary>
@@ -1711,6 +1736,18 @@
   </summary>
 </histogram>
 
+<histogram name="Apps.AppsInFolders" units="Apps">
+<!-- Name completed by histogram_suffixes
+     name="AppListFolderExperiment" -->
+
+  <owner>newcomer@chromium.org</owner>
+  <summary>
+    The total number of apps in folders ignoring OEM folders. This is logged
+    each time the app list is initialized. The suffix denotes whether the
+    fullscreen app list feature has been enabled.
+  </summary>
+</histogram>
+
 <histogram name="Apps.NoteTakingApp.DefaultLaunchResult"
     enum="NoteTakingAppLaunchResult">
   <owner>derat@chromium.org</owner>
@@ -67183,6 +67220,14 @@
   </summary>
 </histogram>
 
+<histogram name="SBClientDownload.ZipFileContainsAppDirectory" enum="Boolean">
+  <owner>jialiul@chromium.org</owner>
+  <summary>
+    A Mac-only metric that records whether a downloaded zip file contains an
+    .app directory, signifying the presence of installable software.
+  </summary>
+</histogram>
+
 <histogram name="SBClientDownload.ZipFileHasArchiveButNoExecutable"
     enum="Boolean">
   <owner>mattm@chromium.org</owner>
@@ -75169,12 +75214,26 @@
 </histogram>
 
 <histogram name="SoftwareReporter.PromptShown" enum="Boolean">
+  <obsolete>
+    Replaced 2017-08-01 with SoftwareReporter.PromptShownWithType.
+  </obsolete>
   <owner>ftirelo@chromium.org</owner>
   <summary>
     Whether the user has been prompted to run the Chrome Cleanup Tool.
   </summary>
 </histogram>
 
+<histogram name="SoftwareReporter.PromptShownWithType"
+    enum="SoftwareReporterPromptShownWithType">
+  <owner>ftirelo@chromium.org</owner>
+  <summary>
+    Whether the user has been prompted to run the Chrome Cleanup Tool and which
+    type of prompt has been shown.
+
+    This is logged once a prompt is presented to the user.
+  </summary>
+</histogram>
+
 <histogram name="SoftwareReporter.PromptUsage" enum="SRTPromptUsage">
   <owner>mad@chromium.org</owner>
   <summary>Usage of the Software Removal Tool (SRT) Prompt.</summary>
@@ -90422,6 +90481,12 @@
   <affected-histogram name="Startup.AppListFirstPaintWarmStart"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="AppListFolderExperiment" separator=".">
+  <suffix name="FullscreenAppListEnabled" label="Peeking Launcher Enabled"/>
+  <suffix name="FullscreenAppListDisabled" label="Peeking Launcher Disabled"/>
+  <affected-histogram name="Apps.AppsInFolders"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="ArcUserTypes" separator=".">
   <suffix name="Managed" label="User with forced Play Store feature"/>
   <suffix name="Unmanaged" label="User with optional Play Store feature"/>
diff --git a/tools/perf/benchmarks/service_worker.py b/tools/perf/benchmarks/service_worker.py
index 66d700d..a6845ea 100644
--- a/tools/perf/benchmarks/service_worker.py
+++ b/tools/perf/benchmarks/service_worker.py
@@ -184,7 +184,6 @@
     return StoryExpectations()
 
 
-@benchmark.Disabled('android-webview')  # http://crbug.com/653924
 @benchmark.Owner(emails=['horo@chromium.org'])
 class ServiceWorkerMicroBenchmarkPerfTest(perf_benchmark.PerfBenchmark):
   """This test is a microbenchmark of service worker.
@@ -200,11 +199,6 @@
   def Name(cls):
     return 'service_worker.service_worker_micro_benchmark'
 
-  @classmethod
-  def ShouldDisable(cls, possible_browser):  # http://crbug.com/597656
-      return (possible_browser.browser_type == 'reference' and
-              possible_browser.platform.GetDeviceTypeName() == 'Nexus 5X')
-
   def GetExpectations(self):
     class StoryExpectations(story.expectations.StoryExpectations):
       def SetExpectations(self):
diff --git a/tools/perf/benchmarks/smoothness.py b/tools/perf/benchmarks/smoothness.py
index 435954a..fd404a7 100644
--- a/tools/perf/benchmarks/smoothness.py
+++ b/tools/perf/benchmarks/smoothness.py
@@ -174,8 +174,6 @@
     return StoryExpectations()
 
 
-@benchmark.Disabled('win') # http://crbug.com/692663
-@benchmark.Disabled('android-webview')  # http://crbug.com/653933
 @benchmark.Owner(emails=['kbr@chromium.org', 'zmo@chromium.org'])
 class SmoothnessMaps(perf_benchmark.PerfBenchmark):
   page_set = page_sets.MapsPageSet
@@ -191,8 +189,6 @@
     return StoryExpectations()
 
 
-@benchmark.Disabled('android',
-                    'mac')     # crbug.com/567802
 @benchmark.Owner(emails=['ssid@chromium.org'])
 class SmoothnessKeyDesktopMoveCases(_Smoothness):
   page_set = page_sets.KeyDesktopMoveCasesPageSet
@@ -201,11 +197,6 @@
   def Name(cls):
     return 'smoothness.key_desktop_move_cases'
 
-  @classmethod
-  def ShouldDisable(cls, possible_browser):  # http://crbug.com/597656
-      return (possible_browser.browser_type == 'reference' and
-              possible_browser.platform.GetOSName() == 'win')
-
   def GetExpectations(self):
     class StoryExpectations(story_module.expectations.StoryExpectations):
       def SetExpectations(self):
@@ -240,9 +231,6 @@
     return StoryExpectations()
 
 
-@benchmark.Disabled('android')  # crbug.com/589580
-@benchmark.Disabled('android-reference')  # crbug.com/588786
-@benchmark.Disabled('mac')  # crbug.com/563615
 @benchmark.Owner(emails=['alancutter@chromium.org'])
 class SmoothnessToughAnimationCases(_Smoothness):
   page_set = page_sets.ToughAnimationCasesPageSet
@@ -576,8 +564,6 @@
     return StoryExpectations()
 
 
-@benchmark.Disabled('android')  # http://crbug.com/531593
-@benchmark.Disabled('win')  # http://crbug.com/652372
 class SmoothnessToughImageDecodeCases(_Smoothness):
   page_set = page_sets.ToughImageDecodeCasesPageSet
 
diff --git a/tools/perf/benchmarks/start_with_ext.py b/tools/perf/benchmarks/start_with_ext.py
index c251088..ce326122 100644
--- a/tools/perf/benchmarks/start_with_ext.py
+++ b/tools/perf/benchmarks/start_with_ext.py
@@ -31,8 +31,6 @@
 
 
 @benchmark.Enabled('has tabs')
-@benchmark.Disabled('mac')  # crbug.com/563424
-@benchmark.Disabled('win', 'linux', 'reference', 'android')
 class StartWithExtCold(_StartWithExt):
   """Measure time to start Chrome cold with extensions."""
   options = {'pageset_repeat': 5}
@@ -50,8 +48,6 @@
 
 
 @benchmark.Enabled('has tabs')
-@benchmark.Disabled('mac')  # crbug.com/563424
-@benchmark.Disabled('win', 'linux', 'reference', 'android')
 class StartWithExtWarm(_StartWithExt):
   """Measure time to start Chrome warm with extensions."""
   options = {'pageset_repeat': 20}
diff --git a/tools/perf/benchmarks/tracing.py b/tools/perf/benchmarks/tracing.py
index 10d12c6d..c0f5bb4 100644
--- a/tools/perf/benchmarks/tracing.py
+++ b/tools/perf/benchmarks/tracing.py
@@ -37,9 +37,6 @@
     return StoryExpectations()
 
 
-# TODO(ssid): Enable on reference builds once stable browser starts supporting
-# background mode memory-infra. crbug.com/621195.
-@benchmark.Disabled('reference')
 @benchmark.Owner(emails=['ssid@chromium.org'])
 class TracingWithBackgroundMemoryInfra(perf_benchmark.PerfBenchmark):
   """Measures the overhead of background memory-infra dumps"""
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc
index 14a2a31e..7cc00f54 100644
--- a/ui/android/delegated_frame_host_android.cc
+++ b/ui/android/delegated_frame_host_android.cc
@@ -202,7 +202,7 @@
   support_->SetNeedsBeginFrame(needs_begin_frames);
 }
 
-void DelegatedFrameHostAndroid::OnSurfaceCreated(
+void DelegatedFrameHostAndroid::OnFirstSurfaceActivation(
     const viz::SurfaceInfo& surface_info) {
   // TODO(fsamuel): Once surface synchronization is turned on, the fallback
   // surface should be set here.
diff --git a/ui/android/delegated_frame_host_android.h b/ui/android/delegated_frame_host_android.h
index 75a18fd..00a03ae 100644
--- a/ui/android/delegated_frame_host_android.h
+++ b/ui/android/delegated_frame_host_android.h
@@ -95,7 +95,7 @@
   void OnNeedsBeginFrames(bool needs_begin_frames) override;
 
   // viz::HostFrameSinkClient implementation.
-  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
 
   void CreateNewCompositorFrameSinkSupport();
 
diff --git a/ui/app_list/app_list_constants.cc b/ui/app_list/app_list_constants.cc
index 80d62e83..6cf98b8e4 100644
--- a/ui/app_list/app_list_constants.cc
+++ b/ui/app_list/app_list_constants.cc
@@ -152,6 +152,17 @@
 const ui::ResourceBundle::FontStyle kItemTextFontStyle =
     ui::ResourceBundle::SmallFont;
 
+// The UMA histogram that logs usage of the original and redesigned folders.
+const char kAppListFolderOpenedHistogram[] = "Apps.AppListFolderOpened";
+
+// The UMA histogram that logs how the app list transitions from peeking to
+// fullscreen.
+const char kAppListPeekingToFullscreenHistogram[] =
+    "Apps.AppListPeekingToFullscreen";
+
+// The UMA histogram that logs how the app list is shown.
+const char kAppListToggleMethodHistogram[] = "Apps.AppListShowSource";
+
 // The UMA histogram that logs which page gets opened by the user.
 const char kPageOpenedHistogram[] = "Apps.AppListPageOpened";
 
diff --git a/ui/app_list/app_list_constants.h b/ui/app_list/app_list_constants.h
index d4cf5ed8..0efc7bd 100644
--- a/ui/app_list/app_list_constants.h
+++ b/ui/app_list/app_list_constants.h
@@ -108,7 +108,39 @@
 
 APP_LIST_EXPORT extern const ui::ResourceBundle::FontStyle kItemTextFontStyle;
 
+// The different ways that the app list can transition from PEEKING to
+// FULLSCREEN_ALL_APPS. This enum must not have its order altered as it is used
+// in histograms.
+enum AppListPeekingToFullscreenSource {
+  kSwipe = 0,
+  kExpandArrow = 1,
+  kMousepadScroll = 2,
+  kMousewheelScroll = 3,
+  kMaxPeekingToFullscreen = 4,
+};
+
+// The different ways the app list can be shown. This enum must not have its
+// order altered as it is used in histograms.
+enum AppListShowSource {
+  kSearchKey = 0,
+  kShelfButton = 1,
+  kSwipeFromShelf = 2,
+  kMaxAppListToggleMethod = 3,
+};
+
+// The two versions of folders. This enum must not have its order altered as it
+// is used in histograms.
+enum AppListFolderOpened {
+  kOldFolders = 0,
+  kFullscreenAppListFolders = 1,
+  kMaxFolderOpened = 2,
+};
+
+APP_LIST_EXPORT extern const char kAppListFolderOpenedHistogram[];
+APP_LIST_EXPORT extern const char kAppListPeekingToFullscreenHistogram[];
+APP_LIST_EXPORT extern const char kAppListToggleMethodHistogram[];
 APP_LIST_EXPORT extern const char kPageOpenedHistogram[];
+
 APP_LIST_EXPORT extern const char kSearchResultOpenDisplayTypeHistogram[];
 APP_LIST_EXPORT extern const char kSearchQueryLength[];
 APP_LIST_EXPORT extern const char kSearchResultDistanceFromOrigin[];
diff --git a/ui/app_list/app_list_model.cc b/ui/app_list/app_list_model.cc
index f7653e1..752aba0 100644
--- a/ui/app_list/app_list_model.cc
+++ b/ui/app_list/app_list_model.cc
@@ -7,6 +7,8 @@
 #include <string>
 #include <utility>
 
+#include "base/metrics/histogram_macros.h"
+#include "ui/app_list/app_list_features.h"
 #include "ui/app_list/app_list_folder_item.h"
 #include "ui/app_list/app_list_item.h"
 #include "ui/app_list/app_list_model_observer.h"
@@ -26,7 +28,9 @@
   top_level_item_list_->AddObserver(this);
 }
 
-AppListModel::~AppListModel() { top_level_item_list_->RemoveObserver(this); }
+AppListModel::~AppListModel() {
+  top_level_item_list_->RemoveObserver(this);
+}
 
 void AppListModel::AddObserver(AppListModelObserver* observer) {
   observers_.AddObserver(observer);
@@ -163,12 +167,10 @@
 
   // Add the items to the new folder.
   target_item_ptr->set_position(
-      new_folder->item_list()->CreatePositionBefore(
-          syncer::StringOrdinal()));
+      new_folder->item_list()->CreatePositionBefore(syncer::StringOrdinal()));
   AddItemToFolderItemAndNotify(new_folder, std::move(target_item_ptr));
   source_item_ptr->set_position(
-      new_folder->item_list()->CreatePositionBefore(
-          syncer::StringOrdinal()));
+      new_folder->item_list()->CreatePositionBefore(syncer::StringOrdinal()));
   AddItemToFolderItemAndNotify(new_folder, std::move(source_item_ptr));
 
   return new_folder->id();
@@ -176,8 +178,8 @@
 
 void AppListModel::MoveItemToFolder(AppListItem* item,
                                     const std::string& folder_id) {
-  DVLOG(2) << "MoveItemToFolder: " << folder_id
-           << " <- " << item->ToDebugString();
+  DVLOG(2) << "MoveItemToFolder: " << folder_id << " <- "
+           << item->ToDebugString();
   if (item->folder_id() == folder_id)
     return;
   AppListFolderItem* dest_folder = FindOrCreateFolderItem(folder_id);
@@ -193,8 +195,8 @@
 bool AppListModel::MoveItemToFolderAt(AppListItem* item,
                                       const std::string& folder_id,
                                       syncer::StringOrdinal position) {
-  DVLOG(2) << "MoveItemToFolderAt: " << folder_id
-           << "[" << position.ToDebugString() << "]"
+  DVLOG(2) << "MoveItemToFolderAt: " << folder_id << "["
+           << position.ToDebugString() << "]"
            << " <- " << item->ToDebugString();
   if (item->folder_id() == folder_id)
     return false;
@@ -317,6 +319,27 @@
     DeleteItem(folder_ids[i]);
 }
 
+void AppListModel::RecordItemsInFoldersForUMA() {
+  int number_of_items_in_folders = 0;
+  for (size_t i = 0; i < top_level_item_list_->item_count(); i++) {
+    AppListItem* item = top_level_item_list_->item_at(i);
+    if (item->GetItemType() != AppListFolderItem::kItemType)
+      continue;
+
+    AppListFolderItem* folder = static_cast<AppListFolderItem*>(item);
+    if (folder->folder_type() == AppListFolderItem::FOLDER_TYPE_OEM)
+      continue;  // Don't count OEM folders.
+    number_of_items_in_folders += folder->item_list()->item_count();
+  }
+  if (features::IsFullscreenAppListEnabled()) {
+    UMA_HISTOGRAM_COUNTS_100("Apps.AppsInFolders.FullscreenAppListEnabled",
+                             number_of_items_in_folders);
+  } else {
+    UMA_HISTOGRAM_COUNTS_100("Apps.AppsInFolders.FullscreenAppListDisabled",
+                             number_of_items_in_folders);
+  }
+}
+
 void AppListModel::SetCustomLauncherPageEnabled(bool enabled) {
   custom_launcher_page_enabled_ = enabled;
   for (auto& observer : observers_)
diff --git a/ui/app_list/app_list_model.h b/ui/app_list/app_list_model.h
index 1d0644a7..18de509 100644
--- a/ui/app_list/app_list_model.h
+++ b/ui/app_list/app_list_model.h
@@ -135,6 +135,10 @@
   // is false, removes any non-OEM folders.
   void SetFoldersEnabled(bool folders_enabled);
 
+  // Records the number of items stored in folders for UMA, not counting OEM
+  // folders.
+  void RecordItemsInFoldersForUMA();
+
   // Sets whether or not the custom launcher page should be enabled.
   void SetCustomLauncherPageEnabled(bool enabled);
   bool custom_launcher_page_enabled() const {
diff --git a/ui/app_list/views/app_list_main_view.cc b/ui/app_list/views/app_list_main_view.cc
index 56e4442..8d959d4 100644
--- a/ui/app_list/views/app_list_main_view.cc
+++ b/ui/app_list/views/app_list_main_view.cc
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/strings/string_util.h"
 #include "ui/app_list/app_list_constants.h"
@@ -181,10 +182,13 @@
 
 void AppListMainView::ActivateApp(AppListItem* item, int event_flags) {
   // TODO(jennyz): Activate the folder via AppListModel notification.
-  if (item->GetItemType() == AppListFolderItem::kItemType)
+  if (item->GetItemType() == AppListFolderItem::kItemType) {
     contents_view_->ShowFolderContent(static_cast<AppListFolderItem*>(item));
-  else
+    UMA_HISTOGRAM_ENUMERATION(kAppListFolderOpenedHistogram, kOldFolders,
+                              kMaxFolderOpened);
+  } else {
     item->Activate(event_flags);
+  }
 }
 
 void AppListMainView::CancelDragInActiveFolder() {
diff --git a/ui/app_list/views/app_list_view.cc b/ui/app_list/views/app_list_view.cc
index e01e68e..0099119 100644
--- a/ui/app_list/views/app_list_view.cc
+++ b/ui/app_list/views/app_list_view.cc
@@ -228,6 +228,7 @@
 
   UMA_HISTOGRAM_TIMES("Apps.AppListCreationTime",
                       base::Time::Now() - start_time);
+  app_list_main_view_->model()->RecordItemsInFoldersForUMA();
 }
 
 void AppListView::SetBubbleArrow(views::BubbleBorder::Arrow arrow) {
@@ -546,6 +547,8 @@
           SetState(FULLSCREEN_SEARCH);
           break;
         case PEEKING:
+          UMA_HISTOGRAM_ENUMERATION(kAppListPeekingToFullscreenHistogram,
+                                    kSwipe, kMaxPeekingToFullscreen);
           SetState(FULLSCREEN_ALL_APPS);
           break;
         case CLOSED:
@@ -830,6 +833,12 @@
     case ui::ET_MOUSEWHEEL:
       SetState(event->AsMouseWheelEvent()->y_offset() < 0 ? FULLSCREEN_ALL_APPS
                                                           : CLOSED);
+      if (app_list_state_ == FULLSCREEN_ALL_APPS) {
+        UMA_HISTOGRAM_ENUMERATION(kAppListPeekingToFullscreenHistogram,
+                                  kMousewheelScroll, kMaxPeekingToFullscreen);
+      }
+      // Return true unconditionally because all mousewheel events are large
+      // enough to transition the app list.
       return true;
     case ui::ET_SCROLL:
     case ui::ET_SCROLL_FLING_START: {
@@ -837,6 +846,10 @@
           kAppListMinScrollToSwitchStates) {
         SetState(event->AsScrollEvent()->y_offset() < 0 ? FULLSCREEN_ALL_APPS
                                                         : CLOSED);
+        if (app_list_state_ == FULLSCREEN_ALL_APPS) {
+          UMA_HISTOGRAM_ENUMERATION(kAppListPeekingToFullscreenHistogram,
+                                    kMousepadScroll, kMaxPeekingToFullscreen);
+        }
         return true;
       }
       break;
diff --git a/ui/app_list/views/apps_container_view.cc b/ui/app_list/views/apps_container_view.cc
index e297c919..ab652ab5 100644
--- a/ui/app_list/views/apps_container_view.cc
+++ b/ui/app_list/views/apps_container_view.cc
@@ -84,8 +84,8 @@
 void AppsContainerView::SetDragAndDropHostOfCurrentAppList(
     ApplicationDragAndDropHost* drag_and_drop_host) {
   apps_grid_view()->SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
-  app_list_folder_view()->items_grid_view()->
-      SetDragAndDropHostOfCurrentAppList(drag_and_drop_host);
+  app_list_folder_view()->items_grid_view()->SetDragAndDropHostOfCurrentAppList(
+      drag_and_drop_host);
 }
 
 void AppsContainerView::ReparentFolderItemTransit(
@@ -230,8 +230,8 @@
   // Get the active folder's icon bounds relative to AppsContainerView.
   AppListItemView* folder_item_view =
       apps_grid_view_->activated_folder_item_view();
-  gfx::Rect to_grid_view = folder_item_view->ConvertRectToParent(
-      folder_item_view->GetIconBounds());
+  gfx::Rect to_grid_view =
+      folder_item_view->ConvertRectToParent(folder_item_view->GetIconBounds());
   gfx::Rect to_container = apps_grid_view_->ConvertRectToParent(to_grid_view);
 
   return FolderImage::GetTopIconsBounds(to_container);
diff --git a/ui/app_list/views/expand_arrow_view.cc b/ui/app_list/views/expand_arrow_view.cc
index 9a1be87..2f013cb 100644
--- a/ui/app_list/views/expand_arrow_view.cc
+++ b/ui/app_list/views/expand_arrow_view.cc
@@ -139,7 +139,8 @@
 void ExpandArrowView::TransitToFullscreenAllAppsState() {
   UMA_HISTOGRAM_ENUMERATION(kPageOpenedHistogram, AppListModel::STATE_APPS,
                             AppListModel::STATE_LAST);
-
+  UMA_HISTOGRAM_ENUMERATION(kAppListPeekingToFullscreenHistogram, kExpandArrow,
+                            kMaxPeekingToFullscreen);
   contents_view_->SetActiveState(AppListModel::STATE_APPS);
   app_list_view_->SetState(AppListView::FULLSCREEN_ALL_APPS);
 }
diff --git a/ui/app_list/views/search_box_view.cc b/ui/app_list/views/search_box_view.cc
index 7f3f7a05..872b037 100644
--- a/ui/app_list/views/search_box_view.cc
+++ b/ui/app_list/views/search_box_view.cc
@@ -65,6 +65,7 @@
 constexpr int kSearchBoxBorderCornerRadiusSearchResult = 4;
 constexpr int kMicIconSize = 24;
 constexpr int kCloseIconSize = 24;
+constexpr int kSearchBoxFocusBorderCornerRadius = 28;
 
 constexpr int kLightVibrantBlendAlpha = 0xE6;
 
@@ -921,9 +922,9 @@
     return;
   selected_ = selected;
   if (selected) {
-    SetBorder(views::CreateRoundedRectBorder(
-        kSearchBoxBorderWidth, kSearchBoxBorderCornerRadiusFullscreen,
-        kSearchBoxBorderColor));
+    SetBorder(views::CreateRoundedRectBorder(kSearchBoxBorderWidth,
+                                             kSearchBoxFocusBorderCornerRadius,
+                                             kSearchBoxBorderColor));
   } else {
     SetDefaultBorder();
   }
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index bc61e1d6..3a64eaf4 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -554,7 +554,8 @@
     observer.OnCompositingStarted(this, start_time);
 }
 
-void Compositor::OnSurfaceCreated(const viz::SurfaceInfo& surface_info) {
+void Compositor::OnFirstSurfaceActivation(
+    const viz::SurfaceInfo& surface_info) {
   // TODO(fsamuel): Once surface synchronization is turned on, the fallback
   // surface should be set here.
 }
diff --git a/ui/compositor/compositor.h b/ui/compositor/compositor.h
index 95d086f..f70914f 100644
--- a/ui/compositor/compositor.h
+++ b/ui/compositor/compositor.h
@@ -390,7 +390,7 @@
   void DidLoseLayerTreeFrameSink() override {}
 
   // viz::HostFrameSinkClient implementation.
-  void OnSurfaceCreated(const viz::SurfaceInfo& surface_info) override;
+  void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
 
   bool IsLocked() { return !active_locks_.empty(); }
 
diff --git a/ui/events/blink/event_with_callback.cc b/ui/events/blink/event_with_callback.cc
index 39793f4e..132e081 100644
--- a/ui/events/blink/event_with_callback.cc
+++ b/ui/events/blink/event_with_callback.cc
@@ -72,15 +72,28 @@
     InputHandlerProxy::EventDisposition disposition,
     const LatencyInfo& latency,
     std::unique_ptr<DidOverscrollParams> did_overscroll_params) {
-  for (auto& original_event : original_events_) {
-    std::unique_ptr<DidOverscrollParams> did_overscroll_params_copy;
-    if (did_overscroll_params) {
-      did_overscroll_params_copy =
-          base::MakeUnique<DidOverscrollParams>(*did_overscroll_params);
-    }
-    std::move(original_event.callback_)
-        .Run(disposition, std::move(original_event.event_), latency,
-             std::move(did_overscroll_params));
+  // |original_events_| could be empty if this is the scroll event extracted
+  // from the matrix multiplication.
+  if (original_events_.size() == 0)
+    return;
+
+  // Ack the oldest event with original latency.
+  std::move(original_events_.front().callback_)
+      .Run(disposition, std::move(original_events_.front().event_), latency,
+           did_overscroll_params
+               ? base::MakeUnique<DidOverscrollParams>(*did_overscroll_params)
+               : nullptr);
+  original_events_.pop_front();
+
+  // Ack other events with coalesced latency to avoid redundant tracking.
+  LatencyInfo coalesced_latency = latency;
+  coalesced_latency.set_coalesced();
+  for (auto& coalesced_event : original_events_) {
+    std::move(coalesced_event.callback_)
+        .Run(disposition, std::move(coalesced_event.event_), coalesced_latency,
+             did_overscroll_params
+                 ? base::MakeUnique<DidOverscrollParams>(*did_overscroll_params)
+                 : nullptr);
   }
 }
 
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 1c92b8ec..8666ffd 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -541,6 +541,7 @@
   void SetUp() override {
     bool wheel_scroll_latching_enabled = GetParam();
     event_disposition_recorder_.clear();
+    latency_info_recorder_.clear();
     input_handler_proxy_ = base::MakeUnique<TestInputHandlerProxy>(
         &mock_input_handler_, &mock_client_, wheel_scroll_latching_enabled);
     if (input_handler_proxy_->compositor_event_queue_)
@@ -603,6 +604,7 @@
       const ui::LatencyInfo& latency_info,
       std::unique_ptr<ui::DidOverscrollParams> overscroll_params) {
     event_disposition_recorder_.push_back(event_disposition);
+    latency_info_recorder_.push_back(latency_info);
   }
 
   std::deque<std::unique_ptr<EventWithCallback>>& event_queue() {
@@ -620,6 +622,7 @@
   std::unique_ptr<TestInputHandlerProxy> input_handler_proxy_;
   testing::StrictMock<MockInputHandlerProxyClient> mock_client_;
   std::vector<InputHandlerProxy::EventDisposition> event_disposition_recorder_;
+  std::vector<ui::LatencyInfo> latency_info_recorder_;
 
   base::MessageLoop loop_;
   base::WeakPtrFactory<InputHandlerProxyEventQueueTest> weak_ptr_factory_;
@@ -4122,6 +4125,38 @@
       input_handler_proxy_->gesture_scroll_on_impl_thread_for_testing());
 }
 
+TEST_P(InputHandlerProxyEventQueueTest, CoalescedLatencyInfo) {
+  // Handle scroll on compositor.
+  cc::InputHandlerScrollResult scroll_result_did_scroll_;
+  scroll_result_did_scroll_.did_scroll = true;
+
+  EXPECT_CALL(mock_input_handler_, ScrollBegin(testing::_, testing::_))
+      .WillOnce(testing::Return(kImplThreadScrollState));
+  EXPECT_CALL(mock_input_handler_, SetNeedsAnimateInput()).Times(1);
+  EXPECT_CALL(
+      mock_input_handler_,
+      ScrollBy(testing::Property(&cc::ScrollState::delta_y, testing::Gt(0))))
+      .WillOnce(testing::Return(scroll_result_did_scroll_));
+  EXPECT_CALL(mock_input_handler_, ScrollEnd(testing::_));
+
+  HandleGestureEvent(WebInputEvent::kGestureScrollBegin);
+  HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -20);
+  HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -40);
+  HandleGestureEvent(WebInputEvent::kGestureScrollUpdate, -30);
+  HandleGestureEvent(WebInputEvent::kGestureScrollEnd);
+  input_handler_proxy_->DeliverInputForBeginFrame();
+
+  EXPECT_EQ(0ul, event_queue().size());
+  // Should run callbacks for every original events.
+  EXPECT_EQ(5ul, event_disposition_recorder_.size());
+  EXPECT_EQ(5ul, latency_info_recorder_.size());
+  EXPECT_EQ(false, latency_info_recorder_[1].coalesced());
+  // Coalesced events should have latency set to coalesced.
+  EXPECT_EQ(true, latency_info_recorder_[2].coalesced());
+  EXPECT_EQ(true, latency_info_recorder_[3].coalesced());
+  testing::Mock::VerifyAndClearExpectations(&mock_input_handler_);
+}
+
 INSTANTIATE_TEST_CASE_P(AnimateInput,
                         InputHandlerProxyTest,
                         testing::ValuesIn(test_types));
diff --git a/chrome/browser/resources/options/info.svg b/ui/webui/resources/images/info.svg
similarity index 100%
rename from chrome/browser/resources/options/info.svg
rename to ui/webui/resources/images/info.svg