diff --git a/DEPS b/DEPS
index 3824045d..9f33d05 100644
--- a/DEPS
+++ b/DEPS
@@ -105,11 +105,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': 'a619d459b8583675c8b2818a0fb5c5ed299ea1c9',
+  'skia_revision': 'b965fcb47296870643d001acb4a43cec3d88579a',
   # 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': 'ff508d104d43670dbe4170c0961c1d4181c08f7b',
+  'v8_revision': '4fb310a1d7c008cf6b5772ab02c06f6f62bc4d6e',
   # 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.
@@ -117,7 +117,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ANGLE
   # and whatever else without interference from each other.
-  'angle_revision': 'ddd8eaa8dca0b59531eb35612a6130968e1b90fc',
+  'angle_revision': '419acc8f4f3b238e714cbaaddeeea1bedd366bf8',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling build tools
   # and whatever else without interference from each other.
@@ -129,7 +129,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'bfeb9343ee794a48b70c2f638c3d74f96e9afab2',
+  'pdfium_revision': '481749905d444745ee0ba76d9bcf42b3b009bb27',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -165,7 +165,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': 'be45355b46d9b45aa9581f0d439bffcfe929ef20',
+  'catapult_revision': 'f5342c4cf3d3e85e43be84c22bdfd8ebff23ec70',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -181,7 +181,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'feed_revision': 'c5468619d8a2098f55f6b8ce2ab9d9530e4a2475',
+  'feed_revision': '85536a35bac23f2875a3da255ffecd7223f83476',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_build-tools_version
   # and whatever else without interference from each other.
@@ -620,7 +620,7 @@
 
   # Used for embedded builds. CrOS & Linux use the system version.
   'src/third_party/fontconfig/src': {
-      'url': Var('chromium_git') + '/external/fontconfig.git' + '@' + '6cc99d6a82ad67d2f5eac887b28bca13c0dfddde',
+      'url': Var('chromium_git') + '/external/fontconfig.git' + '@' + 'd1f48f11d5dffa1d954a1b0abe44ce9e4bfc3709',
       'condition': 'checkout_linux',
   },
 
@@ -779,7 +779,7 @@
     Var('chromium_git') + '/external/libaddressinput.git' + '@' + 'd955c63ec7048d59dffd20af25eeec23da878d27',
 
   'src/third_party/libaom/source/libaom': {
-    'url': Var('aomedia_git') + '/aom.git' + '@' +  '6eecfe927de9e86b4408fa76d83fcffcae2d904b',
+    'url': Var('aomedia_git') + '/aom.git' + '@' +  '000f2f686d60385b80ce9d4dd2ca1bfd4de922cb',
     'condition': 'checkout_libaom',
   },
 
@@ -923,7 +923,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' +  'e79ac55dc0eacba4ac32c4a9a9b186062bd2c379',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' +  '4d831cea60c7428162cd3843a2b3f0ff225a6e07',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index 2fd802f..4e1a7a9f 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -295,7 +295,8 @@
   return ssl_host_state_delegate_.get();
 }
 
-content::PermissionManager* AwBrowserContext::GetPermissionManager() {
+content::PermissionControllerDelegate*
+AwBrowserContext::GetPermissionControllerDelegate() {
   if (!permission_manager_.get())
     permission_manager_.reset(new AwPermissionManager());
   return permission_manager_.get();
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index b2a79c7..80b40be 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -26,7 +26,7 @@
 class PrefService;
 
 namespace content {
-class PermissionManager;
+class PermissionControllerDelegate;
 class ResourceContext;
 class SSLHostStateDelegate;
 class WebContents;
@@ -99,7 +99,8 @@
   storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
   content::PushMessagingService* GetPushMessagingService() override;
   content::SSLHostStateDelegate* GetSSLHostStateDelegate() override;
-  content::PermissionManager* GetPermissionManager() override;
+  content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+      override;
   content::BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
   content::BackgroundSyncController* GetBackgroundSyncController() override;
   content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
@@ -142,7 +143,7 @@
   std::unique_ptr<PrefService> user_pref_service_;
   std::unique_ptr<policy::BrowserPolicyConnectorBase> browser_policy_connector_;
   std::unique_ptr<AwSSLHostStateDelegate> ssl_host_state_delegate_;
-  std::unique_ptr<content::PermissionManager> permission_manager_;
+  std::unique_ptr<content::PermissionControllerDelegate> permission_manager_;
   std::unique_ptr<web_restrictions::WebRestrictionsClient>
       web_restriction_provider_;
   PrefChangeRegistrar pref_change_registrar_;
diff --git a/android_webview/browser/aw_permission_manager.h b/android_webview/browser/aw_permission_manager.h
index a2aa18c..06c94e783 100644
--- a/android_webview/browser/aw_permission_manager.h
+++ b/android_webview/browser/aw_permission_manager.h
@@ -11,19 +11,19 @@
 #include "base/containers/id_map.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 
 namespace android_webview {
 
 class AwBrowserPermissionRequestDelegate;
 class LastRequestResultCache;
 
-class AwPermissionManager : public content::PermissionManager {
+class AwPermissionManager : public content::PermissionControllerDelegate {
  public:
   AwPermissionManager();
   ~AwPermissionManager() override;
 
-  // PermissionManager implementation.
+  // PermissionControllerDelegate implementation.
   int RequestPermission(
       content::PermissionType permission,
       content::RenderFrameHost* render_frame_host,
diff --git a/android_webview/browser/aw_permission_manager_unittest.cc b/android_webview/browser/aw_permission_manager_unittest.cc
index ab8914b74..ad058f8 100644
--- a/android_webview/browser/aw_permission_manager_unittest.cc
+++ b/android_webview/browser/aw_permission_manager_unittest.cc
@@ -10,7 +10,7 @@
 #include "android_webview/browser/aw_browser_permission_request_delegate.h"
 #include "base/bind.h"
 #include "base/bind_helpers.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller.h"
 #include "content/public/browser/permission_type.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index a803304..40b1979 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -135,9 +135,6 @@
     private static final String SAMSUNG_WORKAROUND_BASE_URL = "email://";
     private static final int SAMSUNG_WORKAROUND_DELAY = 200;
 
-    private static final String DATA_URI_HISTOGRAM_NAME =
-            "Android.WebView.LoadUrl.DataUriHasOctothorpe";
-
     private static class ForceAuxiliaryBitmapRendering {
         private static final boolean sResult = lazyCheck();
         private static boolean lazyCheck() {
@@ -1594,11 +1591,6 @@
         if (additionalHttpHeaders != null) {
             params.setExtraHeaders(new HashMap<String, String>(additionalHttpHeaders));
         }
-
-        if (params.getLoadUrlType() == LoadURLType.DATA && url.contains("#")) {
-            RecordHistogram.recordBooleanHistogram(DATA_URI_HISTOGRAM_NAME, true);
-        }
-
         loadUrl(params);
     }
 
@@ -1659,9 +1651,6 @@
     public void loadData(String data, String mimeType, String encoding) {
         if (TRACE) Log.i(TAG, "%s loadData", this);
         if (isDestroyedOrNoOperation(WARN)) return;
-        if (data.contains("#")) {
-            RecordHistogram.recordBooleanHistogram(DATA_URI_HISTOGRAM_NAME, true);
-        }
         loadUrl(LoadUrlParams.createLoadDataParams(
                 fixupData(data), fixupMimeType(mimeType), isBase64Encoded(encoding)));
     }
@@ -1673,9 +1662,6 @@
             String baseUrl, String data, String mimeType, String encoding, String historyUrl) {
         if (TRACE) Log.i(TAG, "%s loadDataWithBaseURL=%s", this, baseUrl);
         if (isDestroyedOrNoOperation(WARN)) return;
-        if (data.contains("#")) {
-            RecordHistogram.recordBooleanHistogram(DATA_URI_HISTOGRAM_NAME, true);
-        }
 
         data = fixupData(data);
         mimeType = fixupMimeType(mimeType);
diff --git a/ash/host/ash_window_tree_host_platform.cc b/ash/host/ash_window_tree_host_platform.cc
index ac695b3..4124a35f 100644
--- a/ash/host/ash_window_tree_host_platform.cc
+++ b/ash/host/ash_window_tree_host_platform.cc
@@ -54,7 +54,10 @@
   if (!allow_confine_cursor())
     return;
 
-  gfx::Rect confined_bounds(GetBoundsInPixels().size());
+  // We want to limit the cursor to what is visible, which is the size of the
+  // compositor. |GetBoundsInPixels()| may include pixels that are not used.
+  // See https://crbug.com/843354
+  gfx::Rect confined_bounds(GetCompositorSizeInPixels());
   confined_bounds.Inset(transformer_helper_.GetHostInsets());
   last_cursor_confine_bounds_in_pixels_ = confined_bounds;
   platform_window()->ConfineCursorToBounds(confined_bounds);
@@ -162,6 +165,33 @@
   ConfineCursorToRootWindow();
 }
 
+gfx::Size AshWindowTreeHostPlatform::GetCompositorSizeInPixels() const {
+  // For Chrome OS, the platform window size may be slightly different from the
+  // compositor pixel size. This is to prevent any trailing 1px line at the
+  // right or bottom edge due to rounding. This means we may not be using ALL
+  // the pixels on a display, however this is a temporary fix until we figure
+  // out a way to prevent these rounding artifacts.
+  // See https://crbug.com/843354 and https://crbug.com/862424 for more info.
+  if (device_scale_factor() == 1.f)
+    return GetBoundsInPixels().size();
+  return gfx::ScaleToRoundedSize(
+      gfx::ScaleToFlooredSize(GetBoundsInPixels().size(),
+                              1.f / device_scale_factor()),
+      device_scale_factor());
+}
+
+void AshWindowTreeHostPlatform::OnBoundsChanged(const gfx::Rect& new_bounds) {
+  // We need to recompute the bounds in pixels based on the DIP size. This is a
+  // temporary fix needed because the root layer has the bounds in DIP which
+  // when scaled by the compositor does not match the display bounds in pixels.
+  // So we need to change the display bounds to match the root layer's scaled
+  // size.
+  // See https://crbug.com/843354 for more info.
+  const float new_scale = ui::GetScaleFactorForNativeView(window());
+  WindowTreeHostPlatform::OnBoundsChanged(gfx::ScaleToRoundedRect(
+      gfx::ScaleToEnclosedRect(new_bounds, 1.f / new_scale), new_scale));
+}
+
 void AshWindowTreeHostPlatform::DispatchEvent(ui::Event* event) {
   TRACE_EVENT0("input", "AshWindowTreeHostPlatform::DispatchEvent");
   if (event->IsLocatedEvent())
diff --git a/ash/host/ash_window_tree_host_platform.h b/ash/host/ash_window_tree_host_platform.h
index 339cabc..5b25a482 100644
--- a/ash/host/ash_window_tree_host_platform.h
+++ b/ash/host/ash_window_tree_host_platform.h
@@ -61,6 +61,8 @@
   void OnCursorVisibilityChangedNative(bool show) override;
   void SetBoundsInPixels(const gfx::Rect& bounds,
                          const viz::LocalSurfaceId& local_surface_id) override;
+  gfx::Size GetCompositorSizeInPixels() const override;
+  void OnBoundsChanged(const gfx::Rect& new_bounds) override;
   void DispatchEvent(ui::Event* event) override;
 
   // aura::InputMethodMusDelegate:
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index 8fc6adb..65d864f 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -1267,7 +1267,10 @@
   return GetWidget() ? GetKeyboardControllerForWidget(GetWidget()) : nullptr;
 }
 
-void LockContentsView::OnPublicAccountTapped() {
+void LockContentsView::OnPublicAccountTapped(bool is_primary) {
+  // Set the public account user to be the active user.
+  SwapActiveAuthBetweenPrimaryAndSecondary(is_primary);
+
   // Update expanded_view_ in case CurrentBigUserView has changed.
   // 1. It happens when the active big user is changed. For example both
   // primary and secondary big user are public account and user switches from
@@ -1299,8 +1302,9 @@
 
   LoginPublicAccountUserView::Callbacks public_account_callbacks;
   public_account_callbacks.on_tap = auth_user_callbacks.on_tap;
-  public_account_callbacks.on_public_account_tapped = base::BindRepeating(
-      &LockContentsView::OnPublicAccountTapped, base::Unretained(this));
+  public_account_callbacks.on_public_account_tapped =
+      base::BindRepeating(&LockContentsView::OnPublicAccountTapped,
+                          base::Unretained(this), is_primary);
   return new LoginBigUserView(user, auth_user_callbacks,
                               public_account_callbacks);
 }
@@ -1358,6 +1362,8 @@
     opt_to_update->SetAuthEnabled(true /*enabled*/, animate);
   if (opt_to_hide)
     opt_to_hide->SetAuthEnabled(false /*enabled*/, animate);
+
+  Layout();
 }
 
 void LockContentsView::UpdateAuthForAuthUser(LoginAuthUserView* opt_to_update,
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h
index b7229f6..52d7ba7a 100644
--- a/ash/login/ui/lock_contents_view.h
+++ b/ash/login/ui/lock_contents_view.h
@@ -302,7 +302,7 @@
   keyboard::KeyboardController* GetKeyboardController() const;
 
   // Called when the public account is tapped.
-  void OnPublicAccountTapped();
+  void OnPublicAccountTapped(bool is_primary);
 
   // Helper method to allocate a LoginBigUserView instance.
   LoginBigUserView* AllocateLoginBigUserView(
diff --git a/ash/login/ui/lock_debug_view.cc b/ash/login/ui/lock_debug_view.cc
index c1150a9..ea118d9 100644
--- a/ash/login/ui/lock_debug_view.cc
+++ b/ash/login/ui/lock_debug_view.cc
@@ -54,6 +54,7 @@
   kPerUserForceOnlineSignIn,
   kPerUserToggleAuthEnabled,
   kPerUserUseDetachableBase,
+  kPerUserTogglePublicAccount,
 };
 }  // namespace ButtonId
 
@@ -62,6 +63,11 @@
     "Debbie Craig",     "Stella Wong",  "Stephanie Wade",
 };
 
+constexpr const char* kDebugPublicAccountNames[] = {
+    "Seattle Public Library", "San Jose Public Library",
+    "Sunnyvale Public Library", "Mountain View Public Library",
+};
+
 constexpr const char* kDebugDetachableBases[] = {"Base A", "Base B", "Base C"};
 
 constexpr const char kDebugOsVersion[] =
@@ -72,17 +78,23 @@
 constexpr const char kDebugKioskAppId[] = "asdf1234";
 constexpr const char kDebugKioskAppName[] = "Test App Name";
 
+constexpr const char kDebugDefaultLocaleCode[] = "en-GB";
+constexpr const char kDebugDefaultLocaleTitle[] = "English";
+constexpr const char kDebugEnterpriseDomain[] = "library.com";
+
 // Additional state for a user that the debug UI needs to reference.
 struct UserMetadata {
   explicit UserMetadata(const mojom::UserInfoPtr& user_info)
       : account_id(user_info->account_id),
-        display_name(user_info->display_name) {}
+        display_name(user_info->display_name),
+        type(user_info->type) {}
 
   AccountId account_id;
   std::string display_name;
   bool enable_pin = false;
   bool enable_click_to_unlock = false;
   bool enable_auth = true;
+  user_manager::UserType type = user_manager::USER_TYPE_REGULAR;
   mojom::EasyUnlockIconId easy_unlock_id = mojom::EasyUnlockIconId::NONE;
 };
 
@@ -101,6 +113,48 @@
   return "Unknown";
 }
 
+// Update the user data based on |type| and |user_index|.
+mojom::LoginUserInfoPtr PopulateUserData(const mojom::LoginUserInfoPtr& user,
+                                         user_manager::UserType type,
+                                         int user_index) {
+  mojom::LoginUserInfoPtr result = user->Clone();
+  result->basic_user_info->type = type;
+
+  bool is_regular_user = type == user_manager::USER_TYPE_REGULAR;
+  // Set debug user names and email. Useful for the stub user, which does not
+  // have a name  and email set.
+  result->basic_user_info->display_name =
+      is_regular_user
+          ? kDebugUserNames[user_index % base::size(kDebugUserNames)]
+          : kDebugPublicAccountNames[user_index %
+                                     base::size(kDebugPublicAccountNames)];
+  result->basic_user_info->display_email =
+      result->basic_user_info->account_id.GetUserEmail();
+
+  if (is_regular_user) {
+    result->public_account_info.reset();
+  } else {
+    result->public_account_info = ash::mojom::PublicAccountInfo::New();
+    result->public_account_info->enterprise_domain = kDebugEnterpriseDomain;
+    result->public_account_info->default_locale = kDebugDefaultLocaleCode;
+
+    std::vector<ash::mojom::LocaleItemPtr> locales;
+    mojom::LocaleItemPtr locale_item = ash::mojom::LocaleItem::New();
+    locale_item->language_code = kDebugDefaultLocaleCode;
+    locale_item->title = kDebugDefaultLocaleTitle;
+    locales.push_back(std::move(locale_item));
+    result->public_account_info->available_locales = std::move(locales);
+
+    // Request keyboard layouts for the default locale.
+    Shell::Get()
+        ->login_screen_controller()
+        ->RequestPublicSessionKeyboardLayouts(
+            result->basic_user_info->account_id, kDebugDefaultLocaleCode);
+  }
+
+  return result;
+}
+
 }  // namespace
 
 // Applies a series of user-defined transformations to a |LoginDataDispatcher|
@@ -125,7 +179,10 @@
   LoginDataDispatcher* debug_dispatcher() { return &debug_dispatcher_; }
 
   // Changes the number of displayed users to |count|.
-  void SetUserCount(int count) {
+  void SetUserCount(int count) { NotifyUsers(BuildUserList(count)); }
+
+  // Create user list.
+  std::vector<mojom::LoginUserInfoPtr> BuildUserList(int count) {
     DCHECK(!root_users_.empty());
 
     count = std::max(count, 0);
@@ -146,15 +203,20 @@
                 std::to_string(i));
       }
 
-      // Set debug user names. Useful for the stub user, which does not have a
-      // name set.
-      users[i]->basic_user_info->display_name =
-          kDebugUserNames[i % base::size(kDebugUserNames)];
+      // Setup user data based on the user type in debug_users_.
+      user_manager::UserType type = (i < debug_users_.size())
+                                        ? debug_users_[i].type
+                                        : users[i]->basic_user_info->type;
+      users[i] = PopulateUserData(users[i], type, i);
 
       if (i >= debug_users_.size())
         debug_users_.push_back(UserMetadata(users[i]->basic_user_info));
     }
 
+    return users;
+  }
+
+  void NotifyUsers(std::vector<mojom::LoginUserInfoPtr> users) {
     // User notification resets PIN state.
     for (UserMetadata& user : debug_users_)
       user.enable_pin = false;
@@ -256,6 +318,24 @@
             base::TimeDelta::FromHours(8));
   }
 
+  // Convert user type to regular user or public account for the user at
+  // |user_index|.
+  void TogglePublicAccountForUserIndex(size_t user_index) {
+    DCHECK(user_index >= 0 && user_index < debug_users_.size());
+    UserMetadata& user = debug_users_[user_index];
+    user_manager::UserType new_type =
+        user.type == user_manager::USER_TYPE_REGULAR
+            ? user_manager::USER_TYPE_PUBLIC_ACCOUNT
+            : user_manager::USER_TYPE_REGULAR;
+    user.type = new_type;
+
+    std::vector<mojom::LoginUserInfoPtr> users =
+        BuildUserList(debug_users_.size());
+    // Update display name and email in debug users.
+    debug_users_[user_index] = UserMetadata(users[user_index]->basic_user_info);
+    NotifyUsers(std::move(users));
+  }
+
   void ToggleLockScreenNoteButton() {
     if (lock_screen_note_state_ == mojom::TrayActionState::kAvailable) {
       lock_screen_note_state_ = mojom::TrayActionState::kNotAvailable;
@@ -758,6 +838,13 @@
     debug_detachable_base_model_->SetBaseLastUsedForUser(
         debug_data_dispatcher_->GetAccountIdForUserIndex(sender->tag()));
   }
+
+  // Convert this user to regular user or public account.
+  if (sender->id() == ButtonId::kPerUserTogglePublicAccount) {
+    debug_data_dispatcher_->TogglePublicAccountForUserIndex(sender->tag());
+    UpdatePerUserActionContainer();
+    Layout();
+  }
 }
 
 void LockDebugView::UpdatePerUserActionContainer() {
@@ -793,6 +880,10 @@
           ->set_tag(i);
     }
 
+    AddButton("Toggle Public Account", ButtonId::kPerUserTogglePublicAccount,
+              row)
+        ->set_tag(i);
+
     per_user_action_view_container_->AddChildView(row);
   }
 }
diff --git a/ash/login/ui/login_expanded_public_account_view.cc b/ash/login/ui/login_expanded_public_account_view.cc
index 5a34460..456eafb3 100644
--- a/ash/login/ui/login_expanded_public_account_view.cc
+++ b/ash/login/ui/login_expanded_public_account_view.cc
@@ -332,7 +332,7 @@
           current_user_->basic_user_info->account_id,
           selected_language_item_.value, selected_keyboard_item_.value);
     } else if (sender == language_selection_) {
-      if (!language_menu_->IsVisible()) {
+      if (!language_menu_->IsVisible() && !language_items_.empty()) {
         LoginMenuView* view = new LoginMenuView(
             language_items_, language_selection_ /*anchor_view*/,
             base::BindRepeating(&RightPaneView::OnLanguageSelected,
@@ -343,7 +343,7 @@
         language_menu_->Close();
       }
     } else if (sender == keyboard_selection_) {
-      if (!keyboard_menu_->IsVisible()) {
+      if (!keyboard_menu_->IsVisible() && !keyboard_items_.empty()) {
         LoginMenuView* view = new LoginMenuView(
             keyboard_items_, keyboard_selection_ /*anchor_view*/,
             base::BindRepeating(&RightPaneView::OnKeyboardSelected,
diff --git a/ash/login/ui/login_public_account_user_view.cc b/ash/login/ui/login_public_account_user_view.cc
index 1bc004b..31d8ae6f 100644
--- a/ash/login/ui/login_public_account_user_view.cc
+++ b/ash/login/ui/login_public_account_user_view.cc
@@ -113,6 +113,8 @@
   user_view_->SetTapEnabled(!enabled);
   if (enabled)
     arrow_button_->RequestFocus();
+
+  PreferredSizeChanged();
 }
 
 void LoginPublicAccountUserView::UpdateForUser(
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 669e4d3c..13e9c45 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -911,7 +911,7 @@
                                  ? kShelfButtonSpacingNewUi
                                  : kShelfButtonSpacing;
 
-  const int available_size = 400;
+  const int available_size = shelf_->PrimaryAxisValue(width(), height());
   const int first_panel_index = model_->FirstPanelIndex();
   const int last_button_index = first_panel_index - 1;
 
@@ -1713,7 +1713,8 @@
   if (shelf_->is_tablet_mode_animation_running()) {
     AnimateToIdealBounds();
     if (IsShowingOverflowBubble()) {
-      overflow_bubble_->bubble_view()->shelf_view()->OnBoundsChanged(previous_bounds);
+      overflow_bubble_->bubble_view()->shelf_view()->OnBoundsChanged(
+          previous_bounds);
     }
     return;
   }
diff --git a/ash/shelf/shelf_view_unittest.cc b/ash/shelf/shelf_view_unittest.cc
index dbd0f61b..5a2f2dad 100644
--- a/ash/shelf/shelf_view_unittest.cc
+++ b/ash/shelf/shelf_view_unittest.cc
@@ -982,8 +982,6 @@
   test_api_->RunMessageLoopUntilAnimationsDone();
   overflow_test_api.RunMessageLoopUntilAnimationsDone();
   ASSERT_TRUE(test_api_->IsShowingOverflowBubble());
-  EXPECT_EQ(test_api_->GetLastVisibleIndex(), last_visible_index - 1);
-  EXPECT_EQ(last_visible_index, overflow_test_api.GetFirstVisibleIndex());
   EXPECT_FALSE(is_visible_on_shelf(last_visible_index, test_api_.get()));
   EXPECT_TRUE(is_visible_on_shelf(last_visible_index, &overflow_test_api));
 
@@ -993,7 +991,6 @@
   test_api_->RunMessageLoopUntilAnimationsDone();
   overflow_test_api.RunMessageLoopUntilAnimationsDone();
   ASSERT_TRUE(test_api_->IsShowingOverflowBubble());
-  EXPECT_EQ(test_api_->GetLastVisibleIndex(), last_visible_index);
   EXPECT_TRUE(is_visible_on_shelf(last_visible_index, test_api_.get()));
   EXPECT_FALSE(is_visible_on_shelf(last_visible_index, &overflow_test_api));
 }
diff --git a/ash/shell/window_type_launcher.cc b/ash/shell/window_type_launcher.cc
index bfd107a..af54d3a 100644
--- a/ash/shell/window_type_launcher.cc
+++ b/ash/shell/window_type_launcher.cc
@@ -285,7 +285,7 @@
     ModalWindow::OpenModalWindow(GetWidget()->GetNativeView(),
                                  ui::MODAL_TYPE_WINDOW);
   } else if (sender == child_modal_button_) {
-    TestChildModalParent::Create(GetWidget()->GetNativeView()->GetRootWindow());
+    TestChildModalParent::Show(GetWidget()->GetNativeView()->GetRootWindow());
   } else if (sender == transient_button_) {
     NonModalTransient::OpenNonModalTransient(GetWidget()->GetNativeView());
   } else if (sender == show_hide_window_button_) {
diff --git a/ash/wm/test_child_modal_parent.cc b/ash/wm/test_child_modal_parent.cc
index dd1334b..e4ee47dd 100644
--- a/ash/wm/test_child_modal_parent.cc
+++ b/ash/wm/test_child_modal_parent.cc
@@ -8,14 +8,14 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "ui/aura/window.h"
-#include "ui/gfx/canvas.h"
 #include "ui/views/background.h"
-#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/button/md_text_button.h"
 #include "ui/views/controls/native/native_view_host.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/wm/core/window_modality_controller.h"
+#include "ui/wm/core/window_util.h"
 
 using views::Widget;
 
@@ -23,101 +23,87 @@
 
 namespace {
 
-// Parent window size and position.
+// Parent window layout.
 const int kWindowLeft = 170;
 const int kWindowTop = 200;
 const int kWindowWidth = 400;
 const int kWindowHeight = 400;
-
-// Parent window layout.
 const int kButtonHeight = 35;
-const int kTextfieldHeight = 35;
 
 // Child window size.
 const int kChildWindowWidth = 330;
 const int kChildWindowHeight = 200;
 
 // Child window layout.
-const int kChildTextfieldLeft = 20;
-const int kChildTextfieldTop = 50;
-const int kChildTextfieldWidth = 290;
-const int kChildTextfieldHeight = 35;
+const int kTextfieldLeft = 10;
+const int kTextfieldTop = 20;
+const int kTextfieldWidth = 300;
+const int kTextfieldHeight = 35;
 
-const SkColor kModalParentColor = SK_ColorWHITE;
+const SkColor kModalParentColor = SK_ColorBLUE;
 const SkColor kChildColor = SK_ColorWHITE;
 
 }  // namespace
 
 class ChildModalWindow : public views::WidgetDelegateView {
  public:
-  ChildModalWindow();
-  ~ChildModalWindow() override;
+  ChildModalWindow() {
+    SetBackground(views::CreateSolidBackground(kChildColor));
+    views::Textfield* modal_child_textfield = new views::Textfield;
+    AddChildView(modal_child_textfield);
+    modal_child_textfield->SetBounds(kTextfieldLeft, kTextfieldTop,
+                                     kTextfieldWidth, kTextfieldHeight);
+    modal_child_textfield->set_placeholder_text(
+        base::ASCIIToUTF16("modal child window"));
+  }
+  ~ChildModalWindow() override = default;
 
  private:
   // Overridden from View:
-  void OnPaint(gfx::Canvas* canvas) override;
-  gfx::Size CalculatePreferredSize() const override;
+  gfx::Size CalculatePreferredSize() const override {
+    return gfx::Size(kChildWindowWidth, kChildWindowHeight);
+  }
 
   // Overridden from WidgetDelegate:
-  base::string16 GetWindowTitle() const override;
-  bool CanResize() const override;
-  ui::ModalType GetModalType() const override;
+  base::string16 GetWindowTitle() const override {
+    return base::ASCIIToUTF16("Examples: Child Modal Window");
+  }
+  ui::ModalType GetModalType() const override { return ui::MODAL_TYPE_CHILD; }
 
   DISALLOW_COPY_AND_ASSIGN(ChildModalWindow);
 };
 
-ChildModalWindow::ChildModalWindow() {
-  views::Textfield* textfield = new views::Textfield;
-  AddChildView(textfield);
-  textfield->SetBounds(kChildTextfieldLeft, kChildTextfieldTop,
-                       kChildTextfieldWidth, kChildTextfieldHeight);
-}
-
-ChildModalWindow::~ChildModalWindow() = default;
-
-void ChildModalWindow::OnPaint(gfx::Canvas* canvas) {
-  canvas->FillRect(GetLocalBounds(), kChildColor);
-}
-
-gfx::Size ChildModalWindow::CalculatePreferredSize() const {
-  return gfx::Size(kChildWindowWidth, kChildWindowHeight);
-}
-
-base::string16 ChildModalWindow::GetWindowTitle() const {
-  return base::ASCIIToUTF16("Examples: Child Modal Window");
-}
-
-bool ChildModalWindow::CanResize() const {
-  return false;
-}
-
-ui::ModalType ChildModalWindow::GetModalType() const {
-  return ui::MODAL_TYPE_CHILD;
-}
-
 // static
-void TestChildModalParent::Create(aura::Window* context) {
+TestChildModalParent* TestChildModalParent::Show(aura::Window* context) {
+  auto* test_child_modal_parent = new TestChildModalParent(context);
   Widget::CreateWindowWithContextAndBounds(
-      new TestChildModalParent(context), context,
+      test_child_modal_parent, context,
       gfx::Rect(kWindowLeft, kWindowTop, kWindowWidth, kWindowHeight))
       ->Show();
+  return test_child_modal_parent;
 }
 
 TestChildModalParent::TestChildModalParent(aura::Window* context)
-    : widget_(std::make_unique<Widget>()),
-      button_(new views::LabelButton(
+    : modal_parent_(std::make_unique<Widget>()),
+      button_(views::MdTextButton::Create(
           this,
           base::ASCIIToUTF16("Show/Hide Child Modal Window"))),
       textfield_(new views::Textfield),
-      host_(new views::NativeViewHost),
-      child_(nullptr) {
+      host_(new views::NativeViewHost) {
+  textfield_->set_placeholder_text(base::ASCIIToUTF16("top level window"));
   Widget::InitParams params(Widget::InitParams::TYPE_CONTROL);
   params.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
   params.context = context;
-  widget_->Init(params);
-  widget_->GetRootView()->SetBackground(
+  modal_parent_->Init(params);
+  modal_parent_->GetRootView()->SetBackground(
       views::CreateSolidBackground(kModalParentColor));
-  widget_->GetNativeView()->SetName("ModalParent");
+  auto* modal_parent_textfield = new views::Textfield;
+  modal_parent_->GetRootView()->AddChildView(modal_parent_textfield);
+  modal_parent_textfield->SetBounds(kTextfieldLeft, kTextfieldTop,
+                                    kTextfieldWidth, kTextfieldHeight);
+  modal_parent_textfield->set_placeholder_text(
+      base::ASCIIToUTF16("modal parent window"));
+  modal_parent_->GetNativeView()->SetName("ModalParent");
   AddChildView(button_);
   AddChildView(textfield_);
   AddChildView(host_);
@@ -125,49 +111,26 @@
 
 TestChildModalParent::~TestChildModalParent() = default;
 
-void TestChildModalParent::ShowChild() {
-  if (!child_)
-    child_ = CreateChild();
-  child_->Show();
-}
-
 aura::Window* TestChildModalParent::GetModalParent() const {
-  return widget_->GetNativeView();
+  return modal_parent_->GetNativeView();
 }
 
-aura::Window* TestChildModalParent::GetChild() const {
-  if (child_)
-    return child_->GetNativeView();
-  return nullptr;
-}
-
-Widget* TestChildModalParent::CreateChild() {
-  Widget* child = Widget::CreateWindowWithParent(new ChildModalWindow,
-                                                 GetWidget()->GetNativeView());
-  wm::SetModalParent(child->GetNativeView(), GetModalParent());
-  child->AddObserver(this);
-  child->GetNativeView()->SetName("ChildModalWindow");
-  return child;
+aura::Window* TestChildModalParent::ShowModalChild() {
+  DCHECK(!modal_child_);
+  modal_child_ = Widget::CreateWindowWithParent(new ChildModalWindow,
+                                                GetWidget()->GetNativeView());
+  wm::SetModalParent(modal_child_->GetNativeView(),
+                     modal_parent_->GetNativeView());
+  modal_child_->AddObserver(this);
+  modal_child_->GetNativeView()->SetName("ChildModalWindow");
+  modal_child_->Show();
+  return modal_child_->GetNativeView();
 }
 
 base::string16 TestChildModalParent::GetWindowTitle() const {
   return base::ASCIIToUTF16("Examples: Child Modal Parent");
 }
 
-bool TestChildModalParent::CanResize() const {
-  return false;
-}
-
-void TestChildModalParent::DeleteDelegate() {
-  if (child_) {
-    child_->RemoveObserver(this);
-    child_->Close();
-    child_ = NULL;
-  }
-
-  delete this;
-}
-
 void TestChildModalParent::Layout() {
   int running_y = y();
   button_->SetBounds(x(), running_y, width(), kButtonHeight);
@@ -180,28 +143,23 @@
 void TestChildModalParent::ViewHierarchyChanged(
     const ViewHierarchyChangedDetails& details) {
   if (details.is_add && details.child == this) {
-    host_->Attach(widget_->GetNativeWindow());
+    host_->Attach(modal_parent_->GetNativeView());
     GetWidget()->GetNativeView()->SetName("Parent");
   }
 }
 
 void TestChildModalParent::ButtonPressed(views::Button* sender,
                                          const ui::Event& event) {
-  if (sender == button_) {
-    if (!child_)
-      child_ = CreateChild();
-    if (child_->IsVisible())
-      child_->Hide();
-    else
-      child_->Show();
-  }
+  DCHECK_EQ(sender, button_);
+  if (!modal_child_)
+    ShowModalChild();
+  else
+    modal_child_->Close();
 }
 
 void TestChildModalParent::OnWidgetDestroying(Widget* widget) {
-  if (child_) {
-    DCHECK_EQ(child_, widget);
-    child_ = NULL;
-  }
+  DCHECK_EQ(modal_child_, widget);
+  modal_child_ = nullptr;
 }
 
 }  // namespace ash
diff --git a/ash/wm/test_child_modal_parent.h b/ash/wm/test_child_modal_parent.h
index d6f3d55..630d96ce 100644
--- a/ash/wm/test_child_modal_parent.h
+++ b/ash/wm/test_child_modal_parent.h
@@ -13,7 +13,6 @@
 #include "ui/views/widget/widget_observer.h"
 
 namespace views {
-class LabelButton;
 class NativeViewHost;
 class Textfield;
 class View;
@@ -27,23 +26,22 @@
                              public views::ButtonListener,
                              public views::WidgetObserver {
  public:
-  // Creates the test window.
-  static void Create(aura::Window* context);
+  // Create and show a top-level window that hosts a modal parent. Returns the
+  // widget delegate, which is owned by the widget and deleted on window close.
+  static TestChildModalParent* Show(aura::Window* context = nullptr);
 
   explicit TestChildModalParent(aura::Window* context);
   ~TestChildModalParent() override;
 
-  void ShowChild();
+  // Returns the modal parent window hosted within the top-level window.
   aura::Window* GetModalParent() const;
-  aura::Window* GetChild() const;
+
+  // Create, show, and returns a child-modal window.
+  aura::Window* ShowModalChild();
 
  private:
-  views::Widget* CreateChild();
-
   // Overridden from views::WidgetDelegate:
   base::string16 GetWindowTitle() const override;
-  bool CanResize() const override;
-  void DeleteDelegate() override;
 
   // Overridden from views::View:
   void Layout() override;
@@ -56,13 +54,12 @@
   // Overridden from WidgetObserver:
   void OnWidgetDestroying(views::Widget* widget) override;
 
-  // This is the Widget this class creates to contain the child Views. This
-  // class is *not* the WidgetDelegateView for this Widget.
-  std::unique_ptr<views::Widget> widget_;
+  // The widget for the modal parent, a child of TestChildModalParent's Widget.
+  std::unique_ptr<views::Widget> modal_parent_;
 
   // The button to toggle showing and hiding the child window. The child window
   // does not block input to this button.
-  views::LabelButton* button_;
+  views::Button* button_;
 
   // The text field to indicate the keyboard focus.
   views::Textfield* textfield_;
@@ -70,8 +67,8 @@
   // The host for the modal parent.
   views::NativeViewHost* host_;
 
-  // The child window.
-  views::Widget* child_;
+  // The modal child widget.
+  views::Widget* modal_child_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(TestChildModalParent);
 };
diff --git a/ash/wm/window_modality_controller_unittest.cc b/ash/wm/window_modality_controller_unittest.cc
index 12d25315..ea46fd9f 100644
--- a/ash/wm/window_modality_controller_unittest.cc
+++ b/ash/wm/window_modality_controller_unittest.cc
@@ -449,149 +449,137 @@
 
 // Child-modal test.
 // Creates:
-// - A |parent| window that hosts a |modal_parent| window within itself. The
-//   |parent| and |modal_parent| windows are not the same window.  The
+// - A |top_level| window that hosts a |modal_parent| window within itself. The
+//   |top_level| and |modal_parent| windows are not the same window. The
 //   |modal_parent| window is not activatable, because it's contained within the
-//   |parent| window.
-// - A |child| window with parent window |parent|, but is modal to
+//   |top_level| window.
+// - A |modal_child| window with parent window |top_level|, but is modal to
 //   |modal_parent| window.
 // Validates:
-// - Clicking on the |modal_parent| should activate the |child| window.
-// - Clicking on the |parent| window outside of the |modal_parent| bounds should
-//   activate the |parent| window.
-// - Clicking on the |child| while |parent| is active should activate the
-//   |child| window.
+// - Clicking on the |modal_parent| should activate the |modal_child| window.
+// - Clicking on the |top_level| window outside of the |modal_parent| bounds
+//   should activate the |top_level| window.
+// - Clicking on the |modal_child| while |top_level| is active should activate
+//   the |modal_child| window.
 // - Focus should follow the active window.
 TEST_F(WindowModalityControllerTest, ChildModal) {
-  TestChildModalParent* delegate = new TestChildModalParent(nullptr);
-  views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
-      delegate, nullptr /* context */, gfx::Rect(0, 0, 400, 400));
-  widget->Show();
-
-  aura::Window* parent = widget->GetNativeView();
-  EXPECT_TRUE(wm::IsActiveWindow(parent));
+  TestChildModalParent* delegate = TestChildModalParent::Show();
+  aura::Window* top_level = delegate->GetWidget()->GetNativeView();
+  EXPECT_TRUE(wm::IsActiveWindow(top_level));
 
   aura::Window* modal_parent = delegate->GetModalParent();
   EXPECT_NE(nullptr, modal_parent);
-  EXPECT_NE(parent, modal_parent);
+  EXPECT_NE(top_level, modal_parent);
   EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
 
-  delegate->ShowChild();
-  aura::Window* child = delegate->GetChild();
-  EXPECT_NE(nullptr, child);
-
-  EXPECT_TRUE(wm::IsActiveWindow(child));
+  aura::Window* modal_child = delegate->ShowModalChild();
+  EXPECT_NE(nullptr, modal_child);
+  EXPECT_TRUE(wm::IsActiveWindow(modal_child));
   EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
-  EXPECT_FALSE(wm::IsActiveWindow(parent));
+  EXPECT_FALSE(wm::IsActiveWindow(top_level));
 
-  EXPECT_TRUE(child->HasFocus());
+  EXPECT_TRUE(modal_child->HasFocus());
   EXPECT_FALSE(modal_parent->HasFocus());
-  EXPECT_FALSE(parent->HasFocus());
+  EXPECT_FALSE(top_level->HasFocus());
 
   wm::ActivateWindow(modal_parent);
 
-  EXPECT_TRUE(wm::IsActiveWindow(child));
+  EXPECT_TRUE(wm::IsActiveWindow(modal_child));
   EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
-  EXPECT_FALSE(wm::IsActiveWindow(parent));
+  EXPECT_FALSE(wm::IsActiveWindow(top_level));
 
-  EXPECT_TRUE(child->HasFocus());
+  EXPECT_TRUE(modal_child->HasFocus());
   EXPECT_FALSE(modal_parent->HasFocus());
-  EXPECT_FALSE(parent->HasFocus());
+  EXPECT_FALSE(top_level->HasFocus());
 
-  wm::ActivateWindow(parent);
+  wm::ActivateWindow(top_level);
 
-  EXPECT_FALSE(wm::IsActiveWindow(child));
+  EXPECT_FALSE(wm::IsActiveWindow(modal_child));
   EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
-  EXPECT_TRUE(wm::IsActiveWindow(parent));
+  EXPECT_TRUE(wm::IsActiveWindow(top_level));
 
-  EXPECT_FALSE(child->HasFocus());
+  EXPECT_FALSE(modal_child->HasFocus());
   EXPECT_FALSE(modal_parent->HasFocus());
-  EXPECT_TRUE(parent->HasFocus());
+  EXPECT_TRUE(top_level->HasFocus());
 
-  wm::ActivateWindow(child);
+  wm::ActivateWindow(modal_child);
 
-  EXPECT_TRUE(wm::IsActiveWindow(child));
+  EXPECT_TRUE(wm::IsActiveWindow(modal_child));
   EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
-  EXPECT_FALSE(wm::IsActiveWindow(parent));
+  EXPECT_FALSE(wm::IsActiveWindow(top_level));
 
-  EXPECT_TRUE(child->HasFocus());
+  EXPECT_TRUE(modal_child->HasFocus());
   EXPECT_FALSE(modal_parent->HasFocus());
-  EXPECT_FALSE(parent->HasFocus());
+  EXPECT_FALSE(top_level->HasFocus());
 }
 
 // Same as |ChildModal| test, but using |EventGenerator| rather than bypassing
 // it by calling |ActivateWindow|.
 TEST_F(WindowModalityControllerTest, ChildModalEventGenerator) {
-  TestChildModalParent* delegate = new TestChildModalParent(nullptr);
-  views::Widget* widget = views::Widget::CreateWindowWithContextAndBounds(
-      delegate, nullptr /* context */, gfx::Rect(0, 0, 400, 400));
-  widget->Show();
-
-  aura::Window* parent = widget->GetNativeView();
-  EXPECT_TRUE(wm::IsActiveWindow(parent));
+  TestChildModalParent* delegate = TestChildModalParent::Show();
+  aura::Window* top_level = delegate->GetWidget()->GetNativeView();
+  EXPECT_TRUE(wm::IsActiveWindow(top_level));
 
   aura::Window* modal_parent = delegate->GetModalParent();
   EXPECT_NE(nullptr, modal_parent);
-  EXPECT_NE(parent, modal_parent);
+  EXPECT_NE(top_level, modal_parent);
   EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
 
-  delegate->ShowChild();
-  aura::Window* child = delegate->GetChild();
-  EXPECT_NE(nullptr, child);
-
-  EXPECT_TRUE(wm::IsActiveWindow(child));
+  aura::Window* modal_child = delegate->ShowModalChild();
+  EXPECT_NE(nullptr, modal_child);
+  EXPECT_TRUE(wm::IsActiveWindow(modal_child));
   EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
-  EXPECT_FALSE(wm::IsActiveWindow(parent));
+  EXPECT_FALSE(wm::IsActiveWindow(top_level));
 
-  EXPECT_TRUE(child->HasFocus());
+  EXPECT_TRUE(modal_child->HasFocus());
   EXPECT_FALSE(modal_parent->HasFocus());
-  EXPECT_FALSE(parent->HasFocus());
+  EXPECT_FALSE(top_level->HasFocus());
 
   {
     ui::test::EventGenerator generator(
         Shell::GetPrimaryRootWindow(),
-        parent->bounds().origin() +
-            gfx::Vector2d(10, parent->bounds().height() - 10));
+        top_level->bounds().origin() +
+            gfx::Vector2d(10, top_level->bounds().height() - 10));
     generator.ClickLeftButton();
     generator.ClickLeftButton();
 
-    EXPECT_TRUE(wm::IsActiveWindow(child));
+    EXPECT_TRUE(wm::IsActiveWindow(modal_child));
     EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
-    EXPECT_FALSE(wm::IsActiveWindow(parent));
+    EXPECT_FALSE(wm::IsActiveWindow(top_level));
 
-    EXPECT_TRUE(child->HasFocus());
+    EXPECT_TRUE(modal_child->HasFocus());
     EXPECT_FALSE(modal_parent->HasFocus());
-    EXPECT_FALSE(parent->HasFocus());
+    EXPECT_FALSE(top_level->HasFocus());
   }
 
   {
     ui::test::EventGenerator generator(
         Shell::GetPrimaryRootWindow(),
-        parent->bounds().origin() + gfx::Vector2d(10, 10));
+        top_level->bounds().origin() + gfx::Vector2d(10, 10));
     generator.ClickLeftButton();
 
-    EXPECT_FALSE(wm::IsActiveWindow(child));
+    EXPECT_FALSE(wm::IsActiveWindow(modal_child));
     EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
-    EXPECT_TRUE(wm::IsActiveWindow(parent));
+    EXPECT_TRUE(wm::IsActiveWindow(top_level));
 
-    EXPECT_FALSE(child->HasFocus());
+    EXPECT_FALSE(modal_child->HasFocus());
     EXPECT_FALSE(modal_parent->HasFocus());
-    EXPECT_TRUE(parent->HasFocus());
+    EXPECT_TRUE(top_level->HasFocus());
   }
 
   {
     ui::test::EventGenerator generator(
         Shell::GetPrimaryRootWindow(),
-        child->bounds().origin() + gfx::Vector2d(10, 10));
+        modal_child->bounds().origin() + gfx::Vector2d(10, 10));
     generator.ClickLeftButton();
 
-    EXPECT_TRUE(wm::IsActiveWindow(child));
+    EXPECT_TRUE(wm::IsActiveWindow(modal_child));
     EXPECT_FALSE(wm::IsActiveWindow(modal_parent));
-    EXPECT_FALSE(wm::IsActiveWindow(parent));
+    EXPECT_FALSE(wm::IsActiveWindow(top_level));
 
-    EXPECT_TRUE(child->HasFocus());
+    EXPECT_TRUE(modal_child->HasFocus());
     EXPECT_FALSE(modal_parent->HasFocus());
-    EXPECT_FALSE(parent->HasFocus());
+    EXPECT_FALSE(top_level->HasFocus());
   }
 }
 
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 5b91c88..e93ed5c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -2941,6 +2941,7 @@
       # AssertsTest doesn't really belong in //base but it's preferable to
       # stick it here than create another target for a single test.
       "android/javatests/src/org/chromium/base/AssertsTest.java",
+      "android/javatests/src/org/chromium/base/AsyncTaskTest.java",
       "android/javatests/src/org/chromium/base/AdvancedMockContextTest.java",
       "android/javatests/src/org/chromium/base/ApiCompatibilityUtilsTest.java",
       "android/javatests/src/org/chromium/base/CommandLineInitUtilTest.java",
diff --git a/base/android/javatests/src/org/chromium/base/AsyncTaskTest.java b/base/android/javatests/src/org/chromium/base/AsyncTaskTest.java
new file mode 100644
index 0000000..2fd92be
--- /dev/null
+++ b/base/android/javatests/src/org/chromium/base/AsyncTaskTest.java
@@ -0,0 +1,128 @@
+// 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.
+
+package org.chromium.base;
+
+import android.support.annotation.NonNull;
+import android.support.test.filters.SmallTest;
+
+import org.hamcrest.CoreMatchers;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.BaseJUnit4ClassRunner;
+
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for our AsyncTask modifications
+ *
+ * Not a robolectric test because the reflection doesn't work with ShadowAsyncTask.
+ */
+@RunWith(BaseJUnit4ClassRunner.class)
+public class AsyncTaskTest {
+    private static class SpecialChromeAsyncTask extends AsyncTask<Void, Void, Void> {
+        @Override
+        protected Void doInBackground(Void... params) {
+            return null;
+        }
+    }
+
+    private static class SpecialOsAsyncTask extends android.os.AsyncTask<Void, Void, Void> {
+        @Override
+        protected Void doInBackground(Void... params) {
+            return null;
+        }
+    }
+
+    private static class SpecialRunnable implements Runnable {
+        @Override
+        public void run() {}
+    }
+
+    private static final int QUEUE_SIZE = 40;
+
+    @Rule
+    public ExpectedException thrown = ExpectedException.none();
+
+    /**
+     * Test filling the queue with basic Runnables, then add a final AsyncTask to overfill it, and
+     * ensure the Runnable is the one blamed in the exception message.
+     */
+    @Test
+    @SmallTest
+    public void testChromeThreadPoolExecutorRunnables() {
+        Executor executor = new AsyncTask.ChromeThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS,
+                new ArrayBlockingQueue<Runnable>(QUEUE_SIZE), new ThreadFactory() {
+                    @Override
+                    public Thread newThread(@NonNull Runnable r) {
+                        return null;
+                    }
+                });
+        for (int i = 0; i < QUEUE_SIZE; i++) {
+            executor.execute(new SpecialRunnable());
+        }
+        thrown.expect(RejectedExecutionException.class);
+        thrown.expectMessage(
+                CoreMatchers.containsString("org.chromium.base.AsyncTaskTest$SpecialRunnable"));
+        thrown.expectMessage(
+                CoreMatchers.not(CoreMatchers.containsString("SpecialChromeAsyncTask")));
+        new SpecialChromeAsyncTask().executeOnExecutor(executor);
+    }
+
+    /**
+     * Test filling the queue with Chrome AsyncTasks, then add a final OS AsyncTask to
+     * overfill it and ensure the Chrome AsyncTask is the one blamed in the exception message.
+     */
+    @Test
+    @SmallTest
+    public void testChromeThreadPoolExecutorChromeAsyncTask() {
+        Executor executor = new AsyncTask.ChromeThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS,
+                new ArrayBlockingQueue<Runnable>(QUEUE_SIZE), new ThreadFactory() {
+                    @Override
+                    public Thread newThread(@NonNull Runnable r) {
+                        return null;
+                    }
+                });
+        for (int i = 0; i < QUEUE_SIZE; i++) {
+            new SpecialChromeAsyncTask().executeOnExecutor(executor);
+        }
+        thrown.expect(RejectedExecutionException.class);
+        thrown.expectMessage(CoreMatchers.containsString(
+                "org.chromium.base.AsyncTaskTest$SpecialChromeAsyncTask"));
+        thrown.expectMessage(CoreMatchers.not(CoreMatchers.containsString("SpecialOsAsyncTask")));
+        new SpecialOsAsyncTask().executeOnExecutor(executor);
+    }
+
+    /**
+     * Test filling the queue with android.os.AsyncTasks, then add a final ChromeAsyncTask to
+     * overfill it and ensure the OsAsyncTask is the one blamed in the exception message.
+     */
+    @Test
+    @SmallTest
+    public void testChromeThreadPoolExecutorOsAsyncTask() {
+        Executor executor = new AsyncTask.ChromeThreadPoolExecutor(1, 1, 1, TimeUnit.SECONDS,
+                new ArrayBlockingQueue<Runnable>(QUEUE_SIZE), new ThreadFactory() {
+                    @Override
+                    public Thread newThread(@NonNull Runnable r) {
+                        return null;
+                    }
+                });
+        for (int i = 0; i < QUEUE_SIZE; i++) {
+            new SpecialOsAsyncTask().executeOnExecutor(executor);
+        }
+        thrown.expect(RejectedExecutionException.class);
+        thrown.expectMessage(
+                CoreMatchers.containsString("org.chromium.base.AsyncTaskTest$SpecialOsAsyncTask"));
+        thrown.expectMessage(
+                CoreMatchers.not(CoreMatchers.containsString("SpecialChromeAsyncTask")));
+        new SpecialChromeAsyncTask().executeOnExecutor(executor);
+    }
+}
diff --git a/build/android/gyp/javac.py b/build/android/gyp/javac.py
index 1425deea8..b5ae57a6 100755
--- a/build/android/gyp/javac.py
+++ b/build/android/gyp/javac.py
@@ -26,8 +26,6 @@
 ERRORPRONE_WARNINGS_TO_TURN_OFF = [
   # TODO(crbug.com/834807): Follow steps in bug
   'DoubleBraceInitialization',
-  # TODO(crbug.com/834801): Follow steps in bug.
-  'ParcelableCreator',
   # TODO(crbug.com/834790): Follow steps in bug.
   'CatchAndPrintStackTrace',
   # TODO(crbug.com/801210): Follow steps in bug.
@@ -99,6 +97,7 @@
   'MissingOverride',
   'NarrowingCompoundAssignment',
   'ParameterName',
+  'ParcelableCreator',
   'ReferenceEquality',
   'StaticGuardedByInstance',
   'StaticQualifiedUsingExpression',
diff --git a/cc/layers/surface_layer.h b/cc/layers/surface_layer.h
index a1cec403..fcc684c 100644
--- a/cc/layers/surface_layer.h
+++ b/cc/layers/surface_layer.h
@@ -60,7 +60,7 @@
  private:
   ~SurfaceLayer() override;
 
-  // Returns a SurfaceRange corresponding the surface layer.
+  // Returns a SurfaceRange corresponding to the surface layer.
   viz::SurfaceRange GetSurfaceRange() const;
 
   viz::SurfaceId primary_surface_id_;
diff --git a/cc/paint/image_transfer_cache_entry.cc b/cc/paint/image_transfer_cache_entry.cc
index 7a44948..448ca06 100644
--- a/cc/paint/image_transfer_cache_entry.cc
+++ b/cc/paint/image_transfer_cache_entry.cc
@@ -70,22 +70,19 @@
                             : 0u;
 
   // Compute and cache the size of the data.
-  // We write the following:
-  // - Image color type (uint32_t)
-  // - Image width (uint32_t)
-  // - Image height (uint32_t)
-  // - Pixels size (uint32_t)
-  // - Pixels (variable)
   base::CheckedNumeric<size_t> safe_size;
+  safe_size += PaintOpWriter::HeaderBytes();
   safe_size += sizeof(uint32_t);  // color type
   safe_size += sizeof(uint32_t);  // width
   safe_size += sizeof(uint32_t);  // height
   safe_size += sizeof(uint32_t);  // has mips
   safe_size += sizeof(size_t);    // pixels size
-  safe_size += pixmap_->computeByteSize();
-  safe_size += PaintOpWriter::HeaderBytes();
   safe_size += target_color_space_size + sizeof(size_t);
   safe_size += pixmap_color_space_size + sizeof(size_t);
+  // Include 4 bytes of padding so we can always align our data pointer to a
+  // 4-byte boundary.
+  safe_size += 4;
+  safe_size += pixmap_->computeByteSize();
   size_ = safe_size.ValueOrDie();
 }
 
@@ -119,8 +116,11 @@
   // TODO(enne): we should consider caching these in some form.
   writer.Write(pixmap_->colorSpace());
   writer.Write(target_color_space_);
+  writer.AlignMemory(4);
   writer.WriteData(pixmap_size, pixmap_->addr());
-  if (writer.size() != data.size())
+
+  // Size can't be 0 after serialization unless the writer has become invalid.
+  if (writer.size() == 0u)
     return false;
 
   return true;
@@ -171,6 +171,9 @@
       width, height, color_type, kPremul_SkAlphaType, pixmap_color_space);
   if (image_info.computeMinByteSize() > pixel_size)
     return false;
+
+  // Align data to a 4-byte boundry, to match what we did when writing.
+  reader.AlignMemory(4);
   const volatile void* pixel_data = reader.ExtractReadableMemory(pixel_size);
   if (!reader.valid())
     return false;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 0829d62a..ddc912c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -985,7 +985,7 @@
         Tab tab = getActivityTab();
         if (tab != null) getTabContentManager().cacheTabThumbnail(tab);
 
-        VrShellDelegate.maybeUnregisterVrEntryHook(this);
+        VrShellDelegate.maybeUnregisterVrEntryHook();
         markSessionEnd();
         super.onPauseWithNative();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 26e622d..ef9e844 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -1730,6 +1730,9 @@
         // BottomSheet can be opened before native is initialized.
         if (!mUIInitialized) return getBottomSheet() != null && getBottomSheet().handleBackPress();
 
+        if (getManualFillingController() != null && getManualFillingController().handleBackPress())
+            return true;
+
         final Tab currentTab = getActivityTab();
 
         if (exitFullscreenIfShowing()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
index c98c9d60..b46ccc5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryCoordinator.java
@@ -161,7 +161,6 @@
     }
 
     /**
-     * TODO(fhorschig): Remove this function. The accessory probably shouldn't know this concept.
      * Dismisses the accessory by hiding it's view, clearing potentially left over suggestions and
      * hiding the keyboard.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
index 4d49c34..0c649fd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryMediator.java
@@ -82,10 +82,13 @@
     }
 
     void dismiss() {
+        mModel.setActiveTab(null);
         mVisibilityDelegate.onCloseKeyboardAccessory();
-        if (mModel.getAutofillSuggestions() == null) return; // Nothing to do here.
-        mModel.getAutofillSuggestions().dismiss();
-        mModel.setAutofillSuggestions(null);
+        if (mModel.getAutofillSuggestions() != null) {
+            mModel.getAutofillSuggestions().dismiss();
+            mModel.setAutofillSuggestions(null);
+        }
+        updateVisibility();
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
index bb03635..06ca190 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingCoordinator.java
@@ -21,7 +21,6 @@
  */
 public class ManualFillingCoordinator {
     private final ManualFillingMediator mMediator = new ManualFillingMediator();
-    // Ideally, it just manages |Provider|s and attaches them to the accessory when tabs change.
 
     /**
      * Creates a the manual filling controller.
@@ -47,6 +46,14 @@
         mMediator.destroy();
     }
 
+    /**
+     * Handles tapping on the Android back button.
+     * @return Whether tapping the back button dismissed the accessory sheet or not.
+     */
+    public boolean handleBackPress() {
+        return mMediator.handleBackPress();
+    }
+
     void registerActionProvider(Provider<KeyboardAccessoryData.Action> actionProvider) {
         mMediator.registerActionProvider(actionProvider);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
index 69bf561..1e6543f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingMediator.java
@@ -176,6 +176,14 @@
         mKeyboardAccessory.destroy();
     }
 
+    boolean handleBackPress() {
+        if (mAccessorySheet.isShown()) {
+            mKeyboardAccessory.dismiss();
+            return true;
+        }
+        return false;
+    }
+
     @Override
     public void onChangeAccessorySheet(int tabIndex) {
         assert mActivity != null : "ManualFillingMediator needs initialization.";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
index e31383c..ceb12a7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -128,16 +128,12 @@
      * @return Whether Contextual Search is enabled or not.
      */
     public static boolean isEnabled() {
-        if (sEnabled == null) {
-            sEnabled = detectEnabled();
-        }
+        if (sEnabled == null) sEnabled = detectEnabled();
         return sEnabled.booleanValue();
     }
 
     private static boolean detectEnabled() {
-        if (SysUtils.isLowEndDevice()) {
-            return false;
-        }
+        if (SysUtils.isLowEndDevice()) return false;
 
         // Allow this user-flippable flag to disable the feature.
         if (CommandLine.getInstance().hasSwitch(ChromeSwitches.DISABLE_CONTEXTUAL_SEARCH)) {
@@ -150,9 +146,7 @@
         }
 
         // Allow disabling the feature remotely.
-        if (getBooleanParam(DISABLED_PARAM)) {
-            return false;
-        }
+        if (getBooleanParam(DISABLED_PARAM)) return false;
 
         return true;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 6f1a70c..06b0fb8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -1396,8 +1396,8 @@
      * to expand the selection to a whole word.
      */
     @Override
-    public void handleSelection(String selection, boolean selectionValid, SelectionType type,
-            float x, float y) {
+    public void handleSelection(
+            String selection, boolean selectionValid, @SelectionType int type, float x, float y) {
         if (mIsAccessibilityModeEnabled) return;
 
         if (!selection.isEmpty()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
index 3c2eb19..e9436b4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
@@ -92,10 +92,9 @@
     }
 
     private int getPromoTapTriggeredLimit() {
-        if (mTapTriggeredPromoLimitForTesting != null) {
-            return mTapTriggeredPromoLimitForTesting.intValue();
-        }
-        return TAP_TRIGGERED_PROMO_LIMIT;
+        return mTapTriggeredPromoLimitForTesting != null
+                ? mTapTriggeredPromoLimitForTesting.intValue()
+                : TAP_TRIGGERED_PROMO_LIMIT;
     }
 
     /**
@@ -109,10 +108,10 @@
      * @return Whether a Tap gesture is currently supported as a trigger for the feature.
      */
     boolean isTapSupported() {
-        if (!isUserUndecided()) return true;
-
-        if (ContextualSearchFieldTrial.isContextualSearchTapDisableOverrideEnabled()) return true;
-
+        if (!isUserUndecided()
+                || ContextualSearchFieldTrial.isContextualSearchTapDisableOverrideEnabled()) {
+            return true;
+        }
         return getPromoTapsRemaining() != 0;
     }
 
@@ -121,9 +120,10 @@
      *         explicitly interacts with the feature.
      */
     boolean shouldPrefetchSearchResult() {
-        if (isMandatoryPromoAvailable()) return false;
-
-        if (!PrefServiceBridge.getInstance().getNetworkPredictionEnabled()) return false;
+        if (isMandatoryPromoAvailable()
+                || !PrefServiceBridge.getInstance().getNetworkPredictionEnabled()) {
+            return false;
+        }
 
         // We never preload on long-press so users can cut & paste without hitting the servers.
         return mSelectionController.getSelectionType() == SelectionType.TAP;
@@ -134,13 +134,12 @@
      * @return Whether the previous tap should resolve.
      */
     boolean shouldPreviousTapResolve() {
-        if (isMandatoryPromoAvailable()) return false;
+        if (isMandatoryPromoAvailable()
+                || ContextualSearchFieldTrial.isSearchTermResolutionDisabled()) {
+            return false;
+        }
 
-        if (ContextualSearchFieldTrial.isSearchTermResolutionDisabled()) return false;
-
-        if (isPromoAvailable()) return isBasePageHTTP(mNetworkCommunicator.getBasePageUrl());
-
-        return true;
+        return isPromoAvailable() ? isBasePageHTTP(mNetworkCommunicator.getBasePageUrl()) : true;
     }
 
     /**
@@ -150,18 +149,16 @@
     boolean canSendSurroundings() {
         if (mDidOverrideDecidedStateForTesting) return mDecidedStateForTesting;
 
-        if (isPromoAvailable()) return isBasePageHTTP(mNetworkCommunicator.getBasePageUrl());
-
-        return true;
+        return isPromoAvailable() ? isBasePageHTTP(mNetworkCommunicator.getBasePageUrl()) : true;
     }
 
     /**
      * @return Whether the Mandatory Promo is enabled.
      */
     boolean isMandatoryPromoAvailable() {
-        if (!isUserUndecided()) return false;
-
-        if (!ContextualSearchFieldTrial.isMandatoryPromoEnabled()) return false;
+        if (!isUserUndecided() || !ContextualSearchFieldTrial.isMandatoryPromoEnabled()) {
+            return false;
+        }
 
         return getPromoOpenCount() >= ContextualSearchFieldTrial.getMandatoryPromoLimit();
     }
@@ -180,9 +177,7 @@
         if (isPromoAvailable()) {
             DisableablePromoTapCounter promoTapCounter = getPromoTapCounter();
             // Bump the counter only when it is still enabled.
-            if (promoTapCounter.isEnabled()) {
-                promoTapCounter.increment();
-            }
+            if (promoTapCounter.isEnabled()) promoTapCounter.increment();
         }
         int tapsSinceOpen = mPreferenceManager.incrementInt(
                 ChromePreferenceManager.CONTEXTUAL_SEARCH_TAP_SINCE_OPEN_COUNT);
@@ -239,7 +234,8 @@
      *         is no exiting request.
      */
     boolean shouldCreateVerbatimRequest() {
-        SelectionType selectionType = mSelectionController.getSelectionType();
+        @SelectionType
+        int selectionType = mSelectionController.getSelectionType();
         return (mSelectionController.getSelectedText() != null
                 && (selectionType == SelectionType.LONG_PRESS
                 || (selectionType == SelectionType.TAP && !shouldPreviousTapResolve())));
@@ -315,11 +311,10 @@
      * @return Whether the search provider icon should be animated.
      */
     boolean shouldAnimateSearchProviderIcon() {
-        if (mSearchPanel.isShowing()) {
-            return false;
-        }
+        if (mSearchPanel.isShowing()) return false;
 
-        SelectionType selectionType = mSelectionController.getSelectionType();
+        @SelectionType
+        int selectionType = mSelectionController.getSelectionType();
         if (selectionType == SelectionType.TAP) {
             long currentTimeMillis = System.currentTimeMillis();
             long lastAnimatedTimeMillis =
@@ -455,9 +450,7 @@
         if (telephonyManager == null) return "";
 
         String simCountryIso = telephonyManager.getSimCountryIso();
-        if (TextUtils.isEmpty(simCountryIso)) return "";
-
-        return simCountryIso;
+        return TextUtils.isEmpty(simCountryIso) ? "" : simCountryIso;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
index 64d1eea..6f2bbd9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
@@ -71,11 +71,10 @@
             // TODO(donnd): Call TemplateURL once we have an API for 3rd-party providers.
             Uri baseLowPriorityUri = getUriTemplate(searchTerm, alternateTerm, mid, true);
             mLowPriorityUri = makeLowPriorityUri(baseLowPriorityUri);
-            mIsLowPriority = true;
         } else {
-            mIsLowPriority = false;
             mLowPriorityUri = null;
         }
+        mIsLowPriority = isLowPriorityEnabled;
     }
 
     /**
@@ -118,11 +117,8 @@
      * @return either the low-priority or normal-priority URL for this search request.
      */
     String getSearchUrl() {
-        if (mIsLowPriority && mLowPriorityUri != null) {
-            return mLowPriorityUri.toString();
-        } else {
-            return mNormalPriorityUri.toString();
-        }
+        return mIsLowPriority && mLowPriorityUri != null ? mLowPriorityUri.toString()
+                                                         : mNormalPriorityUri.toString();
     }
 
     /**
@@ -201,9 +197,7 @@
             boolean shouldPrefetch) {
         Uri uri = Uri.parse(TemplateUrlService.getInstance().getUrlForContextualSearchQuery(
                 query, alternateTerm, shouldPrefetch, CTXS_TWO_REQUEST_PROTOCOL));
-        if (!TextUtils.isEmpty(mid)) {
-            uri = makeKPTriggeringUri(uri, mid);
-        }
+        if (!TextUtils.isEmpty(mid)) uri = makeKPTriggeringUri(uri, mid);
         return uri;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
index 6f720d68..500e6855 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.contextualsearch;
 
+import android.support.annotation.IntDef;
 import android.support.annotation.Nullable;
 import android.text.TextUtils;
 
@@ -17,6 +18,8 @@
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.touch_selection.SelectionEventType;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -27,10 +30,12 @@
     /**
      * The type of selection made by the user.
      */
-    public enum SelectionType {
-        UNDETERMINED,
-        TAP,
-        LONG_PRESS
+    @IntDef({SelectionType.UNDETERMINED, SelectionType.TAP, SelectionType.LONG_PRESS})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SelectionType {
+        int UNDETERMINED = 0;
+        int TAP = 1;
+        int LONG_PRESS = 2;
     }
 
     private static final String TAG = "ContextualSearch";
@@ -57,7 +62,7 @@
     private final Pattern mContainsWordPattern;
 
     private String mSelectedText;
-    private SelectionType mSelectionType;
+    private @SelectionType int mSelectionType;
     private boolean mWasTapGestureDetected;
     // Reflects whether the last tap was valid and whether we still have a tap-based selection.
     private ContextualSearchTapState mLastTapState;
@@ -179,7 +184,8 @@
     /**
      * @return the type of the selection.
      */
-    SelectionType getSelectionType() {
+    @SelectionType
+    int getSelectionType() {
         return mSelectionType;
     }
 
@@ -297,7 +303,7 @@
      * @param selection The text that was selected.
      * @param type The type of selection made by the user.
      */
-    private void handleSelection(String selection, SelectionType type) {
+    private void handleSelection(String selection, @SelectionType int type) {
         mShouldHandleSelectionModification = true;
         boolean isValidSelection = validateSelectionSuppression(selection);
         mHandler.handleSelection(selection, isValidSelection, type, mX, mY);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionHandler.java
index fd5e5880..d7284a3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionHandler.java
@@ -34,8 +34,8 @@
     /**
      * Handle a new selection of the given type, created at the given x,y position.
      */
-    public void handleSelection(String selection, boolean selectionValid, SelectionType type,
-            float x, float y);
+    public void handleSelection(
+            String selection, boolean selectionValid, @SelectionType int type, float x, float y);
 
     /**
      * Handle a modification to the selection, done at the given x,y position.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
index 13fe723..a83677a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
@@ -4,6 +4,7 @@
 
 package org.chromium.chrome.browser.contextualsearch;
 
+import android.support.annotation.IntDef;
 import android.util.Pair;
 
 import org.chromium.base.metrics.RecordHistogram;
@@ -12,6 +13,8 @@
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -26,183 +29,310 @@
     private static final boolean TAP = true;
 
     // Constants used to log UMA "enum" histograms about the Contextual Search's preference state.
-    private static final int PREFERENCE_UNINITIALIZED = 0;
-    private static final int PREFERENCE_ENABLED = 1;
-    private static final int PREFERENCE_DISABLED = 2;
-    private static final int PREFERENCE_HISTOGRAM_BOUNDARY = 3;
+    @IntDef({Preference.UNINITIALIZED, Preference.ENABLED, Preference.DISABLED})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface Preference {
+        int UNINITIALIZED = 0;
+        int ENABLED = 1;
+        int DISABLED = 2;
+        int NUM_ENTRIES = 3;
+    }
 
     // Constants used to log UMA "enum" histograms about whether search results were seen.
-    private static final int RESULTS_SEEN = 0;
-    private static final int RESULTS_NOT_SEEN = 1;
-    private static final int RESULTS_SEEN_BOUNDARY = 2;
+    @IntDef({Results.SEEN, Results.NOT_SEEN})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface Results {
+        int SEEN = 0;
+        int NOT_SEEN = 1;
+        int NUM_ENTRIES = 2;
+    }
 
     // Constants used to log UMA "enum" histograms about whether the selection is valid.
-    private static final int SELECTION_VALID = 0;
-    private static final int SELECTION_INVALID = 1;
-    private static final int SELECTION_BOUNDARY = 2;
+    @IntDef({Selection.VALID, Selection.INVALID})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface Selection {
+        int VALID = 0;
+        int INVALID = 1;
+        int NUM_ENTRIES = 2;
+    }
 
     // Constants used to log UMA "enum" histograms about a request's outcome.
-    private static final int REQUEST_NOT_FAILED = 0;
-    private static final int REQUEST_FAILED = 1;
-    private static final int REQUEST_BOUNDARY = 2;
+    @IntDef({Request.NOT_FAILED, Request.FAILED})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface Request {
+        int NOT_FAILED = 0;
+        int FAILED = 1;
+        int NUM_ENTRIES = 2;
+    }
 
     // Constants used to log UMA "enum" histograms about the panel's state transitions.
     // Entry code: first entry into CLOSED.
-    private static final int ENTER_CLOSED_FROM_OTHER = 0;
-    private static final int ENTER_CLOSED_FROM_PEEKED_BACK_PRESS = 1;
-    private static final int ENTER_CLOSED_FROM_PEEKED_BASE_PAGE_SCROLL = 2;
-    private static final int ENTER_CLOSED_FROM_PEEKED_TEXT_SELECT_TAP = 3;
-    private static final int ENTER_CLOSED_FROM_EXPANDED_BACK_PRESS = 4;
-    private static final int ENTER_CLOSED_FROM_EXPANDED_BASE_PAGE_TAP = 5;
-    private static final int ENTER_CLOSED_FROM_EXPANDED_FLING = 6;
-    private static final int ENTER_CLOSED_FROM_MAXIMIZED_BACK_PRESS = 7;
-    private static final int ENTER_CLOSED_FROM_MAXIMIZED_FLING = 8;
-    private static final int ENTER_CLOSED_FROM_MAXIMIZED_TAB_PROMOTION = 9;
-    private static final int ENTER_CLOSED_FROM_MAXIMIZED_SERP_NAVIGATION = 10;
-    private static final int ENTER_CLOSED_FROM_BOUNDARY = 11;
+    @IntDef({EnterClosedFrom.OTHER, EnterClosedFrom.PEEKED_BACK_PRESS,
+            EnterClosedFrom.PEEKED_BASE_PAGE_SCROLL, EnterClosedFrom.PEEKED_TEXT_SELECT_TAP,
+            EnterClosedFrom.EXPANDED_BACK_PRESS, EnterClosedFrom.EXPANDED_BASE_PAGE_TAP,
+            EnterClosedFrom.EXPANDED_FLING, EnterClosedFrom.MAXIMIZED_BACK_PRESS,
+            EnterClosedFrom.MAXIMIZED_FLING, EnterClosedFrom.MAXIMIZED_TAB_PROMOTION,
+            EnterClosedFrom.MAXIMIZED_SERP_NAVIGATION})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface EnterClosedFrom {
+        int OTHER = 0;
+        int PEEKED_BACK_PRESS = 1;
+        int PEEKED_BASE_PAGE_SCROLL = 2;
+        int PEEKED_TEXT_SELECT_TAP = 3;
+        int EXPANDED_BACK_PRESS = 4;
+        int EXPANDED_BASE_PAGE_TAP = 5;
+        int EXPANDED_FLING = 6;
+        int MAXIMIZED_BACK_PRESS = 7;
+        int MAXIMIZED_FLING = 8;
+        int MAXIMIZED_TAB_PROMOTION = 9;
+        int MAXIMIZED_SERP_NAVIGATION = 10;
+        int NUM_ENTRIES = 11;
+    }
 
     // Entry code: first entry into PEEKED.
-    private static final int ENTER_PEEKED_FROM_OTHER = 0;
-    private static final int ENTER_PEEKED_FROM_CLOSED_TEXT_SELECT_TAP = 1;
-    private static final int ENTER_PEEKED_FROM_CLOSED_EXT_SELECT_LONG_PRESS = 2;
-    private static final int ENTER_PEEKED_FROM_PEEKED_TEXT_SELECT_TAP = 3;
-    private static final int ENTER_PEEKED_FROM_PEEKED_TEXT_SELECT_LONG_PRESS = 4;
-    private static final int ENTER_PEEKED_FROM_EXPANDED_SEARCH_BAR_TAP = 5;
-    private static final int ENTER_PEEKED_FROM_EXPANDED_SWIPE = 6;
-    private static final int ENTER_PEEKED_FROM_EXPANDED_FLING = 7;
-    private static final int ENTER_PEEKED_FROM_MAXIMIZED_SWIPE = 8;
-    private static final int ENTER_PEEKED_FROM_MAXIMIZED_FLING = 9;
-    private static final int ENTER_PEEKED_FROM_BOUNDARY = 10;
+    @IntDef({EnterPeekedFrom.OTHER, EnterPeekedFrom.CLOSED_TEXT_SELECT_TAP,
+            EnterPeekedFrom.CLOSED_EXT_SELECT_LONG_PRESS, EnterPeekedFrom.PEEKED_TEXT_SELECT_TAP,
+            EnterPeekedFrom.PEEKED_TEXT_SELECT_LONG_PRESS, EnterPeekedFrom.EXPANDED_SEARCH_BAR_TAP,
+            EnterPeekedFrom.EXPANDED_SWIPE, EnterPeekedFrom.EXPANDED_FLING,
+            EnterPeekedFrom.MAXIMIZED_SWIPE, EnterPeekedFrom.MAXIMIZED_FLING})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface EnterPeekedFrom {
+        int OTHER = 0;
+        int CLOSED_TEXT_SELECT_TAP = 1;
+        int CLOSED_EXT_SELECT_LONG_PRESS = 2;
+        int PEEKED_TEXT_SELECT_TAP = 3;
+        int PEEKED_TEXT_SELECT_LONG_PRESS = 4;
+        int EXPANDED_SEARCH_BAR_TAP = 5;
+        int EXPANDED_SWIPE = 6;
+        int EXPANDED_FLING = 7;
+        int MAXIMIZED_SWIPE = 8;
+        int MAXIMIZED_FLING = 9;
+        int NUM_ENTRIES = 10;
+    }
 
     // Entry code: first entry into EXPANDED.
-    private static final int ENTER_EXPANDED_FROM_OTHER = 0;
-    private static final int ENTER_EXPANDED_FROM_PEEKED_SEARCH_BAR_TAP = 1;
-    private static final int ENTER_EXPANDED_FROM_PEEKED_SWIPE = 2;
-    private static final int ENTER_EXPANDED_FROM_PEEKED_FLING = 3;
-    private static final int ENTER_EXPANDED_FROM_MAXIMIZED_SWIPE = 4;
-    private static final int ENTER_EXPANDED_FROM_MAXIMIZED_FLING = 5;
-    private static final int ENTER_EXPANDED_FROM_BOUNDARY = 6;
+    @IntDef({EnterExpandedFrom.OTHER, EnterExpandedFrom.PEEKED_SEARCH_BAR_TAP,
+            EnterExpandedFrom.PEEKED_SWIPE, EnterExpandedFrom.PEEKED_FLING,
+            EnterExpandedFrom.MAXIMIZED_SWIPE, EnterExpandedFrom.MAXIMIZED_FLING})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface EnterExpandedFrom {
+        int OTHER = 0;
+        int PEEKED_SEARCH_BAR_TAP = 1;
+        int PEEKED_SWIPE = 2;
+        int PEEKED_FLING = 3;
+        int MAXIMIZED_SWIPE = 4;
+        int MAXIMIZED_FLING = 5;
+        int NUM_ENTRIES = 6;
+    }
 
     // Entry code: first entry into MAXIMIZED.
-    private static final int ENTER_MAXIMIZED_FROM_OTHER = 0;
-    private static final int ENTER_MAXIMIZED_FROM_PEEKED_SWIPE = 1;
-    private static final int ENTER_MAXIMIZED_FROM_PEEKED_FLING = 2;
-    private static final int ENTER_MAXIMIZED_FROM_EXPANDED_SWIPE = 3;
-    private static final int ENTER_MAXIMIZED_FROM_EXPANDED_FLING = 4;
-    private static final int ENTER_MAXIMIZED_FROM_EXPANDED_SERP_NAVIGATION = 5;
-    private static final int ENTER_MAXIMIZED_FROM_BOUNDARY = 6;
+    @IntDef({EnterMaximizedFrom.OTHER, EnterMaximizedFrom.PEEKED_SWIPE,
+            EnterMaximizedFrom.PEEKED_FLING, EnterMaximizedFrom.EXPANDED_SWIPE,
+            EnterMaximizedFrom.EXPANDED_FLING, EnterMaximizedFrom.EXPANDED_SERP_NAVIGATION})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface EnterMaximizedFrom {
+        int OTHER = 0;
+        int PEEKED_SWIPE = 1;
+        int PEEKED_FLING = 2;
+        int EXPANDED_SWIPE = 3;
+        int EXPANDED_FLING = 4;
+        int EXPANDED_SERP_NAVIGATION = 5;
+        int NUM_ENTRIES = 6;
+    }
 
     // Exit code: first exit from CLOSED (or UNDEFINED).
-    private static final int EXIT_CLOSED_TO_OTHER = 0;
-    private static final int EXIT_CLOSED_TO_PEEKED_TEXT_SELECT_TAP = 1;
-    private static final int EXIT_CLOSED_TO_PEEKED_TEXT_SELECT_LONG_PRESS = 2;
-    private static final int EXIT_CLOSED_TO_BOUNDARY = 3;
+    @IntDef({ExitClosedTo.OTHER, ExitClosedTo.PEEKED_TEXT_SELECT_TAP,
+            ExitClosedTo.PEEKED_TEXT_SELECT_LONG_PRESS})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ExitClosedTo {
+        int OTHER = 0;
+        int PEEKED_TEXT_SELECT_TAP = 1;
+        int PEEKED_TEXT_SELECT_LONG_PRESS = 2;
+        int NUM_ENTRIES = 3;
+    }
 
     // Exit code: first exit from PEEKED.
-    private static final int EXIT_PEEKED_TO_OTHER = 0;
-    private static final int EXIT_PEEKED_TO_CLOSED_BACK_PRESS = 1;
-    private static final int EXIT_PEEKED_TO_CLOSED_BASE_PAGE_SCROLL = 2;
-    private static final int EXIT_PEEKED_TO_CLOSED_TEXT_SELECT_TAP = 3;
-    private static final int EXIT_PEEKED_TO_PEEKED_TEXT_SELECT_TAP = 4;
-    private static final int EXIT_PEEKED_TO_PEEKED_TEXT_SELECT_LONG_PRESS = 5;
-    private static final int EXIT_PEEKED_TO_EXPANDED_SEARCH_BAR_TAP = 6;
-    private static final int EXIT_PEEKED_TO_EXPANDED_SWIPE = 7;
-    private static final int EXIT_PEEKED_TO_EXPANDED_FLING = 8;
-    private static final int EXIT_PEEKED_TO_MAXIMIZED_SWIPE = 9;
-    private static final int EXIT_PEEKED_TO_MAXIMIZED_FLING = 10;
-    private static final int EXIT_PEEKED_TO_BOUNDARY = 11;
+    @IntDef({ExitPeekedTo.OTHER, ExitPeekedTo.CLOSED_BACK_PRESS,
+            ExitPeekedTo.CLOSED_BASE_PAGE_SCROLL, ExitPeekedTo.CLOSED_TEXT_SELECT_TAP,
+            ExitPeekedTo.PEEKED_TEXT_SELECT_TAP, ExitPeekedTo.PEEKED_TEXT_SELECT_LONG_PRESS,
+            ExitPeekedTo.EXPANDED_SEARCH_BAR_TAP, ExitPeekedTo.EXPANDED_SWIPE,
+            ExitPeekedTo.EXPANDED_FLING, ExitPeekedTo.MAXIMIZED_SWIPE,
+            ExitPeekedTo.MAXIMIZED_FLING})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ExitPeekedTo {
+        int OTHER = 0;
+        int CLOSED_BACK_PRESS = 1;
+        int CLOSED_BASE_PAGE_SCROLL = 2;
+        int CLOSED_TEXT_SELECT_TAP = 3;
+        int PEEKED_TEXT_SELECT_TAP = 4;
+        int PEEKED_TEXT_SELECT_LONG_PRESS = 5;
+        int EXPANDED_SEARCH_BAR_TAP = 6;
+        int EXPANDED_SWIPE = 7;
+        int EXPANDED_FLING = 8;
+        int MAXIMIZED_SWIPE = 9;
+        int MAXIMIZED_FLING = 10;
+        int NUM_ENTRIES = 11;
+    }
 
     // Exit code: first exit from EXPANDED.
-    private static final int EXIT_EXPANDED_TO_OTHER = 0;
-    private static final int EXIT_EXPANDED_TO_CLOSED_BACK_PRESS = 1;
-    private static final int EXIT_EXPANDED_TO_CLOSED_BASE_PAGE_TAP = 2;
-    private static final int EXIT_EXPANDED_TO_CLOSED_FLING = 3;
-    private static final int EXIT_EXPANDED_TO_PEEKED_SEARCH_BAR_TAP = 4;
-    private static final int EXIT_EXPANDED_TO_PEEKED_SWIPE = 5;
-    private static final int EXIT_EXPANDED_TO_PEEKED_FLING = 6;
-    private static final int EXIT_EXPANDED_TO_MAXIMIZED_SWIPE = 7;
-    private static final int EXIT_EXPANDED_TO_MAXIMIZED_FLING = 8;
-    private static final int EXIT_EXPANDED_TO_MAXIMIZED_SERP_NAVIGATION = 9;
-    private static final int EXIT_EXPANDED_TO_BOUNDARY = 10;
+    @IntDef({ExitExpandedTo.OTHER, ExitExpandedTo.CLOSED_BACK_PRESS,
+            ExitExpandedTo.CLOSED_BASE_PAGE_TAP, ExitExpandedTo.CLOSED_FLING,
+            ExitExpandedTo.PEEKED_SEARCH_BAR_TAP, ExitExpandedTo.PEEKED_SWIPE,
+            ExitExpandedTo.PEEKED_FLING, ExitExpandedTo.MAXIMIZED_SWIPE,
+            ExitExpandedTo.MAXIMIZED_FLING, ExitExpandedTo.MAXIMIZED_SERP_NAVIGATION})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ExitExpandedTo {
+        int OTHER = 0;
+        int CLOSED_BACK_PRESS = 1;
+        int CLOSED_BASE_PAGE_TAP = 2;
+        int CLOSED_FLING = 3;
+        int PEEKED_SEARCH_BAR_TAP = 4;
+        int PEEKED_SWIPE = 5;
+        int PEEKED_FLING = 6;
+        int MAXIMIZED_SWIPE = 7;
+        int MAXIMIZED_FLING = 8;
+        int MAXIMIZED_SERP_NAVIGATION = 9;
+        int NUM_ENTRIES = 10;
+    }
 
     // Exit code: first exit from MAXIMIZED.
-    private static final int EXIT_MAXIMIZED_TO_OTHER = 0;
-    private static final int EXIT_MAXIMIZED_TO_CLOSED_BACK_PRESS = 1;
-    private static final int EXIT_MAXIMIZED_TO_CLOSED_FLING = 2;
-    private static final int EXIT_MAXIMIZED_TO_CLOSED_TAB_PROMOTION = 3;
-    private static final int EXIT_MAXIMIZED_TO_CLOSED_SERP_NAVIGATION = 4;
-    private static final int EXIT_MAXIMIZED_TO_PEEKED_SWIPE = 5;
-    private static final int EXIT_MAXIMIZED_TO_PEEKED_FLING = 6;
-    private static final int EXIT_MAXIMIZED_TO_EXPANDED_SWIPE = 7;
-    private static final int EXIT_MAXIMIZED_TO_EXPANDED_FLING = 8;
-    private static final int EXIT_MAXIMIZED_TO_BOUNDARY = 9;
+    @IntDef({ExitMaximizedTo.OTHER, ExitMaximizedTo.CLOSED_BACK_PRESS, ExitMaximizedTo.CLOSED_FLING,
+            ExitMaximizedTo.CLOSED_TAB_PROMOTION, ExitMaximizedTo.CLOSED_SERP_NAVIGATION,
+            ExitMaximizedTo.PEEKED_SWIPE, ExitMaximizedTo.PEEKED_FLING,
+            ExitMaximizedTo.EXPANDED_SWIPE, ExitMaximizedTo.EXPANDED_FLING})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ExitMaximizedTo {
+        int OTHER = 0;
+        int CLOSED_BACK_PRESS = 1;
+        int CLOSED_FLING = 2;
+        int CLOSED_TAB_PROMOTION = 3;
+        int CLOSED_SERP_NAVIGATION = 4;
+        int PEEKED_SWIPE = 5;
+        int PEEKED_FLING = 6;
+        int EXPANDED_SWIPE = 7;
+        int EXPANDED_FLING = 8;
+        int NUM_ENTRIES = 9;
+    }
 
     // Constants used to log UMA "enum" histograms with details about whether search results
     // were seen, and what the original triggering gesture was.
-    private static final int RESULTS_SEEN_FROM_TAP = 0;
-    private static final int RESULTS_NOT_SEEN_FROM_TAP = 1;
-    private static final int RESULTS_SEEN_FROM_LONG_PRESS = 2;
-    private static final int RESULTS_NOT_SEEN_FROM_LONG_PRESS = 3;
-    private static final int RESULTS_BY_GESTURE_BOUNDARY = 4;
+    @IntDef({ResultsByGesture.SEEN_FROM_TAP, ResultsByGesture.NOT_SEEN_FROM_TAP,
+            ResultsByGesture.SEEN_FROM_LONG_PRESS, ResultsByGesture.NOT_SEEN_FROM_LONG_PRESS})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ResultsByGesture {
+        int SEEN_FROM_TAP = 0;
+        int NOT_SEEN_FROM_TAP = 1;
+        int SEEN_FROM_LONG_PRESS = 2;
+        int NOT_SEEN_FROM_LONG_PRESS = 3;
+        int NUM_ENTRIES = 4;
+    }
 
     // Constants used to log UMA "enum" histograms with details about whether search results
     // were seen, and whether any existing tap suppression heuristics were satisfied.
-    private static final int RESULTS_SEEN_SUPPRESSION_HEURSTIC_SATISFIED = 0;
-    private static final int RESULTS_NOT_SEEN_SUPPRESSION_HEURSTIC_SATISFIED = 1;
-    private static final int RESULTS_SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED = 2;
-    private static final int RESULTS_NOT_SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED = 3;
-    private static final int RESULTS_SEEN_SUPPRESSION_BOUNDARY = 4;
+    @IntDef({ResultsBySuppression.SEEN_SUPPRESSION_HEURSTIC_SATISFIED,
+            ResultsBySuppression.NOT_SEEN_SUPPRESSION_HEURSTIC_SATISFIED,
+            ResultsBySuppression.SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED,
+            ResultsBySuppression.NOT_SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ResultsBySuppression {
+        int SEEN_SUPPRESSION_HEURSTIC_SATISFIED = 0;
+        int NOT_SEEN_SUPPRESSION_HEURSTIC_SATISFIED = 1;
+        int SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED = 2;
+        int NOT_SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED = 3;
+        int NUM_ENTRIES = 4;
+    }
 
     // Constants used to log UMA "enum" histograms with details about whether search results
     // were seen, and what the original triggering gesture was.
-    private static final int PROMO_ENABLED_FROM_TAP = 0;
-    private static final int PROMO_DISABLED_FROM_TAP = 1;
-    private static final int PROMO_UNDECIDED_FROM_TAP = 2;
-    private static final int PROMO_ENABLED_FROM_LONG_PRESS = 3;
-    private static final int PROMO_DISABLED_FROM_LONG_PRESS = 4;
-    private static final int PROMO_UNDECIDED_FROM_LONG_PRESS = 5;
-    private static final int PROMO_BY_GESTURE_BOUNDARY = 6;
+    @IntDef({Promo.ENABLED_FROM_TAP, Promo.DISABLED_FROM_TAP, Promo.UNDECIDED_FROM_TAP,
+            Promo.ENABLED_FROM_LONG_PRESS, Promo.DISABLED_FROM_LONG_PRESS,
+            Promo.UNDECIDED_FROM_LONG_PRESS})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface Promo {
+        int ENABLED_FROM_TAP = 0;
+        int DISABLED_FROM_TAP = 1;
+        int UNDECIDED_FROM_TAP = 2;
+        int ENABLED_FROM_LONG_PRESS = 3;
+        int DISABLED_FROM_LONG_PRESS = 4;
+        int UNDECIDED_FROM_LONG_PRESS = 5;
+        int NUM_ENTRIES = 6;
+    }
 
     // Constants used to log UMA "enum" histograms for HTTP / HTTPS.
-    private static final int PROTOCOL_IS_HTTP = 0;
-    private static final int PROTOCOL_NOT_HTTP = 1;
-    private static final int PROTOCOL_BOUNDARY = 2;
+    @IntDef({Protocol.IS_HTTP, Protocol.NOT_HTTP})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface Protocol {
+        int IS_HTTP = 0;
+        int NOT_HTTP = 1;
+        int NUM_ENTRIES = 2;
+    }
 
     // Constants used to log UMA "enum" histograms for single / multi-word.
-    private static final int RESOLVED_SINGLE_WORD = 0;
-    private static final int RESOLVED_MULTI_WORD = 1;
-    private static final int RESOLVED_BOUNDARY = 2;
+    @IntDef({ResolvedGranularity.SINGLE_WORD, ResolvedGranularity.MULTI_WORD})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ResolvedGranularity {
+        int SINGLE_WORD = 0;
+        int MULTI_WORD = 1;
+        int NUM_ENTRIES = 2;
+    }
 
     // Constants used to log UMA "enum" histograms for triggering the Translate Onebox.
-    private static final int DID_FORCE_TRANSLATE = 0;
-    private static final int WOULD_FORCE_TRANSLATE = 1;
-    private static final int FORCE_TRANSLATE_BOUNDARY = 2;
+    @IntDef({ForceTranslate.DID_FORCE, ForceTranslate.WOULD_FORCE})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface ForceTranslate {
+        int DID_FORCE = 0;
+        int WOULD_FORCE = 1;
+        int NUM_ENTRIES = 2;
+    }
 
     // Constants used to log UMA "enum" histograms for Quick Answers.
-    private static final int QUICK_ANSWER_ACTIVATED_WAS_AN_ANSWER_SEEN = 0;
-    private static final int QUICK_ANSWER_ACTIVATED_WAS_AN_ANSWER_NOT_SEEN = 1;
-    private static final int QUICK_ANSWER_ACTIVATED_NOT_AN_ANSWER_SEEN = 2;
-    private static final int QUICK_ANSWER_ACTIVATED_NOT_AN_ANSWER_NOT_SEEN = 3;
-    private static final int QUICK_ANSWER_NOT_ACTIVATED_SEEN = 4;
-    private static final int QUICK_ANSWER_NOT_ACTIVATED_NOT_SEEN = 5;
-    private static final int QUICK_ANSWER_SEEN_BOUNDARY = 6;
+    @IntDef({QuickAnswerSeen.ACTIVATED_WAS_AN_ANSWER_SEEN,
+            QuickAnswerSeen.ACTIVATED_WAS_AN_ANSWER_NOT_SEEN,
+            QuickAnswerSeen.ACTIVATED_NOT_AN_ANSWER_SEEN,
+            QuickAnswerSeen.ACTIVATED_NOT_AN_ANSWER_NOT_SEEN, QuickAnswerSeen.NOT_ACTIVATED_SEEN,
+            QuickAnswerSeen.NOT_ACTIVATED_NOT_SEEN})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface QuickAnswerSeen {
+        int ACTIVATED_WAS_AN_ANSWER_SEEN = 0;
+        int ACTIVATED_WAS_AN_ANSWER_NOT_SEEN = 1;
+        int ACTIVATED_NOT_AN_ANSWER_SEEN = 2;
+        int ACTIVATED_NOT_AN_ANSWER_NOT_SEEN = 3;
+        int NOT_ACTIVATED_SEEN = 4;
+        int NOT_ACTIVATED_NOT_SEEN = 5;
+        int NUM_ENTRIES = 6;
+    }
 
     // Constants for "Bar Overlap" with triggering gesture, and whether the results were seen.
-    private static final int BAR_OVERLAP_RESULTS_SEEN_FROM_TAP = 0;
-    private static final int BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP = 1;
-    private static final int NO_BAR_OVERLAP_RESULTS_SEEN_FROM_TAP = 2;
-    private static final int NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP = 3;
-    private static final int BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS = 4;
-    private static final int BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS = 5;
-    private static final int NO_BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS = 6;
-    private static final int NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS = 7;
-    private static final int BAR_OVERLAP_RESULTS_BOUNDARY = 8;
+    @IntDef({BarOverlapResults.BAR_OVERLAP_RESULTS_SEEN_FROM_TAP,
+            BarOverlapResults.BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP,
+            BarOverlapResults.NO_BAR_OVERLAP_RESULTS_SEEN_FROM_TAP,
+            BarOverlapResults.NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP,
+            BarOverlapResults.BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS,
+            BarOverlapResults.BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS,
+            BarOverlapResults.NO_BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS,
+            BarOverlapResults.NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface BarOverlapResults {
+        int BAR_OVERLAP_RESULTS_SEEN_FROM_TAP = 0;
+        int BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP = 1;
+        int NO_BAR_OVERLAP_RESULTS_SEEN_FROM_TAP = 2;
+        int NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP = 3;
+        int BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS = 4;
+        int BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS = 5;
+        int NO_BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS = 6;
+        int NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS = 7;
+        int NUM_ENTRIES = 8;
+    }
 
     // Constants for quick action intent resolution histogram.
-    private static final int QUICK_ACTION_RESOLVE_FAILED = 0;
-    private static final int QUICK_ACTION_RESOLVE_SINGLE = 1;
-    private static final int QUICK_ACTION_RESOLVE_MULTIPLE = 2;
-    private static final int QUICK_ACTION_RESOLVE_BOUNDARY = 3;
+    @IntDef({QuickActionResolve.FAILED, QuickActionResolve.SINGLE, QuickActionResolve.MULTIPLE})
+    @Retention(RetentionPolicy.SOURCE)
+    private @interface QuickActionResolve {
+        int FAILED = 0;
+        int SINGLE = 1;
+        int MULTIPLE = 2;
+        int NUM_ENTRIES = 3;
+    }
 
     /**
      * Key used in maps from {state, reason} to state entry (exit) logging code.
@@ -220,12 +350,8 @@
 
         @Override
         public boolean equals(Object obj) {
-            if (!(obj instanceof StateChangeKey)) {
-                return false;
-            }
-            if (obj == this) {
-                return true;
-            }
+            if (!(obj instanceof StateChangeKey)) return false;
+            if (obj == this) return true;
             StateChangeKey other = (StateChangeKey) obj;
             return mState.equals(other.mState) && mReason == other.mReason;
         }
@@ -243,25 +369,25 @@
     static {
         Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.BACK_PRESS),
-                ENTER_CLOSED_FROM_PEEKED_BACK_PRESS);
+                EnterClosedFrom.PEEKED_BACK_PRESS);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.BASE_PAGE_SCROLL),
-                ENTER_CLOSED_FROM_PEEKED_BASE_PAGE_SCROLL);
+                EnterClosedFrom.PEEKED_BASE_PAGE_SCROLL);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_TAP),
-                ENTER_CLOSED_FROM_PEEKED_TEXT_SELECT_TAP);
+                EnterClosedFrom.PEEKED_TEXT_SELECT_TAP);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.BACK_PRESS),
-                ENTER_CLOSED_FROM_EXPANDED_BACK_PRESS);
+                EnterClosedFrom.EXPANDED_BACK_PRESS);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.BASE_PAGE_TAP),
-                ENTER_CLOSED_FROM_EXPANDED_BASE_PAGE_TAP);
+                EnterClosedFrom.EXPANDED_BASE_PAGE_TAP);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.FLING),
-                ENTER_CLOSED_FROM_EXPANDED_FLING);
+                EnterClosedFrom.EXPANDED_FLING);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.BACK_PRESS),
-                ENTER_CLOSED_FROM_MAXIMIZED_BACK_PRESS);
+                EnterClosedFrom.MAXIMIZED_BACK_PRESS);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.FLING),
-                ENTER_CLOSED_FROM_MAXIMIZED_FLING);
+                EnterClosedFrom.MAXIMIZED_FLING);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.TAB_PROMOTION),
-                ENTER_CLOSED_FROM_MAXIMIZED_TAB_PROMOTION);
+                EnterClosedFrom.MAXIMIZED_TAB_PROMOTION);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SERP_NAVIGATION),
-                ENTER_CLOSED_FROM_MAXIMIZED_SERP_NAVIGATION);
+                EnterClosedFrom.MAXIMIZED_SERP_NAVIGATION);
         ENTER_CLOSED_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
     }
 
@@ -271,28 +397,28 @@
         Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
         // Note: we don't distinguish entering PEEKED from UNDEFINED / CLOSED.
         codes.put(new StateChangeKey(PanelState.UNDEFINED, StateChangeReason.TEXT_SELECT_TAP),
-                ENTER_PEEKED_FROM_CLOSED_TEXT_SELECT_TAP);
-        codes.put(new StateChangeKey(PanelState.UNDEFINED,
-                StateChangeReason.TEXT_SELECT_LONG_PRESS),
-                ENTER_PEEKED_FROM_CLOSED_EXT_SELECT_LONG_PRESS);
+                EnterPeekedFrom.CLOSED_TEXT_SELECT_TAP);
+        codes.put(
+                new StateChangeKey(PanelState.UNDEFINED, StateChangeReason.TEXT_SELECT_LONG_PRESS),
+                EnterPeekedFrom.CLOSED_EXT_SELECT_LONG_PRESS);
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.TEXT_SELECT_TAP),
-                ENTER_PEEKED_FROM_CLOSED_TEXT_SELECT_TAP);
+                EnterPeekedFrom.CLOSED_TEXT_SELECT_TAP);
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.TEXT_SELECT_LONG_PRESS),
-                ENTER_PEEKED_FROM_CLOSED_EXT_SELECT_LONG_PRESS);
+                EnterPeekedFrom.CLOSED_EXT_SELECT_LONG_PRESS);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_TAP),
-                ENTER_PEEKED_FROM_PEEKED_TEXT_SELECT_TAP);
+                EnterPeekedFrom.PEEKED_TEXT_SELECT_TAP);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_LONG_PRESS),
-                ENTER_PEEKED_FROM_PEEKED_TEXT_SELECT_LONG_PRESS);
+                EnterPeekedFrom.PEEKED_TEXT_SELECT_LONG_PRESS);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SEARCH_BAR_TAP),
-                ENTER_PEEKED_FROM_EXPANDED_SEARCH_BAR_TAP);
+                EnterPeekedFrom.EXPANDED_SEARCH_BAR_TAP);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SWIPE),
-                ENTER_PEEKED_FROM_EXPANDED_SWIPE);
+                EnterPeekedFrom.EXPANDED_SWIPE);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.FLING),
-                ENTER_PEEKED_FROM_EXPANDED_FLING);
+                EnterPeekedFrom.EXPANDED_FLING);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SWIPE),
-                ENTER_PEEKED_FROM_MAXIMIZED_SWIPE);
+                EnterPeekedFrom.MAXIMIZED_SWIPE);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.FLING),
-                ENTER_PEEKED_FROM_MAXIMIZED_FLING);
+                EnterPeekedFrom.MAXIMIZED_FLING);
         ENTER_PEEKED_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
     }
 
@@ -301,15 +427,15 @@
     static {
         Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SEARCH_BAR_TAP),
-                ENTER_EXPANDED_FROM_PEEKED_SEARCH_BAR_TAP);
+                EnterExpandedFrom.PEEKED_SEARCH_BAR_TAP);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SWIPE),
-                ENTER_EXPANDED_FROM_PEEKED_SWIPE);
+                EnterExpandedFrom.PEEKED_SWIPE);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.FLING),
-                ENTER_EXPANDED_FROM_PEEKED_FLING);
+                EnterExpandedFrom.PEEKED_FLING);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SWIPE),
-                ENTER_EXPANDED_FROM_MAXIMIZED_SWIPE);
+                EnterExpandedFrom.MAXIMIZED_SWIPE);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.FLING),
-                ENTER_EXPANDED_FROM_MAXIMIZED_FLING);
+                EnterExpandedFrom.MAXIMIZED_FLING);
         ENTER_EXPANDED_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
     }
 
@@ -318,15 +444,15 @@
     static {
         Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SWIPE),
-                ENTER_MAXIMIZED_FROM_PEEKED_SWIPE);
+                EnterMaximizedFrom.PEEKED_SWIPE);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.FLING),
-                ENTER_MAXIMIZED_FROM_PEEKED_FLING);
+                EnterMaximizedFrom.PEEKED_FLING);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SWIPE),
-                ENTER_MAXIMIZED_FROM_EXPANDED_SWIPE);
+                EnterMaximizedFrom.EXPANDED_SWIPE);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.FLING),
-                ENTER_MAXIMIZED_FROM_EXPANDED_FLING);
+                EnterMaximizedFrom.EXPANDED_FLING);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SERP_NAVIGATION),
-                ENTER_MAXIMIZED_FROM_EXPANDED_SERP_NAVIGATION);
+                EnterMaximizedFrom.EXPANDED_SERP_NAVIGATION);
         ENTER_MAXIMIZED_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
     }
 
@@ -335,9 +461,9 @@
     static {
         Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_TAP),
-                EXIT_CLOSED_TO_PEEKED_TEXT_SELECT_TAP);
+                ExitClosedTo.PEEKED_TEXT_SELECT_TAP);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_LONG_PRESS),
-                EXIT_CLOSED_TO_PEEKED_TEXT_SELECT_LONG_PRESS);
+                ExitClosedTo.PEEKED_TEXT_SELECT_LONG_PRESS);
         EXIT_CLOSED_TO_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
     }
 
@@ -346,25 +472,25 @@
     static {
         Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BACK_PRESS),
-                EXIT_PEEKED_TO_CLOSED_BACK_PRESS);
+                ExitPeekedTo.CLOSED_BACK_PRESS);
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BASE_PAGE_SCROLL),
-                EXIT_PEEKED_TO_CLOSED_BASE_PAGE_SCROLL);
+                ExitPeekedTo.CLOSED_BASE_PAGE_SCROLL);
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BASE_PAGE_TAP),
-                EXIT_PEEKED_TO_CLOSED_TEXT_SELECT_TAP);
+                ExitPeekedTo.CLOSED_TEXT_SELECT_TAP);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_TAP),
-                EXIT_PEEKED_TO_PEEKED_TEXT_SELECT_TAP);
+                ExitPeekedTo.PEEKED_TEXT_SELECT_TAP);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.TEXT_SELECT_LONG_PRESS),
-                EXIT_PEEKED_TO_PEEKED_TEXT_SELECT_LONG_PRESS);
+                ExitPeekedTo.PEEKED_TEXT_SELECT_LONG_PRESS);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SEARCH_BAR_TAP),
-                EXIT_PEEKED_TO_EXPANDED_SEARCH_BAR_TAP);
+                ExitPeekedTo.EXPANDED_SEARCH_BAR_TAP);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SWIPE),
-                EXIT_PEEKED_TO_EXPANDED_SWIPE);
+                ExitPeekedTo.EXPANDED_SWIPE);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.FLING),
-                EXIT_PEEKED_TO_EXPANDED_FLING);
+                ExitPeekedTo.EXPANDED_FLING);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SWIPE),
-                EXIT_PEEKED_TO_MAXIMIZED_SWIPE);
+                ExitPeekedTo.MAXIMIZED_SWIPE);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.FLING),
-                EXIT_PEEKED_TO_MAXIMIZED_FLING);
+                ExitPeekedTo.MAXIMIZED_FLING);
         EXIT_PEEKED_TO_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
     }
 
@@ -373,23 +499,23 @@
     static {
         Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BACK_PRESS),
-                EXIT_EXPANDED_TO_CLOSED_BACK_PRESS);
+                ExitExpandedTo.CLOSED_BACK_PRESS);
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BASE_PAGE_TAP),
-                EXIT_EXPANDED_TO_CLOSED_BASE_PAGE_TAP);
+                ExitExpandedTo.CLOSED_BASE_PAGE_TAP);
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.FLING),
-                EXIT_EXPANDED_TO_CLOSED_FLING);
+                ExitExpandedTo.CLOSED_FLING);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SEARCH_BAR_TAP),
-                EXIT_EXPANDED_TO_PEEKED_SEARCH_BAR_TAP);
+                ExitExpandedTo.PEEKED_SEARCH_BAR_TAP);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SWIPE),
-                EXIT_EXPANDED_TO_PEEKED_SWIPE);
+                ExitExpandedTo.PEEKED_SWIPE);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.FLING),
-                EXIT_EXPANDED_TO_PEEKED_FLING);
+                ExitExpandedTo.PEEKED_FLING);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SWIPE),
-                EXIT_EXPANDED_TO_MAXIMIZED_SWIPE);
+                ExitExpandedTo.MAXIMIZED_SWIPE);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.FLING),
-                EXIT_EXPANDED_TO_MAXIMIZED_FLING);
+                ExitExpandedTo.MAXIMIZED_FLING);
         codes.put(new StateChangeKey(PanelState.MAXIMIZED, StateChangeReason.SERP_NAVIGATION),
-                EXIT_EXPANDED_TO_MAXIMIZED_SERP_NAVIGATION);
+                ExitExpandedTo.MAXIMIZED_SERP_NAVIGATION);
         EXIT_EXPANDED_TO_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
     }
 
@@ -398,21 +524,21 @@
     static {
         Map<StateChangeKey, Integer> codes = new HashMap<StateChangeKey, Integer>();
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.BACK_PRESS),
-                EXIT_MAXIMIZED_TO_CLOSED_BACK_PRESS);
+                ExitMaximizedTo.CLOSED_BACK_PRESS);
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.FLING),
-                EXIT_MAXIMIZED_TO_CLOSED_FLING);
+                ExitMaximizedTo.CLOSED_FLING);
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.TAB_PROMOTION),
-                EXIT_MAXIMIZED_TO_CLOSED_TAB_PROMOTION);
+                ExitMaximizedTo.CLOSED_TAB_PROMOTION);
         codes.put(new StateChangeKey(PanelState.CLOSED, StateChangeReason.SERP_NAVIGATION),
-                EXIT_MAXIMIZED_TO_CLOSED_SERP_NAVIGATION);
+                ExitMaximizedTo.CLOSED_SERP_NAVIGATION);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.SWIPE),
-                EXIT_MAXIMIZED_TO_PEEKED_SWIPE);
+                ExitMaximizedTo.PEEKED_SWIPE);
         codes.put(new StateChangeKey(PanelState.PEEKED, StateChangeReason.FLING),
-                EXIT_MAXIMIZED_TO_PEEKED_FLING);
+                ExitMaximizedTo.PEEKED_FLING);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.SWIPE),
-                EXIT_MAXIMIZED_TO_EXPANDED_SWIPE);
+                ExitMaximizedTo.EXPANDED_SWIPE);
         codes.put(new StateChangeKey(PanelState.EXPANDED, StateChangeReason.FLING),
-                EXIT_MAXIMIZED_TO_EXPANDED_FLING);
+                ExitMaximizedTo.EXPANDED_FLING);
         EXIT_MAXIMIZED_TO_STATE_CHANGE_CODES = Collections.unmodifiableMap(codes);
     }
 
@@ -423,10 +549,12 @@
         final boolean unseen = false;
         final boolean seen = true;
         Map<Pair<Boolean, Boolean>, Integer> codes = new HashMap<Pair<Boolean, Boolean>, Integer>();
-        codes.put(new Pair<Boolean, Boolean>(seen, TAP), RESULTS_SEEN_FROM_TAP);
-        codes.put(new Pair<Boolean, Boolean>(unseen, TAP), RESULTS_NOT_SEEN_FROM_TAP);
-        codes.put(new Pair<Boolean, Boolean>(seen, LONG_PRESS), RESULTS_SEEN_FROM_LONG_PRESS);
-        codes.put(new Pair<Boolean, Boolean>(unseen, LONG_PRESS), RESULTS_NOT_SEEN_FROM_LONG_PRESS);
+        codes.put(new Pair<Boolean, Boolean>(seen, TAP), ResultsByGesture.SEEN_FROM_TAP);
+        codes.put(new Pair<Boolean, Boolean>(unseen, TAP), ResultsByGesture.NOT_SEEN_FROM_TAP);
+        codes.put(new Pair<Boolean, Boolean>(seen, LONG_PRESS),
+                ResultsByGesture.SEEN_FROM_LONG_PRESS);
+        codes.put(new Pair<Boolean, Boolean>(unseen, LONG_PRESS),
+                ResultsByGesture.NOT_SEEN_FROM_LONG_PRESS);
         SEEN_BY_GESTURE_CODES = Collections.unmodifiableMap(codes);
     }
 
@@ -435,16 +563,16 @@
     static {
         Map<Pair<Integer, Boolean>, Integer> codes =
                 new HashMap<Pair<Integer, Boolean>, Integer>();
-        codes.put(new Pair<Integer, Boolean>(PREFERENCE_ENABLED, TAP), PROMO_ENABLED_FROM_TAP);
-        codes.put(new Pair<Integer, Boolean>(PREFERENCE_DISABLED, TAP), PROMO_DISABLED_FROM_TAP);
-        codes.put(new Pair<Integer, Boolean>(PREFERENCE_UNINITIALIZED, TAP),
-                PROMO_UNDECIDED_FROM_TAP);
-        codes.put(new Pair<Integer, Boolean>(PREFERENCE_ENABLED, LONG_PRESS),
-                PROMO_ENABLED_FROM_LONG_PRESS);
-        codes.put(new Pair<Integer, Boolean>(PREFERENCE_DISABLED, LONG_PRESS),
-                PROMO_DISABLED_FROM_LONG_PRESS);
-        codes.put(new Pair<Integer, Boolean>(PREFERENCE_UNINITIALIZED, LONG_PRESS),
-                PROMO_UNDECIDED_FROM_LONG_PRESS);
+        codes.put(new Pair<Integer, Boolean>(Preference.ENABLED, TAP), Promo.ENABLED_FROM_TAP);
+        codes.put(new Pair<Integer, Boolean>(Preference.DISABLED, TAP), Promo.DISABLED_FROM_TAP);
+        codes.put(new Pair<Integer, Boolean>(Preference.UNINITIALIZED, TAP),
+                Promo.UNDECIDED_FROM_TAP);
+        codes.put(new Pair<Integer, Boolean>(Preference.ENABLED, LONG_PRESS),
+                Promo.ENABLED_FROM_LONG_PRESS);
+        codes.put(new Pair<Integer, Boolean>(Preference.DISABLED, LONG_PRESS),
+                Promo.DISABLED_FROM_LONG_PRESS);
+        codes.put(new Pair<Integer, Boolean>(Preference.UNINITIALIZED, LONG_PRESS),
+                Promo.UNDECIDED_FROM_LONG_PRESS);
         PROMO_BY_GESTURE_CODES = Collections.unmodifiableMap(codes);
     }
 
@@ -455,7 +583,7 @@
      */
     public static void logPreferenceState() {
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchPreferenceState",
-                getPreferenceValue(), PREFERENCE_HISTOGRAM_BOUNDARY);
+                getPreferenceValue(), Preference.NUM_ENTRIES);
     }
 
     /**
@@ -529,7 +657,8 @@
      */
     public static void logSearchTermResolvedWords(boolean isSingleWord) {
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchResolvedTermWords",
-                isSingleWord ? RESOLVED_SINGLE_WORD : RESOLVED_MULTI_WORD, RESOLVED_BOUNDARY);
+                isSingleWord ? ResolvedGranularity.SINGLE_WORD : ResolvedGranularity.MULTI_WORD,
+                ResolvedGranularity.NUM_ENTRIES);
     }
 
     /**
@@ -539,7 +668,7 @@
      */
     public static void logBasePageProtocol(boolean isHttpBasePage) {
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchBasePageProtocol",
-                isHttpBasePage ? PROTOCOL_IS_HTTP : PROTOCOL_NOT_HTTP, PROTOCOL_BOUNDARY);
+                isHttpBasePage ? Protocol.IS_HTTP : Protocol.NOT_HTTP, Protocol.NUM_ENTRIES);
     }
 
     /**
@@ -549,7 +678,7 @@
      */
     public static void logPreferenceChange(boolean enabled) {
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchPreferenceStateChange",
-                enabled ? PREFERENCE_ENABLED : PREFERENCE_DISABLED, PREFERENCE_HISTOGRAM_BOUNDARY);
+                enabled ? Preference.ENABLED : Preference.DISABLED, Preference.NUM_ENTRIES);
     }
 
     /**
@@ -561,17 +690,17 @@
     public static void logPromoOutcome(boolean wasTap, boolean wasMandatory) {
         int preferenceCode = getPreferenceValue();
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchFirstRunFlowOutcome",
-                preferenceCode, PREFERENCE_HISTOGRAM_BOUNDARY);
+                preferenceCode, Preference.NUM_ENTRIES);
 
         int preferenceByGestureCode = getPromoByGestureStateCode(preferenceCode, wasTap);
         if (wasMandatory) {
             RecordHistogram.recordEnumeratedHistogram(
                     "Search.ContextualSearchMandatoryPromoOutcomeByGesture",
-                    preferenceByGestureCode, PROMO_BY_GESTURE_BOUNDARY);
+                    preferenceByGestureCode, Promo.NUM_ENTRIES);
         } else {
             RecordHistogram.recordEnumeratedHistogram(
-                    "Search.ContextualSearchPromoOutcomeByGesture",
-                    preferenceByGestureCode, PROMO_BY_GESTURE_BOUNDARY);
+                    "Search.ContextualSearchPromoOutcomeByGesture", preferenceByGestureCode,
+                    Promo.NUM_ENTRIES);
         }
     }
 
@@ -678,7 +807,7 @@
      */
     public static void logPromoSeen(boolean wasPanelSeen, boolean wasTap) {
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchFirstRunPanelSeen",
-                wasPanelSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
+                wasPanelSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
         logHistogramByGesture(wasPanelSeen, wasTap, "Search.ContextualSearchPromoSeenByGesture");
     }
 
@@ -690,7 +819,7 @@
      */
     public static void logResultsSeen(boolean wasPanelSeen, boolean wasTap) {
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchResultsSeen",
-                wasPanelSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
+                wasPanelSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
         logHistogramByGesture(wasPanelSeen, wasTap, "Search.ContextualSearchResultsSeenByGesture");
     }
 
@@ -724,7 +853,7 @@
             boolean wasPanelSeen, boolean wasTap, boolean wasBarOverlap) {
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchBarOverlapSeen",
                 getBarOverlapEnum(wasBarOverlap, wasPanelSeen, wasTap),
-                BAR_OVERLAP_RESULTS_BOUNDARY);
+                BarOverlapResults.NUM_ENTRIES);
     }
 
     /**
@@ -820,12 +949,12 @@
     public static void logTapDurationSeen(boolean wasSearchContentViewSeen, boolean isTapShort) {
         if (isTapShort) {
             RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapShortDurationSeen",
-                    wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN,
-                    RESULTS_SEEN_BOUNDARY);
+                    wasSearchContentViewSeen ? Results.SEEN : Results.NOT_SEEN,
+                    Results.NUM_ENTRIES);
         } else {
             RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapLongDurationSeen",
-                    wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN,
-                    RESULTS_SEEN_BOUNDARY);
+                    wasSearchContentViewSeen ? Results.SEEN : Results.NOT_SEEN,
+                    Results.NUM_ENTRIES);
         }
     }
 
@@ -860,7 +989,7 @@
 
         // We just record CTR of short words.
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapShortWordSeen",
-                wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
+                wasSearchContentViewSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
     }
 
     /**
@@ -873,7 +1002,7 @@
         if (!isTapOnLongWord) return;
 
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapLongWordSeen",
-                wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
+                wasSearchContentViewSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
     }
 
     /**
@@ -887,7 +1016,7 @@
 
         // We just record CTR of words tapped in the "middle".
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchTapOnWordMiddleSeen",
-                wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
+                wasSearchContentViewSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
     }
 
     /**
@@ -900,8 +1029,8 @@
         if (isWordAnEntity) {
             // We just record CTR of probable entity words.
             RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchEntitySeen",
-                    wasSearchContentViewSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN,
-                    RESULTS_SEEN_BOUNDARY);
+                    wasSearchContentViewSeen ? Results.SEEN : Results.NOT_SEEN,
+                    Results.NUM_ENTRIES);
         }
     }
 
@@ -915,17 +1044,18 @@
             boolean wasAnySuppressionHeuristicSatisfied) {
         int code;
         if (wasAnySuppressionHeuristicSatisfied) {
-            code = wasSearchContentViewSeen ? RESULTS_SEEN_SUPPRESSION_HEURSTIC_SATISFIED
-                    : RESULTS_NOT_SEEN_SUPPRESSION_HEURSTIC_SATISFIED;
+            code = wasSearchContentViewSeen
+                    ? ResultsBySuppression.SEEN_SUPPRESSION_HEURSTIC_SATISFIED
+                    : ResultsBySuppression.NOT_SEEN_SUPPRESSION_HEURSTIC_SATISFIED;
         } else {
-            code = wasSearchContentViewSeen ? RESULTS_SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED
-                    : RESULTS_NOT_SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED;
+            code = wasSearchContentViewSeen
+                    ? ResultsBySuppression.SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED
+                    : ResultsBySuppression.NOT_SEEN_SUPPRESSION_HEURSTIC_NOT_SATISFIED;
         }
 
         RecordHistogram.recordEnumeratedHistogram(
-                "Search.ContextualSearchTapSuppressionSeen.AnyHeuristicSatisfied",
-                code,
-                RESULTS_SEEN_SUPPRESSION_BOUNDARY);
+                "Search.ContextualSearchTapSuppressionSeen.AnyHeuristicSatisfied", code,
+                ResultsBySuppression.NUM_ENTRIES);
     }
 
     /**
@@ -934,7 +1064,7 @@
      */
     public static void logSelectionIsValid(boolean isSelectionValid) {
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchSelectionValid",
-                isSelectionValid ? SELECTION_VALID : SELECTION_INVALID, SELECTION_BOUNDARY);
+                isSelectionValid ? Selection.VALID : Selection.INVALID, Selection.NUM_ENTRIES);
     }
 
     /**
@@ -944,7 +1074,7 @@
     public static void logNormalPrioritySearchRequestOutcome(boolean isFailure) {
         RecordHistogram.recordEnumeratedHistogram(
                 "Search.ContextualSearchNormalPrioritySearchRequestStatus",
-                isFailure ? REQUEST_FAILED : REQUEST_NOT_FAILED, REQUEST_BOUNDARY);
+                isFailure ? Request.FAILED : Request.NOT_FAILED, Request.NUM_ENTRIES);
     }
 
     /**
@@ -954,7 +1084,7 @@
     public static void logLowPrioritySearchRequestOutcome(boolean isFailure) {
         RecordHistogram.recordEnumeratedHistogram(
                 "Search.ContextualSearchLowPrioritySearchRequestStatus",
-                isFailure ? REQUEST_FAILED : REQUEST_NOT_FAILED, REQUEST_BOUNDARY);
+                isFailure ? Request.FAILED : Request.NOT_FAILED, Request.NUM_ENTRIES);
     }
 
     /**
@@ -964,7 +1094,7 @@
     public static void logFallbackSearchRequestOutcome(boolean isFailure) {
         RecordHistogram.recordEnumeratedHistogram(
                 "Search.ContextualSearchFallbackSearchRequestStatus",
-                isFailure ? REQUEST_FAILED : REQUEST_NOT_FAILED, REQUEST_BOUNDARY);
+                isFailure ? Request.FAILED : Request.NOT_FAILED, Request.NUM_ENTRIES);
     }
 
     /**
@@ -1007,7 +1137,7 @@
             boolean wasSearchContentViewSeen, boolean didActivate, boolean didAnswer) {
         RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchQuickAnswerSeen",
                 getQuickAnswerSeenValue(didActivate, didAnswer, wasSearchContentViewSeen),
-                QUICK_ANSWER_SEEN_BOUNDARY);
+                QuickAnswerSeen.NUM_ENTRIES);
     }
 
     /**
@@ -1021,32 +1151,28 @@
         int code;
         switch (toState) {
             case CLOSED:
-                code = getStateChangeCode(fromState, reason,
-                        ENTER_CLOSED_STATE_CHANGE_CODES, ENTER_CLOSED_FROM_OTHER);
+                code = getStateChangeCode(
+                        fromState, reason, ENTER_CLOSED_STATE_CHANGE_CODES, EnterClosedFrom.OTHER);
                 RecordHistogram.recordEnumeratedHistogram(
-                        "Search.ContextualSearchEnterClosed",
-                        code, ENTER_CLOSED_FROM_BOUNDARY);
+                        "Search.ContextualSearchEnterClosed", code, EnterClosedFrom.NUM_ENTRIES);
                 break;
             case PEEKED:
-                code = getStateChangeCode(fromState, reason,
-                        ENTER_PEEKED_STATE_CHANGE_CODES, ENTER_PEEKED_FROM_OTHER);
+                code = getStateChangeCode(
+                        fromState, reason, ENTER_PEEKED_STATE_CHANGE_CODES, EnterPeekedFrom.OTHER);
                 RecordHistogram.recordEnumeratedHistogram(
-                        "Search.ContextualSearchEnterPeeked",
-                        code, ENTER_PEEKED_FROM_BOUNDARY);
+                        "Search.ContextualSearchEnterPeeked", code, EnterPeekedFrom.NUM_ENTRIES);
                 break;
             case EXPANDED:
-                code = getStateChangeCode(fromState, reason,
-                        ENTER_EXPANDED_STATE_CHANGE_CODES, ENTER_EXPANDED_FROM_OTHER);
-                RecordHistogram.recordEnumeratedHistogram(
-                        "Search.ContextualSearchEnterExpanded",
-                        code, ENTER_EXPANDED_FROM_BOUNDARY);
+                code = getStateChangeCode(fromState, reason, ENTER_EXPANDED_STATE_CHANGE_CODES,
+                        EnterExpandedFrom.OTHER);
+                RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchEnterExpanded",
+                        code, EnterExpandedFrom.NUM_ENTRIES);
                 break;
             case MAXIMIZED:
-                code = getStateChangeCode(fromState, reason,
-                        ENTER_MAXIMIZED_STATE_CHANGE_CODES, ENTER_MAXIMIZED_FROM_OTHER);
-                RecordHistogram.recordEnumeratedHistogram(
-                        "Search.ContextualSearchEnterMaximized",
-                        code, ENTER_MAXIMIZED_FROM_BOUNDARY);
+                code = getStateChangeCode(fromState, reason, ENTER_MAXIMIZED_STATE_CHANGE_CODES,
+                        EnterMaximizedFrom.OTHER);
+                RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchEnterMaximized",
+                        code, EnterMaximizedFrom.NUM_ENTRIES);
                 break;
             default:
                 break;
@@ -1121,28 +1247,28 @@
         switch (fromState) {
             case UNDEFINED:
             case CLOSED:
-                code = getStateChangeCode(toState, reason,
-                        EXIT_CLOSED_TO_STATE_CHANGE_CODES, EXIT_CLOSED_TO_OTHER);
+                code = getStateChangeCode(
+                        toState, reason, EXIT_CLOSED_TO_STATE_CHANGE_CODES, ExitClosedTo.OTHER);
                 RecordHistogram.recordEnumeratedHistogram(
-                        "Search.ContextualSearchExitClosed", code, EXIT_CLOSED_TO_BOUNDARY);
+                        "Search.ContextualSearchExitClosed", code, ExitClosedTo.NUM_ENTRIES);
                 break;
             case PEEKED:
-                code = getStateChangeCode(toState, reason,
-                        EXIT_PEEKED_TO_STATE_CHANGE_CODES, EXIT_PEEKED_TO_OTHER);
+                code = getStateChangeCode(
+                        toState, reason, EXIT_PEEKED_TO_STATE_CHANGE_CODES, ExitPeekedTo.OTHER);
                 RecordHistogram.recordEnumeratedHistogram(
-                        "Search.ContextualSearchExitPeeked", code, EXIT_PEEKED_TO_BOUNDARY);
+                        "Search.ContextualSearchExitPeeked", code, ExitPeekedTo.NUM_ENTRIES);
                 break;
             case EXPANDED:
-                code = getStateChangeCode(toState, reason,
-                        EXIT_EXPANDED_TO_STATE_CHANGE_CODES, EXIT_EXPANDED_TO_OTHER);
+                code = getStateChangeCode(
+                        toState, reason, EXIT_EXPANDED_TO_STATE_CHANGE_CODES, ExitExpandedTo.OTHER);
                 RecordHistogram.recordEnumeratedHistogram(
-                        "Search.ContextualSearchExitExpanded", code, EXIT_EXPANDED_TO_BOUNDARY);
+                        "Search.ContextualSearchExitExpanded", code, ExitExpandedTo.NUM_ENTRIES);
                 break;
             case MAXIMIZED:
-                code = getStateChangeCode(toState, reason,
-                        EXIT_MAXIMIZED_TO_STATE_CHANGE_CODES, EXIT_MAXIMIZED_TO_OTHER);
+                code = getStateChangeCode(toState, reason, EXIT_MAXIMIZED_TO_STATE_CHANGE_CODES,
+                        ExitMaximizedTo.OTHER);
                 RecordHistogram.recordEnumeratedHistogram(
-                        "Search.ContextualSearchExitMaximized", code, EXIT_MAXIMIZED_TO_BOUNDARY);
+                        "Search.ContextualSearchExitMaximized", code, ExitMaximizedTo.NUM_ENTRIES);
                 break;
             default:
                 break;
@@ -1181,35 +1307,25 @@
      * @param wasTap Whether the gesture was a Tap.
      * @return The value for the enum histogram.
      */
-    private static int getBarOverlapEnum(
+    private static @BarOverlapResults int getBarOverlapEnum(
             boolean didBarOverlap, boolean wasPanelSeen, boolean wasTap) {
         if (wasTap) {
             if (didBarOverlap) {
-                if (wasPanelSeen) {
-                    return BAR_OVERLAP_RESULTS_SEEN_FROM_TAP;
-                } else {
-                    return BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP;
-                }
+                return wasPanelSeen ? BarOverlapResults.BAR_OVERLAP_RESULTS_SEEN_FROM_TAP
+                                    : BarOverlapResults.BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP;
             } else {
-                if (wasPanelSeen) {
-                    return NO_BAR_OVERLAP_RESULTS_SEEN_FROM_TAP;
-                } else {
-                    return NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP;
-                }
+                return wasPanelSeen ? BarOverlapResults.NO_BAR_OVERLAP_RESULTS_SEEN_FROM_TAP
+                                    : BarOverlapResults.NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_TAP;
             }
         } else {
             if (didBarOverlap) {
-                if (wasPanelSeen) {
-                    return BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS;
-                } else {
-                    return BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS;
-                }
+                return wasPanelSeen
+                        ? BarOverlapResults.BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS
+                        : BarOverlapResults.BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS;
             } else {
-                if (wasPanelSeen) {
-                    return NO_BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS;
-                } else {
-                    return NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS;
-                }
+                return wasPanelSeen
+                        ? BarOverlapResults.NO_BAR_OVERLAP_RESULTS_SEEN_FROM_LONG_PRESS
+                        : BarOverlapResults.NO_BAR_OVERLAP_RESULTS_NOT_SEEN_FROM_LONG_PRESS;
             }
         }
     }
@@ -1220,9 +1336,9 @@
      * @param didForceTranslate Whether the translation onebox was forced.
      */
     public static void logTranslateOnebox(boolean didForceTranslate) {
-        int code = didForceTranslate ? DID_FORCE_TRANSLATE : WOULD_FORCE_TRANSLATE;
+        int code = didForceTranslate ? ForceTranslate.DID_FORCE : ForceTranslate.WOULD_FORCE;
         RecordHistogram.recordEnumeratedHistogram(
-                "Search.ContextualSearchShouldTranslate", code, FORCE_TRANSLATE_BOUNDARY);
+                "Search.ContextualSearchShouldTranslate", code, ForceTranslate.NUM_ENTRIES);
     }
 
     /**
@@ -1251,7 +1367,7 @@
     public static void logContextualCardsResultsSeen(boolean wasSeen) {
         RecordHistogram.recordEnumeratedHistogram(
                 "Search.ContextualSearchContextualCardsIntegration.ResultsSeen",
-                wasSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
+                wasSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
     }
 
     /**
@@ -1261,13 +1377,14 @@
      */
     public static void logQuickActionIntentResolution(int quickActionCategory,
             int numMatchingAppsApps) {
-        int code = numMatchingAppsApps == 0 ? QUICK_ACTION_RESOLVE_FAILED
-                : numMatchingAppsApps == 1 ? QUICK_ACTION_RESOLVE_SINGLE
-                        : QUICK_ACTION_RESOLVE_MULTIPLE;
+        int code = numMatchingAppsApps == 0
+                ? QuickActionResolve.FAILED
+                : numMatchingAppsApps == 1 ? QuickActionResolve.SINGLE
+                                           : QuickActionResolve.MULTIPLE;
         RecordHistogram.recordEnumeratedHistogram(
                 "Search.ContextualSearchQuickActions.IntentResolution."
                         + getLabelForQuickActionCategory(quickActionCategory),
-                code, QUICK_ACTION_RESOLVE_BOUNDARY);
+                code, QuickActionResolve.NUM_ENTRIES);
     }
 
     /**
@@ -1281,8 +1398,8 @@
                 "Search.ContextualSearchQuickActions.Shown", quickActionShown);
         if (quickActionShown) {
             RecordHistogram.recordEnumeratedHistogram(
-                    "Search.ContextualSearchQuickActions.Category",
-                    quickActionCategory, QuickActionCategory.BOUNDARY);
+                    "Search.ContextualSearchQuickActions.Category", quickActionCategory,
+                    QuickActionResolve.NUM_ENTRIES);
         }
     }
 
@@ -1292,10 +1409,9 @@
      * @param quickActionCategory The {@link QuickActionCategory} for the quick action.
      */
     public static void logQuickActionResultsSeen(boolean wasSeen, int quickActionCategory) {
-        RecordHistogram.recordEnumeratedHistogram(
-                "Search.ContextualSearchQuickActions.ResultsSeen."
+        RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchQuickActions.ResultsSeen."
                         + getLabelForQuickActionCategory(quickActionCategory),
-                wasSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
+                wasSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
     }
 
     /**
@@ -1322,11 +1438,11 @@
         if (predictionKind == AssistRankerPrediction.SHOW) {
             RecordHistogram.recordEnumeratedHistogram(
                     "Search.ContextualSearch.Ranker.NotSuppressed.ResultsSeen",
-                    wasPanelSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
+                    wasPanelSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
         } else if (predictionKind == AssistRankerPrediction.SUPPRESS) {
             RecordHistogram.recordEnumeratedHistogram(
                     "Search.ContextualSearch.Ranker.WouldSuppress.ResultsSeen",
-                    wasPanelSeen ? RESULTS_SEEN : RESULTS_NOT_SEEN, RESULTS_SEEN_BOUNDARY);
+                    wasPanelSeen ? Results.SEEN : Results.NOT_SEEN, Results.NUM_ENTRIES);
         }
     }
 
@@ -1414,11 +1530,11 @@
     private static int getPreferenceValue() {
         PrefServiceBridge preferences = PrefServiceBridge.getInstance();
         if (preferences.isContextualSearchUninitialized()) {
-            return PREFERENCE_UNINITIALIZED;
+            return Preference.UNINITIALIZED;
         } else if (preferences.isContextualSearchDisabled()) {
-            return PREFERENCE_DISABLED;
+            return Preference.DISABLED;
         }
-        return PREFERENCE_ENABLED;
+        return Preference.ENABLED;
     }
 
     /**
@@ -1428,27 +1544,21 @@
      * @param wasSeen Whether the search panel was opened.
      * @return The encoded value.
      */
-    private static int getQuickAnswerSeenValue(
+    private static @QuickAnswerSeen int getQuickAnswerSeenValue(
             boolean didActivate, boolean didAnswer, boolean wasSeen) {
         if (wasSeen) {
             if (didActivate) {
-                if (didAnswer) {
-                    return QUICK_ANSWER_ACTIVATED_WAS_AN_ANSWER_SEEN;
-                } else {
-                    return QUICK_ANSWER_ACTIVATED_NOT_AN_ANSWER_SEEN;
-                }
+                return didAnswer ? QuickAnswerSeen.ACTIVATED_WAS_AN_ANSWER_SEEN
+                                 : QuickAnswerSeen.ACTIVATED_NOT_AN_ANSWER_SEEN;
             } else {
-                return QUICK_ANSWER_NOT_ACTIVATED_SEEN;
+                return QuickAnswerSeen.NOT_ACTIVATED_SEEN;
             }
         } else {
             if (didActivate) {
-                if (didAnswer) {
-                    return QUICK_ANSWER_ACTIVATED_WAS_AN_ANSWER_NOT_SEEN;
-                } else {
-                    return QUICK_ANSWER_ACTIVATED_NOT_AN_ANSWER_NOT_SEEN;
-                }
+                return didAnswer ? QuickAnswerSeen.ACTIVATED_WAS_AN_ANSWER_NOT_SEEN
+                                 : QuickAnswerSeen.ACTIVATED_NOT_AN_ANSWER_NOT_SEEN;
             } else {
-                return QUICK_ANSWER_NOT_ACTIVATED_NOT_SEEN;
+                return QuickAnswerSeen.NOT_ACTIVATED_NOT_SEEN;
             }
         }
     }
@@ -1462,8 +1572,7 @@
     private static void logHistogramByGesture(boolean wasPanelSeen, boolean wasTap,
             String histogramName) {
         RecordHistogram.recordEnumeratedHistogram(histogramName,
-                getPanelSeenByGestureStateCode(wasPanelSeen, wasTap),
-                RESULTS_BY_GESTURE_BOUNDARY);
+                getPanelSeenByGestureStateCode(wasPanelSeen, wasTap), ResultsByGesture.NUM_ENTRIES);
     }
 
     private static String getLabelForQuickActionCategory(int quickActionCategory) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMediaParserBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMediaParserBridge.java
new file mode 100644
index 0000000..4413b87a
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMediaParserBridge.java
@@ -0,0 +1,48 @@
+// 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.
+
+package org.chromium.chrome.browser.download;
+
+import org.chromium.base.Callback;
+
+/**
+ * A JNI bridge that owns a native side DownloadMediaParser, which parses media file safely in an
+ * utility process.
+ */
+public class DownloadMediaParserBridge {
+    private long mNativeDownloadMediaParserBridge;
+
+    public DownloadMediaParserBridge() {
+        mNativeDownloadMediaParserBridge = nativeInit();
+    }
+
+    /**
+     * Destroys the native object of DownloadMediaParser. This will result in the utility process
+     * being destroyed.
+     */
+    public void destory() {
+        nativeDestory(mNativeDownloadMediaParserBridge);
+        mNativeDownloadMediaParserBridge = 0;
+    }
+
+    /**
+     * Parses a media file to retrieve media metadata and video thumbnail.
+     * @param mimeType The mime type of the media file.
+     * @param filePath The absolute path of the media file.
+     * @param totalSize Total size of the media file.
+     * @param callback Callback to get the result.
+     */
+    public void parseMediaFile(
+            String mimeType, String filePath, long totalSize, Callback<Boolean> callback) {
+        if (mNativeDownloadMediaParserBridge != 0) {
+            nativeParseMediaFile(
+                    mNativeDownloadMediaParserBridge, mimeType, filePath, totalSize, callback);
+        }
+    }
+
+    private native long nativeInit();
+    private native void nativeDestory(long nativeDownloadMediaParserBridge);
+    private native void nativeParseMediaFile(long nativeDownloadMediaParserBridge, String mimeType,
+            String filePath, long totalSize, Callback<Boolean> callback);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorController.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorController.java
index ef1f356c..b38af80 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorController.java
@@ -18,6 +18,7 @@
 
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.ContextUtils;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
@@ -46,6 +47,8 @@
 
     private static final int DURATION_MS = 10000;
 
+    private static boolean sSkipSystemCheckForTesting = false;
+
     @SuppressLint("StaticFieldLeak")
     private static OfflineIndicatorController sInstance;
 
@@ -120,6 +123,8 @@
      */
     @TargetApi(Build.VERSION_CODES.M)
     private boolean performSystemCheckForValidatedNetwork() {
+        if (sSkipSystemCheckForTesting) return false;
+
         // NetworkCapabilities.NET_CAPABILITY_VALIDATED is only available on Marshmallow and
         // later versions.
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return false;
@@ -200,4 +205,9 @@
         if (!mIsShowingOfflineIndicator) return;
         snackbarManager.dismissSnackbars(this);
     }
+
+    @VisibleForTesting
+    static void skipSystemCheckForTesting() {
+        sSkipSystemCheckForTesting = true;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarCoordinator.java
index 2ec9676..ee1f40f4b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarCoordinator.java
@@ -143,6 +143,10 @@
         mMediator.setToolbarSwipeLayout(layout);
     }
 
+    public View getMenuButton() {
+        return mMenuButton.getMenuButton();
+    }
+
     /**
      * Clean up any state when the bottom toolbar is destroyed.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
index 55b962f1..71b036d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/MenuButton.java
@@ -54,4 +54,8 @@
     boolean isShowingAppMenuUpdateBadge() {
         return mUpdateBadgeView.getVisibility() == View.VISIBLE;
     }
+
+    View getMenuButton() {
+        return mMenuButtonView;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
index 063301d..6751eee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarLayout.java
@@ -41,6 +41,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.util.ViewUtils;
 import org.chromium.chrome.browser.widget.PulseDrawable;
 import org.chromium.chrome.browser.widget.ScrimView;
@@ -155,6 +156,12 @@
         mMenuButton = (TintedImageButton) findViewById(R.id.menu_button);
         mMenuBadge = (ImageView) findViewById(R.id.menu_badge);
         mMenuButtonWrapper = findViewById(R.id.menu_button_wrapper);
+        if (FeatureUtilities.isBottomToolbarEnabled()) {
+            UiUtils.removeViewFromParent(mMenuButtonWrapper);
+            mMenuButtonWrapper = null;
+            mMenuButton = null;
+            mMenuBadge = null;
+        }
 
         // Initialize the provider to an empty version to avoid null checking everywhere.
         mToolbarDataProvider = new ToolbarDataProvider() {
@@ -271,8 +278,10 @@
 
         mAppMenuButtonHelper = appMenuButtonHelper;
 
-        mMenuButton.setOnTouchListener(mAppMenuButtonHelper);
-        mMenuButton.setAccessibilityDelegate(mAppMenuButtonHelper);
+        if (mMenuButton != null) {
+            mMenuButton.setOnTouchListener(mAppMenuButtonHelper);
+            mMenuButton.setAccessibilityDelegate(mAppMenuButtonHelper);
+        }
     }
 
     /** Notified that the menu was shown. */
@@ -818,6 +827,7 @@
 
     @Override
     public void removeAppMenuUpdateBadge(boolean animate) {
+        if (mMenuBadge == null) return;
         boolean wasShowingMenuBadge = mShowMenuBadge;
         mShowMenuBadge = false;
         setMenuButtonContentDescription(false);
@@ -876,6 +886,7 @@
      * bitmap.
      */
     protected void setAppMenuUpdateBadgeToVisible(boolean animate) {
+        if (mMenuBadge == null || mMenuButton == null) return;
         setMenuButtonContentDescription(true);
         if (!animate || mIsMenuBadgeAnimationRunning) {
             mMenuBadge.setVisibility(View.VISIBLE);
@@ -920,6 +931,7 @@
      * @param useLightDrawable Whether the light drawable should be used.
      */
     protected void setAppMenuUpdateBadgeDrawable(boolean useLightDrawable) {
+        if (mMenuBadge == null) return;
         mMenuBadge.setImageResource(useLightDrawable ? R.drawable.badge_update_light
                 : R.drawable.badge_update_dark);
     }
@@ -931,7 +943,7 @@
      */
     protected void setMenuButtonHighlightDrawable(boolean highlighting) {
         // Return if onFinishInflate didn't finish
-        if (mMenuButtonWrapper == null) return;
+        if (mMenuButtonWrapper == null || mMenuButton == null) return;
 
         if (highlighting) {
             if (mHighlightDrawable == null) {
@@ -953,6 +965,7 @@
      * @param isUpdateBadgeVisible Whether the update menu badge is visible.
      */
     protected void setMenuButtonContentDescription(boolean isUpdateBadgeVisible) {
+        if (mMenuButton == null) return;
         if (isUpdateBadgeVisible) {
             mMenuButton.setContentDescription(getResources().getString(
                     R.string.accessibility_toolbar_btn_menu_update));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index d1c8fff..b0508ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -866,6 +866,8 @@
      * @return The view containing the pop up menu button.
      */
     public View getMenuButton() {
+        if (mBottomToolbarCoordinator != null) return mBottomToolbarCoordinator.getMenuButton();
+
         return mToolbar.getMenuButton();
     }
 
@@ -1313,7 +1315,9 @@
         updateReloadState(tabCrashed);
         updateBookmarkButtonStatus();
 
-        mToolbar.getMenuButtonWrapper().setVisibility(View.VISIBLE);
+        if (mToolbar.getMenuButtonWrapper() != null) {
+            mToolbar.getMenuButtonWrapper().setVisibility(View.VISIBLE);
+        }
     }
 
     private void updateBookmarkButtonStatus() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 29548c9..3b9e5be 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -83,6 +83,7 @@
 import org.chromium.chrome.browser.widget.newtab.NewTabButton;
 import org.chromium.chrome.browser.widget.textbubble.TextBubble;
 import org.chromium.components.feature_engagement.EventConstants;
+import org.chromium.ui.UiUtils;
 import org.chromium.ui.base.LocalizationUtils;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
 
@@ -375,6 +376,10 @@
             mToolbarButtonsContainer = (ViewGroup) findViewById(R.id.toolbar_buttons);
 
             mHomeButton = (TintedImageButton) findViewById(R.id.home_button);
+            if (FeatureUtilities.isBottomToolbarEnabled() && mHomeButton != null) {
+                UiUtils.removeViewFromParent(mHomeButton);
+                mHomeButton = null;
+            }
 
             mUrlBar = (TextView) findViewById(R.id.url_bar);
 
@@ -389,7 +394,7 @@
 
             setLayoutTransition(null);
 
-            getMenuButtonWrapper().setVisibility(View.VISIBLE);
+            if (getMenuButtonWrapper() != null) getMenuButtonWrapper().setVisibility(View.VISIBLE);
             inflateTabSwitchingResources();
 
             setWillNotDraw(false);
@@ -464,14 +469,19 @@
 
     private void inflateTabSwitchingResources() {
         mToggleTabStackButton = (ImageView) findViewById(R.id.tab_switcher_button);
-        mNewTabButton = (NewTabButton) findViewById(R.id.new_tab_button);
+        if (FeatureUtilities.isBottomToolbarEnabled()) {
+            UiUtils.removeViewFromParent(mToggleTabStackButton);
+            mToggleTabStackButton = null;
+        } else {
+            mToggleTabStackButton.setClickable(false);
+            mTabSwitcherButtonDrawable =
+                    TabSwitcherDrawable.createTabSwitcherDrawable(getContext(), false);
+            mTabSwitcherButtonDrawableLight =
+                    TabSwitcherDrawable.createTabSwitcherDrawable(getContext(), true);
+            mToggleTabStackButton.setImageDrawable(mTabSwitcherButtonDrawable);
+        }
 
-        mToggleTabStackButton.setClickable(false);
-        mTabSwitcherButtonDrawable =
-                TabSwitcherDrawable.createTabSwitcherDrawable(getContext(), false);
-        mTabSwitcherButtonDrawableLight =
-                TabSwitcherDrawable.createTabSwitcherDrawable(getContext(), true);
-        mToggleTabStackButton.setImageDrawable(mTabSwitcherButtonDrawable);
+        mNewTabButton = (NewTabButton) findViewById(R.id.new_tab_button);
         mTabSwitcherModeViews.add(mNewTabButton);
 
         // Ensure that the new tab button will not draw over the toolbar buttons if the
@@ -491,24 +501,26 @@
     }
 
     private void enableTabSwitchingResources() {
-        mToggleTabStackButton.setOnClickListener(this);
-        mToggleTabStackButton.setOnLongClickListener(this);
-        mToggleTabStackButton.setOnKeyListener(new KeyboardNavigationListener() {
-            @Override
-            public View getNextFocusForward() {
-                final TintedImageButton menuButton = getMenuButton();
-                if (menuButton != null && menuButton.isShown()) {
-                    return menuButton;
-                } else {
-                    return getCurrentTabView();
+        if (mToggleTabStackButton != null) {
+            mToggleTabStackButton.setOnClickListener(this);
+            mToggleTabStackButton.setOnLongClickListener(this);
+            mToggleTabStackButton.setOnKeyListener(new KeyboardNavigationListener() {
+                @Override
+                public View getNextFocusForward() {
+                    final TintedImageButton menuButton = getMenuButton();
+                    if (menuButton != null && menuButton.isShown()) {
+                        return menuButton;
+                    } else {
+                        return getCurrentTabView();
+                    }
                 }
-            }
 
-            @Override
-            public View getNextFocusBackward() {
-                return findViewById(R.id.url_bar);
-            }
-        });
+                @Override
+                public View getNextFocusBackward() {
+                    return findViewById(R.id.url_bar);
+                }
+            });
+        }
         mNewTabButton.setOnClickListener(this);
         mNewTabButton.setOnLongClickListener(this);
     }
@@ -535,22 +547,23 @@
             if (FeatureUtilities.isNewTabPageButtonEnabled()) changeIconToNTPIcon(mHomeButton);
         }
 
-        getMenuButton().setOnKeyListener(new KeyboardNavigationListener() {
-            @Override
-            public View getNextFocusForward() {
-                return getCurrentTabView();
-            }
+        if (getMenuButton() != null)
+            getMenuButton().setOnKeyListener(new KeyboardNavigationListener() {
+                @Override
+                public View getNextFocusForward() {
+                    return getCurrentTabView();
+                }
 
-            @Override
-            public View getNextFocusBackward() {
-                return mToggleTabStackButton;
-            }
+                @Override
+                public View getNextFocusBackward() {
+                    return mToggleTabStackButton;
+                }
 
-            @Override
-            protected boolean handleEnterKeyPress() {
-                return getMenuButtonHelper().onEnterKeyPress(getMenuButton());
-            }
-        });
+                @Override
+                protected boolean handleEnterKeyPress() {
+                    return getMenuButtonHelper().onEnterKeyPress(getMenuButton());
+                }
+            });
         onHomeButtonUpdate(HomepageManager.isHomepageEnabled());
 
         if (mLocationBar.useModernDesign()) mNewTabButton.setIsModern();
@@ -1399,9 +1412,9 @@
         }
 
         // Draw the menu button if necessary.
-        if (!mShowMenuBadge && mTabSwitcherAnimationMenuDrawable != null
+        final TintedImageButton menuButton = getMenuButton();
+        if (menuButton != null && !mShowMenuBadge && mTabSwitcherAnimationMenuDrawable != null
                 && mUrlExpansionPercent != 1f) {
-            final TintedImageButton menuButton = getMenuButton();
             mTabSwitcherAnimationMenuDrawable.setBounds(menuButton.getPaddingLeft(),
                     menuButton.getPaddingTop(),
                     menuButton.getWidth() - menuButton.getPaddingRight(),
@@ -1419,8 +1432,10 @@
         Drawable badgeDrawable = mUseLightDrawablesForTextureCapture
                 ? mTabSwitcherAnimationMenuBadgeLightDrawable
                         : mTabSwitcherAnimationMenuBadgeDarkDrawable;
-        if (mShowMenuBadge && badgeDrawable != null && mUrlExpansionPercent != 1f) {
-            final View menuBadge = getMenuBadge();
+
+        final View menuBadge = getMenuBadge();
+        if (menuBadge != null && mShowMenuBadge && badgeDrawable != null
+                && mUrlExpansionPercent != 1f) {
             badgeDrawable.setBounds(menuBadge.getPaddingLeft(), menuBadge.getPaddingTop(),
                     menuBadge.getWidth() - menuBadge.getPaddingRight(),
                     menuBadge.getHeight() - menuBadge.getPaddingBottom());
@@ -1791,7 +1806,9 @@
                 // This is to deal with the view going invisible when resuming the activity and
                 // running this animation.  The view is still there and clickable but does not
                 // render and only a layout triggers a refresh.  See crbug.com/306890.
-                if (!mToggleTabStackButton.isEnabled()) requestLayout();
+                if (mToggleTabStackButton != null && !mToggleTabStackButton.isEnabled()) {
+                    requestLayout();
+                }
             }
         });
 
@@ -1975,6 +1992,7 @@
      * switcher mode.
      */
     private void updateTabSwitcherButtonRipple() {
+        if (mToggleTabStackButton == null) return;
         if (mTabSwitcherState == ENTERING_TAB_SWITCHER) {
             mToggleTabStackButton.setBackgroundColor(
                     ApiCompatibilityUtils.getColor(getResources(), android.R.color.transparent));
@@ -2101,16 +2119,19 @@
         float toolbarButtonTranslationX = MathUtils.flipSignIf(
                 URL_FOCUS_TOOLBAR_BUTTONS_TRANSLATION_X_DP, isRtl) * density;
 
-        animator = ObjectAnimator.ofFloat(
-                getMenuButtonWrapper(), TRANSLATION_X, toolbarButtonTranslationX);
-        animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
-        animator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
-        animators.add(animator);
+        final View menuButtonWrapper = getMenuButtonWrapper();
+        if (menuButtonWrapper != null) {
+            animator = ObjectAnimator.ofFloat(
+                    menuButtonWrapper, TRANSLATION_X, toolbarButtonTranslationX);
+            animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
+            animator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
+            animators.add(animator);
 
-        animator = ObjectAnimator.ofFloat(getMenuButtonWrapper(), ALPHA, 0);
-        animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
-        animator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
-        animators.add(animator);
+            animator = ObjectAnimator.ofFloat(menuButtonWrapper, ALPHA, 0);
+            animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
+            animator.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
+            animators.add(animator);
+        }
 
         if (mToggleTabStackButton != null) {
             animator = ObjectAnimator.ofFloat(
@@ -2139,17 +2160,20 @@
         animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
         animators.add(animator);
 
-        animator = ObjectAnimator.ofFloat(getMenuButtonWrapper(), TRANSLATION_X, 0);
-        animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
-        animator.setStartDelay(URL_CLEAR_FOCUS_MENU_DELAY_MS);
-        animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
-        animators.add(animator);
+        final View menuButtonWrapper = getMenuButtonWrapper();
+        if (menuButtonWrapper != null) {
+            animator = ObjectAnimator.ofFloat(menuButtonWrapper, TRANSLATION_X, 0);
+            animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
+            animator.setStartDelay(URL_CLEAR_FOCUS_MENU_DELAY_MS);
+            animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+            animators.add(animator);
 
-        animator = ObjectAnimator.ofFloat(getMenuButtonWrapper(), ALPHA, 1);
-        animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
-        animator.setStartDelay(URL_CLEAR_FOCUS_MENU_DELAY_MS);
-        animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
-        animators.add(animator);
+            animator = ObjectAnimator.ofFloat(menuButtonWrapper, ALPHA, 1);
+            animator.setDuration(URL_FOCUS_TOOLBAR_BUTTONS_DURATION_MS);
+            animator.setStartDelay(URL_CLEAR_FOCUS_MENU_DELAY_MS);
+            animator.setInterpolator(BakedBezierInterpolator.TRANSFORM_CURVE);
+            animators.add(animator);
+        }
 
         if (mToggleTabStackButton != null) {
             animator = ObjectAnimator.ofFloat(mToggleTabStackButton, TRANSLATION_X, 0);
@@ -2644,7 +2668,10 @@
             }
         }
 
-        getMenuButton().setTint(mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
+        if (getMenuButton() != null) {
+            getMenuButton().setTint(mUseLightToolbarDrawables ? mLightModeTint : mDarkModeTint);
+        }
+
         if (mLocationBar.useModernDesign()) {
             updateModernLocationBarColor(getLocationBarColorForToolbarColor(currentPrimaryColor));
         }
@@ -2687,7 +2714,9 @@
             mNewTabButton.setContentDescription(newTabContentDescription);
         }
 
-        getMenuButtonWrapper().setVisibility(View.VISIBLE);
+        if (getMenuButtonWrapper() != null) {
+            getMenuButtonWrapper().setVisibility(View.VISIBLE);
+        }
 
         if (mLocationBar.useModernDesign()) {
             DrawableCompat.setTint(mLocationBarBackground,
@@ -2723,6 +2752,7 @@
 
     @Override
     public void showAppMenuUpdateBadge() {
+        if (getMenuBadge() == null) return;
         super.showAppMenuUpdateBadge();
 
         // Set up variables.
@@ -2745,6 +2775,7 @@
 
     @Override
     public void removeAppMenuUpdateBadge(boolean animate) {
+        if (getMenuBadge() == null) return;
         super.removeAppMenuUpdateBadge(animate);
 
         if (mBrowsingModeViews.contains(getMenuBadge())) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrAlertDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrAlertDialog.java
index 0d1b7ab..41f83c3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrAlertDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrAlertDialog.java
@@ -16,19 +16,15 @@
  * This class implements a VrAlertDialog which is similar to Android AlertDialog in VR.
  */
 public class VrAlertDialog extends AlertDialog {
-    private VrDialogManager mVrDialogManager;
     private ModalDialogManager mModalDialogManager;
     private ModalDialogView mModalDialogView;
-    private boolean mIsShowing;
     private CharSequence mMessage;
     private DialogButton mButtonPositive;
     private DialogButton mButtonNegative;
     protected View mView;
 
-    public VrAlertDialog(Context context, VrDialogManager vrDialogManager,
-            ModalDialogManager modalDialogManager) {
+    public VrAlertDialog(Context context, ModalDialogManager modalDialogManager) {
         super(context);
-        mVrDialogManager = vrDialogManager;
         mModalDialogManager = modalDialogManager;
     }
 
@@ -60,7 +56,6 @@
     public void show() {
         mModalDialogView = createView();
         mModalDialogManager.showDialog(mModalDialogView, ModalDialogManager.APP_MODAL);
-        mIsShowing = true;
     }
 
     /**
@@ -103,7 +98,6 @@
      */
     @Override
     public void dismiss() {
-        mIsShowing = false;
         mModalDialogManager.cancelDialog(mModalDialogView);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrFirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrFirstRunActivity.java
index b98b591..40fd1b2b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrFirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrFirstRunActivity.java
@@ -24,8 +24,6 @@
 
     private static final BooleanHistogramSample sFreNotCompleteBrowserHistogram =
             new BooleanHistogramSample("VRFreNotComplete.Browser");
-    private static final BooleanHistogramSample sFreNotCompleteAutopresentHistogram =
-            new BooleanHistogramSample("VRFreNotComplete.WebVRAutopresent");
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrIntentUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrIntentUtils.java
index 954db6e9..026b6a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrIntentUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrIntentUtils.java
@@ -124,4 +124,13 @@
         intent.removeCategory(DAYDREAM_CATEGORY);
         assert !isVrIntent(intent);
     }
+
+    /**
+     * Adds the necessary VR flags to an intent.
+     * @param intent The intent to add VR flags to.
+     * @return the intent with VR flags set.
+     */
+    public static Intent setupVrIntent(Intent intent) {
+        return VrShellDelegate.getVrClassesWrapper().setupVrIntent(intent);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
index ad32d5a5..2beeed4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellDelegate.java
@@ -18,7 +18,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.graphics.Color;
-import android.graphics.PointF;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
@@ -43,6 +42,7 @@
 import org.chromium.base.Log;
 import org.chromium.base.PackageUtils;
 import org.chromium.base.ThreadUtils;
+import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.library_loader.LibraryLoader;
@@ -64,7 +64,6 @@
 import org.chromium.content_public.browser.ScreenOrientationProvider;
 import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.display.DisplayAndroidManager;
-import org.chromium.ui.widget.UiWidgetFactory;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -208,8 +207,7 @@
 
     private static final List<VrModeObserver> sVrModeObservers = new ArrayList<>();
 
-    private UiWidgetFactory mUiWidgetFactoryBeforeEnterVr;
-
+    @VisibleForTesting
     protected boolean mTestWorkaroundDontCancelVrEntryOnResume;
 
     private long mNativeVrShellDelegate;
@@ -360,6 +358,10 @@
         sVrModeObservers.remove(observer);
     }
 
+    /**
+     * Immediately exits VR. If the user is in headset, they will see monoscopic UI while in the
+     * headset, so use with caution.
+     */
     public static void forceExitVrImmediately() {
         if (sInstance == null) return;
         sInstance.shutdownVr(true, true);
@@ -439,25 +441,6 @@
     }
 
     /**
-     * Returns the current {@VrSupportLevel}.
-     */
-    @CalledByNative
-    public static int getVrSupportLevel() {
-        if (sVrSupportLevel != null) return sVrSupportLevel;
-        VrClassesWrapper wrapper = getVrClassesWrapper();
-        if (wrapper == null) {
-            sVrSupportLevel = VrSupportLevel.VR_DISABLED;
-        } else if (!isVrCoreCompatible()) {
-            sVrSupportLevel = VrSupportLevel.VR_NEEDS_UPDATE;
-        } else if (wrapper.isDaydreamReadyDevice()) {
-            sVrSupportLevel = VrSupportLevel.VR_DAYDREAM;
-        } else {
-            sVrSupportLevel = VrSupportLevel.VR_CARDBOARD;
-        }
-        return sVrSupportLevel;
-    }
-
-    /**
      * If VR Shell is enabled, and the activity is supported, register with the Daydream
      * platform that this app would like to be launched in VR when the device enters VR.
      */
@@ -508,7 +491,7 @@
      * When the app is pausing we need to unregister with the Daydream platform to prevent this app
      * from being launched from the background when the device enters VR.
      */
-    public static void maybeUnregisterVrEntryHook(ChromeActivity activity) {
+    public static void maybeUnregisterVrEntryHook() {
         // Daydream is not supported on pre-N devices.
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return;
         if (sInstance != null) return; // Will be handled in onPause.
@@ -641,7 +624,7 @@
 
         VrShellDelegate instance = getInstance(activity);
         if (instance == null) return;
-        instance.onNewIntentWithNativeInternal(activity, intent);
+        instance.onNewVrIntent();
     }
 
     /**
@@ -717,28 +700,42 @@
         }
     }
 
+    /**
+     * See VrClassesWrapper#bootsToVr().
+     */
+    public static boolean bootsToVr() {
+        if (getVrClassesWrapper() == null) return false;
+        return getVrClassesWrapper().bootsToVr();
+    }
+
+    /**
+     * @return A Daydream Api instance, for interacting with Daydream platform features.
+     */
+    public static VrDaydreamApi getVrDaydreamApi() {
+        if (sVrDaydreamApi == null) {
+            if (getVrClassesWrapper() == null) return null;
+            sVrDaydreamApi = getVrClassesWrapper().createVrDaydreamApi();
+        }
+        return sVrDaydreamApi;
+    }
+
+    public static boolean isDaydreamReadyDevice() {
+        return getVrClassesWrapper() != null && getVrClassesWrapper().isDaydreamReadyDevice();
+    }
+
+    /**
+     * @return A helper class for creating VR-specific classes that may not be available at compile
+     * time.
+     */
+    /* package */ static VrClassesWrapper getVrClassesWrapper() {
+        if (sVrClassesWrapper == null) sVrClassesWrapper = createVrClassesWrapper();
+        return sVrClassesWrapper;
+    }
+
     /* package */ static boolean isVrModeEnabled(Activity activity) {
         return sVrModeEnabledActivitys.contains(activity);
     }
 
-    @CalledByNative
-    private static VrShellDelegate getInstance() {
-        Activity activity = ApplicationStatus.getLastTrackedFocusedActivity();
-        if (!(activity instanceof ChromeActivity)) return null;
-        return getInstance((ChromeActivity) activity);
-    }
-
-    private static VrShellDelegate getInstance(ChromeActivity activity) {
-        if (!LibraryLoader.getInstance().isInitialized()) return null;
-        if (activity == null || !activitySupportsPresentation(activity)) return null;
-        if (sInstance != null) return sInstance;
-        VrClassesWrapper wrapper = getVrClassesWrapper();
-        if (wrapper == null) return null;
-        ThreadUtils.assertOnUiThread();
-        sInstance = new VrShellDelegate(activity);
-        return sInstance;
-    }
-
     private static boolean activitySupportsPresentation(Activity activity) {
         return activity instanceof ChromeTabbedActivity || activity instanceof CustomTabActivity
                 || activity instanceof WebappActivity;
@@ -759,21 +756,12 @@
                 isDaydreamCurrentViewer);
     }
 
-    /**
-     * See VrClassesWrapper#bootsToVr().
-     */
-    public static boolean bootsToVr() {
-        if (getVrClassesWrapper() == null) return false;
-        return getVrClassesWrapper().bootsToVr();
-    }
-
-    /**
-     * @return A helper class for creating VR-specific classes that may not be available at compile
-     * time.
-     */
-    public static VrClassesWrapper getVrClassesWrapper() {
-        if (sVrClassesWrapper == null) sVrClassesWrapper = createVrClassesWrapper();
-        return sVrClassesWrapper;
+    private static VrCoreVersionChecker getVrCoreVersionChecker() {
+        if (sVrCoreVersionChecker == null) {
+            if (getVrClassesWrapper() == null) return null;
+            sVrCoreVersionChecker = getVrClassesWrapper().createVrCoreVersionChecker();
+        }
+        return sVrCoreVersionChecker;
     }
 
     @SuppressWarnings("unchecked")
@@ -793,23 +781,10 @@
         }
     }
 
-    /**
-     * @return A Daydream Api instance, for interacting with Daydream platform features.
-     */
-    public static VrDaydreamApi getVrDaydreamApi() {
-        if (sVrDaydreamApi == null) {
-            if (getVrClassesWrapper() == null) return null;
-            sVrDaydreamApi = getVrClassesWrapper().createVrDaydreamApi();
-        }
-        return sVrDaydreamApi;
-    }
-
-    private static VrCoreVersionChecker getVrCoreVersionChecker() {
-        if (sVrCoreVersionChecker == null) {
-            if (getVrClassesWrapper() == null) return null;
-            sVrCoreVersionChecker = getVrClassesWrapper().createVrCoreVersionChecker();
-        }
-        return sVrCoreVersionChecker;
+    private static void setSystemUiVisibilityForVr(Activity activity) {
+        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        int flags = activity.getWindow().getDecorView().getSystemUiVisibility();
+        activity.getWindow().getDecorView().setSystemUiVisibility(flags | VR_SYSTEM_UI_FLAGS);
     }
 
     // We need a custom Intent for entering VR in order to support VR in Custom Tabs. Custom Tabs
@@ -866,23 +841,15 @@
         return getVrDaydreamApi().isDaydreamCurrentViewer();
     }
 
-    // TODO(mthiesse): Should have package visibility only. We need to unify our vr and vr_shell
-    // packages.
-    public static boolean isInVrSession() {
+    /* package */ static boolean isInVrSession() {
         return getVrClassesWrapper() != null && getVrClassesWrapper().isInVrSession();
     }
 
-    public static boolean isDaydreamReadyDevice() {
-        return getVrClassesWrapper() != null && getVrClassesWrapper().isDaydreamReadyDevice();
-    }
-
-    public static boolean deviceSupportsVrLaunches() {
+    /* package */ static boolean deviceSupportsVrLaunches() {
         return isDaydreamReadyDevice();
     }
 
-    // TODO(mthiesse): Should have package visibility only. We need to unify our vr and vr_shell
-    // packages.
-    public static boolean willChangeDensityInVr(ChromeActivity activity) {
+    /* package */ static boolean willChangeDensityInVr(ChromeActivity activity) {
         // Only N+ support launching in VR at all, other OS versions don't care about this.
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return false;
 
@@ -941,7 +908,7 @@
     }
 
     /**
-     *  @return Whether or not VR is supported on this platform.
+     *  @return Whether or not VR is enabled in this build.
      */
     /* package */ static boolean isVrEnabled() {
         return getVrClassesWrapper() != null;
@@ -1034,9 +1001,42 @@
         ApplicationStatus.registerStateListenerForAllActivities(sVrLifecycleObserver);
     }
 
-    protected static boolean isDisplayingUrl() {
-        if (sInstance == null) return false;
-        return sInstance.mVrShell.isDisplayingUrlForTesting();
+    /**
+     * Returns the current {@VrSupportLevel}.
+     */
+    @CalledByNative
+    private static int getVrSupportLevel() {
+        if (sVrSupportLevel == null) {
+            VrClassesWrapper wrapper = getVrClassesWrapper();
+            if (wrapper == null) {
+                sVrSupportLevel = VrSupportLevel.VR_DISABLED;
+            } else if (!isVrCoreCompatible()) {
+                sVrSupportLevel = VrSupportLevel.VR_NEEDS_UPDATE;
+            } else if (wrapper.isDaydreamReadyDevice()) {
+                sVrSupportLevel = VrSupportLevel.VR_DAYDREAM;
+            } else {
+                sVrSupportLevel = VrSupportLevel.VR_CARDBOARD;
+            }
+        }
+        return sVrSupportLevel;
+    }
+
+    @CalledByNative
+    private static VrShellDelegate getInstance() {
+        Activity activity = ApplicationStatus.getLastTrackedFocusedActivity();
+        if (!(activity instanceof ChromeActivity)) return null;
+        return getInstance((ChromeActivity) activity);
+    }
+
+    private static VrShellDelegate getInstance(ChromeActivity activity) {
+        if (!LibraryLoader.getInstance().isInitialized()) return null;
+        if (activity == null || !activitySupportsPresentation(activity)) return null;
+        if (sInstance != null) return sInstance;
+        VrClassesWrapper wrapper = getVrClassesWrapper();
+        if (wrapper == null) return null;
+        ThreadUtils.assertOnUiThread();
+        sInstance = new VrShellDelegate(activity);
+        return sInstance;
     }
 
     protected VrShellDelegate(ChromeActivity activity) {
@@ -1044,8 +1044,8 @@
         // If an activity isn't resumed at the point, it must have been paused.
         mPaused = ApplicationStatus.getStateForActivity(activity) != ActivityState.RESUMED;
         mVisible = activity.hasWindowFocus();
-        updateVrSupportLevel(null);
         mNativeVrShellDelegate = nativeInit();
+        updateVrSupportLevel(null);
         mFeedbackFrequency = VrFeedbackStatus.getFeedbackFrequency();
         ensureLifecycleObserverInitialized();
         if (!mPaused) onResume();
@@ -1161,6 +1161,7 @@
                 buttonText, null, true);
     }
 
+    @VisibleForTesting
     protected boolean isVrBrowsingEnabled() {
         return isVrBrowsingEnabled(mActivity, getVrSupportLevel());
     }
@@ -1217,16 +1218,11 @@
     }
 
     private void enterVr(final boolean tentativeWebVrMode) {
-        // We can't enter VR before the application resumes, or we encounter bizarre crashes
-        // related to gpu surfaces.
-        // TODO(mthiesse): Is the above comment still accurate? It may have been tied to our HTML
-        // UI which is gone.
+        // We should only enter VR when we're the resumed Activity or our changes to things like
+        // system UI flags might get lost.
         assert !mPaused;
+        assert mNativeVrShellDelegate != 0;
         if (mInVr) return;
-        if (mNativeVrShellDelegate == 0) {
-            cancelPendingVrEntry();
-            return;
-        }
         mInVr = true;
         setVrModeEnabled(mActivity, true);
 
@@ -1246,11 +1242,11 @@
         mExitedDueToUnsupportedMode = false;
 
         addVrViews();
-        boolean webVrMode = mRequestedWebVr || tentativeWebVrMode;
         // Make sure that assets component is registered when creating native VR shell.
         if (!sRegisteredVrAssetsComponent) {
             registerVrAssetsComponentIfDaydreamUser(isDaydreamCurrentViewer());
         }
+        boolean webVrMode = mRequestedWebVr || tentativeWebVrMode;
         mVrShell.initializeNative(webVrMode, getVrClassesWrapper().bootsToVr());
         mVrShell.setWebVrModeEnabled(webVrMode);
 
@@ -1263,51 +1259,28 @@
         mVrShell.getContainer().setOnSystemUiVisibilityChangeListener(this);
 
         maybeSetPresentResult(true);
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.VR_BROWSING_NATIVE_ANDROID_UI)) {
-            mUiWidgetFactoryBeforeEnterVr = UiWidgetFactory.getInstance();
-            UiWidgetFactory.setInstance(
-                    new VrUiWidgetFactory(mVrShell, mActivity.getModalDialogManager()));
-        }
 
         for (VrModeObserver observer : sVrModeObservers) observer.onEnterVr();
     }
 
-    private void onVrIntent() {
-        if (USE_HIDE_ANIMATION) mNeedsAnimationCancel = true;
-
-        assert !mInternalIntentUsedToStartVr;
-        nativeRecordVrStartAction(mNativeVrShellDelegate, VrStartAction.INTENT_LAUNCH);
-
-        if (mInVr) return;
-
-        mStartedFromVrIntent = true;
-        // Setting DON succeeded will cause us to enter VR when resuming.
-        mDonSucceeded = true;
-    }
-
-    private void onEnterVrUnsupported() {
-        // Auto-presentation is unsupported, but we still need to remove the black overlay before we
-        // exit to Daydream so that the user doesn't see black when they come back to Chrome. The
-        // overlay will be removed when we get paused by Daydream.
+    private void onVrIntentUnsupported() {
+        // If entering VR is unsupported for some reason, clean up what we did in
+        // maybeHandleVrIntentPreNative.
         assert !mInVr;
-        mNeedsAnimationCancel = false;
         mStartedFromVrIntent = false;
-        // We remove the VR-specific system UI flags here so that the system UI shows up properly
-        // when Chrome is resumed in non-VR mode.
-        assert mRestoreSystemUiVisibility;
-        restoreWindowMode();
-
-        boolean launched = getVrDaydreamApi().launchVrHomescreen();
-        assert launched;
+        cancelPendingVrEntry();
 
         // Some Samsung devices change the screen density after exiting VR mode which causes
         // us to restart Chrome with the VR intent that originally started it. We don't want to
         // enable VR mode when the user opens Chrome again in 2D mode, so we remove VR specific
         // extras.
         VrIntentUtils.removeVrExtras(mActivity.getIntent());
+
+        // We may still be showing the STAY_HIDDEN animation, so cancel it if necessary.
+        cancelStartupAnimationIfNeeded();
     }
 
-    private void onNewIntentWithNativeInternal(ChromeActivity activity, Intent intent) {
+    private void onNewVrIntent() {
         // We set the the system UI in maybeHandleVrIntentPreNative, so make sure we restore it when
         // we exit VR, or cancel VR entry.
         mRestoreSystemUiVisibility = true;
@@ -1315,24 +1288,29 @@
         // Nothing to do if we were launched by an internal intent.
         if (mInternalIntentUsedToStartVr) {
             mInternalIntentUsedToStartVr = false;
+            // This is extremely unlikely in practice. Some code must have called shutdownVR() while
+            // we were entering VR through NFC insertion.
+            if (!mDonSucceeded) cancelPendingVrEntry();
             return;
         }
 
-        setVrModeEnabled(mActivity, true);
+        if (USE_HIDE_ANIMATION) mNeedsAnimationCancel = true;
 
-        if (isVrBrowsingSupported(mActivity)) {
-            if (DEBUG_LOGS) Log.i(TAG, "onNewIntentWithNative: vr");
-            onVrIntent();
-        } else {
-            if (DEBUG_LOGS) Log.i(TAG, "onNewIntentWithNative: unsupported");
-            // TODO(ymalik): Currently we always return to Daydream home, this makes less sense if
-            // a non-VR app sends an intent, perhaps just ignoring the intent is better.
-            onEnterVrUnsupported();
+        if (!isVrBrowsingSupported(mActivity)) {
+            onVrIntentUnsupported();
             return;
         }
 
+        if (mInVr) return;
+
+        mStartedFromVrIntent = true;
+        // Setting DON succeeded will cause us to enter VR when resuming.
+        mDonSucceeded = true;
+
+        nativeRecordVrStartAction(mNativeVrShellDelegate, VrStartAction.INTENT_LAUNCH);
+
         if (!mPaused) {
-            // Note that cancelling the animation below is what causes us to enter VR mode. We start
+            // Note that canceling the animation below is what causes us to enter VR mode. We start
             // an intermediate activity to cancel the animation which causes onPause and onResume to
             // be called and we enter VR mode in onResume (because we set the mEnterVrOnStartup bit
             // above). If Chrome is already running, onResume which will be called after
@@ -1386,12 +1364,6 @@
                 && orientation == Configuration.ORIENTATION_LANDSCAPE;
     }
 
-    private static void setSystemUiVisibilityForVr(Activity activity) {
-        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-        int flags = activity.getWindow().getDecorView().getSystemUiVisibility();
-        activity.getWindow().getDecorView().setSystemUiVisibility(flags | VR_SYSTEM_UI_FLAGS);
-    }
-
     @TargetApi(Build.VERSION_CODES.KITKAT)
     private void setWindowModeForVr() {
         // Decouple the compositor size from the view size, or we'll get an unnecessary resize due
@@ -1573,6 +1545,7 @@
         return true;
     }
 
+    @VisibleForTesting
     protected void onResume() {
         if (DEBUG_LOGS) Log.i(TAG, "onResume");
         if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) return;
@@ -1693,7 +1666,7 @@
         if (mInVr) mVrShell.pause();
     }
 
-    protected void onPause() {
+    private void onPause() {
         if (DEBUG_LOGS) Log.i(TAG, "onPause");
         mPaused = true;
         if (mCancellingEntryAnimation) return;
@@ -1784,13 +1757,9 @@
 
         mShowingDaydreamDoff = false;
 
-        if (mShowingDoffForGvrUpdate) {
-            mShowVrServicesUpdatePrompt = success;
-        }
+        if (mShowingDoffForGvrUpdate) mShowVrServicesUpdatePrompt = success;
 
-        if (success) {
-            shutdownVr(true /* disableVrMode */, true /* stayingInChrome */);
-        }
+        if (success) shutdownVr(true /* disableVrMode */, true /* stayingInChrome */);
 
         callOnExitVrRequestListener(success);
         mShowingDoffForGvrUpdate = false;
@@ -1807,8 +1776,7 @@
     @CalledByNative
     private void setListeningForWebVrActivate(boolean listening) {
         if (DEBUG_LOGS) Log.i(TAG, "WebVR page listening for vrdisplayactivate: " + listening);
-        // Non-Daydream devices may not have the concept of display activate. So disable
-        // mListeningForWebVrActivate for them.
+        // Non-Daydream devices do not have the concept of activation.
         if (getVrSupportLevel() != VrSupportLevel.VR_DAYDREAM) return;
         if (mListeningForWebVrActivate == listening) return;
         mListeningForWebVrActivate = listening;
@@ -1853,7 +1821,7 @@
     /**
      * Exits VR Shell, performing all necessary cleanup.
      */
-    protected void shutdownVr(boolean disableVrMode, boolean stayingInChrome) {
+    private void shutdownVr(boolean disableVrMode, boolean stayingInChrome) {
         if (DEBUG_LOGS) Log.i(TAG, "shuttdown VR");
         cancelPendingVrEntry();
 
@@ -1884,9 +1852,6 @@
         // prompt.
         if (mShowingExitVrPrompt) callOnExitVrRequestListener(true);
 
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.VR_BROWSING_NATIVE_ANDROID_UI)) {
-            UiWidgetFactory.setInstance(mUiWidgetFactoryBeforeEnterVr);
-        }
         for (VrModeObserver observer : sVrModeObservers) observer.onExitVr();
     }
 
@@ -1973,11 +1938,13 @@
                 GVR_KEYBOARD_UPDATE_RESULT);
     }
 
+    @VisibleForTesting
     protected boolean canLaunch2DIntentsInternal() {
         return getVrClassesWrapper().supports2dInVr()
                 && !sVrModeEnabledActivitys.contains(sInstance.mActivity);
     }
 
+    @VisibleForTesting
     protected boolean createVrShell() {
         assert mVrShell == null;
         if (getVrClassesWrapper() == null) return false;
@@ -2004,6 +1971,7 @@
         mActivity.onEnterVr();
     }
 
+    @VisibleForTesting
     protected boolean isBlackOverlayVisible() {
         View overlay = mActivity.getWindow().findViewById(R.id.vr_overlay_view);
         return overlay != null;
@@ -2029,6 +1997,7 @@
     /**
      * @param api The VrDaydreamApi object this delegate will use instead of the default one
      */
+    @VisibleForTesting
     protected void overrideDaydreamApi(VrDaydreamApi api) {
         sVrDaydreamApi = api;
     }
@@ -2036,13 +2005,15 @@
     /**
      * @return The VrShell for the VrShellDelegate instance
      */
-    protected static VrShell getVrShell() {
-        return sInstance == null ? null : sInstance.mVrShell;
+    @VisibleForTesting
+    protected VrShell getVrShell() {
+        return mVrShell;
     }
 
     /**
      * @param versionChecker The VrCoreVersionChecker object this delegate will use
      */
+    @VisibleForTesting
     protected void overrideVrCoreVersionChecker(VrCoreVersionChecker versionChecker) {
         sVrCoreVersionChecker = versionChecker;
         updateVrSupportLevel(null);
@@ -2051,48 +2022,32 @@
     /**
      * @param frequency Sets how often to show the feedback prompt.
      */
+    @VisibleForTesting
     protected void setFeedbackFrequency(int frequency) {
         mFeedbackFrequency = frequency;
     }
 
+    @VisibleForTesting
     protected boolean isListeningForWebVrActivate() {
         return mListeningForWebVrActivate;
     }
 
+    @VisibleForTesting
     protected boolean isVrEntryComplete() {
         return mInVr && !mProbablyInDon;
     }
 
+    @VisibleForTesting
     protected boolean isShowingDoff() {
         return mShowingDaydreamDoff;
     }
 
-    protected void acceptDoffPromptForTesting() {
-        mVrShell.acceptDoffPromptForTesting();
-    }
-
-    protected boolean allow2dIntentsForTesting() {
-        return false;
-    }
-
+    @VisibleForTesting
     protected void onBroadcastReceived() {}
 
+    @VisibleForTesting
     protected void setExpectingIntent(boolean expectingIntent) {}
 
-    protected void performControllerActionForTesting(
-            int elementName, int actionType, PointF position) {
-        mVrShell.performControllerActionForTesting(elementName, actionType, position);
-    }
-
-    protected void setUiExpectingActivityForTesting(
-            int quiescenceTimeoutMs, Runnable resultCallback) {
-        mVrShell.setUiExpectingActivityForTesting(quiescenceTimeoutMs, resultCallback);
-    }
-
-    protected int getLastUiActivityResultForTesting() {
-        return mVrShell.getLastUiActivityResultForTesting();
-    }
-
     /**
      * @return Pointer to the native VrShellDelegate object.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellImpl.java
index e2bf2665..ac9c10f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrShellImpl.java
@@ -64,6 +64,7 @@
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.display.VirtualDisplayAndroid;
+import org.chromium.ui.widget.UiWidgetFactory;
 
 /**
  * This view extends from GvrLayout which wraps a GLSurfaceView that renders VR shell.
@@ -104,6 +105,7 @@
     private boolean mReprojectedRendering;
 
     private TabRedirectHandler mNonVrTabRedirectHandler;
+    private UiWidgetFactory mNonVrUiWidgetFactory;
 
     private TabModelSelector mTabModelSelector;
     private float mLastContentWidth;
@@ -162,6 +164,12 @@
             mActivity.getFindToolbarManager().hideToolbar();
         }
 
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.VR_BROWSING_NATIVE_ANDROID_UI)) {
+            mNonVrUiWidgetFactory = UiWidgetFactory.getInstance();
+            UiWidgetFactory.setInstance(
+                    new VrUiWidgetFactory(this, mActivity.getModalDialogManager()));
+        }
+
         // This overrides the default intent created by GVR to return to Chrome when the DON flow
         // is triggered by resuming the GvrLayout, which is the usual way Daydream apps enter VR.
         // See VrShellDelegate#getEnterVrPendingIntent for why we need to do this.
@@ -774,6 +782,8 @@
             mActivity.getToolbarManager().setProgressBarEnabled(true);
         }
 
+        if (mNonVrUiWidgetFactory != null) UiWidgetFactory.setInstance(mNonVrUiWidgetFactory);
+
         FrameLayout decor = (FrameLayout) mActivity.getWindow().getDecorView();
         decor.removeView(mUiView);
         super.shutdown();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrToast.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrToast.java
index ec9edf9..4ec17fa93 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrToast.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrToast.java
@@ -12,7 +12,6 @@
 /**
  * This class implements a Toast which is similar to Android Toast in VR.
  */
-
 public class VrToast extends android.widget.Toast {
     private VrToastManager mVrToastManager;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrUiWidgetFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrUiWidgetFactory.java
index 8e66e5e9..5b56053 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/VrUiWidgetFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/VrUiWidgetFactory.java
@@ -36,7 +36,7 @@
 
     @Override
     public AlertDialog createAlertDialog(Context context) {
-        return new VrAlertDialog(context, mVrShell, mModalDialogManager);
+        return new VrAlertDialog(context, mModalDialogManager);
     }
 
     @Override
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 1aaa3b10..9379e719 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -421,6 +421,7 @@
   "java/src/org/chromium/chrome/browser/download/DownloadLocationDialogBridge.java",
   "java/src/org/chromium/chrome/browser/download/DownloadManagerDelegate.java",
   "java/src/org/chromium/chrome/browser/download/DownloadManagerService.java",
+  "java/src/org/chromium/chrome/browser/download/DownloadMediaParserBridge.java",
   "java/src/org/chromium/chrome/browser/download/DownloadMetrics.java",
   "java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java",
   "java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
index 36278db..082b9b3d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -1489,6 +1489,7 @@
     @Feature({"Android-TabSwitcher"})
     @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
     @RetryOnFailure
+    @DisabledTest(message = "crbug.com/863676")
     public void testToolbarSwipePrevTab() throws InterruptedException, TimeoutException {
         ChromeTabUtils.newTabFromMenu(
                 InstrumentationRegistry.getInstrumentation(), mActivityTestRule.getActivity());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
index fada84a..921e7c8b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
@@ -43,9 +43,9 @@
     }
 
     private AutofillProfile createTestProfile() {
-        return new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
-                "John Major", "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "",
-                "US", "555 123-4567", "jm@example.com", "");
+        return new AutofillProfile("" /* guid */, "" /* origin */, "John Major", "Acme Inc.",
+                "123 Main", "California", "Los Angeles", "", "90210", "", "US", "555 123-4567",
+                "jm@example.com", "");
     }
 
     @Test
@@ -54,21 +54,15 @@
     @RetryOnFailure
     public void testAddAndEditProfiles()
             throws InterruptedException, ExecutionException, TimeoutException {
-        AutofillProfile profile = new AutofillProfile(
-                "" /* guid */, "https://www.example.com" /* origin */,
-                "John Smith", "Acme Inc.",
-                "1 Main\nApt A", "CA", "San Francisco", "",
-                "94102", "",
-                "US", "4158889999", "john@acme.inc", "");
+        AutofillProfile profile = new AutofillProfile("" /* guid */, "" /* origin */, "John Smith",
+                "Acme Inc.", "1 Main\nApt A", "CA", "San Francisco", "", "94102", "", "US",
+                "4158889999", "john@acme.inc", "");
         String profileOneGUID = mHelper.setProfile(profile);
         Assert.assertEquals(1, mHelper.getNumberOfProfilesForSettings());
 
-        AutofillProfile profile2 = new AutofillProfile(
-                "" /* guid */, "http://www.example.com" /* origin */,
-                "John Hackock", "Acme Inc.",
-                "1 Main\nApt A", "CA", "San Francisco", "",
-                "94102", "",
-                "US", "4158889999", "john@acme.inc", "");
+        AutofillProfile profile2 = new AutofillProfile("" /* guid */, "" /* origin */,
+                "John Hackock", "Acme Inc.", "1 Main\nApt A", "CA", "San Francisco", "", "94102",
+                "", "US", "4158889999", "john@acme.inc", "");
         String profileTwoGUID = mHelper.setProfile(profile2);
         Assert.assertEquals(2, mHelper.getNumberOfProfilesForSettings());
 
@@ -80,7 +74,7 @@
 
         AutofillProfile storedProfile = mHelper.getProfile(profileOneGUID);
         Assert.assertEquals(profileOneGUID, storedProfile.getGUID());
-        Assert.assertEquals("https://www.example.com", storedProfile.getOrigin());
+        Assert.assertEquals("", storedProfile.getOrigin());
         Assert.assertEquals("CA", storedProfile.getCountryCode());
         Assert.assertEquals("San Francisco", storedProfile.getLocality());
         Assert.assertNotNull(mHelper.getProfile(profileTwoGUID));
@@ -92,12 +86,9 @@
     @RetryOnFailure
     public void testUpdateLanguageCodeInProfile()
             throws InterruptedException, ExecutionException, TimeoutException {
-        AutofillProfile profile = new AutofillProfile(
-                "" /* guid */, "https://www.example.com" /* origin */,
-                "John Smith", "Acme Inc.",
-                "1 Main\nApt A", "CA", "San Francisco", "",
-                "94102", "",
-                "US", "4158889999", "john@acme.inc", "fr");
+        AutofillProfile profile = new AutofillProfile("" /* guid */, "" /* origin */, "John Smith",
+                "Acme Inc.", "1 Main\nApt A", "CA", "San Francisco", "", "94102", "", "US",
+                "4158889999", "john@acme.inc", "fr");
         Assert.assertEquals("fr", profile.getLanguageCode());
         String profileOneGUID = mHelper.setProfile(profile);
         Assert.assertEquals(1, mHelper.getNumberOfProfilesForSettings());
@@ -116,7 +107,7 @@
         Assert.assertEquals("en", storedProfile2.getLanguageCode());
         Assert.assertEquals("US", storedProfile2.getCountryCode());
         Assert.assertEquals("San Francisco", storedProfile2.getLocality());
-        Assert.assertEquals("https://www.example.com", storedProfile2.getOrigin());
+        Assert.assertEquals("", storedProfile2.getOrigin());
     }
 
     @Test
@@ -139,14 +130,12 @@
     public void testAddAndEditCreditCards()
             throws InterruptedException, ExecutionException, TimeoutException {
         CreditCard card = new CreditCard(
-                "" /* guid */, "https://www.example.com" /* origin */,
-                "Visa", "1234123412341234", "", "5", "2020");
+                "" /* guid */, "" /* origin */, "Visa", "1234123412341234", "", "5", "2020");
         String cardOneGUID = mHelper.setCreditCard(card);
         Assert.assertEquals(1, mHelper.getNumberOfCreditCardsForSettings());
 
-        CreditCard card2 = new CreditCard(
-                "" /* guid */, "http://www.example.com" /* origin */,
-                "American Express", "1234123412341234", "", "8", "2020");
+        CreditCard card2 = new CreditCard("" /* guid */, "" /* origin */, "American Express",
+                "1234123412341234", "", "8", "2020");
         String cardTwoGUID = mHelper.setCreditCard(card2);
         Assert.assertEquals(2, mHelper.getNumberOfCreditCardsForSettings());
 
@@ -159,7 +148,7 @@
 
         CreditCard storedCard = mHelper.getCreditCard(cardOneGUID);
         Assert.assertEquals(cardOneGUID, storedCard.getGUID());
-        Assert.assertEquals("https://www.example.com", storedCard.getOrigin());
+        Assert.assertEquals("", storedCard.getOrigin());
         Assert.assertEquals("Visa", storedCard.getName());
         Assert.assertEquals("10", storedCard.getMonth());
         Assert.assertEquals("4012888888881881", storedCard.getNumber());
@@ -195,20 +184,14 @@
             throws InterruptedException, ExecutionException, TimeoutException {
         // The constructor should accept country names and ISO 3166-1-alpha-2 country codes.
         // getCountryCode() should return a country code.
-        AutofillProfile profile1 = new AutofillProfile(
-                "" /* guid */, "https://www.example.com" /* origin */,
-                "John Smith", "Acme Inc.",
-                "1 Main\nApt A", "Quebec", "Montreal", "",
-                "H3B 2Y5", "",
-                "Canada", "514-670-1234", "john@acme.inc", "");
+        AutofillProfile profile1 = new AutofillProfile("" /* guid */, "" /* origin */, "John Smith",
+                "Acme Inc.", "1 Main\nApt A", "Quebec", "Montreal", "", "H3B 2Y5", "", "Canada",
+                "514-670-1234", "john@acme.inc", "");
         String profileGuid1 = mHelper.setProfile(profile1);
 
-        AutofillProfile profile2 = new AutofillProfile(
-                "" /* guid */, "https://www.example.com" /* origin */,
-                "Greg Smith", "Ucme Inc.",
-                "123 Bush\nApt 125", "Quebec", "Montreal", "",
-                "H3B 2Y5", "",
-                "CA", "514-670-4321", "greg@ucme.inc", "");
+        AutofillProfile profile2 = new AutofillProfile("" /* guid */, "" /* origin */, "Greg Smith",
+                "Ucme Inc.", "123 Bush\nApt 125", "Quebec", "Montreal", "", "H3B 2Y5", "", "CA",
+                "514-670-4321", "greg@ucme.inc", "");
         String profileGuid2 = mHelper.setProfile(profile2);
 
         Assert.assertEquals(2, mHelper.getNumberOfProfilesForSettings());
@@ -232,13 +215,10 @@
         final String streetAddress2 = streetAddress1 + "\n"
                 + "Fourth floor\n"
                 + "The red bell";
-        AutofillProfile profile = new AutofillProfile(
-                "" /* guid */, "https://www.example.com" /* origin */,
-                "Monsieur Jean DELHOURME", "Acme Inc.",
-                streetAddress1,
-                "Tahiti", "Mahina", "Orofara",
-                "98709", "CEDEX 98703",
-                "French Polynesia", "44.71.53", "john@acme.inc", "");
+        AutofillProfile profile =
+                new AutofillProfile("" /* guid */, "" /* origin */, "Monsieur Jean DELHOURME",
+                        "Acme Inc.", streetAddress1, "Tahiti", "Mahina", "Orofara", "98709",
+                        "CEDEX 98703", "French Polynesia", "44.71.53", "john@acme.inc", "");
         String profileGuid1 = mHelper.setProfile(profile);
         Assert.assertEquals(1, mHelper.getNumberOfProfilesForSettings());
         AutofillProfile storedProfile1 = mHelper.getProfile(profileGuid1);
@@ -264,33 +244,20 @@
     @SmallTest
     @Feature({"Autofill"})
     public void testLabels() throws InterruptedException, ExecutionException, TimeoutException {
-        AutofillProfile profile1 = new AutofillProfile(
-                 "" /* guid */, "https://www.example.com" /* origin */,
-                 "John Major", "Acme Inc.",
-                 "123 Main", "California", "Los Angeles", "",
-                 "90210", "",
-                 "US", "555 123-4567", "jm@example.com", "");
+        AutofillProfile profile1 = new AutofillProfile("" /* guid */, "" /* origin */, "John Major",
+                "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US",
+                "555 123-4567", "jm@example.com", "");
         // An almost identical profile.
-        AutofillProfile profile2 = new AutofillProfile(
-                 "" /* guid */, "https://www.example.com" /* origin */,
-                 "John Major", "Acme Inc.",
-                 "123 Main", "California", "Los Angeles", "",
-                 "90210", "",
-                 "US", "555 123-4567", "jm-work@example.com", "");
+        AutofillProfile profile2 = new AutofillProfile("" /* guid */, "" /* origin */, "John Major",
+                "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US",
+                "555 123-4567", "jm-work@example.com", "");
         // A different profile.
-        AutofillProfile profile3 = new AutofillProfile(
-                 "" /* guid */, "https://www.example.com" /* origin */,
-                 "Jasper Lundgren", "",
-                 "1500 Second Ave", "California", "Hollywood", "",
-                 "90068", "",
-                 "US", "555 123-9876", "jasperl@example.com", "");
+        AutofillProfile profile3 = new AutofillProfile("" /* guid */, "" /* origin */,
+                "Jasper Lundgren", "", "1500 Second Ave", "California", "Hollywood", "", "90068",
+                "", "US", "555 123-9876", "jasperl@example.com", "");
         // A profile where a lot of stuff is missing.
-        AutofillProfile profile4 = new AutofillProfile(
-                 "" /* guid */, "https://www.example.com" /* origin */,
-                 "Joe Sergeant", "",
-                 "", "Texas", "Fort Worth", "",
-                 "", "",
-                 "US", "", "", "");
+        AutofillProfile profile4 = new AutofillProfile("" /* guid */, "" /* origin */,
+                "Joe Sergeant", "", "", "Texas", "Fort Worth", "", "", "", "US", "", "", "");
 
         mHelper.setProfile(profile1);
         mHelper.setProfile(profile2);
@@ -319,18 +286,15 @@
     public void testProfilesFrecency()
             throws InterruptedException, ExecutionException, TimeoutException {
         // Create 3 profiles.
-        AutofillProfile profile1 =
-                new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
-                        "John Major", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
-                        "90210", "", "US", "555 123-4567", "jm@example.com", "");
-        AutofillProfile profile2 =
-                new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
-                        "John Major", "Acme Inc.", "123 Main", "California", "Los Angeles", "",
-                        "90210", "", "US", "555 123-4567", "jm-work@example.com", "");
-        AutofillProfile profile3 =
-                new AutofillProfile("" /* guid */, "https://www.example.com" /* origin */,
-                        "Jasper Lundgren", "", "1500 Second Ave", "California", "Hollywood", "",
-                        "90068", "", "US", "555 123-9876", "jasperl@example.com", "");
+        AutofillProfile profile1 = new AutofillProfile("" /* guid */, "" /* origin */, "John Major",
+                "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US",
+                "555 123-4567", "jm@example.com", "");
+        AutofillProfile profile2 = new AutofillProfile("" /* guid */, "" /* origin */, "John Major",
+                "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US",
+                "555 123-4567", "jm-work@example.com", "");
+        AutofillProfile profile3 = new AutofillProfile("" /* guid */, "" /* origin */,
+                "Jasper Lundgren", "", "1500 Second Ave", "California", "Hollywood", "", "90068",
+                "", "US", "555 123-9876", "jasperl@example.com", "");
 
         String guid1 = mHelper.setProfile(profile1);
         String guid2 = mHelper.setProfile(profile2);
@@ -363,8 +327,8 @@
     public void testCreditCardsFrecency()
             throws InterruptedException, ExecutionException, TimeoutException {
         // Create 3 credit cards.
-        CreditCard card1 = new CreditCard("" /* guid */, "https://www.example.com" /* origin */,
-                "Visa", "1234123412341234", "", "5", "2020");
+        CreditCard card1 = new CreditCard(
+                "" /* guid */, "" /* origin */, "Visa", "1234123412341234", "", "5", "2020");
 
         CreditCard card2 = new CreditCard("" /* guid */, "http://www.example.com" /* origin */,
                 "American Express", "1234123412341234", "", "8", "2020");
@@ -400,15 +364,15 @@
     public void testCreditCardsDeduping()
             throws InterruptedException, ExecutionException, TimeoutException {
         // Create a local card and an identical server card.
-        CreditCard card1 = new CreditCard("" /* guid */, "https://www.example.com" /* origin */,
-                true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234", "", "5",
-                "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN,
-                "" /* billingAddressId */, "" /* serverId */);
+        CreditCard card1 = new CreditCard("" /* guid */, "" /* origin */, true /* isLocal */,
+                false /* isCached */, "John Doe", "1234123412341234", "", "5", "2020", "Visa",
+                0 /* issuerIconDrawableId */, CardType.UNKNOWN, "" /* billingAddressId */,
+                "" /* serverId */);
 
-        CreditCard card2 = new CreditCard("" /* guid */, "https://www.example.com" /* origin */,
-                false /* isLocal */, false /* isCached */, "John Doe", "1234123412341234", "", "5",
-                "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN,
-                "" /* billingAddressId */, "" /* serverId */);
+        CreditCard card2 = new CreditCard("" /* guid */, "" /* origin */, false /* isLocal */,
+                false /* isCached */, "John Doe", "1234123412341234", "", "5", "2020", "Visa",
+                0 /* issuerIconDrawableId */, CardType.UNKNOWN, "" /* billingAddressId */,
+                "" /* serverId */);
 
         mHelper.setCreditCard(card1);
         mHelper.addServerCreditCard(card2);
@@ -446,11 +410,10 @@
     @RetryOnFailure
     public void testCreditCardUseStatsSettingAndGetting()
             throws InterruptedException, ExecutionException, TimeoutException {
-        String guid = mHelper.setCreditCard(
-                new CreditCard("" /* guid */, "https://www.example.com" /* origin */,
-                        true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234",
-                        "", "5", "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN,
-                        "" /* billingAddressId */, "" /* serverId */));
+        String guid = mHelper.setCreditCard(new CreditCard("" /* guid */, "" /* origin */,
+                true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234", "", "5",
+                "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN,
+                "" /* billingAddressId */, "" /* serverId */));
 
         // Make sure the credit card does not have the specific use stats form the start.
         Assert.assertTrue(1234 != mHelper.getCreditCardUseCountForTesting(guid));
@@ -496,11 +459,10 @@
     @RetryOnFailure
     public void testRecordAndLogCreditCardUse()
             throws InterruptedException, ExecutionException, TimeoutException {
-        String guid = mHelper.setCreditCard(
-                new CreditCard("" /* guid */, "https://www.example.com" /* origin */,
-                        true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234",
-                        "", "5", "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN,
-                        "" /* billingAddressId */, "" /* serverId */));
+        String guid = mHelper.setCreditCard(new CreditCard("" /* guid */, "" /* origin */,
+                true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234", "", "5",
+                "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN,
+                "" /* billingAddressId */, "" /* serverId */));
 
         // Set specific use stats for the credit card.
         mHelper.setCreditCardUseStatsForTesting(guid, 1234, 1234);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
index 744101d..1bef395 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/keyboard_accessory/ManualFillingIntegrationTest.java
@@ -13,6 +13,7 @@
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.selectTabAtPosition;
 import static org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingTestHelper.whenDisplayed;
 
+import android.support.test.espresso.Espresso;
 import android.support.test.filters.SmallTest;
 
 import org.junit.Assert;
@@ -162,5 +163,27 @@
         mHelper.waitToBeHidden(withId(R.id.keyboard_accessory_sheet));
     }
 
+    @Test
+    @SmallTest
+    public void testPressingBackButtonHidesAccessorySheet()
+            throws InterruptedException, TimeoutException {
+        mHelper.loadTestPage(false);
+        mHelper.createTestTab();
+
+        // Focus the field to bring up the accessory.
+        mHelper.clickPasswordField();
+        mHelper.waitForKeyboard();
+
+        // Click the tab to show the sheet and hide the keyboard.
+        whenDisplayed(withId(R.id.tabs)).perform(selectTabAtPosition(0));
+        mHelper.waitForKeyboardToDisappear();
+        whenDisplayed(withId(R.id.keyboard_accessory_sheet));
+
+        Espresso.pressBack();
+
+        mHelper.waitToBeHidden(withId(R.id.keyboard_accessory_sheet));
+        mHelper.waitToBeHidden(withId(R.id.keyboard_accessory));
+    }
+
     // TODO(fhorschig): Check that it overlays info bars.
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java
index f02ef72..74e8052 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java
@@ -148,6 +148,7 @@
      * this will throw a BadParcelableException.
      */
     @SuppressLint("ParcelCreator")
+    @SuppressWarnings("ParcelableCreator")
     private static class InvalidParcelable implements Parcelable {
         @Override
         public void writeToParcel(Parcel parcel, int params) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java
index 8da9b68..5582737 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java
@@ -15,7 +15,6 @@
 
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.CommandLineFlags;
-import org.chromium.base.test.util.DisableIf;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeFeatureList;
@@ -49,6 +48,7 @@
 
     @Before
     public void setUp() throws Exception {
+        OfflineIndicatorController.skipSystemCheckForTesting();
         mActivityTestRule.startMainActivityOnBlankPage();
         ThreadUtils.runOnUiThreadBlocking(() -> {
             if (!NetworkChangeNotifier.isInitialized()) {
@@ -93,7 +93,6 @@
     }
 
     @Test
-    @DisableIf.Build(sdk_is_greater_than = 22, message = "https://crbug.com/859849")
     @MediumTest
     public void testHideOfflineIndicatorWhenBackToOnline() throws Exception {
         EmbeddedTestServer testServer =
@@ -110,15 +109,13 @@
         checkOfflineIndicatorVisibility(mActivityTestRule.getActivity(), true);
 
         // Reconnect the network.
-        ThreadUtils.runOnUiThreadBlocking(
-                () -> { NetworkChangeNotifier.forceConnectivityState(true); });
+        setNetworkConnectivity(true);
 
         // Offline indicator should go away.
         checkOfflineIndicatorVisibility(mActivityTestRule.getActivity(), false);
     }
 
     @Test
-    @DisableIf.Build(sdk_is_greater_than = 22, message = "https://crbug.com/859849")
     @MediumTest
     public void testDoNotShowOfflineIndicatorOnErrorPageWhenOffline() throws Exception {
         EmbeddedTestServer testServer =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
index e3a892f..a79186f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/TestVrShellDelegate.java
@@ -41,16 +41,11 @@
     }
 
     public static boolean isDisplayingUrlForTesting() {
-        return VrShellDelegate.isDisplayingUrl();
+        return TestVrShellDelegate.getInstance().getVrShell().isDisplayingUrlForTesting();
     }
 
     public static VrShell getVrShellForTesting() {
-        return VrShellDelegate.getVrShell();
-    }
-
-    @Override
-    public void shutdownVr(boolean disableVrMode, boolean stayingInChrome) {
-        super.shutdownVr(disableVrMode, stayingInChrome);
+        return TestVrShellDelegate.getInstance().getVrShell();
     }
 
     public void overrideDaydreamApiForTesting(VrDaydreamApi api) {
@@ -85,25 +80,21 @@
         return super.isShowingDoff();
     }
 
-    @Override
     public void acceptDoffPromptForTesting() {
-        super.acceptDoffPromptForTesting();
+        getVrShell().acceptDoffPromptForTesting();
     }
 
-    @Override
     public void performControllerActionForTesting(
             int elementName, int actionType, PointF position) {
-        super.performControllerActionForTesting(elementName, actionType, position);
+        getVrShell().performControllerActionForTesting(elementName, actionType, position);
     }
 
-    @Override
     public void setUiExpectingActivityForTesting(int quiescenceTimeoutMs, Runnable resultCallback) {
-        super.setUiExpectingActivityForTesting(quiescenceTimeoutMs, resultCallback);
+        getVrShell().setUiExpectingActivityForTesting(quiescenceTimeoutMs, resultCallback);
     }
 
-    @Override
     public int getLastUiActivityResultForTesting() {
-        return super.getLastUiActivityResultForTesting();
+        return getVrShell().getLastUiActivityResultForTesting();
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
index abd0222..e81e58b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
@@ -257,7 +257,7 @@
             throws IllegalArgumentException, InterruptedException, TimeoutException {
         exitPresentationToVrShellImpl(
                 XrTestFramework.getFileUrlForHtmlTestFile("test_navigation_webxr_page"),
-                mXrTestFramework, "exclusiveSession.end();");
+                mXrTestFramework, "immersiveSession.end();");
     }
 
     private void exitPresentationToVrShellImpl(String url, TestFramework framework,
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java
index f5733df..7a1ff6b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrFeedbackInfoBarTest.java
@@ -172,7 +172,7 @@
     }
 
     /**
-     * Tests that we show the prompt if the VR browser is used after exiting a WebXR exclusive
+     * Tests that we show the prompt if the VR browser is used after exiting a WebXR immersive
      * session.
      */
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
index 0515d8f..f7954a1b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrInputTest.java
@@ -88,7 +88,7 @@
     private void assertAppButtonEffect(boolean shouldHaveExited, TestFramework framework) {
         String boolExpression = (framework instanceof VrTestFramework)
                 ? "!vrDisplay.isPresenting"
-                : "sessionInfos[sessionTypes.EXCLUSIVE].currentSession == null";
+                : "sessionInfos[sessionTypes.IMMERSIVE].currentSession == null";
         Assert.assertEquals("App button exited presentation", shouldHaveExited,
                 TestFramework.pollJavaScriptBoolean(
                         boolExpression, POLL_TIMEOUT_SHORT_MS, framework.getFirstTabWebContents()));
@@ -109,7 +109,7 @@
     }
 
     /**
-     * Tests that screen touches are not registered when in an exclusive session.
+     * Tests that screen touches are not registered when in an immersive session.
      */
     @Test
     @MediumTest
@@ -199,7 +199,7 @@
     }
 
     /**
-     * Tests that Daydream controller clicks are registered as XR input in an exclusive session.
+     * Tests that Daydream controller clicks are registered as XR input in an immersive session.
      */
     @Test
     @MediumTest
@@ -347,7 +347,7 @@
     }
 
     /**
-     * Tests that focus is locked to the device with an exclusive session for the purposes of
+     * Tests that focus is locked to the device with an immersive session for the purposes of
      * VR input.
      */
     @Test
@@ -386,7 +386,7 @@
 
     /**
      * Tests that pressing the Daydream controller's 'app' button causes the user to exit a
-     * WebXR exclusive session.
+     * WebXR immersive session.
      */
     @Test
     @MediumTest
@@ -440,7 +440,7 @@
 
     /**
      * Verifies that pressing the Daydream controller's 'app' button does not cause the user to exit
-     * a WebXR exclusive session when VR browsing is disabled.
+     * a WebXR immersive session when VR browsing is disabled.
      */
     @Test
     @MediumTest
@@ -457,7 +457,7 @@
 
     /**
      * Verifies that pressing the Daydream controller's 'app' button does not cause the user to exit
-     * a WebXR exclusive session when VR browsing isn't supported by the Activity.
+     * a WebXR immersive session when VR browsing isn't supported by the Activity.
      */
     @Test
     @MediumTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
index 55de46b..e75a999 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrVrTransitionTest.java
@@ -98,7 +98,7 @@
     }
 
     /**
-     * Tests that a successful request for an exclusive session actually enters VR.
+     * Tests that a successful request for an immersive session actually enters VR.
      */
     @Test
     @MediumTest
@@ -227,7 +227,7 @@
     }
 
     /**
-     * Tests that the exclusive session promise doesn't resolve if the DON flow is
+     * Tests that the immersive session promise doesn't resolve if the DON flow is
      * not completed.
      */
     @Test
@@ -267,7 +267,7 @@
     }
 
     /**
-     * Tests that the exclusive session promise is rejected if the DON flow is canceled.
+     * Tests that the immersive session promise is rejected if the DON flow is canceled.
      */
     @Test
     @MediumTest
@@ -315,7 +315,7 @@
     }
 
     /**
-     * Tests that the omnibox reappears after exiting an exclusive session.
+     * Tests that the omnibox reappears after exiting an immersive session.
      */
     @Test
     @MediumTest
@@ -361,7 +361,7 @@
     }
 
     /**
-     * Tests that window.requestAnimationFrame stops firing while in a WebXR exclusive session, but
+     * Tests that window.requestAnimationFrame stops firing while in a WebXR immersive session, but
      * resumes afterwards.
      */
     @Test
@@ -374,7 +374,7 @@
             throws InterruptedException {
         windowRafStopsFiringWhilePresentingImpl(
                 XrTestFramework.getFileUrlForHtmlTestFile(
-                        "webxr_test_window_raf_stops_firing_during_exclusive_session"),
+                        "webxr_test_window_raf_stops_firing_during_immersive_session"),
                 mXrTestFramework);
     }
 
@@ -433,7 +433,7 @@
     }
 
     /**
-     * Tests that window.rAF continues to fire when we have a non-exclusive session.
+     * Tests that window.rAF continues to fire when we have a non-immersive session.
      */
     @Test
     @MediumTest
@@ -441,18 +441,18 @@
             .Remove({"enable-webvr"})
             @CommandLineFlags.Add({"enable-features=WebXR"})
             @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
-            public void testWindowRafFiresDuringNonExclusiveSession() throws InterruptedException {
+            public void testWindowRafFiresDuringNonImmersiveSession() throws InterruptedException {
         mXrTestFramework.loadUrlAndAwaitInitialization(
                 XrTestFramework.getFileUrlForHtmlTestFile(
-                        "test_window_raf_fires_during_non_exclusive_session"),
+                        "test_window_raf_fires_during_non_immersive_session"),
                 PAGE_LOAD_TIMEOUT_S);
         XrTestFramework.waitOnJavaScriptStep(mXrTestFramework.getFirstTabWebContents());
         XrTestFramework.endTest(mXrTestFramework.getFirstTabWebContents());
     }
 
     /**
-     * Tests that non-exclusive sessions stop receiving rAFs during an exclusive session, but resume
-     * once the exclusive session ends.
+     * Tests that non-immersive sessions stop receiving rAFs during an immersive session, but resume
+     * once the immersive session ends.
      */
     @Test
     @MediumTest
@@ -460,19 +460,19 @@
             .Remove({"enable-webvr"})
             @CommandLineFlags.Add({"enable-features=WebXR"})
             @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
-            public void testNonExclusiveStopsDuringExclusive() throws InterruptedException {
+            public void testNonImmersiveStopsDuringImmersive() throws InterruptedException {
         mXrTestFramework.loadUrlAndAwaitInitialization(
                 XrTestFramework.getFileUrlForHtmlTestFile(
-                        "test_non_exclusive_stops_during_exclusive"),
+                        "test_non_immersive_stops_during_immersive"),
                 PAGE_LOAD_TIMEOUT_S);
         XrTestFramework.executeStepAndWait(
-                "stepBeforeExclusive()", mXrTestFramework.getFirstTabWebContents());
+                "stepBeforeImmersive()", mXrTestFramework.getFirstTabWebContents());
         TransitionUtils.enterPresentationOrFail(mXrTestFramework);
         XrTestFramework.executeStepAndWait(
-                "stepDuringExclusive()", mXrTestFramework.getFirstTabWebContents());
+                "stepDuringImmersive()", mXrTestFramework.getFirstTabWebContents());
         TransitionUtils.forceExitVr();
         XrTestFramework.executeStepAndWait(
-                "stepAfterExclusive()", mXrTestFramework.getFirstTabWebContents());
+                "stepAfterImmersive()", mXrTestFramework.getFirstTabWebContents());
         XrTestFramework.endTest(mXrTestFramework.getFirstTabWebContents());
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/TransitionUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/TransitionUtils.java
index 2bdbe68..2e1323a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/TransitionUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/TransitionUtils.java
@@ -69,8 +69,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                VrShellDelegateUtils.getDelegateInstance().shutdownVr(
-                        true /* disableVrMode */, true /* stayingInChrome */);
+                VrShellDelegate.forceExitVrImmediately();
             }
         });
     }
@@ -221,7 +220,7 @@
                 new Intent(ContextUtils.getApplicationContext(), VrMainActivity.class);
         intent.setData(Uri.parse(url));
         intent.addCategory(VrIntentUtils.DAYDREAM_CATEGORY);
-        VrShellDelegate.getVrClassesWrapper().setupVrIntent(intent);
+        VrIntentUtils.setupVrIntent(intent);
 
         if (autopresent) {
             // Daydream removes this category for deep-linked URLs for legacy reasons.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/XrTransitionUtils.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/XrTransitionUtils.java
index 6a68c347..14d8d32e 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/XrTransitionUtils.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/util/XrTransitionUtils.java
@@ -21,7 +21,7 @@
 
 /**
  * Class containing utility functions for transitioning between different
- * states in WebXR, e.g. entering exclusive or AR sessions.
+ * states in WebXR, e.g. entering immersive or AR sessions.
  */
 public class XrTransitionUtils extends TransitionUtils {
     /**
@@ -30,10 +30,10 @@
      */
     public static void enterPresentationOrFail(WebContents webContents) {
         XrTestFramework.runJavaScriptOrFail(
-                "sessionTypeToRequest = sessionTypes.EXCLUSIVE", POLL_TIMEOUT_LONG_MS, webContents);
+                "sessionTypeToRequest = sessionTypes.IMMERSIVE", POLL_TIMEOUT_LONG_MS, webContents);
         enterPresentation(webContents);
         Assert.assertTrue(XrTestFramework.pollJavaScriptBoolean(
-                "sessionInfos[sessionTypes.EXCLUSIVE].currentSession != null", POLL_TIMEOUT_LONG_MS,
+                "sessionInfos[sessionTypes.IMMERSIVE].currentSession != null", POLL_TIMEOUT_LONG_MS,
                 webContents));
         Assert.assertTrue(TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
     }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index ede7063..6896f9f98 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1056,6 +1056,7 @@
     "plugins/pdf_iframe_navigation_throttle.h",
     "plugins/pdf_plugin_placeholder_observer.cc",
     "plugins/pdf_plugin_placeholder_observer.h",
+    "policy/browser_dm_token_storage.cc",
     "policy/browser_dm_token_storage.h",
     "policy/browser_dm_token_storage_win.cc",
     "policy/browser_dm_token_storage_win.h",
@@ -2082,6 +2083,8 @@
       "android/download/download_manager_service.h",
       "android/download/download_media_parser.cc",
       "android/download/download_media_parser.h",
+      "android/download/download_media_parser_bridge.cc",
+      "android/download/download_media_parser_bridge.h",
       "android/download/duplicate_download_infobar_delegate.cc",
       "android/download/duplicate_download_infobar_delegate.h",
       "android/download/intercept_download_resource_throttle.cc",
@@ -3163,8 +3166,6 @@
   } else {
     # Non-Windows.
     sources += [
-      "policy/browser_dm_token_storage_stub.cc",
-      "policy/browser_dm_token_storage_stub.h",
       "profile_resetter/triggered_profile_resetter_stub.cc",
       "profiles/profile_shortcut_manager_stub.cc",
     ]
@@ -4434,6 +4435,7 @@
       "../android/java/src/org/chromium/chrome/browser/download/DownloadItem.java",
       "../android/java/src/org/chromium/chrome/browser/download/DownloadLocationDialogBridge.java",
       "../android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java",
+      "../android/java/src/org/chromium/chrome/browser/download/DownloadMediaParserBridge.java",
       "../android/java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java",
       "../android/java/src/org/chromium/chrome/browser/download/service/DownloadBackgroundTask.java",
       "../android/java/src/org/chromium/chrome/browser/download/service/DownloadTaskScheduler.java",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 11c9c71..d4cdb7b1 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -105,7 +105,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/common/feature_h264_with_openh264_ffmpeg.h"
 #include "device/base/features.h"
-#include "device/gamepad/public/cpp/gamepad_switches.h"
+#include "device/gamepad/public/cpp/gamepad_features.h"
 #include "device/vr/buildflags/buildflags.h"
 #include "extensions/buildflags/buildflags.h"
 #include "google_apis/drive/drive_switches.h"
@@ -1157,12 +1157,24 @@
       base::size(kProactiveTabFreezeAndDiscard_FreezeAndDiscard), nullptr}};
 #endif
 
-const FeatureEntry::Choice kGamepadPollingRateChoices[] = {
-    {"60 Hz (Default)", "", ""},  // 16 ms, technically 62.5 Hz
-    {"100 Hz", switches::kGamepadPollingInterval, "10"},
-    {"125 Hz", switches::kGamepadPollingInterval, "8"},
-    {"200 Hz", switches::kGamepadPollingInterval, "5"},
-    {"250 Hz", switches::kGamepadPollingInterval, "4"},
+const FeatureEntry::FeatureParam kGamepadPollingRate100Hz[] = {
+    {features::kGamepadPollingIntervalParamKey, "10"}};
+const FeatureEntry::FeatureParam kGamepadPollingRate125Hz[] = {
+    {features::kGamepadPollingIntervalParamKey, "8"}};
+const FeatureEntry::FeatureParam kGamepadPollingRate200Hz[] = {
+    {features::kGamepadPollingIntervalParamKey, "5"}};
+const FeatureEntry::FeatureParam kGamepadPollingRate250Hz[] = {
+    {features::kGamepadPollingIntervalParamKey, "4"}};
+
+const FeatureEntry::FeatureVariation kGamepadPollingRateVariations[] = {
+    {"(100 Hz)", kGamepadPollingRate100Hz, base::size(kGamepadPollingRate100Hz),
+     nullptr},
+    {"(125 Hz)", kGamepadPollingRate125Hz, base::size(kGamepadPollingRate125Hz),
+     nullptr},
+    {"(200 Hz)", kGamepadPollingRate200Hz, base::size(kGamepadPollingRate200Hz),
+     nullptr},
+    {"(250 Hz)", kGamepadPollingRate250Hz, base::size(kGamepadPollingRate250Hz),
+     nullptr},
 };
 
 // RECORDING USER METRICS FOR FLAGS:
@@ -1464,6 +1476,9 @@
     {"new-tab-button-position", flag_descriptions::kNewTabButtonPosition,
      flag_descriptions::kNewTabButtonPositionDescription, kOsDesktop,
      MULTI_VALUE_TYPE(kNewTabButtonPositionChoices)},
+    {"single-tab-mode", flag_descriptions::kSingleTabMode,
+     flag_descriptions::kSingleTabModeDescription, kOsDesktop,
+     FEATURE_VALUE_TYPE(features::kSingleTabMode)},
     {"site-settings", flag_descriptions::kSiteSettings,
      flag_descriptions::kSiteSettingsDescription, kOsDesktop,
      FEATURE_VALUE_TYPE(features::kSiteSettings)},
@@ -1580,6 +1595,9 @@
     {"shelf-hover-previews", flag_descriptions::kShelfHoverPreviewsName,
      flag_descriptions::kShelfHoverPreviewsDescription, kOsCrOS,
      SINGLE_VALUE_TYPE(chromeos::switches::kShelfHoverPreviews)},
+    {"shelf-new-ui", flag_descriptions::kShelfNewUiName,
+     flag_descriptions::kShelfNewUiDescription, kOsCrOS,
+     SINGLE_VALUE_TYPE(chromeos::switches::kShelfNewUi)},
     {"show-taps", flag_descriptions::kShowTapsName,
      flag_descriptions::kShowTapsDescription, kOsCrOS,
      SINGLE_VALUE_TYPE(ash::switches::kShowTaps)},
@@ -2247,10 +2265,6 @@
      FEATURE_WITH_PARAMS_VALUE_TYPE(features::kWebXrRenderPath,
                                     kWebXrRenderPathVariations,
                                     "WebXrRenderPath")},
-    {"vr-browsing-experimental-rendering",
-     flag_descriptions::kVrBrowsingExperimentalRenderingName,
-     flag_descriptions::kVrBrowsingExperimentalRenderingDescription, kOsAndroid,
-     FEATURE_VALUE_TYPE(features::kVrBrowsingExperimentalRendering)},
     // TODO(crbug.com/731802): Only these should be #if defined(OS_ANDROID).
     {"vr-browsing-tabs-view", flag_descriptions::kVrBrowsingTabsViewName,
      flag_descriptions::kVrBrowsingTabsViewDescription, kOsAndroid,
@@ -4031,7 +4045,9 @@
 
     {"gamepad-polling-rate", flag_descriptions::kGamepadPollingRateName,
      flag_descriptions::kGamepadPollingRateDescription, kOsDesktop,
-     MULTI_VALUE_TYPE(kGamepadPollingRateChoices)},
+     FEATURE_WITH_PARAMS_VALUE_TYPE(features::kGamepadPollingInterval,
+                                    kGamepadPollingRateVariations,
+                                    "GamepadPollingInterval")},
 
 #if defined(OS_CHROMEOS)
     {"enable-drive-fs", flag_descriptions::kEnableDriveFsName,
diff --git a/chrome/browser/android/download/download_media_parser_bridge.cc b/chrome/browser/android/download/download_media_parser_bridge.cc
new file mode 100644
index 0000000..fa3f371
--- /dev/null
+++ b/chrome/browser/android/download/download_media_parser_bridge.cc
@@ -0,0 +1,47 @@
+// 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.
+
+#include "chrome/browser/android/download/download_media_parser_bridge.h"
+
+#include "base/android/jni_string.h"
+#include "base/files/file_path.h"
+#include "base/task_scheduler/post_task.h"
+#include "chrome/browser/android/download/download_media_parser.h"
+#include "jni/DownloadMediaParserBridge_jni.h"
+
+// static
+jlong JNI_DownloadMediaParserBridge_Init(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& jcaller) {
+  auto* bridge = new DownloadMediaParserBridge;
+  return reinterpret_cast<intptr_t>(bridge);
+}
+
+DownloadMediaParserBridge::DownloadMediaParserBridge()
+    : disk_io_task_runner_(
+          base::CreateSingleThreadTaskRunnerWithTraits({base::MayBlock()})),
+      parser_(std::make_unique<DownloadMediaParser>(disk_io_task_runner_)) {}
+
+DownloadMediaParserBridge::~DownloadMediaParserBridge() = default;
+
+void DownloadMediaParserBridge::Destory(JNIEnv* env, jobject obj) {
+  delete this;
+}
+
+void DownloadMediaParserBridge::ParseMediaFile(
+    JNIEnv* env,
+    jobject obj,
+    const base::android::JavaParamRef<jstring>& jmime_type,
+    const base::android::JavaParamRef<jstring>& jfile_path,
+    jlong jtotal_size,
+    const base::android::JavaParamRef<jobject>& jcallback) {
+  base::FilePath file_path(
+      base::android::ConvertJavaStringToUTF8(env, jfile_path));
+  std::string mime_type =
+      base::android::ConvertJavaStringToUTF8(env, jmime_type);
+
+  // TODO(xingliu): Pass the result back to Java.
+  parser_->ParseMediaFile(static_cast<int64_t>(jtotal_size), mime_type,
+                          file_path, base::DoNothing());
+}
diff --git a/chrome/browser/android/download/download_media_parser_bridge.h b/chrome/browser/android/download/download_media_parser_bridge.h
new file mode 100644
index 0000000..52bcba0
--- /dev/null
+++ b/chrome/browser/android/download/download_media_parser_bridge.h
@@ -0,0 +1,41 @@
+// 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.
+
+#ifndef CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_MEDIA_PARSER_BRIDGE_H_
+#define CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_MEDIA_PARSER_BRIDGE_H_
+
+#include <memory>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+
+class DownloadMediaParser;
+
+// The JNI bridge that uses DownloadMediaParser to parse local media file. The
+// bridge is owned by the Java side.
+class DownloadMediaParserBridge {
+ public:
+  DownloadMediaParserBridge();
+  ~DownloadMediaParserBridge();
+
+  void Destory(JNIEnv* env, jobject obj);
+  void ParseMediaFile(JNIEnv* env,
+                      jobject obj,
+                      const base::android::JavaParamRef<jstring>& jmime_type,
+                      const base::android::JavaParamRef<jstring>& jfile_path,
+                      jlong jtotal_size,
+                      const base::android::JavaParamRef<jobject>& jcallback);
+
+ private:
+  // The task runner that performs blocking disk IO. Created by this object.
+  scoped_refptr<base::SingleThreadTaskRunner> disk_io_task_runner_;
+
+  // The media parser that does actual jobs in a sandboxed process.
+  std::unique_ptr<DownloadMediaParser> parser_;
+
+  DISALLOW_COPY_AND_ASSIGN(DownloadMediaParserBridge);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_DOWNLOAD_DOWNLOAD_MEDIA_PARSER_BRIDGE_H_
diff --git a/chrome/browser/android/vr/vr_shell.cc b/chrome/browser/android/vr/vr_shell.cc
index 113fef4b..395646e 100644
--- a/chrome/browser/android/vr/vr_shell.cc
+++ b/chrome/browser/android/vr/vr_shell.cc
@@ -1345,8 +1345,6 @@
   ui_initial_state.in_web_vr = for_web_vr;
   ui_initial_state.has_or_can_request_audio_permission =
       has_or_can_request_audio_permission;
-  ui_initial_state.skips_redraw_when_not_dirty =
-      base::FeatureList::IsEnabled(features::kVrBrowsingExperimentalRendering);
   ui_initial_state.assets_supported = AssetsLoader::AssetsSupported();
   ui_initial_state.is_standalone_vr_device = is_standalone_vr_device;
   ui_initial_state.create_tabs_view =
diff --git a/chrome/browser/android/vr/vr_shell_gl.cc b/chrome/browser/android/vr/vr_shell_gl.cc
index 5a459e5a..0597d3e3 100644
--- a/chrome/browser/android/vr/vr_shell_gl.cc
+++ b/chrome/browser/android/vr/vr_shell_gl.cc
@@ -127,8 +127,6 @@
 // Drop at most one frame in MaxDropRate.
 constexpr int kWebVrUnstuffMaxDropRate = 7;
 
-constexpr float kRedrawSceneAngleDeltaDegrees = 1.0;
-
 // Taken from the GVR source code, this is the default vignette border fraction.
 constexpr float kContentVignetteBorder = 0.04;
 constexpr float kContentVignetteScale = 1.0 + (kContentVignetteBorder * 2.0);
@@ -1583,31 +1581,14 @@
     ui_updated = true;
   }
 
-  // TODO(mthiesse): Determine if a visible controller is actually drawn in the
-  // viewport.
-  bool controller_dirty = ui_->IsControllerVisible();
-
   ui_updated |= content_frame_available_;
   ReportUiStatusForTesting(scene_start, ui_updated);
 
-  // TODO(mthiesse): Refine this notion of when we need to redraw. If only a
-  // portion of the screen is dirtied, we can update just redraw that portion.
-  bool redraw_needed = controller_dirty || ui_updated;
-
-  bool head_moved =
-      HeadMoveExceedsThreshold(last_used_head_pose_, render_info_.head_pose,
-                               kRedrawSceneAngleDeltaDegrees);
-
-  bool dirty = is_webvr_frame || head_moved || redraw_needed;
-
   base::TimeDelta scene_time = base::TimeTicks::Now() - scene_start;
   // Don't double-count the controller time that was part of the scene time.
   ui_processing_time_.AddSample(scene_time - controller_time);
   TRACE_EVENT_END0("gpu", "SceneUpdate");
 
-  if (!dirty && ui_->SkipsRedrawWhenNotDirty())
-    return;
-
   UpdateViewports();
 
   // If needed, resize the primary buffer for use with WebVR. Resizing
diff --git a/chrome/browser/app_controller_mac.h b/chrome/browser/app_controller_mac.h
index 2b9a68a9..9836d28 100644
--- a/chrome/browser/app_controller_mac.h
+++ b/chrome/browser/app_controller_mac.h
@@ -193,6 +193,10 @@
 // already existed, notify the AppController of the profile in use.
 void CreateGuestProfileIfNeeded();
 
+// Called when Enterprise startup dialog is close and repost
+// applicationDidFinished notification.
+void EnterpriseStartupDialogClosed();
+
 }  // namespace app_controller_mac
 
 #endif  // CHROME_BROWSER_APP_CONTROLLER_MAC_H_
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm
index 2f5749e..b1cd4aa 100644
--- a/chrome/browser/app_controller_mac.mm
+++ b/chrome/browser/app_controller_mac.mm
@@ -197,9 +197,6 @@
   return has_entry && entry->IsSigninRequired();
 }
 
-// Called when Chrome is launched successfully.
-void LaunchFinished(NSNotification* notify);
-
 }  // namespace
 
 @interface AppController () <HandoffActiveURLObserverBridgeDelegate>
@@ -230,11 +227,6 @@
 // NTP after all the |urls| have been opened.
 - (void)openUrlsReplacingNTP:(const std::vector<GURL>&)urls;
 
-// Finish Chrome launching. It usually called by -applicationDidFinishLaunching:
-// notification. However, it will be delayed until Chrome browser window is
-// really if there is the EnterpriseStartupDialog blocks Chrome window display.
-- (void)doApplicationDidFinishLaunching:(NSNotification*)notify;
-
 // Whether instances of this class should use the Handoff feature.
 - (BOOL)shouldUseHandoff;
 
@@ -742,7 +734,15 @@
 
 // This is called after profiles have been loaded and preferences registered.
 // It is safe to access the default profile here.
-- (void)doApplicationDidFinishLaunching:(NSNotification*)notify {
+- (void)applicationDidFinishLaunching:(NSNotification*)notify {
+  if (g_browser_process->browser_policy_connector()
+          ->machine_level_user_cloud_policy_controller()
+          ->IsEnterpriseStartupDialogShowing()) {
+    // As Chrome is not ready when the Enterprise startup dialog is being shown.
+    // Store the notification as it will be reposted when the dialog is closed.
+    return;
+  }
+
   MacStartupProfiler::GetInstance()->Profile(
       MacStartupProfiler::DID_FINISH_LAUNCHING);
   MacStartupProfiler::GetInstance()->RecordMetrics();
@@ -816,20 +816,6 @@
 #endif
 }
 
-- (void)applicationDidFinishLaunching:(NSNotification*)notify {
-  if (g_browser_process->browser_policy_connector()
-          ->machine_level_user_cloud_policy_controller()
-          ->IsEnterpriseStartupDialogShowing()) {
-    // Repost the function with a delayed task if the enterprise startup dialog
-    // is being displayed. Because Chrome is not ready when the dialog is shown.
-    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-        FROM_HERE, base::BindOnce(&LaunchFinished, notify),
-        base::TimeDelta::FromSeconds(0));
-  } else {
-    [self doApplicationDidFinishLaunching:notify];
-  }
-}
-
 // Helper function for populating and displaying the in progress downloads at
 // exit alert panel.
 - (BOOL)userWillWaitForInProgressDownloads:(int)downloadCount {
@@ -1757,13 +1743,6 @@
   }
 }
 
-void LaunchFinished(NSNotification* notify) {
-  AppController* controller =
-      base::mac::ObjCCastStrict<AppController>([NSApp delegate]);
-  if (controller == nil)
-    [controller doApplicationDidFinishLaunching:notify];
-}
-
 }  // namespace
 
 namespace app_controller_mac {
@@ -1779,4 +1758,15 @@
       std::string());
 }
 
+void EnterpriseStartupDialogClosed() {
+  AppController* controller =
+      base::mac::ObjCCastStrict<AppController>([NSApp delegate]);
+  if (controller != nil) {
+    NSNotification* notify = [NSNotification
+        notificationWithName:NSApplicationDidFinishLaunchingNotification
+                      object:NSApp];
+    [controller applicationDidFinishLaunching:notify];
+  }
+}
+
 }  // namespace app_controller_mac
diff --git a/chrome/browser/captive_portal/captive_portal_browsertest.cc b/chrome/browser/captive_portal/captive_portal_browsertest.cc
index bb58d4f2..281f752e 100644
--- a/chrome/browser/captive_portal/captive_portal_browsertest.cc
+++ b/chrome/browser/captive_portal/captive_portal_browsertest.cc
@@ -82,8 +82,6 @@
 using captive_portal::CaptivePortalResult;
 using content::BrowserThread;
 using content::WebContents;
-using net::URLRequestFailedJob;
-using net::URLRequestMockHTTPJob;
 
 namespace {
 
@@ -139,6 +137,16 @@
 const char* const kMockHttpsQuickTimeoutUrl =
     "https://mock.captive.portal.quick.timeout/title2.html";
 
+// The intercepted URLs used to mock errors.
+const char* const kMockHttpConnectionTimeoutErr =
+    "http://mock.captive.portal.quick.error/timeout";
+const char* const kMockHttpsConnectionTimeoutErr =
+    "https://mock.captive.portal.quick.error/timeout";
+const char* const kMockHttpsConnectionUnexpectedErr =
+    "https://mock.captive.portal.quick.error/unexpected";
+const char* const kMockHttpConnectionConnectionClosedErr =
+    "http://mock.captive.portal.quick.error/connection_closed";
+
 // Expected title of a tab once an HTTPS load completes, when not behind a
 // captive portal.
 const char* const kInternetConnectedTitle = "Title Of Awesomeness";
@@ -898,6 +906,20 @@
   }
 
   auto url_string = params->url_request.url.spec();
+  net::Error error = net::OK;
+  if (url_string == kMockHttpConnectionTimeoutErr ||
+      url_string == kMockHttpsConnectionTimeoutErr) {
+    error = net::ERR_CONNECTION_TIMED_OUT;
+  } else if (url_string == kMockHttpsConnectionUnexpectedErr) {
+    error = net::ERR_UNEXPECTED;
+  } else if (url_string == kMockHttpConnectionConnectionClosedErr) {
+    error = net::ERR_CONNECTION_CLOSED;
+  }
+  if (error != net::OK) {
+    params->client->OnComplete(network::URLLoaderCompletionStatus(error));
+    return true;
+  }
+
   if (url_string == kMockHttpsUrl || url_string == kMockHttpsUrl2 ||
       url_string == kMockHttpsQuickTimeoutUrl ||
       params->url_request.url.path() == kRedirectToMockHttpsPath) {
@@ -939,8 +961,8 @@
         }
       }
     } else {
-      // Once logged in to the portal, HTTPS requests return the
-      // page that was actually requested.
+      // Once logged in to the portal, HTTPS requests return the page that was
+      // actually requested.
       content::URLLoaderInterceptor::WriteResponse(
           "HTTP/1.1 200 OK\nContent-type: text/html\n\n",
           GetContents("title2.html"), params->client.get());
@@ -1146,9 +1168,7 @@
   int active_index = browser->tab_strip_model()->active_index();
   int expected_tab_count = browser->tab_strip_model()->count();
 
-  ui_test_utils::NavigateToURL(
-      browser,
-      URLRequestFailedJob::GetMockHttpsUrl(net::ERR_CONNECTION_TIMED_OUT));
+  ui_test_utils::NavigateToURL(browser, GURL(kMockHttpsConnectionTimeoutErr));
 
   // An attempt to detect a captive portal should have started by now.  If not,
   // abort early to prevent hanging.
@@ -1641,15 +1661,14 @@
 // also trigger the link doctor page, which results in the load of a second
 // error page.
 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpTimeout) {
-  GURL url = URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_TIMED_OUT);
-  NavigateToPageExpectNoTest(browser(), url, 2);
+  NavigateToPageExpectNoTest(browser(), GURL(kMockHttpConnectionTimeoutErr), 2);
 }
 
 // Make sure there's no check for a captive portal on HTTPS errors other than
 // timeouts, when they preempt the slow load timer.
 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, HttpsNonTimeoutError) {
-  GURL url = URLRequestFailedJob::GetMockHttpsUrl(net::ERR_UNEXPECTED);
-  NavigateToPageExpectNoTest(browser(), url, 1);
+  NavigateToPageExpectNoTest(browser(), GURL(kMockHttpsConnectionUnexpectedErr),
+                             1);
 }
 
 // Make sure no captive portal test triggers on HTTPS timeouts of iframes.
@@ -1667,18 +1686,16 @@
 // error.  The check is triggered by a slow loading page, and the page
 // errors out only after getting a captive portal result.
 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RequestFails) {
-  SetUpCaptivePortalService(
-      browser()->profile(),
-      URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_CLOSED));
+  SetUpCaptivePortalService(browser()->profile(),
+                            GURL(kMockHttpConnectionConnectionClosedErr));
   SlowLoadNoCaptivePortal(browser(), captive_portal::RESULT_NO_RESPONSE);
 }
 
 // Same as above, but for the rather unlikely case that the connection times out
 // before the timer triggers.
 IN_PROC_BROWSER_TEST_F(CaptivePortalBrowserTest, RequestFailsFastTimout) {
-  SetUpCaptivePortalService(
-      browser()->profile(),
-      URLRequestFailedJob::GetMockHttpUrl(net::ERR_CONNECTION_CLOSED));
+  SetUpCaptivePortalService(browser()->profile(),
+                            GURL(kMockHttpConnectionConnectionClosedErr));
   FastTimeoutNoCaptivePortal(browser(), captive_portal::RESULT_NO_RESPONSE);
 }
 
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 2c95438..6787c04a 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -229,6 +229,7 @@
 #include <Security/Security.h>
 
 #include "base/mac/scoped_nsautorelease_pool.h"
+#include "chrome/browser/app_controller_mac.h"
 #include "chrome/browser/mac/keystone_glue.h"
 #endif  // defined(OS_MACOSX)
 
@@ -756,7 +757,12 @@
   switch (connector->machine_level_user_cloud_policy_controller()
               ->WaitUntilPolicyEnrollmentFinished()) {
     case RegisterResult::kNoEnrollmentNeeded:
+    case RegisterResult::kEnrollmentSuccessBeforeDialogDisplayed:
+      return true;
     case RegisterResult::kEnrollmentSuccess:
+#if defined(OS_MACOSX)
+      app_controller_mac::EnterpriseStartupDialogClosed();
+#endif
       return true;
     case RegisterResult::kRestartDueToFailure:
       chrome::AttemptRestart();
diff --git a/chrome/browser/chromeos/arc/auth/arc_auth_context.cc b/chrome/browser/chromeos/arc/auth/arc_auth_context.cc
index 1145ea2..97470a7 100644
--- a/chrome/browser/chromeos/arc/auth/arc_auth_context.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_auth_context.cc
@@ -19,6 +19,7 @@
 #include "content/public/common/url_constants.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 #include "google_apis/gaia/gaia_constants.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace arc {
 
@@ -123,9 +124,9 @@
     return;
   }
 
-  ubertoken_fetcher_.reset(new UbertokenFetcher(token_service_, this,
-                                                GaiaConstants::kChromeOSSource,
-                                                profile_->GetRequestContext()));
+  ubertoken_fetcher_.reset(
+      new UbertokenFetcher(token_service_, this, GaiaConstants::kChromeOSSource,
+                           profile_->GetURLLoaderFactory()));
   ubertoken_fetcher_->StartFetchingToken(account_id_);
 }
 
@@ -156,7 +157,7 @@
 void ArcAuthContext::OnUbertokenSuccess(const std::string& token) {
   ResetFetchers();
   merger_fetcher_.reset(new GaiaAuthFetcher(
-      this, GaiaConstants::kChromeOSSource, profile_->GetRequestContext()));
+      this, GaiaConstants::kChromeOSSource, profile_->GetURLLoaderFactory()));
   merger_fetcher_->StartMergeSession(token, std::string());
 }
 
diff --git a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
index 05cbb66..c48859a 100644
--- a/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
+++ b/chrome/browser/chromeos/child_accounts/screen_time_controller.cc
@@ -106,13 +106,15 @@
                                  first_screen_start_time_, now, last_state);
   SaveCurrentStateToPref(state);
 
+  // Show/hide time limits message based on the policy enforcement.
+  UpdateTimeLimitsMessage(
+      state.is_locked, state.is_locked ? state.next_unlock_time : base::Time());
+
   if (state.is_locked) {
     DCHECK(!state.next_unlock_time.is_null());
-    LockScreen(true /*force_lock_by_policy*/, state.next_unlock_time);
+    if (!session_manager::SessionManager::Get()->IsScreenLocked())
+      ForceScreenLockByPolicy(state.next_unlock_time);
   } else {
-    LockScreen(false /*force_lock_by_policy*/,
-               base::Time() /*next_unlock_time*/);
-
     base::Optional<TimeLimitNotificationType> notification_type;
     switch (state.next_state_active_policy) {
       case usage_time_limit::ActivePolicies::kFixedLimit:
@@ -175,28 +177,31 @@
   }
 }
 
-void ScreenTimeController::LockScreen(bool force_lock_by_policy,
-                                      base::Time next_unlock_time) {
-  bool is_locked = session_manager::SessionManager::Get()->IsScreenLocked();
-  // No-op if the screen is currently not locked and policy does not force the
-  // lock.
-  if (!is_locked && !force_lock_by_policy)
-    return;
+void ScreenTimeController::ForceScreenLockByPolicy(
+    base::Time next_unlock_time) {
+  DCHECK(!session_manager::SessionManager::Get()->IsScreenLocked());
+  chromeos::DBusThreadManager::Get()
+      ->GetSessionManagerClient()
+      ->RequestLockScreen();
 
-  // Request to show lock screen.
-  if (!is_locked && force_lock_by_policy) {
-    chromeos::DBusThreadManager::Get()
-        ->GetSessionManagerClient()
-        ->RequestLockScreen();
-  }
+  // Update the time limits message when the lock screen UI is ready.
+  next_unlock_time_ = next_unlock_time;
+}
+
+void ScreenTimeController::UpdateTimeLimitsMessage(
+    bool visible,
+    base::Time next_unlock_time) {
+  DCHECK(visible || next_unlock_time.is_null());
+  if (!session_manager::SessionManager::Get()->IsScreenLocked())
+    return;
 
   AccountId account_id =
       chromeos::ProfileHelper::Get()
           ->GetUserByProfile(Profile::FromBrowserContext(context_))
           ->GetAccountId();
   LoginScreenClient::Get()->login_screen()->SetAuthEnabledForUser(
-      account_id, !force_lock_by_policy,
-      force_lock_by_policy ? next_unlock_time : base::Optional<base::Time>());
+      account_id, !visible,
+      visible ? next_unlock_time : base::Optional<base::Time>());
 }
 
 void ScreenTimeController::ShowNotification(
@@ -389,6 +394,10 @@
   session_manager::SessionState session_state =
       session_manager::SessionManager::Get()->session_state();
   if (session_state == session_manager::SessionState::LOCKED) {
+    if (next_unlock_time_) {
+      UpdateTimeLimitsMessage(true /*visible*/, next_unlock_time_.value());
+      next_unlock_time_.reset();
+    }
     SaveScreenTimeProgressBeforeExit();
   } else if (session_state == session_manager::SessionState::ACTIVE) {
     base::Time now = base::Time::Now();
diff --git a/chrome/browser/chromeos/child_accounts/screen_time_controller.h b/chrome/browser/chromeos/child_accounts/screen_time_controller.h
index 38d2286..63d607d 100644
--- a/chrome/browser/chromeos/child_accounts/screen_time_controller.h
+++ b/chrome/browser/chromeos/child_accounts/screen_time_controller.h
@@ -47,11 +47,19 @@
   // the bed time is approaching.
   enum TimeLimitNotificationType { kScreenTime, kBedTime };
 
-  // Show and update the lock screen when necessary.
-  // |force_lock_by_policy|: If true, force to lock the screen based on the
-  //                         screen time policy.
-  // |next_unlock_time|:     When the screen is available again.
-  void LockScreen(bool force_lock_by_policy, base::Time next_unlock_time);
+  // Request to lock the screen and show the time limits message when the screen
+  // is locked.
+  void ForceScreenLockByPolicy(base::Time next_unlock_time);
+
+  // Update visibility and content of the time limits message in the lock
+  // screen.
+  // |visible|: If true, user authentication is disabled and a message is shown
+  //            to indicate when user will be able to unlock the screen.
+  //            If false, message is dismissed and user is able to unlock
+  //            immediately.
+  // |next_unlock_time|: When user will be able to unlock the screen, only valid
+  //                     when |visible| is true.
+  void UpdateTimeLimitsMessage(bool visible, base::Time next_unlock_time);
 
   // Show a notification indicating the remaining screen time.
   void ShowNotification(ScreenTimeController::TimeLimitNotificationType type,
@@ -106,6 +114,9 @@
 
   PrefChangeRegistrar pref_change_registrar_;
 
+  // Used to update the time limits message, if any, when screen is locked.
+  base::Optional<base::Time> next_unlock_time_;
+
   DISALLOW_COPY_AND_ASSIGN(ScreenTimeController);
 };
 
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service.cc b/chrome/browser/chromeos/crostini/crostini_registry_service.cc
index 6cf6d63..6b822db7 100644
--- a/chrome/browser/chromeos/crostini/crostini_registry_service.cc
+++ b/chrome/browser/chromeos/crostini/crostini_registry_service.cc
@@ -116,7 +116,8 @@
                           base::StringPiece prefs_key,
                           base::StringPiece search_value,
                           std::string* result,
-                          bool require_startup_notify = false) {
+                          bool require_startup_notify = false,
+                          bool need_display = false) {
   result->clear();
   for (const auto& item : prefs->DictItems()) {
     if (item.first == kCrostiniTerminalId)
@@ -128,6 +129,13 @@
              ->GetBool())
       continue;
 
+    if (need_display) {
+      const base::Value* no_display = item.second.FindKeyOfType(
+          kAppNoDisplayKey, base::Value::Type::BOOLEAN);
+      if (no_display && no_display->GetBool())
+        continue;
+    }
+
     const base::Value* value = item.second.FindKey(prefs_key);
     if (!value)
       continue;
@@ -378,8 +386,9 @@
       FindAppIdResult::UniqueMatch)
     return app_id;
 
-  if (FindAppId(apps, kAppNameKey, key, &app_id) ==
-      FindAppIdResult::UniqueMatch)
+  if (FindAppId(apps, kAppNameKey, key, &app_id,
+                false /* require_startup_notification */,
+                true /* need_display */) == FindAppIdResult::UniqueMatch)
     return app_id;
 
   return kCrostiniAppIdPrefix + *window_app_id;
diff --git a/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc b/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc
index 591e235..c987f15 100644
--- a/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc
+++ b/chrome/browser/chromeos/crostini/crostini_registry_service_unittest.cc
@@ -411,4 +411,16 @@
             CrostiniTestHelper::GenerateAppId("app2", "vm", "container"));
 }
 
+TEST_F(CrostiniRegistryServiceTest, GetCrostiniAppIdNameSkipNoDisplay) {
+  ApplicationList app_list =
+      CrostiniTestHelper::BasicAppList("app", "vm", "container");
+  *app_list.add_apps() = CrostiniTestHelper::BasicApp("app2", "name2");
+  *app_list.add_apps() = CrostiniTestHelper::BasicApp("another_app2", "name2",
+                                                      true /* no_display */);
+  service()->UpdateApplicationList(app_list);
+
+  std::string window_app_id = WindowIdForWMClass("name2");
+  EXPECT_EQ(service()->GetCrostiniShelfAppId(&window_app_id, nullptr),
+            CrostiniTestHelper::GenerateAppId("app2", "vm", "container"));
+}
 }  // namespace crostini
diff --git a/chrome/browser/chromeos/crostini/crostini_test_helper.cc b/chrome/browser/chromeos/crostini/crostini_test_helper.cc
index 4a27b10d..3caafaf 100644
--- a/chrome/browser/chromeos/crostini/crostini_test_helper.cc
+++ b/chrome/browser/chromeos/crostini/crostini_test_helper.cc
@@ -79,12 +79,14 @@
 
 // static
 App CrostiniTestHelper::BasicApp(const std::string& desktop_file_id,
-                                 const std::string& name) {
+                                 const std::string& name,
+                                 bool no_display) {
   App app;
   app.set_desktop_file_id(desktop_file_id);
   App::LocaleString::Entry* entry = app.mutable_name()->add_values();
   entry->set_locale(std::string());
   entry->set_value(name.empty() ? desktop_file_id : name);
+  app.set_no_display(no_display);
   return app;
 }
 
diff --git a/chrome/browser/chromeos/crostini/crostini_test_helper.h b/chrome/browser/chromeos/crostini/crostini_test_helper.h
index f4556a9..3abf8aa 100644
--- a/chrome/browser/chromeos/crostini/crostini_test_helper.h
+++ b/chrome/browser/chromeos/crostini/crostini_test_helper.h
@@ -45,9 +45,11 @@
       const std::string& vm_name = kCrostiniDefaultVmName,
       const std::string& container_name = kCrostiniDefaultContainerName);
 
-  // Returns an App with the desktop file id and default name as provided.
+  // Returns an App with the desktop file id, default name, and no_display
+  // as provided.
   static vm_tools::apps::App BasicApp(const std::string& desktop_file_id,
-                                      const std::string& name = "");
+                                      const std::string& name = "",
+                                      bool no_display = false);
 
   // Returns an ApplicationList with a single desktop file.
   static vm_tools::apps::ApplicationList BasicAppList(
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
index 6ef652b8..4cfe19a2 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_drive.cc
@@ -1529,8 +1529,7 @@
       content::BrowserContext::GetDefaultStoragePartition(GetProfile())
           ->GetURLLoaderFactoryForBrowserProcess();
   auth_service_ = std::make_unique<google_apis::AuthService>(
-      oauth2_token_service, account_id, GetProfile()->GetRequestContext(),
-      url_loader_factory, scopes);
+      oauth2_token_service, account_id, url_loader_factory, scopes);
   auth_service_->StartAuthentication(base::Bind(
       &FileManagerPrivateInternalGetDownloadUrlFunction::OnTokenFetched, this));
 }
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
index 61f6dcf..c963b70 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_misc.cc
@@ -358,8 +358,6 @@
 
   ProfileOAuth2TokenService* oauth_service =
       ProfileOAuth2TokenServiceFactory::GetForProfile(GetProfile());
-  net::URLRequestContextGetter* url_request_context_getter =
-      g_browser_process->system_request_context();
 
   if (!oauth_service) {
     drive::EventLogger* logger = file_manager::util::GetLogger(GetProfile());
@@ -376,7 +374,6 @@
       SigninManagerFactory::GetForProfile(GetProfile());
   auth_service_ = std::make_unique<google_apis::AuthService>(
       oauth_service, signin_manager->GetAuthenticatedAccountId(),
-      url_request_context_getter,
       g_browser_process->system_network_context_manager()
           ->GetSharedURLLoaderFactory(),
       scopes);
diff --git a/chrome/browser/chromeos/login/auth/chrome_login_performer.cc b/chrome/browser/chromeos/login/auth/chrome_login_performer.cc
index ece58b47..d005964 100644
--- a/chrome/browser/chromeos/login/auth/chrome_login_performer.cc
+++ b/chrome/browser/chromeos/login/auth/chrome_login_performer.cc
@@ -100,8 +100,8 @@
       !connector->IsNonEnterpriseUser(account_id.GetUserEmail())) {
     wildcard_login_checker_.reset(new policy::WildcardLoginChecker());
     if (refresh_token.empty()) {
-      wildcard_login_checker_->StartWithSigninContext(
-          GetSigninRequestContext(),
+      wildcard_login_checker_->StartWithSigninURLLoaderFactory(
+          GetSigninURLLoaderFactory(),
           base::Bind(&ChromeLoginPerformer::OnlineWildcardLoginCheckCompleted,
                      weak_factory_.GetWeakPtr(), success_callback,
                      failure_callback));
@@ -170,8 +170,9 @@
   return ProfileHelper::GetSigninProfile();
 }
 
-net::URLRequestContextGetter* ChromeLoginPerformer::GetSigninRequestContext() {
-  return login::GetSigninContext();
+scoped_refptr<network::SharedURLLoaderFactory>
+ChromeLoginPerformer::GetSigninURLLoaderFactory() {
+  return login::GetSigninURLLoaderFactory();
 }
 
 void ChromeLoginPerformer::OnlineWildcardLoginCheckCompleted(
diff --git a/chrome/browser/chromeos/login/auth/chrome_login_performer.h b/chrome/browser/chromeos/login/auth/chrome_login_performer.h
index 1353e94..0d169774 100644
--- a/chrome/browser/chromeos/login/auth/chrome_login_performer.h
+++ b/chrome/browser/chromeos/login/auth/chrome_login_performer.h
@@ -61,7 +61,8 @@
   scoped_refptr<Authenticator> CreateAuthenticator() override;
   bool CheckPolicyForUser(const AccountId& account_id) override;
   content::BrowserContext* GetSigninContext() override;
-  net::URLRequestContextGetter* GetSigninRequestContext() override;
+  scoped_refptr<network::SharedURLLoaderFactory> GetSigninURLLoaderFactory()
+      override;
 
  private:
   void OnlineWildcardLoginCheckCompleted(
diff --git a/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc b/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc
index a404bd1..2be584c 100644
--- a/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc
+++ b/chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.cc
@@ -52,7 +52,8 @@
 TokenRevoker::TokenRevoker()
     : gaia_fetcher_(this,
                     GaiaConstants::kChromeOSSource,
-                    g_browser_process->system_request_context()) {}
+                    g_browser_process->system_network_context_manager()
+                        ->GetSharedURLLoaderFactory()) {}
 
 TokenRevoker::~TokenRevoker() {}
 
@@ -99,7 +100,7 @@
   oauth_status_ = OAUTH_STARTED_WITH_AUTH_CODE;
   oauth_fetcher_.reset(policy::PolicyOAuth2TokenFetcher::CreateInstance());
   oauth_fetcher_->StartWithAuthCode(
-      auth_code, g_browser_process->system_request_context(),
+      auth_code,
       g_browser_process->system_network_context_manager()
           ->GetSharedURLLoaderFactory(),
       base::Bind(&EnterpriseEnrollmentHelperImpl::OnTokenFetched,
@@ -270,7 +271,7 @@
   std::string refresh_token = oauth_fetcher_->OAuth2RefreshToken();
   oauth_fetcher_.reset(policy::PolicyOAuth2TokenFetcher::CreateInstance());
   oauth_fetcher_->StartWithRefreshToken(
-      refresh_token, g_browser_process->system_request_context(),
+      refresh_token,
       g_browser_process->system_network_context_manager()
           ->GetSharedURLLoaderFactory(),
       base::Bind(&EnterpriseEnrollmentHelperImpl::OnTokenFetched,
diff --git a/chrome/browser/chromeos/login/helper.cc b/chrome/browser/chromeos/login/helper.cc
index b3f01e3a..252e360 100644
--- a/chrome/browser/chromeos/login/helper.cc
+++ b/chrome/browser/chromeos/login/helper.cc
@@ -33,6 +33,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/display/display.h"
@@ -196,6 +197,20 @@
   return signin_partition->GetURLRequestContext();
 }
 
+scoped_refptr<network::SharedURLLoaderFactory> GetSigninURLLoaderFactory() {
+  content::StoragePartition* signin_partition = GetSigninPartition();
+
+  // Special case for unit tests. There's no LoginDisplayHost thus no
+  // webview instance. See http://crbug.com/477402
+  if (!signin_partition && !LoginDisplayHost::default_host())
+    return ProfileHelper::GetSigninProfile()->GetURLLoaderFactory();
+
+  if (!signin_partition)
+    return nullptr;
+
+  return signin_partition->GetURLLoaderFactoryForBrowserProcess();
+}
+
 void SaveSyncPasswordDataToProfile(const UserContext& user_context,
                                    Profile* profile) {
   DCHECK(user_context.GetSyncPasswordData().has_value());
diff --git a/chrome/browser/chromeos/login/helper.h b/chrome/browser/chromeos/login/helper.h
index 6639b7f..da77d51 100644
--- a/chrome/browser/chromeos/login/helper.h
+++ b/chrome/browser/chromeos/login/helper.h
@@ -11,6 +11,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/strings/string16.h"
 #include "chromeos/network/network_handler_callbacks.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -32,6 +33,10 @@
 class URLRequestContextGetter;
 }
 
+namespace network {
+class SharedURLLoaderFactory;
+}
+
 namespace chromeos {
 
 // Returns bounds of the screen to use for login wizard.
@@ -109,6 +114,12 @@
 // flow, the context of the sign-in webview storage partition is returned.
 net::URLRequestContextGetter* GetSigninContext();
 
+// Returns the URLLoaderFactory that contains sign-in cookies. For old iframe
+// based flow, the URLLoaderFactory of the sign-in profile is returned. For
+// webview basedflow, the URLLoaderFactory of the sign-in webview storage
+// partition is returned.
+scoped_refptr<network::SharedURLLoaderFactory> GetSigninURLLoaderFactory();
+
 // Saves sync password hash and salt to profile prefs. These will be used to
 // detect Gaia password reuses.
 void SaveSyncPasswordDataToProfile(const UserContext& user_context,
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index fa12950..b733db37 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -1610,25 +1610,27 @@
       OAuth2LoginManagerFactory::GetInstance()->GetForProfile(profile);
   login_manager->AddObserver(this);
 
-  net::URLRequestContextGetter* auth_request_context = GetAuthRequestContext();
+  scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory =
+      GetAuthURLLoaderFactory();
 
-  // Authentication request context may not be available if user was not
+  // Authentication URLLoaderFactory may not be available if user was not
   // signing in with GAIA webview (i.e. webview instance hasn't been
-  // initialized at all). Use fallback request context if authenticator was
+  // initialized at all). Use fallback URLLoaderFactory if authenticator was
   // provided.
   // Authenticator instance may not be initialized for session
   // restore case when Chrome is restarting after crash or to apply custom user
-  // flags. In that case auth_request_context will be nullptr which is accepted
-  // by RestoreSession() for session restore case.
-  if (!auth_request_context &&
+  // flags. In that case auth_url_loader_factory will be nullptr which is
+  // accepted by RestoreSession() for session restore case.
+  if (!auth_url_loader_factory &&
       (authenticator_.get() && authenticator_->authentication_context())) {
-    auth_request_context = content::BrowserContext::GetDefaultStoragePartition(
-                               authenticator_->authentication_context())
-                               ->GetURLRequestContext();
+    auth_url_loader_factory =
+        content::BrowserContext::GetDefaultStoragePartition(
+            authenticator_->authentication_context())
+            ->GetURLLoaderFactoryForBrowserProcess();
   }
-  login_manager->RestoreSession(auth_request_context, session_restore_strategy_,
-                                user_context_.GetRefreshToken(),
-                                user_context_.GetAccessToken());
+  login_manager->RestoreSession(
+      auth_url_loader_factory, session_restore_strategy_,
+      user_context_.GetRefreshToken(), user_context_.GetAccessToken());
 }
 
 void UserSessionManager::InitRlzImpl(Profile* profile,
@@ -1851,6 +1853,15 @@
   return signin_partition->GetURLRequestContext();
 }
 
+scoped_refptr<network::SharedURLLoaderFactory>
+UserSessionManager::GetAuthURLLoaderFactory() const {
+  content::StoragePartition* signin_partition = login::GetSigninPartition();
+  if (!signin_partition)
+    return nullptr;
+
+  return signin_partition->GetURLLoaderFactoryForBrowserProcess();
+}
+
 void UserSessionManager::OnEasyUnlockKeyOpsFinished(const std::string& user_id,
                                                     bool success) {
   const user_manager::User* user = user_manager::UserManager::Get()->FindUser(
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.h b/chrome/browser/chromeos/login/session/user_session_manager.h
index a2f9ae9..62bf49d 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.h
+++ b/chrome/browser/chromeos/login/session/user_session_manager.h
@@ -14,6 +14,7 @@
 #include "base/callback.h"
 #include "base/containers/flat_map.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/singleton.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
@@ -50,6 +51,10 @@
 class URLRequestContextGetter;
 }
 
+namespace network {
+class SharedURLLoaderFactory;
+}
+
 namespace user_manager {
 class User;
 }  // namespace user_manager
@@ -280,8 +285,11 @@
   // Update Easy unlock cryptohome keys for given user context.
   void UpdateEasyUnlockKeys(const UserContext& user_context);
 
-  // Returns the auth request context associated with auth data.
+  // Returns the auth request context/URLLoaderFactory associated with auth
+  // data.
   net::URLRequestContextGetter* GetAuthRequestContext() const;
+  scoped_refptr<network::SharedURLLoaderFactory> GetAuthURLLoaderFactory()
+      const;
 
   // Removes a profile from the per-user input methods states map.
   void RemoveProfileForTesting(Profile* profile);
diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc b/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc
index d60ff085..499aea7 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc
@@ -22,6 +22,7 @@
 #include "components/user_manager/user_manager.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_urls.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace chromeos {
 
@@ -51,12 +52,12 @@
 }
 
 void OAuth2LoginManager::RestoreSession(
-    net::URLRequestContextGetter* auth_request_context,
+    scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory,
     SessionRestoreStrategy restore_strategy,
     const std::string& oauth2_refresh_token,
     const std::string& oauth2_access_token) {
   DCHECK(user_profile_);
-  auth_request_context_ = auth_request_context;
+  auth_url_loader_factory_ = auth_url_loader_factory;
   restore_strategy_ = restore_strategy;
   refresh_token_ = oauth2_refresh_token;
   oauthlogin_access_token_ = oauth2_access_token;
@@ -192,7 +193,7 @@
 }
 
 void OAuth2LoginManager::FetchOAuth2Tokens() {
-  DCHECK(auth_request_context_.get());
+  DCHECK(auth_url_loader_factory_);
   if (restore_strategy_ != RESTORE_FROM_COOKIE_JAR) {
     NOTREACHED();
     SetSessionRestoreState(SESSION_RESTORE_FAILED);
@@ -206,8 +207,8 @@
   std::string signin_scoped_device_id =
       signin_client->GetSigninScopedDeviceId();
 
-  oauth2_token_fetcher_.reset(
-      new OAuth2TokenFetcher(this, auth_request_context_.get()));
+  oauth2_token_fetcher_ =
+      std::make_unique<OAuth2TokenFetcher>(this, auth_url_loader_factory_);
   oauth2_token_fetcher_->StartExchangeFromCookies(std::string(),
                                                   signin_scoped_device_id);
 }
diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_manager.h b/chrome/browser/chromeos/login/signin/oauth2_login_manager.h
index 418ac1b..c015839 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_login_manager.h
+++ b/chrome/browser/chromeos/login/signin/oauth2_login_manager.h
@@ -9,18 +9,22 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/login/signin/oauth2_login_verifier.h"
 #include "chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "google_apis/gaia/oauth2_token_service.h"
-#include "net/url_request/url_request_context_getter.h"
 
 class GoogleServiceAuthError;
 class Profile;
 class ProfileOAuth2TokenService;
 
+namespace network {
+class SharedURLLoaderFactory;
+}
+
 namespace chromeos {
 
 // This class is responsible for restoring authenticated web sessions out of
@@ -83,12 +87,12 @@
   // Restores and verifies OAuth tokens following specified |restore_strategy|.
   // For |restore_strategy| RESTORE_FROM_PASSED_OAUTH2_REFRESH_TOKEN, parameter
   // |oauth2_refresh_token| needs to have a non-empty value.
-  // For |restore_strategy| RESTORE_FROM_COOKIE_JAR |auth_request_context| must
-  // be initialized.
-  void RestoreSession(net::URLRequestContextGetter* auth_request_context,
-                      SessionRestoreStrategy restore_strategy,
-                      const std::string& oauth2_refresh_token,
-                      const std::string& oauth2_access_token);
+  // For |restore_strategy| RESTORE_FROM_COOKIE_JAR.
+  void RestoreSession(
+      scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory,
+      SessionRestoreStrategy restore_strategy,
+      const std::string& oauth2_refresh_token,
+      const std::string& oauth2_access_token);
 
   // Continues session restore after transient network errors.
   void ContinueSessionRestore();
@@ -217,7 +221,7 @@
   // Keeps the track if we have already reported OAuth2 token being loaded
   // by OAuth2TokenService.
   Profile* user_profile_;
-  scoped_refptr<net::URLRequestContextGetter> auth_request_context_;
+  scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory_;
   SessionRestoreStrategy restore_strategy_;
   SessionRestoreState state_;
 
diff --git a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc
index f305df36..abcce6d2 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.cc
@@ -12,6 +12,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/google_service_auth_error.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
 
 using content::BrowserThread;
@@ -29,9 +30,9 @@
 
 OAuth2TokenFetcher::OAuth2TokenFetcher(
     OAuth2TokenFetcher::Delegate* delegate,
-    net::URLRequestContextGetter* context_getter)
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
     : delegate_(delegate),
-      auth_fetcher_(this, GaiaConstants::kChromeSource, context_getter),
+      auth_fetcher_(this, GaiaConstants::kChromeSource, url_loader_factory),
       retry_count_(0) {
   DCHECK(delegate);
 }
diff --git a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h
index e93e1ee..99fc784e 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h
+++ b/chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h
@@ -10,12 +10,13 @@
 #include "base/callback_forward.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
 }
 
 namespace chromeos {
@@ -34,8 +35,9 @@
     virtual void OnOAuth2TokensFetchFailed() = 0;
   };
 
-  OAuth2TokenFetcher(OAuth2TokenFetcher::Delegate* delegate,
-                     net::URLRequestContextGetter* context_getter);
+  OAuth2TokenFetcher(
+      OAuth2TokenFetcher::Delegate* delegate,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
   ~OAuth2TokenFetcher() override;
 
   void StartExchangeFromCookies(const std::string& session_index,
diff --git a/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc b/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc
index 303b613..b6956e3e 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_token_initializer.cc
@@ -5,7 +5,9 @@
 #include "chrome/browser/chromeos/login/signin/oauth2_token_initializer.h"
 
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/common/chrome_features.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace chromeos {
 
@@ -19,7 +21,8 @@
   callback_ = callback;
   user_context_ = user_context;
   oauth2_token_fetcher_.reset(new OAuth2TokenFetcher(
-      this, g_browser_process->system_request_context()));
+      this, g_browser_process->system_network_context_manager()
+                ->GetSharedURLLoaderFactory()));
   if (user_context.GetDeviceId().empty())
     NOTREACHED() << "Device ID is not set";
   oauth2_token_fetcher_->StartExchangeFromAuthCode(user_context.GetAuthCode(),
diff --git a/chrome/browser/chromeos/oauth2_token_service_delegate.cc b/chrome/browser/chromeos/oauth2_token_service_delegate.cc
index a77b672e..c46347ec 100644
--- a/chrome/browser/chromeos/oauth2_token_service_delegate.cc
+++ b/chrome/browser/chromeos/oauth2_token_service_delegate.cc
@@ -30,7 +30,6 @@
 OAuth2AccessTokenFetcher*
 ChromeOSOAuth2TokenServiceDelegate::CreateAccessTokenFetcher(
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     OAuth2AccessTokenConsumer* consumer) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
@@ -139,11 +138,6 @@
   account_manager_->UpsertToken(account_key, refresh_token);
 }
 
-net::URLRequestContextGetter*
-ChromeOSOAuth2TokenServiceDelegate::GetRequestContext() const {
-  return account_manager_->GetUrlRequestContext();
-}
-
 OAuth2TokenServiceDelegate::LoadCredentialsState
 ChromeOSOAuth2TokenServiceDelegate::GetLoadCredentialsState() const {
   return load_credentials_state_;
diff --git a/chrome/browser/chromeos/oauth2_token_service_delegate.h b/chrome/browser/chromeos/oauth2_token_service_delegate.h
index 6b9bcfd..b374391 100644
--- a/chrome/browser/chromeos/oauth2_token_service_delegate.h
+++ b/chrome/browser/chromeos/oauth2_token_service_delegate.h
@@ -35,7 +35,6 @@
   // OAuth2TokenServiceDelegate overrides
   OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       OAuth2AccessTokenConsumer* consumer) override;
   bool RefreshTokenIsAvailable(const std::string& account_id) const override;
@@ -47,7 +46,6 @@
   void LoadCredentials(const std::string& primary_account_id) override;
   void UpdateCredentials(const std::string& account_id,
                          const std::string& refresh_token) override;
-  net::URLRequestContextGetter* GetRequestContext() const override;
   LoadCredentialsState GetLoadCredentialsState() const override;
   void RevokeCredentials(const std::string& account_id) override;
   void RevokeAllCredentials() override;
diff --git a/chrome/browser/chromeos/oauth2_token_service_delegate_unittest.cc b/chrome/browser/chromeos/oauth2_token_service_delegate_unittest.cc
index d3254e14d..62573c8 100644
--- a/chrome/browser/chromeos/oauth2_token_service_delegate_unittest.cc
+++ b/chrome/browser/chromeos/oauth2_token_service_delegate_unittest.cc
@@ -21,6 +21,8 @@
 #include "components/signin/core/browser/test_signin_client.h"
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "google_apis/gaia/oauth2_token_service.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -82,16 +84,17 @@
 
 class CrOSOAuthDelegateTest : public testing::Test {
  public:
-  CrOSOAuthDelegateTest() = default;
+  CrOSOAuthDelegateTest()
+      : test_shared_loader_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_)) {}
   ~CrOSOAuthDelegateTest() override = default;
 
  protected:
   void SetUp() override {
     ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
 
-    request_context_ = new net::TestURLRequestContextGetter(
-        scoped_task_environment_.GetMainThreadTaskRunner());
-    account_manager_.Initialize(tmp_dir_.GetPath(), request_context_.get(),
+    account_manager_.Initialize(tmp_dir_.GetPath(), test_shared_loader_factory_,
                                 immediate_callback_runner_);
     scoped_task_environment_.RunUntilIdle();
 
@@ -100,9 +103,7 @@
     pref_service_.registry()->RegisterIntegerPref(
         prefs::kAccountIdMigrationState,
         AccountTrackerService::MIGRATION_NOT_STARTED);
-    client_.reset(new TestSigninClient(&pref_service_));
-    client_->SetURLRequestContext(new net::TestURLRequestContextGetter(
-        base::ThreadTaskRunnerHandle::Get()));
+    client_ = std::make_unique<TestSigninClient>(&pref_service_);
 
     account_tracker_service_.Initialize(client_.get());
 
@@ -116,6 +117,8 @@
         account_info_.account_id /* primary_account_id */);
   }
 
+  void TearDown() override { test_shared_loader_factory_->Detach(); }
+
   AccountInfo CreateAccountInfoTestFixture(const std::string& gaia_id,
                                            const std::string& email) {
     AccountInfo account_info;
@@ -143,7 +146,9 @@
   base::test::ScopedTaskEnvironment scoped_task_environment_;
 
   base::ScopedTempDir tmp_dir_;
-  scoped_refptr<net::URLRequestContextGetter> request_context_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
+      test_shared_loader_factory_;
   AccountInfo account_info_;
   AccountTrackerService account_tracker_service_;
   AccountManager account_manager_;
@@ -264,7 +269,7 @@
   AccountManager account_manager;
   // AccountManager will not be fully initialized until
   // |scoped_task_environment_.RunUntilIdle()| is called.
-  account_manager.Initialize(tmp_dir_.GetPath(), request_context_.get(),
+  account_manager.Initialize(tmp_dir_.GetPath(), test_shared_loader_factory_,
                              immediate_callback_runner_);
 
   // Register callbacks before AccountManager has been fully initialized.
diff --git a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc
index 620f0f2..f212020f 100644
--- a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc
+++ b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.cc
@@ -19,7 +19,6 @@
 #include "google_apis/gaia/gaia_urls.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 using content::BrowserThread;
@@ -46,19 +45,16 @@
 
  private:
   // PolicyOAuth2TokenFetcher overrides.
-  void StartWithSigninContext(
-      net::URLRequestContextGetter* auth_context_getter,
-      net::URLRequestContextGetter* system_context_getter,
+  void StartWithSigninURLLoaderFactory(
+      scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory,
       scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
       const TokenCallback& callback) override;
   void StartWithAuthCode(
       const std::string& auth_code,
-      net::URLRequestContextGetter* system_context_getter,
       scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
       const TokenCallback& callback) override;
   void StartWithRefreshToken(
       const std::string& oauth2_refresh_token,
-      net::URLRequestContextGetter* system_context_getter,
       scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
       const TokenCallback& callback) override;
 
@@ -103,8 +99,7 @@
   // Auth code which is used to retreive a refresh token.
   std::string auth_code_;
 
-  scoped_refptr<net::URLRequestContextGetter> auth_context_getter_;
-  scoped_refptr<net::URLRequestContextGetter> system_context_getter_;
+  scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory_;
   scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory_;
   std::unique_ptr<GaiaAuthFetcher> refresh_token_fetcher_;
   std::unique_ptr<OAuth2AccessTokenFetcher> access_token_fetcher_;
@@ -135,15 +130,13 @@
 
 PolicyOAuth2TokenFetcherImpl::~PolicyOAuth2TokenFetcherImpl() {}
 
-void PolicyOAuth2TokenFetcherImpl::StartWithSigninContext(
-    net::URLRequestContextGetter* auth_context_getter,
-    net::URLRequestContextGetter* system_context_getter,
+void PolicyOAuth2TokenFetcherImpl::StartWithSigninURLLoaderFactory(
+    scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory,
     scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
     const TokenCallback& callback) {
   DCHECK(!refresh_token_fetcher_ && !access_token_fetcher_);
 
-  auth_context_getter_ = auth_context_getter;
-  system_context_getter_ = system_context_getter;
+  auth_url_loader_factory_ = auth_url_loader_factory;
   system_url_loader_factory_ = system_url_loader_factory;
   callback_ = callback;
   StartFetchingRefreshToken();
@@ -151,13 +144,11 @@
 
 void PolicyOAuth2TokenFetcherImpl::StartWithAuthCode(
     const std::string& auth_code,
-    net::URLRequestContextGetter* system_context_getter,
     scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
     const TokenCallback& callback) {
   DCHECK(!refresh_token_fetcher_ && !access_token_fetcher_);
 
   auth_code_ = auth_code;
-  system_context_getter_ = system_context_getter;
   system_url_loader_factory_ = system_url_loader_factory;
   callback_ = callback;
   StartFetchingRefreshToken();
@@ -165,13 +156,11 @@
 
 void PolicyOAuth2TokenFetcherImpl::StartWithRefreshToken(
     const std::string& oauth2_refresh_token,
-    net::URLRequestContextGetter* system_context_getter,
     scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
     const TokenCallback& callback) {
   DCHECK(!refresh_token_fetcher_ && !access_token_fetcher_);
 
   oauth2_refresh_token_ = oauth2_refresh_token;
-  system_context_getter_ = system_context_getter;
   system_url_loader_factory_ = system_url_loader_factory;
   callback_ = callback;
   StartFetchingAccessToken();
@@ -190,12 +179,12 @@
 
   if (auth_code_.empty()) {
     refresh_token_fetcher_.reset(new GaiaAuthFetcher(
-        this, GaiaConstants::kChromeSource, auth_context_getter_.get()));
+        this, GaiaConstants::kChromeSource, auth_url_loader_factory_));
     refresh_token_fetcher_->DeprecatedStartCookieForOAuthLoginTokenExchange(
         std::string());
   } else {
     refresh_token_fetcher_.reset(new GaiaAuthFetcher(
-        this, GaiaConstants::kChromeSource, system_context_getter_.get()));
+        this, GaiaConstants::kChromeSource, system_url_loader_factory_));
     refresh_token_fetcher_->StartAuthCodeForOAuth2TokenExchange(auth_code_);
   }
 }
@@ -284,9 +273,8 @@
 
  private:
   // PolicyOAuth2TokenFetcher overrides.
-  void StartWithSigninContext(
-      net::URLRequestContextGetter* auth_context_getter,
-      net::URLRequestContextGetter* system_context_getter,
+  void StartWithSigninURLLoaderFactory(
+      scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory,
       scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
       const TokenCallback& callback) override {
     ForwardPolicyToken(callback);
@@ -294,7 +282,6 @@
 
   void StartWithAuthCode(
       const std::string& auth_code,
-      net::URLRequestContextGetter* system_context_getter,
       scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
       const TokenCallback& callback) override {
     ForwardPolicyToken(callback);
@@ -302,7 +289,6 @@
 
   void StartWithRefreshToken(
       const std::string& oauth2_refresh_token,
-      net::URLRequestContextGetter* system_context_getter,
       scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
       const TokenCallback& callback) override {
     ForwardPolicyToken(callback);
diff --git a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h
index f32574d..348b3de 100644
--- a/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h
+++ b/chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h
@@ -13,10 +13,6 @@
 #include "base/memory/ref_counted.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
 
-namespace net {
-class URLRequestContextGetter;
-}
-
 namespace network {
 class SharedURLLoaderFactory;
 }
@@ -45,19 +41,16 @@
 
   // Fetches the device management service's oauth2 token. This may be fetched
   // via signin context, auth code, or oauth2 refresh token.
-  virtual void StartWithSigninContext(
-      net::URLRequestContextGetter* auth_context_getter,
-      net::URLRequestContextGetter* system_context_getter,
+  virtual void StartWithSigninURLLoaderFactory(
+      scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory,
       scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
       const TokenCallback& callback) = 0;
   virtual void StartWithAuthCode(
       const std::string& auth_code,
-      net::URLRequestContextGetter* system_context_getter,
       scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
       const TokenCallback& callback) = 0;
   virtual void StartWithRefreshToken(
       const std::string& oauth2_refresh_token,
-      net::URLRequestContextGetter* system_context_getter,
       scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory,
       const TokenCallback& callback) = 0;
 
diff --git a/chrome/browser/chromeos/policy/upload_job_unittest.cc b/chrome/browser/chromeos/policy/upload_job_unittest.cc
index 657e7270..ba1a938 100644
--- a/chrome/browser/chromeos/policy/upload_job_unittest.cc
+++ b/chrome/browser/chromeos/policy/upload_job_unittest.cc
@@ -73,7 +73,6 @@
   void FetchOAuth2Token(
       RequestImpl* request,
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const std::string& client_id,
       const std::string& client_secret,
@@ -106,7 +105,6 @@
 void MockOAuth2TokenService::FetchOAuth2Token(
     OAuth2TokenService::RequestImpl* request,
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::string& client_id,
     const std::string& client_secret,
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
index 365147c..2614511 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.cc
@@ -172,6 +172,11 @@
   OnPolicyRefreshTimeout();
 }
 
+void UserCloudPolicyManagerChromeOS::SetSignInURLLoaderFactoryForTests(
+    scoped_refptr<network::SharedURLLoaderFactory> signin_url_loader_factory) {
+  signin_url_loader_factory_for_tests_ = signin_url_loader_factory;
+}
+
 void UserCloudPolicyManagerChromeOS::SetSystemURLLoaderFactoryForTests(
     scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory) {
   system_url_loader_factory_for_tests_ = system_url_loader_factory;
@@ -535,26 +540,26 @@
   if (!refresh_token.empty()) {
     token_fetcher_.reset(PolicyOAuth2TokenFetcher::CreateInstance());
     token_fetcher_->StartWithRefreshToken(
-        refresh_token, g_browser_process->system_request_context(),
-        system_url_loader_factory,
+        refresh_token, system_url_loader_factory,
         base::Bind(&UserCloudPolicyManagerChromeOS::OnOAuth2PolicyTokenFetched,
                    base::Unretained(this)));
     return;
   }
 
-  scoped_refptr<net::URLRequestContextGetter> signin_context =
-      chromeos::login::GetSigninContext();
-  if (!signin_context.get()) {
-    LOG(ERROR) << "No signin context for policy oauth token fetch!";
+  scoped_refptr<network::SharedURLLoaderFactory> signin_url_loader_factory =
+      signin_url_loader_factory_for_tests_;
+  if (!signin_url_loader_factory)
+    signin_url_loader_factory = chromeos::login::GetSigninURLLoaderFactory();
+  if (!signin_url_loader_factory) {
+    LOG(ERROR) << "No signin URLLoaderfactory for policy oauth token fetch!";
     OnOAuth2PolicyTokenFetched(
         std::string(), GoogleServiceAuthError(GoogleServiceAuthError::NONE));
     return;
   }
 
   token_fetcher_.reset(PolicyOAuth2TokenFetcher::CreateInstance());
-  token_fetcher_->StartWithSigninContext(
-      signin_context.get(), g_browser_process->system_request_context(),
-      system_url_loader_factory,
+  token_fetcher_->StartWithSigninURLLoaderFactory(
+      signin_url_loader_factory, system_url_loader_factory,
       base::Bind(&UserCloudPolicyManagerChromeOS::OnOAuth2PolicyTokenFetched,
                  base::Unretained(this)));
 }
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h
index e0ca7f8..be341e2 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos.h
@@ -163,8 +163,10 @@
   // Helper function to force a policy fetch timeout.
   void ForceTimeoutForTest();
 
-  // Sets a SharedURLLoaderFactory that should be used for tests instead of
+  // Sets the SharedURLLoaderFactory's that should be used for tests instead of
   // retrieving one from the BrowserProcess object in FetchPolicyOAuthToken().
+  void SetSignInURLLoaderFactoryForTests(
+      scoped_refptr<network::SharedURLLoaderFactory> signin_url_loader_factory);
   void SetSystemURLLoaderFactoryForTests(
       scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory);
 
@@ -294,6 +296,8 @@
   // The SharedURLLoaderFactory used in some tests to simulate network requests.
   scoped_refptr<network::SharedURLLoaderFactory>
       system_url_loader_factory_for_tests_;
+  scoped_refptr<network::SharedURLLoaderFactory>
+      signin_url_loader_factory_for_tests_;
 
   DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyManagerChromeOS);
 };
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
index 25cfb82..9a4ecbb2 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
@@ -133,9 +133,12 @@
         signin_profile_(nullptr),
         user_manager_(new chromeos::FakeChromeUserManager()),
         user_manager_enabler_(base::WrapUnique(user_manager_)),
-        test_shared_loader_factory_(
+        test_signin_shared_loader_factory_(
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
-                &test_url_loader_factory_)) {}
+                &test_signin_url_loader_factory_)),
+        test_system_shared_loader_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_system_url_loader_factory_)) {}
 
   void AddAndSwitchToChildAccountWithProfile() {
     const AccountId child_account_id =
@@ -224,7 +227,8 @@
     signin_profile_ = NULL;
     profile_ = NULL;
     profile_manager_->DeleteTestingProfile(chrome::kInitialProfile);
-    test_shared_loader_factory_->Detach();
+    test_system_shared_loader_factory_->Detach();
+    test_signin_shared_loader_factory_->Detach();
 
     chromeos::DBusThreadManager::Shutdown();
   }
@@ -242,23 +246,6 @@
     EXPECT_FALSE(manager_->core()->service()->IsInitializationComplete());
   }
 
-  // Expects a pending URLFetcher for the |expected_url|, and returns it with
-  // prepared to deliver a response to its delegate.
-  net::TestURLFetcher* PrepareOAuthFetcher(const GURL& expected_url) {
-    net::TestURLFetcher* fetcher = test_url_fetcher_factory_.GetFetcherByID(0);
-    EXPECT_TRUE(fetcher);
-    if (!fetcher)
-      return NULL;
-    EXPECT_TRUE(fetcher->delegate());
-    EXPECT_TRUE(base::StartsWith(fetcher->GetOriginalURL().spec(),
-                                 expected_url.spec(),
-                                 base::CompareCase::SENSITIVE));
-    fetcher->set_url(fetcher->GetOriginalURL());
-    fetcher->set_response_code(200);
-    fetcher->set_status(net::URLRequestStatus());
-    return fetcher;
-  }
-
   // Issues the OAuth2 tokens and returns the device management register job
   // if the flow succeeded.
   MockDeviceManagementJob* IssueOAuthToken(bool has_request_token) {
@@ -273,35 +260,37 @@
 
     if (!has_request_token) {
       GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
-      net::TestURLFetcher* fetcher = nullptr;
+
+      network::URLLoaderCompletionStatus ok_completion_status(net::OK);
+      // Raw headers are needed on the ResourceResponseHead for cookies to be
+      // accessible.
+      network::ResourceResponseHead ok_response_with_oauth_cookie =
+          network::CreateResourceResponseHead(net::HTTP_OK,
+                                              /*report_raw_headers=*/true);
+      network::AddCookiesToResourceResponseHead({kOAuthCodeCookie},
+                                                &ok_response_with_oauth_cookie);
 
       // Issue the oauth_token cookie first.
-      fetcher = PrepareOAuthFetcher(
-          gaia_urls->deprecated_client_login_to_oauth2_url());
-      if (!fetcher)
+      if (!test_signin_url_loader_factory_.SimulateResponseForPendingRequest(
+              gaia_urls->deprecated_client_login_to_oauth2_url(),
+              ok_completion_status, ok_response_with_oauth_cookie,
+              /*content=*/"",
+              /*flags=*/network::TestURLLoaderFactory::kUrlMatchPrefix))
         return nullptr;
 
-      scoped_refptr<net::HttpResponseHeaders> reponse_headers =
-          new net::HttpResponseHeaders("");
-      reponse_headers->AddCookie(kOAuthCodeCookie);
-      fetcher->set_response_headers(reponse_headers);
-      fetcher->delegate()->OnURLFetchComplete(fetcher);
-
+      network::ResourceResponseHead ok_response =
+          network::CreateResourceResponseHead(net::HTTP_OK);
       // Issue the refresh token.
-      // This uses GaiaAuthFetcher() which still uses URLRequests.
-      fetcher = PrepareOAuthFetcher(gaia_urls->oauth2_token_url());
-      if (!fetcher)
-        return NULL;
-      fetcher->SetResponseString(kOAuth2TokenPairData);
-      fetcher->delegate()->OnURLFetchComplete(fetcher);
+      if (!test_signin_url_loader_factory_.SimulateResponseForPendingRequest(
+              gaia_urls->oauth2_token_url(), ok_completion_status, ok_response,
+              kOAuth2TokenPairData))
+        return nullptr;
 
-      // Issue the access token. This uses OAuth2AccessTokenFetcher which uses
-      // the network service.
-      test_url_loader_factory_.SimulateResponseForPendingRequest(
-          GaiaUrls::GetInstance()->oauth2_token_url(),
-          network::URLLoaderCompletionStatus(net::OK),
-          network::CreateResourceResponseHead(net::HTTP_OK),
-          kOAuth2AccessTokenData);
+      // Issue the access token.
+      EXPECT_TRUE(
+          test_system_url_loader_factory_.SimulateResponseForPendingRequest(
+              gaia_urls->oauth2_token_url(), ok_completion_status, ok_response,
+              kOAuth2AccessTokenData));
     } else {
       // Since the refresh token is available, OAuth2TokenService was used
       // to request the access token and not UserCloudPolicyTokenForwarder.
@@ -414,7 +403,10 @@
             base::Unretained(this)),
         active_user->GetAccountId(), task_runner_, task_runner_));
     manager_->AddObserver(&observer_);
-    manager_->SetSystemURLLoaderFactoryForTests(test_shared_loader_factory_);
+    manager_->SetSignInURLLoaderFactoryForTests(
+        test_signin_shared_loader_factory_);
+    manager_->SetSystemURLLoaderFactoryForTests(
+        test_system_shared_loader_factory_);
     should_create_token_forwarder_ = fetch_timeout.is_zero();
   }
 
@@ -439,6 +431,14 @@
     }
   }
 
+  network::TestURLLoaderFactory* test_signin_url_loader_factory() {
+    return &test_signin_url_loader_factory_;
+  }
+
+  network::TestURLLoaderFactory* test_system_url_loader_factory() {
+    return &test_system_url_loader_factory_;
+  }
+
  private:
   // Invoked when a fatal error is encountered.
   void OnFatalErrorEncountered() { fatal_error_encountered_ = true; }
@@ -446,9 +446,13 @@
   bool should_create_token_forwarder_ = false;
   bool fatal_error_encountered_ = false;
 
-  network::TestURLLoaderFactory test_url_loader_factory_;
+  network::TestURLLoaderFactory test_signin_url_loader_factory_;
+  network::TestURLLoaderFactory test_system_url_loader_factory_;
+
   scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
-      test_shared_loader_factory_;
+      test_signin_shared_loader_factory_;
+  scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
+      test_system_shared_loader_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyManagerChromeOSTest);
 };
@@ -546,15 +550,17 @@
   EXPECT_TRUE(manager_->core()->service()->IsInitializationComplete());
   EXPECT_FALSE(manager_->core()->client()->is_registered());
 
+  EXPECT_FALSE(manager_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
   // The PolicyOAuth2TokenFetcher posts delayed retries on some errors. This
   // data will make it fail immediately.
-  net::TestURLFetcher* fetcher = PrepareOAuthFetcher(
-      GaiaUrls::GetInstance()->deprecated_client_login_to_oauth2_url());
-  ASSERT_TRUE(fetcher);
-  fetcher->set_response_code(400);
-  fetcher->SetResponseString("Error=BadAuthentication");
-  EXPECT_FALSE(manager_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
+  EXPECT_TRUE(
+      test_signin_url_loader_factory()->SimulateResponseForPendingRequest(
+          GaiaUrls::GetInstance()->deprecated_client_login_to_oauth2_url(),
+          network::URLLoaderCompletionStatus(net::OK),
+          network::CreateResourceResponseHead(net::HTTP_BAD_REQUEST),
+          "Error=BadAuthentication",
+          /*flags=*/network::TestURLLoaderFactory::kUrlMatchPrefix));
+
   // Server check failed, so profile should not be initialized.
   EXPECT_FALSE(manager_->IsInitializationComplete(POLICY_DOMAIN_CHROME));
   EXPECT_TRUE(PolicyBundle().Equals(manager_->policies()));
diff --git a/chrome/browser/chromeos/policy/wildcard_login_checker.cc b/chrome/browser/chromeos/policy/wildcard_login_checker.cc
index 7d12bce..c8052a91 100644
--- a/chrome/browser/chromeos/policy/wildcard_login_checker.cc
+++ b/chrome/browser/chromeos/policy/wildcard_login_checker.cc
@@ -36,8 +36,8 @@
 
 WildcardLoginChecker::~WildcardLoginChecker() {}
 
-void WildcardLoginChecker::StartWithSigninContext(
-    scoped_refptr<net::URLRequestContextGetter> signin_context,
+void WildcardLoginChecker::StartWithSigninURLLoaderFactory(
+    scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory,
     StatusCallback callback) {
   CHECK(!token_fetcher_);
   CHECK(!user_info_fetcher_);
@@ -46,8 +46,8 @@
   callback_ = std::move(callback);
 
   token_fetcher_.reset(PolicyOAuth2TokenFetcher::CreateInstance());
-  token_fetcher_->StartWithSigninContext(
-      signin_context.get(), g_browser_process->system_request_context(),
+  token_fetcher_->StartWithSigninURLLoaderFactory(
+      auth_url_loader_factory,
       g_browser_process->system_network_context_manager()
           ->GetSharedURLLoaderFactory(),
       base::Bind(&WildcardLoginChecker::OnPolicyTokenFetched,
@@ -65,7 +65,7 @@
 
   token_fetcher_.reset(PolicyOAuth2TokenFetcher::CreateInstance());
   token_fetcher_->StartWithRefreshToken(
-      refresh_token, g_browser_process->system_request_context(),
+      refresh_token,
       g_browser_process->system_network_context_manager()
           ->GetSharedURLLoaderFactory(),
       base::Bind(&WildcardLoginChecker::OnPolicyTokenFetched,
diff --git a/chrome/browser/chromeos/policy/wildcard_login_checker.h b/chrome/browser/chromeos/policy/wildcard_login_checker.h
index 3fac2fb..2ba743e5 100644
--- a/chrome/browser/chromeos/policy/wildcard_login_checker.h
+++ b/chrome/browser/chromeos/policy/wildcard_login_checker.h
@@ -9,12 +9,13 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/time/time.h"
 #include "components/policy/core/common/cloud/user_info_fetcher.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
 }
 
 namespace policy {
@@ -39,8 +40,8 @@
   virtual ~WildcardLoginChecker();
 
   // Starts checking. The result will be reported via |callback_|.
-  void StartWithSigninContext(
-      scoped_refptr<net::URLRequestContextGetter> signin_context,
+  void StartWithSigninURLLoaderFactory(
+      scoped_refptr<network::SharedURLLoaderFactory> auth_url_loader_factory,
       StatusCallback callback);
 
   // Starts checking with a provided refresh token.
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
index 7742b30..afa9138 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.cc
@@ -75,7 +75,6 @@
 void DeviceOAuth2TokenService::FetchOAuth2Token(
     RequestImpl* request,
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::string& client_id,
     const std::string& client_secret,
@@ -100,7 +99,7 @@
       return;
     case DeviceOAuth2TokenServiceDelegate::STATE_TOKEN_VALID:
       // Pass through to OAuth2TokenService to satisfy the request.
-      OAuth2TokenService::FetchOAuth2Token(request, account_id, getter,
+      OAuth2TokenService::FetchOAuth2Token(request, account_id,
                                            url_loader_factory, client_id,
                                            client_secret, scopes);
       return;
@@ -125,7 +124,6 @@
       OAuth2TokenService::FetchOAuth2Token(
           scoped_request->request.get(),
           scoped_request->request->GetAccountId(),
-          GetDeviceDelegate()->GetRequestContext(),
           GetDeviceDelegate()->GetURLLoaderFactory(), scoped_request->client_id,
           scoped_request->client_secret, scoped_request->scopes);
     } else {
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service.h b/chrome/browser/chromeos/settings/device_oauth2_token_service.h
index 7a75849..07a6348 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service.h
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service.h
@@ -49,7 +49,6 @@
   void FetchOAuth2Token(
       RequestImpl* request,
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const std::string& client_id,
       const std::string& client_secret,
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.cc
index be9058b..fcbbeb7 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.cc
@@ -33,11 +33,9 @@
 }
 
 DeviceOAuth2TokenServiceDelegate::DeviceOAuth2TokenServiceDelegate(
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     PrefService* local_state)
-    : url_request_context_getter_(getter),
-      url_loader_factory_(url_loader_factory),
+    : url_loader_factory_(url_loader_factory),
       local_state_(local_state),
       state_(STATE_LOADING),
       max_refresh_token_validation_retries_(3),
@@ -160,11 +158,6 @@
   return std::string();
 }
 
-net::URLRequestContextGetter*
-DeviceOAuth2TokenServiceDelegate::GetRequestContext() const {
-  return url_request_context_getter_.get();
-}
-
 scoped_refptr<network::SharedURLLoaderFactory>
 DeviceOAuth2TokenServiceDelegate::GetURLLoaderFactory() const {
   return url_loader_factory_;
@@ -173,7 +166,6 @@
 OAuth2AccessTokenFetcher*
 DeviceOAuth2TokenServiceDelegate::CreateAccessTokenFetcher(
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     OAuth2AccessTokenConsumer* consumer) {
   std::string refresh_token = GetRefreshToken(account_id);
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.h b/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.h
index 07b4c34..be434be 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.h
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_delegate.h
@@ -22,9 +22,6 @@
 class GaiaOAuthClient;
 }
 
-namespace net {
-class URLRequestContextGetter;
-}
 namespace network {
 class SharedURLLoaderFactory;
 }
@@ -38,7 +35,6 @@
       public gaia::GaiaOAuthClient::Delegate {
  public:
   DeviceOAuth2TokenServiceDelegate(
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       PrefService* local_state);
   ~DeviceOAuth2TokenServiceDelegate() override;
@@ -57,14 +53,11 @@
   // Implementation of OAuth2TokenServiceDelegate.
   bool RefreshTokenIsAvailable(const std::string& account_id) const override;
 
-  net::URLRequestContextGetter* GetRequestContext() const override;
-
   scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory()
       const override;
 
   OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       OAuth2AccessTokenConsumer* consumer) override;
 
@@ -131,7 +124,6 @@
   void ReportServiceError(GoogleServiceAuthError::State error);
 
   // Dependencies.
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   PrefService* local_state_;
 
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.cc
index 239f4b76..72425e2a 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_factory.cc
@@ -41,8 +41,7 @@
   DCHECK(!g_device_oauth2_token_service_);
   g_device_oauth2_token_service_ = new DeviceOAuth2TokenService(
       std::make_unique<DeviceOAuth2TokenServiceDelegate>(
-          g_browser_process->system_request_context(), url_loader_factory,
-          g_browser_process->local_state()));
+          url_loader_factory, g_browser_process->local_state()));
 }
 
 // static
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
index d5228dc..25a33560 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
@@ -68,8 +68,6 @@
  public:
   DeviceOAuth2TokenServiceTest()
       : scoped_testing_local_state_(TestingBrowserProcess::GetGlobal()),
-        request_context_getter_(new net::TestURLRequestContextGetter(
-            base::ThreadTaskRunnerHandle::Get())),
         test_shared_loader_factory_(
             base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
                 &test_url_loader_factory_)) {}
@@ -142,8 +140,7 @@
 
   void CreateService() {
     auto delegate = std::make_unique<DeviceOAuth2TokenServiceDelegate>(
-        request_context_getter_.get(), test_shared_loader_factory_,
-        scoped_testing_local_state_.Get());
+        test_shared_loader_factory_, scoped_testing_local_state_.Get());
     delegate->max_refresh_token_validation_retries_ = 0;
     oauth2_service_.reset(new DeviceOAuth2TokenService(std::move(delegate)));
     oauth2_service_->set_max_authorization_token_fetch_retries_for_testing(0);
@@ -216,7 +213,6 @@
 
   content::TestBrowserThreadBundle test_browser_thread_bundle_;
   ScopedTestingLocalState scoped_testing_local_state_;
-  scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
   network::TestURLLoaderFactory test_url_loader_factory_;
   scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
       test_shared_loader_factory_;
diff --git a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
index bbf5405..43c0ea8 100644
--- a/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
+++ b/chrome/browser/extensions/api/declarative_net_request/declarative_net_request_browsertest.cc
@@ -1632,6 +1632,15 @@
   request->resource_type = content::ResourceType::RESOURCE_TYPE_SCRIPT;
   request->render_frame_id = MSG_ROUTING_NONE;
 
+  // TODO(https://crbug.com/857577): remove this hack. When an unrelated
+  // browser issued request (typically from GaiaAuthFetcher) has run, it causes
+  // the StoragePartitionImpl to create and cache a URLLoaderFactory without the
+  // web request proxying. This resets it so one with the web request proxying
+  // is created the next time a request is made.
+  base::RunLoop().RunUntilIdle();
+  content::BrowserContext::GetDefaultStoragePartition(profile())
+      ->ResetURLLoaderFactoryForBrowserProcessForTesting();
+
   auto loader = network::SimpleURLLoader::Create(std::move(request),
                                                  TRAFFIC_ANNOTATION_FOR_TESTS);
   content::SimpleURLLoaderTestHelper loader_helper;
diff --git a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
index 03882c28ed..1657c78 100644
--- a/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
+++ b/chrome/browser/extensions/api/identity/gaia_web_auth_flow.cc
@@ -94,9 +94,9 @@
 void GaiaWebAuthFlow::Start() {
   ProfileOAuth2TokenService* token_service =
       ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
-  ubertoken_fetcher_.reset(new UbertokenFetcher(token_service, this,
-                                                GaiaConstants::kChromeSource,
-                                                profile_->GetRequestContext()));
+  ubertoken_fetcher_.reset(
+      new UbertokenFetcher(token_service, this, GaiaConstants::kChromeSource,
+                           profile_->GetURLLoaderFactory()));
   ubertoken_fetcher_->set_is_bound_to_channel_id(false);
   ubertoken_fetcher_->StartFetchingToken(account_id_);
 }
diff --git a/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
index 9aa7aa4a..3b61cdd 100644
--- a/chrome/browser/extensions/api/web_request/web_request_apitest.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_apitest.cc
@@ -267,6 +267,17 @@
       bool wait_for_extension_loaded_in_incognito,
       const char* expected_content_regular_window,
       const char* exptected_content_incognito_window);
+
+  // TODO(https://crbug.com/857577): remove this hack. When an unrelated
+  // browser issued request (typically from GaiaAuthFetcher) has run, it causes
+  // the StoragePartitionImpl to create and cache a URLLoaderFactory without the
+  // web request proxying. This resets it so one with the web request proxying
+  // is created the next time a request is made.
+  void ResetStoragePartitionURLLoaderFactory() {
+    base::RunLoop().RunUntilIdle();
+    content::BrowserContext::GetDefaultStoragePartition(profile())
+        ->ResetURLLoaderFactoryForBrowserProcessForTesting();
+  }
 };
 
 class DevToolsFrontendInWebRequestApiTest : public ExtensionApiTest {
@@ -1028,6 +1039,9 @@
     EXPECT_EQ(200, loader->ResponseInfo()->headers->response_code());
   };
 
+  // TODO(https://crbug.com/857577): remove this call.
+  ResetStoragePartitionURLLoaderFactory();
+
   // Now perform a request to "client1.google.com" from the browser process.
   // This should *not* be visible to the WebRequest API. We should still have
   // only seen the single render-initiated request from the first half of the
@@ -1348,6 +1362,9 @@
         }
       };
 
+  // TODO(https://crbug.com/857577): remove this call.
+  ResetStoragePartitionURLLoaderFactory();
+
   // Next, try a series of requests through URLRequestFetchers (rather than a
   // renderer).
   auto* url_loader_factory =
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index ca8ba10..33b48ec 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -611,7 +611,7 @@
 
 const char kEnableOptimizationHintsName[] = "Optimization Hints";
 const char kEnableOptimizationHintsDescription[] =
-    "Enable the Optimization Hints feature which incorporates server hints"
+    "Enable the Optimization Hints feature which incorporates server hints "
     "into decisions for what optimizations to perform on some pages on slow "
     "networks.";
 
@@ -895,9 +895,9 @@
 const char kGamepadExtensionsName[] = "Gamepad Extensions";
 const char kGamepadExtensionsDescription[] =
     "Enables experimental extensions to the Gamepad APIs.";
-const char kGamepadPollingRateName[] = "Gamepad Polling Rate";
+const char kGamepadPollingRateName[] = "Override Gamepad Polling Rate";
 const char kGamepadPollingRateDescription[] =
-    "Changes the rate at which gamepad input devices are polled. Increasing "
+    "Overrides the rate at which gamepad input devices are polled. Increasing "
     "the polling rate improves the average latency of button and axis inputs "
     "but may negatively affect performance.";
 const char kGamepadVibrationName[] = "Gamepad Vibration";
@@ -1542,6 +1542,9 @@
     "Shows previews of the open windows for a given running app when hovering "
     "over the shelf.";
 
+const char kShelfNewUiName[] = "Newest shelf redesign.";
+const char kShelfNewUiDescription[] = "Enables the newest shelf appearance.";
+
 const char kShowAllDialogsWithViewsToolkitName[] =
     "Show all dialogs with Views toolkit";
 const char kShowAllDialogsWithViewsToolkitDescription[] =
@@ -1620,6 +1623,10 @@
 const char kSingleClickAutofillDescription[] =
     "Make autofill suggestions on initial mouse click on a form element.";
 
+const char kSingleTabMode[] = "Single-tab mode";
+const char kSingleTabModeDescription[] =
+    "Windows with a single tab receive a special, minimal visual treatment.";
+
 const char kStrictSiteIsolationName[] = "Strict site isolation";
 const char kStrictSiteIsolationDescription[] =
     "Security mode that enables site isolation for all sites. When enabled, "
@@ -3415,16 +3422,6 @@
 const char kWebVrVsyncAlignDescription[] =
     "Align WebVR application rendering with VSync for smoother animations.";
 
-#if defined(OS_ANDROID)
-
-const char kVrBrowsingExperimentalRenderingName[] =
-    "VR browsing experimental rendering features";
-const char kVrBrowsingExperimentalRenderingDescription[] =
-    "Experimental rendering features for VR browsing (e.g. power-saving "
-    "rendering modes).";
-
-#endif  // OS_ANDROID
-
 #if BUILDFLAG(ENABLE_OCULUS_VR)
 const char kOculusVRName[] = "Oculus hardware support";
 const char kOculusVRDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 6ae8a844..22bfea0e 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -944,6 +944,9 @@
 extern const char kShelfHoverPreviewsName[];
 extern const char kShelfHoverPreviewsDescription[];
 
+extern const char kShelfNewUiName[];
+extern const char kShelfNewUiDescription[];
+
 extern const char kShowAllDialogsWithViewsToolkitName[];
 extern const char kShowAllDialogsWithViewsToolkitDescription[];
 
@@ -989,6 +992,9 @@
 extern const char kSingleClickAutofillName[];
 extern const char kSingleClickAutofillDescription[];
 
+extern const char kSingleTabMode[];
+extern const char kSingleTabModeDescription[];
+
 extern const char kStrictSiteIsolationName[];
 extern const char kStrictSiteIsolationDescription[];
 
@@ -2101,13 +2107,6 @@
 extern const char kWebVrVsyncAlignName[];
 extern const char kWebVrVsyncAlignDescription[];
 
-#if defined(OS_ANDROID)
-
-extern const char kVrBrowsingExperimentalRenderingName[];
-extern const char kVrBrowsingExperimentalRenderingDescription[];
-
-#endif  // OS_ANDROID
-
 #if BUILDFLAG(ENABLE_OCULUS_VR)
 extern const char kOculusVRName[];
 extern const char kOculusVRDescription[];
diff --git a/chrome/browser/net/chrome_network_delegate_unittest.cc b/chrome/browser/net/chrome_network_delegate_unittest.cc
index 55c14278..c1948b1 100644
--- a/chrome/browser/net/chrome_network_delegate_unittest.cc
+++ b/chrome/browser/net/chrome_network_delegate_unittest.cc
@@ -551,7 +551,8 @@
     return &mock_permission_manager_;
   }
 
-  content::PermissionManager* GetPermissionManager() override {
+  content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+      override {
     return &mock_permission_manager_;
   }
 
diff --git a/chrome/browser/net/errorpage_browsertest.cc b/chrome/browser/net/errorpage_browsertest.cc
index 7a64c50..5503482 100644
--- a/chrome/browser/net/errorpage_browsertest.cc
+++ b/chrome/browser/net/errorpage_browsertest.cc
@@ -58,6 +58,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_navigation_observer.h"
 #include "content/public/test/url_loader_interceptor.h"
+#include "google_apis/gaia/gaia_urls.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "net/base/filename_util.h"
 #include "net/base/net_errors.h"
@@ -1034,6 +1035,9 @@
                 return false;
               if (params->url_request.url.path() == "/favicon.ico")
                 return false;
+              if (params->url_request.url.GetOrigin() ==
+                  GaiaUrls::GetInstance()->gaia_url())
+                return false;
               (*requests)++;
               if (*failures < requests_to_fail) {
                 (*failures)++;
diff --git a/chrome/browser/net/proxy_browsertest.cc b/chrome/browser/net/proxy_browsertest.cc
index 578a01c..88cb8db 100644
--- a/chrome/browser/net/proxy_browsertest.cc
+++ b/chrome/browser/net/proxy_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "build/build_config.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
@@ -25,6 +26,8 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/url_loader_interceptor.h"
+#include "google_apis/gaia/gaia_urls.h"
 #include "net/base/load_flags.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/simple_connection_listener.h"
@@ -94,9 +97,25 @@
 
   void SetUp() override {
     ASSERT_TRUE(proxy_server_.Start());
+    // Block the GaiaAuthFetcher related requests, they somehow interfere with
+    // the test when the network service is running.
+    url_loader_interceptor_ = std::make_unique<content::URLLoaderInterceptor>(
+        base::BindLambdaForTesting(
+            [&](content::URLLoaderInterceptor::RequestParams* params) -> bool {
+              if (params->url_request.url.host() ==
+                  GaiaUrls::GetInstance()->gaia_url().host()) {
+                return true;
+              }
+              return false;
+            }));
     InProcessBrowserTest::SetUp();
   }
 
+  void PostRunTestOnMainThread() override {
+    url_loader_interceptor_.reset();
+    InProcessBrowserTest::PostRunTestOnMainThread();
+  }
+
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitchASCII(switches::kProxyServer,
                                     proxy_server_.host_port_pair().ToString());
@@ -106,6 +125,7 @@
   net::SpawnedTestServer proxy_server_;
 
  private:
+  std::unique_ptr<content::URLLoaderInterceptor> url_loader_interceptor_;
   DISALLOW_COPY_AND_ASSIGN(ProxyBrowserTest);
 };
 
diff --git a/chrome/browser/net/reporting_permissions_checker_unittest.cc b/chrome/browser/net/reporting_permissions_checker_unittest.cc
index dc4f025..9012b395 100644
--- a/chrome/browser/net/reporting_permissions_checker_unittest.cc
+++ b/chrome/browser/net/reporting_permissions_checker_unittest.cc
@@ -31,7 +31,8 @@
     return &mock_permission_manager_;
   }
 
-  content::PermissionManager* GetPermissionManager() override {
+  content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+      override {
     return &mock_permission_manager_;
   }
 
diff --git a/chrome/browser/notifications/notification_permission_context_unittest.cc b/chrome/browser/notifications/notification_permission_context_unittest.cc
index 8058b48..609bfab 100644
--- a/chrome/browser/notifications/notification_permission_context_unittest.cc
+++ b/chrome/browser/notifications/notification_permission_context_unittest.cc
@@ -21,7 +21,7 @@
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/web_contents.h"
diff --git a/chrome/browser/notifications/platform_notification_service_unittest.cc b/chrome/browser/notifications/platform_notification_service_unittest.cc
index 0b58b3af..a2c60f1 100644
--- a/chrome/browser/notifications/platform_notification_service_unittest.cc
+++ b/chrome/browser/notifications/platform_notification_service_unittest.cc
@@ -68,7 +68,8 @@
   }
 
   // TestingProfile overrides:
-  content::PermissionManager* GetPermissionManager() override {
+  content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+      override {
     return permission_manager_.get();
   }
 
diff --git a/chrome/browser/password_manager/password_manager_interactive_uitest.cc b/chrome/browser/password_manager/password_manager_interactive_uitest.cc
index bb619b1..fd376b5 100644
--- a/chrome/browser/password_manager/password_manager_interactive_uitest.cc
+++ b/chrome/browser/password_manager/password_manager_interactive_uitest.cc
@@ -316,57 +316,6 @@
                                  "username_field", "password_field", submit);
 }
 
-IN_PROC_BROWSER_TEST_P(
-    PasswordManagerBrowserTestWithConditionalPopupViews,
-    SavedAfterTargetIframeSubmitFollowingNonPasswordFormSubmit) {
-  std::string submit =
-      "document.getElementById('input_submit_button').click();";
-  VerifyPasswordIsSavedAndFilled("/password/iframe_target.html",
-                                 "username_field", "password_field", submit);
-}
-
-IN_PROC_BROWSER_TEST_P(PasswordManagerBrowserTestWithConditionalPopupViews,
-                       SaveNotTriggeredOnOtherFormSubmit) {
-  NavigateToFile("/password/password_form_with_simple_form.html");
-
-  // Fill password form.
-  FillElementWithValue("username_field", "user");
-  FillElementWithValue("password_field", "1234");
-
-  NavigationObserver observer(WebContents());
-  std::unique_ptr<BubbleObserver> prompt_observer(
-      new BubbleObserver(WebContents()));
-  // Submit OTHER form.
-  std::string submit =
-      "document.getElementById('submit_search_button').click();";
-  ASSERT_TRUE(content::ExecuteScript(WebContents(), submit));
-  observer.Wait();
-
-  WaitForPasswordStore();
-  EXPECT_FALSE(prompt_observer->IsSavePromptShownAutomatically());
-}
-
-IN_PROC_BROWSER_TEST_P(PasswordManagerBrowserTestWithConditionalPopupViews,
-                       SaveNotTriggeredOnOtherFormSubmitWithUnownedForm) {
-  NavigateToFile("/password/no_form_elements_with_additional_form.html");
-
-  // Fill in unowned password form inputs.
-  FillElementWithValue("username", "user");
-  FillElementWithValue("password", "1234");
-
-  NavigationObserver observer(WebContents());
-  std::unique_ptr<BubbleObserver> prompt_observer(
-      new BubbleObserver(WebContents()));
-  // Submit OTHER form.
-  std::string submit =
-      "document.getElementById('submit_search_button').click();";
-  ASSERT_TRUE(content::ExecuteScript(WebContents(), submit));
-  observer.Wait();
-
-  WaitForPasswordStore();
-  EXPECT_FALSE(prompt_observer->IsSavePromptShownAutomatically());
-}
-
 INSTANTIATE_TEST_CASE_P(All,
                         PasswordManagerBrowserTestWithConditionalPopupViews,
                         /*popup_views_enabled=*/::testing::Bool());
diff --git a/chrome/browser/permissions/permission_manager.h b/chrome/browser/permissions/permission_manager.h
index 79a9d98b..beb9cae 100644
--- a/chrome/browser/permissions/permission_manager.h
+++ b/chrome/browser/permissions/permission_manager.h
@@ -14,7 +14,7 @@
 #include "components/content_settings/core/browser/content_settings_observer.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/keyed_service/core/keyed_service.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 
 class PermissionContextBase;
 struct PermissionResult;
@@ -25,7 +25,7 @@
 };  // namespace content
 
 class PermissionManager : public KeyedService,
-                          public content::PermissionManager,
+                          public content::PermissionControllerDelegate,
                           public content_settings::Observer {
  public:
   static PermissionManager* Get(Profile* profile);
@@ -49,8 +49,8 @@
 
   // Callers from within chrome/ should use the methods which take the
   // ContentSettingsType enum. The methods which take PermissionType values
-  // are for the content::PermissionManager overrides and shouldn't be used
-  // from chrome/.
+  // are for the content::PermissionControllerDelegate overrides and shouldn't
+  // be used from chrome/.
 
   int RequestPermission(ContentSettingsType permission,
                         content::RenderFrameHost* render_frame_host,
@@ -79,7 +79,7 @@
       content::RenderFrameHost* render_frame_host,
       const GURL& requesting_origin);
 
-  // content::PermissionManager implementation.
+  // content::PermissionControllerDelegate implementation.
   int RequestPermission(
       content::PermissionType permission,
       content::RenderFrameHost* render_frame_host,
diff --git a/chrome/browser/permissions/permission_manager_unittest.cc b/chrome/browser/permissions/permission_manager_unittest.cc
index e29f4d7..6cfbd058 100644
--- a/chrome/browser/permissions/permission_manager_unittest.cc
+++ b/chrome/browser/permissions/permission_manager_unittest.cc
@@ -46,7 +46,7 @@
   PermissionManagerTestingProfile() {}
   ~PermissionManagerTestingProfile() override {}
 
-  PermissionManager* GetPermissionManager() override {
+  PermissionManager* GetPermissionControllerDelegate() override {
     return PermissionManagerFactory::GetForProfile(this);
   }
 
@@ -69,8 +69,8 @@
         callback_called_(false),
         callback_result_(PermissionStatus::ASK) {}
 
-  PermissionManager* GetPermissionManager() {
-    return profile_->GetPermissionManager();
+  PermissionManager* GetPermissionControllerDelegate() {
+    return profile_->GetPermissionControllerDelegate();
   }
 
   HostContentSettingsMap* GetHostContentSettingsMap() {
@@ -79,15 +79,16 @@
 
   void CheckPermissionStatus(PermissionType type,
                              PermissionStatus expected) {
-    EXPECT_EQ(expected, GetPermissionManager()->GetPermissionStatus(
+    EXPECT_EQ(expected, GetPermissionControllerDelegate()->GetPermissionStatus(
                             type, url_.GetOrigin(), url_.GetOrigin()));
   }
 
   void CheckPermissionResult(ContentSettingsType type,
                              ContentSetting expected_status,
                              PermissionStatusSource expected_status_source) {
-    PermissionResult result = GetPermissionManager()->GetPermissionStatus(
-        type, url_.GetOrigin(), url_.GetOrigin());
+    PermissionResult result =
+        GetPermissionControllerDelegate()->GetPermissionStatus(
+            type, url_.GetOrigin(), url_.GetOrigin());
     EXPECT_EQ(expected_status, result.content_setting);
     EXPECT_EQ(expected_status_source, result.source);
   }
@@ -121,7 +122,7 @@
   }
 
   bool PendingRequestsEmpty() {
-    return GetPermissionManager()->pending_requests_.IsEmpty();
+    return GetPermissionControllerDelegate()->pending_requests_.IsEmpty();
   }
 
  private:
@@ -131,7 +132,7 @@
 #if defined(OS_ANDROID)
     GeolocationPermissionContextAndroid* geolocation_permission_context_ =
         static_cast<GeolocationPermissionContextAndroid*>(
-            GetPermissionManager()->GetPermissionContext(
+            GetPermissionControllerDelegate()->GetPermissionContext(
                 CONTENT_SETTINGS_TYPE_GEOLOCATION));
     geolocation_permission_context_->SetLocationSettingsForTesting(
         std::unique_ptr<LocationSettings>(new MockLocationSettings()));
@@ -224,17 +225,18 @@
 TEST_F(PermissionManagerTest, SubscriptionDestroyedCleanlyWithoutUnsubscribe) {
   // Test that the PermissionManager shuts down cleanly with subscriptions that
   // haven't been removed, crbug.com/720071.
-  GetPermissionManager()->SubscribePermissionStatusChange(
+  GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
       PermissionType::GEOLOCATION, url(), url(),
       base::Bind(&PermissionManagerTest::OnPermissionChange,
                  base::Unretained(this)));
 }
 
 TEST_F(PermissionManagerTest, SameTypeChangeNotifies) {
-  int subscription_id = GetPermissionManager()->SubscribePermissionStatusChange(
-      PermissionType::GEOLOCATION, url(), url(),
-      base::Bind(&PermissionManagerTest::OnPermissionChange,
-                 base::Unretained(this)));
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::GEOLOCATION, url(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
 
   GetHostContentSettingsMap()->SetContentSettingDefaultScope(
       url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
@@ -243,14 +245,16 @@
   EXPECT_TRUE(callback_called());
   EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
 
-  GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
 }
 
 TEST_F(PermissionManagerTest, DifferentTypeChangeDoesNotNotify) {
-  int subscription_id = GetPermissionManager()->SubscribePermissionStatusChange(
-      PermissionType::GEOLOCATION, url(), url(),
-      base::Bind(&PermissionManagerTest::OnPermissionChange,
-                 base::Unretained(this)));
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::GEOLOCATION, url(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
 
   GetHostContentSettingsMap()->SetContentSettingDefaultScope(
       url(), GURL(), CONTENT_SETTINGS_TYPE_NOTIFICATIONS, std::string(),
@@ -258,16 +262,19 @@
 
   EXPECT_FALSE(callback_called());
 
-  GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
 }
 
 TEST_F(PermissionManagerTest, ChangeAfterUnsubscribeDoesNotNotify) {
-  int subscription_id = GetPermissionManager()->SubscribePermissionStatusChange(
-      PermissionType::GEOLOCATION, url(), url(),
-      base::Bind(&PermissionManagerTest::OnPermissionChange,
-                 base::Unretained(this)));
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::GEOLOCATION, url(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
 
-  GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
 
   GetHostContentSettingsMap()->SetContentSettingDefaultScope(
       url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
@@ -277,10 +284,11 @@
 }
 
 TEST_F(PermissionManagerTest, DifferentPrimaryUrlDoesNotNotify) {
-  int subscription_id = GetPermissionManager()->SubscribePermissionStatusChange(
-      PermissionType::GEOLOCATION, url(), url(),
-      base::Bind(&PermissionManagerTest::OnPermissionChange,
-                 base::Unretained(this)));
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::GEOLOCATION, url(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
 
   GetHostContentSettingsMap()->SetContentSettingDefaultScope(
       other_url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
@@ -288,14 +296,16 @@
 
   EXPECT_FALSE(callback_called());
 
-  GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
 }
 
 TEST_F(PermissionManagerTest, DifferentSecondaryUrlDoesNotNotify) {
-  int subscription_id = GetPermissionManager()->SubscribePermissionStatusChange(
-      PermissionType::GEOLOCATION, url(), url(),
-      base::Bind(&PermissionManagerTest::OnPermissionChange,
-                 base::Unretained(this)));
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::GEOLOCATION, url(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
 
   GetHostContentSettingsMap()->SetContentSettingDefaultScope(
       url(), other_url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
@@ -303,14 +313,16 @@
 
   EXPECT_FALSE(callback_called());
 
-  GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
 }
 
 TEST_F(PermissionManagerTest, WildCardPatternNotifies) {
-  int subscription_id = GetPermissionManager()->SubscribePermissionStatusChange(
-      PermissionType::GEOLOCATION, url(), url(),
-      base::Bind(&PermissionManagerTest::OnPermissionChange,
-                 base::Unretained(this)));
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::GEOLOCATION, url(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
 
   GetHostContentSettingsMap()->SetDefaultContentSetting(
       CONTENT_SETTINGS_TYPE_GEOLOCATION, CONTENT_SETTING_ALLOW);
@@ -318,7 +330,8 @@
   EXPECT_TRUE(callback_called());
   EXPECT_EQ(PermissionStatus::GRANTED, callback_result());
 
-  GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
 }
 
 TEST_F(PermissionManagerTest, ClearSettingsNotifies) {
@@ -326,10 +339,11 @@
       url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
       CONTENT_SETTING_ALLOW);
 
-  int subscription_id = GetPermissionManager()->SubscribePermissionStatusChange(
-      PermissionType::GEOLOCATION, url(), url(),
-      base::Bind(&PermissionManagerTest::OnPermissionChange,
-                 base::Unretained(this)));
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::GEOLOCATION, url(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
 
   GetHostContentSettingsMap()->ClearSettingsForOneType(
       CONTENT_SETTINGS_TYPE_GEOLOCATION);
@@ -337,14 +351,16 @@
   EXPECT_TRUE(callback_called());
   EXPECT_EQ(PermissionStatus::ASK, callback_result());
 
-  GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
 }
 
 TEST_F(PermissionManagerTest, NewValueCorrectlyPassed) {
-  int subscription_id = GetPermissionManager()->SubscribePermissionStatusChange(
-      PermissionType::GEOLOCATION, url(), url(),
-      base::Bind(&PermissionManagerTest::OnPermissionChange,
-                 base::Unretained(this)));
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::GEOLOCATION, url(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
 
   GetHostContentSettingsMap()->SetContentSettingDefaultScope(
       url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
@@ -353,7 +369,8 @@
   EXPECT_TRUE(callback_called());
   EXPECT_EQ(PermissionStatus::DENIED, callback_result());
 
-  GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
 }
 
 TEST_F(PermissionManagerTest, ChangeWithoutPermissionChangeDoesNotNotify) {
@@ -361,10 +378,11 @@
       url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
       CONTENT_SETTING_ALLOW);
 
-  int subscription_id = GetPermissionManager()->SubscribePermissionStatusChange(
-      PermissionType::GEOLOCATION, url(), url(),
-      base::Bind(&PermissionManagerTest::OnPermissionChange,
-                 base::Unretained(this)));
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::GEOLOCATION, url(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
 
   GetHostContentSettingsMap()->SetContentSettingDefaultScope(
       url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
@@ -372,7 +390,8 @@
 
   EXPECT_FALSE(callback_called());
 
-  GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
 }
 
 TEST_F(PermissionManagerTest, ChangesBackAndForth) {
@@ -380,10 +399,11 @@
       url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
       CONTENT_SETTING_ASK);
 
-  int subscription_id = GetPermissionManager()->SubscribePermissionStatusChange(
-      PermissionType::GEOLOCATION, url(), url(),
-      base::Bind(&PermissionManagerTest::OnPermissionChange,
-                 base::Unretained(this)));
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::GEOLOCATION, url(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
 
   GetHostContentSettingsMap()->SetContentSettingDefaultScope(
       url(), url(), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(),
@@ -401,14 +421,16 @@
   EXPECT_TRUE(callback_called());
   EXPECT_EQ(PermissionStatus::ASK, callback_result());
 
-  GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
 }
 
 TEST_F(PermissionManagerTest, SubscribeMIDIPermission) {
-  int subscription_id = GetPermissionManager()->SubscribePermissionStatusChange(
-      PermissionType::MIDI, url(), url(),
-      base::Bind(&PermissionManagerTest::OnPermissionChange,
-                 base::Unretained(this)));
+  int subscription_id =
+      GetPermissionControllerDelegate()->SubscribePermissionStatusChange(
+          PermissionType::MIDI, url(), url(),
+          base::Bind(&PermissionManagerTest::OnPermissionChange,
+                     base::Unretained(this)));
 
   CheckPermissionStatus(PermissionType::GEOLOCATION, PermissionStatus::ASK);
   GetHostContentSettingsMap()->SetContentSettingDefaultScope(
@@ -418,7 +440,8 @@
 
   EXPECT_FALSE(callback_called());
 
-  GetPermissionManager()->UnsubscribePermissionStatusChange(subscription_id);
+  GetPermissionControllerDelegate()->UnsubscribePermissionStatusChange(
+      subscription_id);
 }
 
 TEST_F(PermissionManagerTest, SuppressPermissionRequests) {
@@ -432,7 +455,7 @@
   NavigateAndCommit(url());
 
   SetPermission(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, CONTENT_SETTING_ALLOW);
-  GetPermissionManager()->RequestPermission(
+  GetPermissionControllerDelegate()->RequestPermission(
       PermissionType::NOTIFICATIONS, main_rfh(), url(), true,
       base::Bind(&PermissionManagerTest::OnPermissionChange,
                  base::Unretained(this)));
@@ -443,7 +466,7 @@
   vr_tab_helper->SetIsInVr(true);
   EXPECT_EQ(
       kNoPendingOperation,
-      GetPermissionManager()->RequestPermission(
+      GetPermissionControllerDelegate()->RequestPermission(
           PermissionType::NOTIFICATIONS, contents->GetMainFrame(), url(), false,
           base::Bind(&PermissionManagerTest::OnPermissionChange,
                      base::Unretained(this))));
@@ -451,7 +474,7 @@
   EXPECT_EQ(PermissionStatus::DENIED, callback_result());
 
   vr_tab_helper->SetIsInVr(false);
-  GetPermissionManager()->RequestPermission(
+  GetPermissionControllerDelegate()->RequestPermission(
       PermissionType::NOTIFICATIONS, main_rfh(), url(), false,
       base::Bind(&PermissionManagerTest::OnPermissionChange,
                  base::Unretained(this)));
@@ -469,7 +492,7 @@
 
   NavigateAndCommit(url());
 
-  GetPermissionManager()->RequestPermission(
+  GetPermissionControllerDelegate()->RequestPermission(
       PermissionType::VIDEO_CAPTURE, main_rfh(), url(), /*user_gesture=*/true,
       base::Bind(&PermissionManagerTest::OnPermissionChange,
                  base::Unretained(this)));
@@ -487,9 +510,10 @@
   GURL insecure_frame("http://www.example.com/geolocation");
   NavigateAndCommit(insecure_frame);
 
-  PermissionResult result = GetPermissionManager()->GetPermissionStatusForFrame(
-      CONTENT_SETTINGS_TYPE_GEOLOCATION, web_contents()->GetMainFrame(),
-      insecure_frame);
+  PermissionResult result =
+      GetPermissionControllerDelegate()->GetPermissionStatusForFrame(
+          CONTENT_SETTINGS_TYPE_GEOLOCATION, web_contents()->GetMainFrame(),
+          insecure_frame);
 
   EXPECT_EQ(CONTENT_SETTING_BLOCK, result.content_setting);
   EXPECT_EQ(PermissionStatusSource::INSECURE_ORIGIN, result.source);
@@ -497,7 +521,7 @@
   GURL secure_frame("https://www.example.com/geolocation");
   NavigateAndCommit(secure_frame);
 
-  result = GetPermissionManager()->GetPermissionStatusForFrame(
+  result = GetPermissionControllerDelegate()->GetPermissionStatusForFrame(
       CONTENT_SETTINGS_TYPE_GEOLOCATION, web_contents()->GetMainFrame(),
       secure_frame);
 
@@ -516,24 +540,25 @@
   const GURL other_chrome_search = GURL("chrome-search://not-local-ntp");
 
   // "Normal" URLs are not affected by GetCanonicalOrigin.
-  EXPECT_EQ(google_com,
-            GetPermissionManager()->GetCanonicalOrigin(google_com, google_com));
-  EXPECT_EQ(google_de,
-            GetPermissionManager()->GetCanonicalOrigin(google_de, google_de));
-  EXPECT_EQ(other_url,
-            GetPermissionManager()->GetCanonicalOrigin(other_url, other_url));
-  EXPECT_EQ(google_base, GetPermissionManager()->GetCanonicalOrigin(
+  EXPECT_EQ(google_com, GetPermissionControllerDelegate()->GetCanonicalOrigin(
+                            google_com, google_com));
+  EXPECT_EQ(google_de, GetPermissionControllerDelegate()->GetCanonicalOrigin(
+                           google_de, google_de));
+  EXPECT_EQ(other_url, GetPermissionControllerDelegate()->GetCanonicalOrigin(
+                           other_url, other_url));
+  EXPECT_EQ(google_base, GetPermissionControllerDelegate()->GetCanonicalOrigin(
                              google_base, google_base));
 
   // The local NTP URL gets mapped to the Google base URL.
-  EXPECT_EQ(google_base,
-            GetPermissionManager()->GetCanonicalOrigin(local_ntp, local_ntp));
+  EXPECT_EQ(google_base, GetPermissionControllerDelegate()->GetCanonicalOrigin(
+                             local_ntp, local_ntp));
   // However, other chrome-search:// URLs, including the remote NTP URL, are
   // not affected.
-  EXPECT_EQ(remote_ntp,
-            GetPermissionManager()->GetCanonicalOrigin(remote_ntp, remote_ntp));
-  EXPECT_EQ(other_chrome_search, GetPermissionManager()->GetCanonicalOrigin(
-                                     other_chrome_search, other_chrome_search));
+  EXPECT_EQ(remote_ntp, GetPermissionControllerDelegate()->GetCanonicalOrigin(
+                            remote_ntp, remote_ntp));
+  EXPECT_EQ(other_chrome_search,
+            GetPermissionControllerDelegate()->GetCanonicalOrigin(
+                other_chrome_search, other_chrome_search));
 }
 
 TEST_F(PermissionManagerTest, GetCanonicalOriginPermissionDelegation) {
@@ -547,10 +572,11 @@
     scoped_feature_list.InitAndDisableFeature(features::kPermissionDelegation);
     // Without permission delegation enabled the requesting origin should always
     // be returned.
-    EXPECT_EQ(requesting_origin, GetPermissionManager()->GetCanonicalOrigin(
-                                     requesting_origin, embedding_origin));
+    EXPECT_EQ(requesting_origin,
+              GetPermissionControllerDelegate()->GetCanonicalOrigin(
+                  requesting_origin, embedding_origin));
     EXPECT_EQ(extensions_requesting_origin,
-              GetPermissionManager()->GetCanonicalOrigin(
+              GetPermissionControllerDelegate()->GetCanonicalOrigin(
                   extensions_requesting_origin, embedding_origin));
   }
 
@@ -559,10 +585,11 @@
     scoped_feature_list.InitAndEnableFeature(features::kPermissionDelegation);
     // With permission delegation, the embedding origin should be returned
     // except in the case of extensions.
-    EXPECT_EQ(embedding_origin, GetPermissionManager()->GetCanonicalOrigin(
-                                    requesting_origin, embedding_origin));
+    EXPECT_EQ(embedding_origin,
+              GetPermissionControllerDelegate()->GetCanonicalOrigin(
+                  requesting_origin, embedding_origin));
     EXPECT_EQ(extensions_requesting_origin,
-              GetPermissionManager()->GetCanonicalOrigin(
+              GetPermissionControllerDelegate()->GetCanonicalOrigin(
                   extensions_requesting_origin, embedding_origin));
   }
 }
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
index 03b8f4ad..81f00a3 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_controller_browsertest.cc
@@ -774,6 +774,42 @@
   EXPECT_TRUE(window_controller()->GetWindowForTesting()->IsVisible());
 }
 
+IN_PROC_BROWSER_TEST_F(PictureInPictureWindowControllerBrowserTest,
+                       EnterPictureInPictureThenNavigateAwayCloseWindow) {
+  GURL test_page_url = ui_test_utils::GetTestUrl(
+      base::FilePath(base::FilePath::kCurrentDirectory),
+      base::FilePath(
+          FILE_PATH_LITERAL("media/picture-in-picture/window-size.html")));
+  ui_test_utils::NavigateToURL(browser(), test_page_url);
+
+  content::WebContents* active_web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_TRUE(active_web_contents);
+
+  SetUpWindowController(active_web_contents);
+  ASSERT_TRUE(window_controller());
+
+  bool result = false;
+  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
+      active_web_contents, "enterPictureInPicture();", &result));
+  EXPECT_TRUE(result);
+
+  EXPECT_TRUE(window_controller()->GetWindowForTesting()->IsVisible());
+
+  // Same document navigations should not close Picture-in-Picture window.
+  EXPECT_TRUE(content::ExecuteScript(
+      active_web_contents, "window.location = '#foo'; window.history.back();"));
+  EXPECT_TRUE(window_controller()->GetWindowForTesting()->IsVisible());
+
+  // Picture-in-Picture window should be closed after navigating away.
+  GURL another_page_url = ui_test_utils::GetTestUrl(
+      base::FilePath(base::FilePath::kCurrentDirectory),
+      base::FilePath(
+          FILE_PATH_LITERAL("media/picture-in-picture/iframe-size.html")));
+  ui_test_utils::NavigateToURL(browser(), another_page_url);
+  EXPECT_FALSE(window_controller()->GetWindowForTesting()->IsVisible());
+}
+
 #if !defined(OS_ANDROID)
 
 // TODO(mlamouri): enable this tests on other platforms when aspect ratio is
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc
index b4a27010..f1270718 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.cc
@@ -4,19 +4,30 @@
 
 #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
 
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/picture_in_picture_window_controller.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "ui/gfx/geometry/size.h"
 
-class PictureInPictureWindowManager::WebContentsDestroyedObserver
+class PictureInPictureWindowManager::ContentsObserver
     : public content::WebContentsObserver {
  public:
-  WebContentsDestroyedObserver(PictureInPictureWindowManager* owner,
-                               content::WebContents* web_contents)
+  ContentsObserver(PictureInPictureWindowManager* owner,
+                   content::WebContents* web_contents)
       : content::WebContentsObserver(web_contents), owner_(owner) {}
 
-  ~WebContentsDestroyedObserver() final = default;
+  ~ContentsObserver() final = default;
+
+  void DidFinishNavigation(content::NavigationHandle* navigation_handle) final {
+    // Closes the active Picture-in-Picture window if user navigates away.
+    if (!navigation_handle->IsInMainFrame() ||
+        !navigation_handle->HasCommitted() ||
+        navigation_handle->IsSameDocument()) {
+      return;
+    }
+    owner_->CloseWindowInternal();
+  }
 
   void WebContentsDestroyed() final { owner_->CloseWindowInternal(); }
 
@@ -55,18 +66,17 @@
 
 void PictureInPictureWindowManager::CreateWindowInternal(
     content::WebContents* web_contents) {
-  destroyed_observer_ =
-      std::make_unique<WebContentsDestroyedObserver>(this, web_contents);
+  contents_observer_ = std::make_unique<ContentsObserver>(this, web_contents);
   pip_window_controller_ =
       content::PictureInPictureWindowController::GetOrCreateForWebContents(
           web_contents);
 }
 
 void PictureInPictureWindowManager::CloseWindowInternal() {
-  DCHECK(destroyed_observer_);
+  DCHECK(contents_observer_);
   DCHECK(pip_window_controller_);
 
-  destroyed_observer_.reset();
+  contents_observer_.reset();
   pip_window_controller_->Close(false /* should_pause_video */);
   pip_window_controller_ = nullptr;
 }
diff --git a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h
index 2d396c6..12cb157f 100644
--- a/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h
+++ b/chrome/browser/picture_in_picture/picture_in_picture_window_manager.h
@@ -36,7 +36,7 @@
 
  private:
   friend struct base::DefaultSingletonTraits<PictureInPictureWindowManager>;
-  class WebContentsDestroyedObserver;
+  class ContentsObserver;
 
   // Create a Picture-in-Picture window and register it in order to be closed
   // when needed.
@@ -52,7 +52,7 @@
   PictureInPictureWindowManager();
   ~PictureInPictureWindowManager();
 
-  std::unique_ptr<WebContentsDestroyedObserver> destroyed_observer_;
+  std::unique_ptr<ContentsObserver> contents_observer_;
   content::PictureInPictureWindowController* pip_window_controller_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(PictureInPictureWindowManager);
diff --git a/chrome/browser/policy/browser_dm_token_storage.cc b/chrome/browser/policy/browser_dm_token_storage.cc
new file mode 100644
index 0000000..4289609f
--- /dev/null
+++ b/chrome/browser/policy/browser_dm_token_storage.cc
@@ -0,0 +1,143 @@
+// 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.
+
+#include "chrome/browser/policy/browser_dm_token_storage.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/base64.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/no_destructor.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/task_runner_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace policy {
+
+// static
+BrowserDMTokenStorage* BrowserDMTokenStorage::storage_for_testing_ = nullptr;
+
+// Static function that can't be overridden. Implementation is only compiled for
+// non-supported platforms.
+#if !defined(OS_WIN)
+// static
+BrowserDMTokenStorage* BrowserDMTokenStorage::Get() {
+  if (storage_for_testing_)
+    return storage_for_testing_;
+
+  static base::NoDestructor<BrowserDMTokenStorage> storage;
+  return storage.get();
+}
+#endif
+
+BrowserDMTokenStorage::BrowserDMTokenStorage() : is_initialized_(false) {
+  DETACH_FROM_SEQUENCE(sequence_checker_);
+
+  // We don't call InitIfNeeded() here so that the global instance can be
+  // created early during startup if needed. The tokens and client ID are read
+  // from the system as part of the first retrieve or store operation.
+}
+
+BrowserDMTokenStorage::~BrowserDMTokenStorage() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+std::string BrowserDMTokenStorage::RetrieveClientId() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  InitIfNeeded();
+  return client_id_;
+}
+
+std::string BrowserDMTokenStorage::RetrieveEnrollmentToken() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  InitIfNeeded();
+  return enrollment_token_;
+}
+
+void BrowserDMTokenStorage::StoreDMToken(const std::string& dm_token,
+                                         StoreCallback callback) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!store_callback_);
+  InitIfNeeded();
+
+  dm_token_ = dm_token;
+
+  store_callback_ = std::move(callback);
+
+  SaveDMToken(dm_token);
+}
+
+std::string BrowserDMTokenStorage::RetrieveDMToken() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(!store_callback_);
+
+  InitIfNeeded();
+  return dm_token_;
+}
+
+void BrowserDMTokenStorage::InitIfNeeded() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (is_initialized_)
+    return;
+
+  is_initialized_ = true;
+  client_id_ = InitClientId();
+  DVLOG(1) << "Client ID = " << client_id_;
+  if (client_id_.empty())
+    return;
+
+  enrollment_token_ = InitEnrollmentToken();
+  DVLOG(1) << "Enrollment token = " << enrollment_token_;
+
+  dm_token_ = InitDMToken();
+  DVLOG(1) << "DM Token = " << dm_token_;
+}
+
+void BrowserDMTokenStorage::OnDMTokenStored(bool success) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  DCHECK(store_callback_);
+
+  if (!store_callback_.is_null())
+    std::move(store_callback_).Run(success);
+}
+
+// Stub implementation. This function will become virtual pure once Mac & Linux
+// implementations are done.
+std::string BrowserDMTokenStorage::InitClientId() {
+  return std::string();
+}
+
+// Stub implementation. This function will become virtual pure once Mac & Linux
+// implementations are done.
+std::string BrowserDMTokenStorage::InitEnrollmentToken() {
+  return std::string();
+}
+
+// Stub implementation. This function will become virtual pure once Mac & Linux
+// implementations are done.
+std::string BrowserDMTokenStorage::InitDMToken() {
+  return std::string();
+}
+
+// Stub implementation. This function will become virtual pure once Mac & Linux
+// implementations are done.
+void BrowserDMTokenStorage::SaveDMToken(const std::string& token) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(std::move(store_callback_), false));
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/browser_dm_token_storage.h b/chrome/browser/policy/browser_dm_token_storage.h
index 4c080d30..ac1a2bf0 100644
--- a/chrome/browser/policy/browser_dm_token_storage.h
+++ b/chrome/browser/policy/browser_dm_token_storage.h
@@ -10,6 +10,11 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/no_destructor.h"
+#include "base/sequence_checker.h"
+#include "base/single_thread_task_runner.h"
 
 namespace policy {
 
@@ -25,19 +30,22 @@
 
   // Returns the global singleton object. Must be called from the UI thread.
   static BrowserDMTokenStorage* Get();
-  // Returns a client ID unique to the machine.
-  virtual std::string RetrieveClientId() = 0;
-  // Returns the enrollment token, or an empty string if there is none.
-  virtual std::string RetrieveEnrollmentToken() = 0;
-  // Asynchronously stores |dm_token| in the registry and calls |callback| with
-  // a boolean to indicate success or failure. It is an error to attempt
-  // concurrent store operations.
+  // Returns a client ID unique to the machine. Virtual for tests.
+  virtual std::string RetrieveClientId();
+  // Returns the enrollment token, or an empty string if there is none. Virtual
+  // for tests.
+  virtual std::string RetrieveEnrollmentToken();
+  // Asynchronously stores |dm_token| and calls |callback| with a boolean to
+  // indicate success or failure. It is an error to attempt concurrent store
+  // operations. Virtual for tests.
   virtual void StoreDMToken(const std::string& dm_token,
-                            StoreCallback callback) = 0;
-  // Returns an already stored DM token from the registry or from the cache in
-  // memory. An empty token is returned if no DM token exists on the system or
-  // an error is encountered.
-  virtual std::string RetrieveDMToken() = 0;
+                            StoreCallback callback);
+  // Returns an already stored DM token. An empty token is returned if no DM
+  // token exists on the system or an error is encountered. Virtual for tests.
+  virtual std::string RetrieveDMToken();
+  // Must be called after the DM token is saved, to ensure that the callback is
+  // invoked.
+  void OnDMTokenStored(bool success);
 
   // Set the mock BrowserDMTokenStorage for testing. The caller owns the
   // instance of the storage.
@@ -46,12 +54,42 @@
   }
 
  protected:
-  BrowserDMTokenStorage() = default;
-  virtual ~BrowserDMTokenStorage() = default;
+  friend class base::NoDestructor<BrowserDMTokenStorage>;
+
+  // Get the global singleton instance by calling BrowserDMTokenStorage::Get().
+  BrowserDMTokenStorage();
+  virtual ~BrowserDMTokenStorage();
 
  private:
   static BrowserDMTokenStorage* storage_for_testing_;
 
+  // Initializes the DMTokenStorage object and caches the ids and tokens. This
+  // is called the first time the BrowserDMTokenStorage is interacted with.
+  void InitIfNeeded();
+
+  // Gets the client ID and stores it in |client_id_|. This implementation is
+  // platform dependant.
+  virtual std::string InitClientId();
+  // Gets the enrollment token and stores it in |enrollment_token_|. This
+  // implementation is platform dependant.
+  virtual std::string InitEnrollmentToken();
+  // Gets the DM token and stores it in |dm_token_|. This implementation is
+  // platform dependant.
+  virtual std::string InitDMToken();
+  // Saves the DM token. This implementation is platform dependant.
+  virtual void SaveDMToken(const std::string& token);
+
+  // Will be called after the DM token is stored.
+  StoreCallback store_callback_;
+
+  bool is_initialized_;
+
+  std::string client_id_;
+  std::string enrollment_token_;
+  std::string dm_token_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+
   DISALLOW_COPY_AND_ASSIGN(BrowserDMTokenStorage);
 };
 
diff --git a/chrome/browser/policy/browser_dm_token_storage_stub.cc b/chrome/browser/policy/browser_dm_token_storage_stub.cc
deleted file mode 100644
index a4ccfb0..0000000
--- a/chrome/browser/policy/browser_dm_token_storage_stub.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// 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.
-
-#include "chrome/browser/policy/browser_dm_token_storage_stub.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/callback.h"
-#include "base/threading/thread_task_runner_handle.h"
-
-namespace policy {
-
-namespace {
-BrowserDMTokenStorage* g_browser_dm_token_storage = nullptr;
-}  // namespace
-
-// static
-BrowserDMTokenStorage* BrowserDMTokenStorage::storage_for_testing_ = nullptr;
-
-// static
-BrowserDMTokenStorage* BrowserDMTokenStorage::Get() {
-  if (storage_for_testing_)
-    return storage_for_testing_;
-  if (g_browser_dm_token_storage == nullptr)
-    g_browser_dm_token_storage = new BrowserDMTokenStorageStub();
-  return g_browser_dm_token_storage;
-}
-
-std::string BrowserDMTokenStorageStub::RetrieveClientId() {
-  return std::string();
-}
-
-std::string BrowserDMTokenStorageStub::RetrieveEnrollmentToken() {
-  return std::string();
-}
-
-void BrowserDMTokenStorageStub::StoreDMToken(const std::string& dm_token,
-                                             StoreCallback callback) {
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(std::move(callback), false));
-}
-
-std::string BrowserDMTokenStorageStub::RetrieveDMToken() {
-  return std::string();
-}
-
-}  // namespace policy
diff --git a/chrome/browser/policy/browser_dm_token_storage_stub.h b/chrome/browser/policy/browser_dm_token_storage_stub.h
deleted file mode 100644
index c4a6853..0000000
--- a/chrome/browser/policy/browser_dm_token_storage_stub.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// 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.
-
-#ifndef CHROME_BROWSER_POLICY_BROWSER_DM_TOKEN_STORAGE_STUB_H_
-#define CHROME_BROWSER_POLICY_BROWSER_DM_TOKEN_STORAGE_STUB_H_
-
-#include "chrome/browser/policy/browser_dm_token_storage.h"
-
-#include <string>
-
-#include "base/macros.h"
-
-namespace policy {
-
-// No-op implementation of BrowserDMTokenStorage. The global singleton instance
-// can be retrieved by calling BrowserDMTokenStorage::Get().
-class BrowserDMTokenStorageStub : public BrowserDMTokenStorage {
- public:
-  // Get the global singleton instance by calling BrowserDMTokenStorage::Get().
-  BrowserDMTokenStorageStub() = default;
-  ~BrowserDMTokenStorageStub() override = default;
-
-  // override BrowserDMTokenStorage
-  std::string RetrieveClientId() override;
-  std::string RetrieveEnrollmentToken() override;
-  void StoreDMToken(const std::string& dm_token,
-                    StoreCallback callback) override;
-  std::string RetrieveDMToken() override;
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(BrowserDMTokenStorageStub);
-};
-
-}  // namespace policy
-
-#endif  // CHROME_BROWSER_POLICY_BROWSER_DM_TOKEN_STORAGE_STUB_H_
diff --git a/chrome/browser/policy/browser_dm_token_storage_unittest.cc b/chrome/browser/policy/browser_dm_token_storage_unittest.cc
new file mode 100644
index 0000000..8d8351e
--- /dev/null
+++ b/chrome/browser/policy/browser_dm_token_storage_unittest.cc
@@ -0,0 +1,135 @@
+// 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.
+
+#include "chrome/browser/policy/browser_dm_token_storage.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::IsEmpty;
+
+namespace policy {
+
+namespace {
+
+constexpr char kClientId1[] = "fake-client-id-1";
+constexpr char kClientId2[] = "fake-client-id-2";
+constexpr char kEnrollmentToken1[] = "fake-enrollment-token-1";
+constexpr char kEnrollmentToken2[] = "fake-enrollment-token-2";
+constexpr char kDMToken1[] = "fake-dm-token-1";
+constexpr char kDMToken2[] = "fake-dm-token-2";
+
+}  // namespace
+
+class MockBrowserDMTokenStorage : public BrowserDMTokenStorage {
+ public:
+  MockBrowserDMTokenStorage() {
+    set_test_client_id(kClientId1);
+    set_test_enrollment_token(kEnrollmentToken1);
+    set_test_dm_token(kDMToken1);
+  }
+
+  // BrowserDMTokenStorage override
+  std::string InitClientId() override { return test_client_id_; }
+  std::string InitEnrollmentToken() override { return test_enrollment_token_; }
+  std::string InitDMToken() override { return test_dm_token_; }
+
+  void set_test_client_id(std::string test_client_id) {
+    test_client_id_ = test_client_id;
+  }
+  void set_test_enrollment_token(std::string test_enrollment_token) {
+    test_enrollment_token_ = test_enrollment_token;
+  }
+  void set_test_dm_token(std::string test_dm_token) {
+    test_dm_token_ = test_dm_token;
+  }
+
+ private:
+  std::string test_client_id_;
+  std::string test_enrollment_token_;
+  std::string test_dm_token_;
+};
+
+class BrowserDMTokenStorageTest : public testing::Test {
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+};
+
+TEST_F(BrowserDMTokenStorageTest, RetrieveClientId) {
+  MockBrowserDMTokenStorage storage;
+  EXPECT_EQ(kClientId1, storage.RetrieveClientId());
+
+  // The client ID value should be cached in memory and not read from the system
+  // again.
+  storage.set_test_client_id(kClientId2);
+  EXPECT_EQ(kClientId1, storage.RetrieveClientId());
+}
+
+TEST_F(BrowserDMTokenStorageTest, RetrieveEnrollmentToken) {
+  MockBrowserDMTokenStorage storage;
+  EXPECT_EQ(kEnrollmentToken1, storage.RetrieveEnrollmentToken());
+
+  // The enrollment token should be cached in memory and not read from the
+  // system again.
+  storage.set_test_enrollment_token(kEnrollmentToken2);
+  EXPECT_EQ(kEnrollmentToken1, storage.RetrieveEnrollmentToken());
+}
+
+TEST_F(BrowserDMTokenStorageTest, RetrieveDMToken) {
+  MockBrowserDMTokenStorage storage;
+  EXPECT_EQ(kDMToken1, storage.RetrieveDMToken());
+
+  // The DM token should be cached in memory and not read from the system again.
+  storage.set_test_dm_token(kDMToken2);
+  EXPECT_EQ(kDMToken1, storage.RetrieveDMToken());
+}
+
+class TestStoreDMTokenDelegate {
+ public:
+  TestStoreDMTokenDelegate() : called_(false), success_(true) {}
+  ~TestStoreDMTokenDelegate() {}
+
+  void OnDMTokenStored(bool success) {
+    run_loop_.Quit();
+    called_ = true;
+    success_ = success;
+  }
+
+  bool WasCalled() {
+    bool was_called = called_;
+    called_ = false;
+    return was_called;
+  }
+
+  bool success() { return success_; }
+
+  void Wait() { run_loop_.Run(); }
+
+ private:
+  bool called_;
+  bool success_;
+  base::RunLoop run_loop_;
+};
+
+TEST_F(BrowserDMTokenStorageTest, StoreDMToken) {
+  MockBrowserDMTokenStorage storage;
+  TestStoreDMTokenDelegate delegate;
+
+  storage.StoreDMToken(
+      kDMToken1, base::BindOnce(&TestStoreDMTokenDelegate::OnDMTokenStored,
+                                base::Unretained(&delegate)));
+
+  delegate.Wait();
+
+  EXPECT_TRUE(delegate.WasCalled());
+  EXPECT_FALSE(delegate.success());
+}
+
+}  // namespace policy
diff --git a/chrome/browser/policy/browser_dm_token_storage_win.cc b/chrome/browser/policy/browser_dm_token_storage_win.cc
index 31dd3d4..321f03e 100644
--- a/chrome/browser/policy/browser_dm_token_storage_win.cc
+++ b/chrome/browser/policy/browser_dm_token_storage_win.cc
@@ -40,67 +40,7 @@
 #endif  // defined(GOOGLE_CHROME_BUILD)
 
 namespace policy {
-
 namespace {
-
-std::string GetClientId() {
-  // For the client id, use the Windows machine GUID.
-  // TODO(crbug.com/821977): Need a backup plan if machine GUID doesn't exist.
-  base::win::RegKey key;
-  LSTATUS status = key.Open(HKEY_LOCAL_MACHINE,
-                            L"SOFTWARE\\Microsoft\\Cryptography", KEY_READ);
-  if (status != ERROR_SUCCESS)
-    return std::string();
-
-  base::string16 value;
-  status = key.ReadValue(L"MachineGuid", &value);
-  if (status != ERROR_SUCCESS)
-    return std::string();
-
-  std::string client_id;
-  if (!base::WideToUTF8(value.c_str(), value.length(), &client_id))
-    return std::string();
-  return client_id;
-}
-
-std::string GetDMToken() {
-  base::win::RegKey key;
-  base::string16 dm_token_key_path;
-  base::string16 dm_token_value_name;
-  InstallUtil::GetMachineLevelUserCloudPolicyDMTokenRegistryPath(
-      &dm_token_key_path, &dm_token_value_name);
-  LONG result = key.Open(HKEY_LOCAL_MACHINE, dm_token_key_path.c_str(),
-                         KEY_QUERY_VALUE | KEY_WOW64_64KEY);
-  if (result != ERROR_SUCCESS)
-    return std::string();
-
-  // At the time of writing (January 2018), the DM token is about 200 bytes
-  // long. The initial size of the buffer should be enough to cover most
-  // realistic future size-increase scenarios, although we still make an effort
-  // to support somewhat larger token sizes just to be safe.
-  constexpr size_t kInitialDMTokenSize = 512;
-
-  DWORD size = kInitialDMTokenSize;
-  std::vector<char> raw_value(size);
-  DWORD dtype = REG_NONE;
-  result = key.ReadValue(dm_token_value_name.c_str(), raw_value.data(), &size,
-                         &dtype);
-  if (result == ERROR_MORE_DATA && size <= installer::kMaxDMTokenLength) {
-    raw_value.resize(size);
-    result = key.ReadValue(dm_token_value_name.c_str(), raw_value.data(), &size,
-                           &dtype);
-  }
-
-  if (result != ERROR_SUCCESS || dtype != REG_BINARY || size == 0) {
-    DVLOG(1) << "Failed to get DMToken from Registry.";
-    return std::string();
-  }
-  DCHECK_LE(size, installer::kMaxDMTokenLength);
-  std::string dm_token;
-  dm_token.assign(raw_value.data(), size);
-  return dm_token;
-}
-
 #if defined(GOOGLE_CHROME_BUILD)
 // Explicitly allow DMTokenStorage impersonate the client since some COM code
 // elsewhere in the browser process may have previously used
@@ -184,11 +124,78 @@
   return false;
 #endif  // defined(GOOGLE_CHROME_BUILD)
 }
-
 }  // namespace
 
-// static
-BrowserDMTokenStorage* BrowserDMTokenStorage::storage_for_testing_ = nullptr;
+std::string BrowserDMTokenStorageWin::InitClientId() {
+  // For the client id, use the Windows machine GUID.
+  // TODO(crbug.com/821977): Need a backup plan if machine GUID doesn't exist.
+  base::win::RegKey key;
+  LSTATUS status = key.Open(HKEY_LOCAL_MACHINE,
+                            L"SOFTWARE\\Microsoft\\Cryptography", KEY_READ);
+  if (status != ERROR_SUCCESS)
+    return std::string();
+
+  base::string16 value;
+  status = key.ReadValue(L"MachineGuid", &value);
+  if (status != ERROR_SUCCESS)
+    return std::string();
+
+  std::string client_id;
+  if (!base::WideToUTF8(value.c_str(), value.length(), &client_id))
+    return std::string();
+  return client_id;
+}
+
+std::string BrowserDMTokenStorageWin::InitEnrollmentToken() {
+  return base::WideToUTF8(
+      InstallUtil::GetMachineLevelUserCloudPolicyEnrollmentToken());
+}
+
+std::string BrowserDMTokenStorageWin::InitDMToken() {
+  base::win::RegKey key;
+  base::string16 dm_token_key_path;
+  base::string16 dm_token_value_name;
+  InstallUtil::GetMachineLevelUserCloudPolicyDMTokenRegistryPath(
+      &dm_token_key_path, &dm_token_value_name);
+  LONG result = key.Open(HKEY_LOCAL_MACHINE, dm_token_key_path.c_str(),
+                         KEY_QUERY_VALUE | KEY_WOW64_64KEY);
+  if (result != ERROR_SUCCESS)
+    return std::string();
+
+  // At the time of writing (January 2018), the DM token is about 200 bytes
+  // long. The initial size of the buffer should be enough to cover most
+  // realistic future size-increase scenarios, although we still make an effort
+  // to support somewhat larger token sizes just to be safe.
+  constexpr size_t kInitialDMTokenSize = 512;
+
+  DWORD size = kInitialDMTokenSize;
+  std::vector<char> raw_value(size);
+  DWORD dtype = REG_NONE;
+  result = key.ReadValue(dm_token_value_name.c_str(), raw_value.data(), &size,
+                         &dtype);
+  if (result == ERROR_MORE_DATA && size <= installer::kMaxDMTokenLength) {
+    raw_value.resize(size);
+    result = key.ReadValue(dm_token_value_name.c_str(), raw_value.data(), &size,
+                           &dtype);
+  }
+
+  if (result != ERROR_SUCCESS || dtype != REG_BINARY || size == 0) {
+    DVLOG(1) << "Failed to get DMToken from Registry.";
+    return std::string();
+  }
+  DCHECK_LE(size, installer::kMaxDMTokenLength);
+  std::string dm_token;
+  dm_token.assign(raw_value.data(), size);
+  return dm_token;
+}
+
+void BrowserDMTokenStorageWin::SaveDMToken(const std::string& token) {
+  base::PostTaskAndReplyWithResult(
+      com_sta_task_runner_.get(), FROM_HERE,
+      base::BindOnce(&StoreDMTokenInRegistry, token),
+      base::BindOnce(&BrowserDMTokenStorage::OnDMTokenStored,
+                     weak_factory_.GetWeakPtr()));
+}
 
 // static
 BrowserDMTokenStorage* BrowserDMTokenStorage::Get() {
@@ -202,85 +209,8 @@
 BrowserDMTokenStorageWin::BrowserDMTokenStorageWin()
     : com_sta_task_runner_(
           base::CreateCOMSTATaskRunnerWithTraits({base::MayBlock()})),
-      is_initialized_(false),
-      weak_factory_(this) {
-  DETACH_FROM_SEQUENCE(sequence_checker_);
+      weak_factory_(this) {}
 
-  // We don't call InitIfNeeded() here so that the global instance can be
-  // created early during startup if needed. The tokens and client ID are read
-  // from the system as part of the first retrieve or store operation.
-}
-
-BrowserDMTokenStorageWin::~BrowserDMTokenStorageWin() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-}
-
-std::string BrowserDMTokenStorageWin::RetrieveClientId() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  InitIfNeeded();
-  return client_id_;
-}
-
-std::string BrowserDMTokenStorageWin::RetrieveEnrollmentToken() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  InitIfNeeded();
-  return enrollment_token_;
-}
-
-void BrowserDMTokenStorageWin::StoreDMToken(const std::string& dm_token,
-                                            StoreCallback callback) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!store_callback_);
-
-  InitIfNeeded();
-
-  dm_token_ = dm_token;
-
-  store_callback_ = std::move(callback);
-
-  base::PostTaskAndReplyWithResult(
-      com_sta_task_runner_.get(), FROM_HERE,
-      base::BindOnce(&StoreDMTokenInRegistry, dm_token),
-      base::BindOnce(&BrowserDMTokenStorageWin::OnDMTokenStored,
-                     weak_factory_.GetWeakPtr()));
-}
-
-std::string BrowserDMTokenStorageWin::RetrieveDMToken() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!store_callback_);
-
-  InitIfNeeded();
-  return dm_token_;
-}
-
-void BrowserDMTokenStorageWin::InitIfNeeded() {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-
-  if (is_initialized_)
-    return;
-
-  is_initialized_ = true;
-  client_id_ = GetClientId();
-  DVLOG(1) << "Client ID = " << client_id_;
-  if (client_id_.empty())
-    return;
-
-  enrollment_token_ = base::WideToUTF8(
-      InstallUtil::GetMachineLevelUserCloudPolicyEnrollmentToken());
-  DVLOG(1) << "Enrollment token = " << enrollment_token_;
-
-  dm_token_ = GetDMToken();
-  DVLOG(1) << "DM Token = " << dm_token_;
-}
-
-void BrowserDMTokenStorageWin::OnDMTokenStored(bool success) {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(store_callback_);
-
-  if (!store_callback_.is_null())
-    std::move(store_callback_).Run(success);
-}
+BrowserDMTokenStorageWin::~BrowserDMTokenStorageWin() {}
 
 }  // namespace policy
diff --git a/chrome/browser/policy/browser_dm_token_storage_win.h b/chrome/browser/policy/browser_dm_token_storage_win.h
index eeefd90..57a82ff 100644
--- a/chrome/browser/policy/browser_dm_token_storage_win.h
+++ b/chrome/browser/policy/browser_dm_token_storage_win.h
@@ -9,6 +9,7 @@
 
 #include <string>
 
+#include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
@@ -25,34 +26,23 @@
   BrowserDMTokenStorageWin();
   ~BrowserDMTokenStorageWin() override;
 
-  // override BrowserDMTokenStorage
-  std::string RetrieveClientId() override;
-  std::string RetrieveEnrollmentToken() override;
-  void StoreDMToken(const std::string& dm_token,
-                    StoreCallback callback) override;
-  std::string RetrieveDMToken() override;
-
  private:
-  // Initialize the DMTokenStorage, reads the |enrollment_token_| and
-  // |dm_token_| from Registry synchronously.
-  void InitIfNeeded();
-
-  void OnDMTokenStored(bool success);
+  // override BrowserDMTokenStorage
+  std::string InitClientId() override;
+  std::string InitEnrollmentToken() override;
+  std::string InitDMToken() override;
+  void SaveDMToken(const std::string& token) override;
 
   scoped_refptr<base::SingleThreadTaskRunner> com_sta_task_runner_;
-  StoreCallback store_callback_;
-
-  bool is_initialized_;
-
-  std::string client_id_;
-  std::string enrollment_token_;
-  std::string dm_token_;
-
-  SEQUENCE_CHECKER(sequence_checker_);
 
   // This should always be the last member of the class.
   base::WeakPtrFactory<BrowserDMTokenStorageWin> weak_factory_;
 
+  FRIEND_TEST_ALL_PREFIXES(BrowserDMTokenStorageWinTest, InitClientId);
+  FRIEND_TEST_ALL_PREFIXES(BrowserDMTokenStorageWinTest, InitEnrollmentToken);
+  FRIEND_TEST_ALL_PREFIXES(BrowserDMTokenStorageWinTest, InitDMToken);
+  FRIEND_TEST_ALL_PREFIXES(BrowserDMTokenStorageWinTest, SaveDMToken);
+
   DISALLOW_COPY_AND_ASSIGN(BrowserDMTokenStorageWin);
 };
 
diff --git a/chrome/browser/policy/browser_dm_token_storage_win_unittest.cc b/chrome/browser/policy/browser_dm_token_storage_win_unittest.cc
index 8dc3f41d..60af151c6 100644
--- a/chrome/browser/policy/browser_dm_token_storage_win_unittest.cc
+++ b/chrome/browser/policy/browser_dm_token_storage_win_unittest.cc
@@ -20,11 +20,8 @@
 namespace {
 
 constexpr wchar_t kClientId1[] = L"fake-client-id-1";
-constexpr wchar_t kClientId2[] = L"fake-client-id-2";
 constexpr wchar_t kEnrollmentToken1[] = L"fake-enrollment-token-1";
-constexpr wchar_t kEnrollmentToken2[] = L"fake-enrollment-token-2";
 constexpr char kDMToken1[] = "fake-dm-token-1";
-constexpr char kDMToken2[] = "fake-dm-token-2";
 
 }  // namespace
 
@@ -73,45 +70,26 @@
   registry_util::RegistryOverrideManager registry_override_manager_;
 };
 
-TEST_F(BrowserDMTokenStorageWinTest, RetrieveClientId) {
+TEST_F(BrowserDMTokenStorageWinTest, InitClientId) {
   ASSERT_TRUE(SetMachineGuid(kClientId1));
   BrowserDMTokenStorageWin storage;
-  EXPECT_EQ(base::WideToUTF8(kClientId1), storage.RetrieveClientId());
-
-  // The client ID value should be cached in memory and not read from the system
-  // again.
-  ASSERT_TRUE(SetMachineGuid(kClientId2));
-  EXPECT_EQ(base::WideToUTF8(kClientId1), storage.RetrieveClientId());
+  EXPECT_EQ(base::WideToUTF8(kClientId1), storage.InitClientId());
 }
 
-TEST_F(BrowserDMTokenStorageWinTest, RetrieveEnrollmentToken) {
+TEST_F(BrowserDMTokenStorageWinTest, InitEnrollmentToken) {
   ASSERT_TRUE(SetMachineGuid(kClientId1));
   ASSERT_TRUE(SetEnrollmentToken(kEnrollmentToken1));
 
   BrowserDMTokenStorageWin storage;
-  EXPECT_EQ(base::WideToUTF8(kEnrollmentToken1),
-            storage.RetrieveEnrollmentToken());
-  // The enrollment token should be cached in memory and not read from the
-  // system again.
-  ASSERT_TRUE(SetEnrollmentToken(kEnrollmentToken2));
-  EXPECT_EQ(base::WideToUTF8(kEnrollmentToken1),
-            storage.RetrieveEnrollmentToken());
+  EXPECT_EQ(base::WideToUTF8(kEnrollmentToken1), storage.InitEnrollmentToken());
 }
 
-TEST_F(BrowserDMTokenStorageWinTest, RetrieveDMToken) {
+TEST_F(BrowserDMTokenStorageWinTest, InitDMToken) {
   ASSERT_TRUE(SetMachineGuid(kClientId1));
 
-  // The DM token will be read from the system regardless there is an enrollment
-  // token or not.
   ASSERT_TRUE(SetDMToken(kDMToken1));
   BrowserDMTokenStorageWin storage;
-  EXPECT_EQ(std::string(kDMToken1), storage.RetrieveDMToken());
-
-  ASSERT_TRUE(SetEnrollmentToken(kEnrollmentToken1));
-  EXPECT_EQ(std::string(kDMToken1), storage.RetrieveDMToken());
-
-  // The DM token should be cached in memory and not read from the system again.
-  ASSERT_TRUE(SetDMToken(kDMToken2));
-  EXPECT_EQ(std::string(kDMToken1), storage.RetrieveDMToken());
+  EXPECT_EQ(std::string(kDMToken1), storage.InitDMToken());
 }
+
 }  // namespace policy
diff --git a/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc b/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
index 7cfaf2e..dfc420e7 100644
--- a/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
+++ b/chrome/browser/policy/cloud/machine_level_user_cloud_policy_browsertest.cc
@@ -427,6 +427,16 @@
   histogram_tester_.ExpectBucketCount(kEnrollmentResultMetrics, expected_result,
                                       1);
   histogram_tester_.ExpectTotalCount(kEnrollmentResultMetrics, 1);
+
+#if defined(OS_MACOSX)
+  // Verify the last mericis of launch is recorded in
+  // applicationDidFinishNotification.
+  if (is_enrollment_token_valid()) {
+    EXPECT_EQ(1u, histogram_tester_
+                      .GetAllSamples("Startup.OSX.DockIconWillFinishBouncing")
+                      .size());
+  }
+#endif
 }
 
 INSTANTIATE_TEST_CASE_P(,
diff --git a/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc b/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc
index 817db66..30036dc4 100644
--- a/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc
+++ b/chrome/browser/policy/machine_level_user_cloud_policy_controller.cc
@@ -103,7 +103,7 @@
   if (!policy_manager)
     return;
   // If there exists an enrollment token, then there are two states:
-  //   1/ There also exists a DM token.  This machine is already registeted, so
+  //   1/ There also exists a DM token.  This machine is already registered, so
   //      the next step is to fetch policies.
   //   2/ There is no DM token.  In this case the machine is not already
   //      registered and needs to request a DM token.
@@ -144,9 +144,9 @@
                    base::Unretained(this)));
 #if defined(OS_WIN)
     // This metric is only published on Windows to indicate how many user level
-    // install Chrome try to enroll the policy which can't store the DM token
-    // in the Registry in the end of enrollment. Mac and Linux does not need
-    // this metric for now as they might use different token storage mechanism
+    // installs try to enroll, as these can't store the DM token
+    // in the registry at the end of enrollment. Mac and Linux do not need
+    // this metric for now as they might use a different token storage mechanism
     // in the future.
     UMA_HISTOGRAM_BOOLEAN(
         "Enterprise.MachineLevelUserCloudPolicyEnrollment.InstallLevel_Win",
diff --git a/chrome/browser/policy/machine_level_user_cloud_policy_controller.h b/chrome/browser/policy/machine_level_user_cloud_policy_controller.h
index 8fb4349d..d2b741cc 100644
--- a/chrome/browser/policy/machine_level_user_cloud_policy_controller.h
+++ b/chrome/browser/policy/machine_level_user_cloud_policy_controller.h
@@ -34,9 +34,12 @@
   enum class RegisterResult {
     kNoEnrollmentNeeded,  // The device won't be enrolled without an enrollment
                           // token.
-    kEnrollmentSuccess,   // The device has been enrolled successfully.
-    kQuitDueToFailure,  // The enrollment has failed or aborted, user choose to
-                        // quit Chrome.
+    kEnrollmentSuccessBeforeDialogDisplayed,  // The enrollment process is
+                                              // finished before dialog
+                                              // displayed.
+    kEnrollmentSuccess,  // The device has been enrolled successfully
+    kQuitDueToFailure,   // The enrollment has failed or aborted, user choose to
+                         // quit Chrome.
     kRestartDueToFailure,  // The enrollment has failed, user choose to restart
   };
 
diff --git a/chrome/browser/policy/machine_level_user_cloud_policy_register_watcher.cc b/chrome/browser/policy/machine_level_user_cloud_policy_register_watcher.cc
index d1a6811..525a56b 100644
--- a/chrome/browser/policy/machine_level_user_cloud_policy_register_watcher.cc
+++ b/chrome/browser/policy/machine_level_user_cloud_policy_register_watcher.cc
@@ -44,7 +44,7 @@
 
   // We are already enrolled successfully.
   if (!token_storage->RetrieveDMToken().empty()) {
-    return RegisterResult::kEnrollmentSuccess;
+    return RegisterResult::kEnrollmentSuccessBeforeDialogDisplayed;
   }
 
   EnterpriseStartupDialog::DialogResultCallback callback = base::BindOnce(
diff --git a/chrome/browser/policy/machine_level_user_cloud_policy_register_watcher_unittest.cc b/chrome/browser/policy/machine_level_user_cloud_policy_register_watcher_unittest.cc
index de3312e..b34e071f 100644
--- a/chrome/browser/policy/machine_level_user_cloud_policy_register_watcher_unittest.cc
+++ b/chrome/browser/policy/machine_level_user_cloud_policy_register_watcher_unittest.cc
@@ -151,7 +151,7 @@
 TEST_F(MachineLevelUserCloudPolicyRegisterWatcherTest,
        NoEnrollmentNeededWithDMToken) {
   storage()->set_dm_token(kDMToken);
-  EXPECT_EQ(RegisterResult::kEnrollmentSuccess,
+  EXPECT_EQ(RegisterResult::kEnrollmentSuccessBeforeDialogDisplayed,
             watcher()->WaitUntilCloudPolicyEnrollmentFinished());
 }
 
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
index b4bad0a..8fed45d1 100644
--- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
+++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_browsertest.cc
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <string>
+#include <vector>
+
 #include "base/command_line.h"
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -9,7 +12,10 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/metrics/subprocess_metrics_provider.h"
+#include "chrome/browser/previews/previews_service.h"
+#include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -17,6 +23,7 @@
 #include "components/optimization_guide/optimization_guide_service_observer.h"
 #include "components/optimization_guide/proto/hints.pb.h"
 #include "components/optimization_guide/test_component_creator.h"
+#include "components/previews/content/previews_ui_service.h"
 #include "components/previews/core/previews_black_list.h"
 #include "components/previews/core/previews_features.h"
 #include "content/public/test/browser_test_utils.h"
@@ -121,6 +128,24 @@
     cmd->AppendSwitchASCII("force-effective-connection-type", "Slow-2G");
   }
 
+  void SetResourceLoadingHintsPatterns() {
+    Profile* profile = browser()->profile();
+    DCHECK(!profile->IsOffTheRecord());
+
+    PreviewsService* previews_service =
+        PreviewsServiceFactory::GetForProfile(profile);
+    previews::PreviewsUIService* previews_ui_service =
+        previews_service->previews_ui_service();
+
+    std::vector<std::string> hints;
+    hints.push_back("jpg");
+    hints.push_back("png");
+    hints.push_back("woff2");
+
+    previews_ui_service->SetResourceLoadingHintsResourcePatternsToBlock(
+        https_url_, hints);
+  }
+
   void SetResourceLoadingHintsWhitelist(
       const std::vector<std::string>&
           whitelisted_resource_loading_hints_sites) {
@@ -215,6 +240,7 @@
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest,
                        MAYBE_ResourceLoadingHintsHttpsWhitelisted) {
+  SetResourceLoadingHintsPatterns();
   TestOptimizationGuideServiceObserver observer;
   AddTestOptimizationGuideServiceObserver(&observer);
   base::RunLoop().RunUntilIdle();
@@ -235,8 +261,9 @@
       static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1);
   histogram_tester.ExpectBucketCount(
       "Previews.InfoBarAction.ResourceLoadingHints", 0, 1);
+  // SetResourceLoadingHintsPatterns sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
-      "ResourceLoadingHints.CountBlockedSubresourcePatterns", 1, 1);
+      "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 1);
 
   // Load the same webpage to ensure that the resource loading hints are sent
   // again.
@@ -249,13 +276,15 @@
       static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 2);
   histogram_tester.ExpectBucketCount(
       "Previews.InfoBarAction.ResourceLoadingHints", 0, 2);
+  // SetResourceLoadingHintsPatterns sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
-      "ResourceLoadingHints.CountBlockedSubresourcePatterns", 1, 2);
+      "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 2);
 }
 
 IN_PROC_BROWSER_TEST_F(
     ResourceLoadingHintsBrowserTest,
     MAYBE_ResourceLoadingHintsHttpsWhitelistedRedirectToHttps) {
+  SetResourceLoadingHintsPatterns();
   TestOptimizationGuideServiceObserver observer;
   AddTestOptimizationGuideServiceObserver(&observer);
   base::RunLoop().RunUntilIdle();
@@ -274,12 +303,14 @@
       static_cast<int>(previews::PreviewsEligibilityReason::ALLOWED), 1);
   histogram_tester.ExpectTotalCount(
       "Previews.InfoBarAction.ResourceLoadingHints", 1);
+  // SetResourceLoadingHintsPatterns sets 3 resource loading hints patterns.
   histogram_tester.ExpectBucketCount(
-      "ResourceLoadingHints.CountBlockedSubresourcePatterns", 1, 1);
+      "ResourceLoadingHints.CountBlockedSubresourcePatterns", 3, 1);
 }
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest,
                        ResourceLoadingHintsHttpsNoWhitelisted) {
+  SetResourceLoadingHintsPatterns();
   TestOptimizationGuideServiceObserver observer;
   AddTestOptimizationGuideServiceObserver(&observer);
   base::RunLoop().RunUntilIdle();
@@ -304,6 +335,7 @@
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest,
                        ResourceLoadingHintsHttp) {
+  SetResourceLoadingHintsPatterns();
   TestOptimizationGuideServiceObserver observer;
   AddTestOptimizationGuideServiceObserver(&observer);
   base::RunLoop().RunUntilIdle();
@@ -328,6 +360,7 @@
 
 IN_PROC_BROWSER_TEST_F(ResourceLoadingHintsBrowserTest,
                        ResourceLoadingHintsHttpsWhitelistedNoTransform) {
+  SetResourceLoadingHintsPatterns();
   TestOptimizationGuideServiceObserver observer;
   AddTestOptimizationGuideServiceObserver(&observer);
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc
index 9296ece..8e11301 100644
--- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc
+++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.cc
@@ -7,8 +7,11 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "chrome/browser/loader/chrome_navigation_data.h"
+#include "chrome/browser/previews/previews_service.h"
+#include "chrome/browser/previews/previews_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "components/previews/content/previews_content_util.h"
+#include "components/previews/content/previews_ui_service.h"
 #include "components/previews/core/previews_experiments.h"
 #include "components/previews/core/previews_user_data.h"
 #include "content/public/browser/browser_thread.h"
@@ -28,6 +31,8 @@
     ResourceLoadingHintsWebContentsObserver(content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents) {
   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
 }
 
 void ResourceLoadingHintsWebContentsObserver::DidFinishNavigation(
@@ -70,8 +75,28 @@
   blink::mojom::PreviewsResourceLoadingHintsPtr hints_ptr =
       blink::mojom::PreviewsResourceLoadingHints::New();
 
-  // TOOD(tbansal): https://crbug.com/856243. Send an actual list of resource
-  // URLs to block.
-  hints_ptr->subresources_to_block.push_back(std::string());
+  const std::vector<std::string>& hints =
+      GetResourceLoadingHintsResourcePatternsToBlock(
+          navigation_handle->GetURL());
+
+  if (hints.empty())
+    return;
+  for (const std::string& hint : hints)
+    hints_ptr->subresources_to_block.push_back(hint);
+
   hints_receiver_ptr->SetResourceLoadingHints(std::move(hints_ptr));
 }
+
+const std::vector<std::string> ResourceLoadingHintsWebContentsObserver::
+    GetResourceLoadingHintsResourcePatternsToBlock(
+        const GURL& document_gurl) const {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK(profile_);
+
+  PreviewsService* previews_service =
+      PreviewsServiceFactory::GetForProfile(profile_);
+  previews::PreviewsUIService* previews_ui_service =
+      previews_service->previews_ui_service();
+  return previews_ui_service->GetResourceLoadingHintsResourcePatternsToBlock(
+      document_gurl);
+}
diff --git a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h
index 8f15a18..f7cd690 100644
--- a/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h
+++ b/chrome/browser/previews/resource_loading_hints/resource_loading_hints_web_contents_observer.h
@@ -5,10 +5,15 @@
 #ifndef CHROME_BROWSER_PREVIEWS_RESOURCE_LOADING_HINTS_RESOURCE_LOADING_HINTS_WEB_CONTENTS_OBSERVER_H_
 #define CHROME_BROWSER_PREVIEWS_RESOURCE_LOADING_HINTS_RESOURCE_LOADING_HINTS_WEB_CONTENTS_OBSERVER_H_
 
+#include <string>
+#include <vector>
+
 #include "base/macros.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
+class Profile;
+
 // Observes navigation events and sends the resource loading hints mojo message
 // to the renderer.
 class ResourceLoadingHintsWebContentsObserver
@@ -35,6 +40,17 @@
   void SendResourceLoadingHints(
       content::NavigationHandle* navigation_handle) const;
 
+  // Returns the pattern of resources that should be blocked when loading
+  // |document_gurl|. The pattern may be a single substring to match against the
+  // URL or it may be an ordered set of substrings to match where the substrings
+  // are separated by the ‘*’ wildcard character (with an implicit ‘*’ at the
+  // beginning and end).
+  const std::vector<std::string> GetResourceLoadingHintsResourcePatternsToBlock(
+      const GURL& document_gurl) const;
+
+  // Set in constructor.
+  Profile* profile_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(ResourceLoadingHintsWebContentsObserver);
 };
 
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 16ef2bd..2d962daa 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -393,6 +393,12 @@
   return io_data_->GetExtensionsRequestContextGetter().get();
 }
 
+scoped_refptr<network::SharedURLLoaderFactory>
+OffTheRecordProfileImpl::GetURLLoaderFactory() {
+  return GetDefaultStoragePartition(this)
+      ->GetURLLoaderFactoryForBrowserProcess();
+}
+
 net::URLRequestContextGetter*
 OffTheRecordProfileImpl::CreateRequestContextForStoragePartition(
     const base::FilePath& partition_path,
@@ -439,7 +445,8 @@
 
 // TODO(mlamouri): we should all these BrowserContext implementation to Profile
 // instead of repeating them inside all Profile implementations.
-content::PermissionManager* OffTheRecordProfileImpl::GetPermissionManager() {
+content::PermissionControllerDelegate*
+OffTheRecordProfileImpl::GetPermissionControllerDelegate() {
   return PermissionManagerFactory::GetForProfile(this);
 }
 
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h
index 8a8b385d..5d31663 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.h
+++ b/chrome/browser/profiles/off_the_record_profile_impl.h
@@ -57,6 +57,7 @@
   PrefService* GetOffTheRecordPrefs() override;
   net::URLRequestContextGetter* GetRequestContext() override;
   net::URLRequestContextGetter* GetRequestContextForExtensions() override;
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
   net::URLRequestContextGetter* CreateRequestContext(
       content::ProtocolHandlerMap* protocol_handlers,
       content::URLRequestInterceptorScopedVector request_interceptors) override;
@@ -101,7 +102,8 @@
   storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
   content::PushMessagingService* GetPushMessagingService() override;
   content::SSLHostStateDelegate* GetSSLHostStateDelegate() override;
-  content::PermissionManager* GetPermissionManager() override;
+  content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+      override;
   content::BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
   content::BackgroundSyncController* GetBackgroundSyncController() override;
   content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index eb71fd16..26616f4 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -12,6 +12,7 @@
 #include "base/containers/hash_tables.h"
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "build/build_config.h"
 #include "components/domain_reliability/clear_mode.h"
 #include "content/public/browser/browser_context.h"
@@ -39,6 +40,10 @@
 class WebUI;
 }
 
+namespace network {
+class SharedURLLoaderFactory;
+}
+
 namespace user_prefs {
 class PrefRegistrySyncable;
 }
@@ -200,6 +205,10 @@
   // is only used for a separate cookie store currently.
   virtual net::URLRequestContextGetter* GetRequestContextForExtensions() = 0;
 
+  // Returns the main URLLoaderFactory.
+  virtual scoped_refptr<network::SharedURLLoaderFactory>
+  GetURLLoaderFactory() = 0;
+
   // Return whether 2 profiles are the same. 2 profiles are the same if they
   // represent the same profile. This can happen if there is pointer equality
   // or if one profile is the incognito version of another profile (or vice
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index b07060f..06b2839 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -55,6 +55,7 @@
 #include "chrome/browser/gcm/gcm_profile_service_factory.h"
 #include "chrome/browser/media/media_device_id_salt.h"
 #include "chrome/browser/net/predictor.h"
+#include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/permissions/permission_manager.h"
 #include "chrome/browser/permissions/permission_manager_factory.h"
 #include "chrome/browser/plugins/chrome_plugin_service_filter.h"
@@ -440,7 +441,9 @@
     chromeos::AccountManager* account_manager =
         factory->GetAccountManager(path.value());
     account_manager->Initialize(
-        path, g_browser_process->system_request_context(),
+        path,
+        g_browser_process->system_network_context_manager()
+            ->GetSharedURLLoaderFactory(),
         base::BindRepeating(&chromeos::DelayNetworkCall,
                             base::TimeDelta::FromMilliseconds(
                                 chromeos::kDefaultNetworkRetryDelayMS)));
@@ -1031,6 +1034,12 @@
   return io_data_.GetExtensionsRequestContextGetter().get();
 }
 
+scoped_refptr<network::SharedURLLoaderFactory>
+ProfileImpl::GetURLLoaderFactory() {
+  return GetDefaultStoragePartition(this)
+      ->GetURLLoaderFactoryForBrowserProcess();
+}
+
 content::BrowserPluginGuestManager* ProfileImpl::GetGuestManager() {
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   return guest_view::GuestViewManager::FromBrowserContext(this);
@@ -1067,7 +1076,8 @@
 
 // TODO(mlamouri): we should all these BrowserContext implementation to Profile
 // instead of repeating them inside all Profile implementations.
-content::PermissionManager* ProfileImpl::GetPermissionManager() {
+content::PermissionControllerDelegate*
+ProfileImpl::GetPermissionControllerDelegate() {
   return PermissionManagerFactory::GetForProfile(this);
 }
 
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 9ca3b5cf..1ec337a 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -87,7 +87,8 @@
   content::SSLHostStateDelegate* GetSSLHostStateDelegate() override;
   content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
       override;
-  content::PermissionManager* GetPermissionManager() override;
+  content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+      override;
   content::BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
   content::BackgroundSyncController* GetBackgroundSyncController() override;
   net::URLRequestContextGetter* CreateRequestContext(
@@ -130,6 +131,7 @@
   PrefService* GetReadOnlyOffTheRecordPrefs() override;
   net::URLRequestContextGetter* GetRequestContext() override;
   net::URLRequestContextGetter* GetRequestContextForExtensions() override;
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
   bool IsSameProfile(Profile* profile) override;
   base::Time GetStartTime() const override;
   base::FilePath last_selected_directory() override;
diff --git a/chrome/browser/push_messaging/push_messaging_service_unittest.cc b/chrome/browser/push_messaging/push_messaging_service_unittest.cc
index cc81ece..4aae8cb 100644
--- a/chrome/browser/push_messaging/push_messaging_service_unittest.cc
+++ b/chrome/browser/push_messaging/push_messaging_service_unittest.cc
@@ -72,7 +72,7 @@
     return PushMessagingServiceFactory::GetForProfile(this);
   }
 
-  PermissionManager* GetPermissionManager() override {
+  PermissionManager* GetPermissionControllerDelegate() override {
     return PermissionManagerFactory::GetForProfile(this);
   }
 
diff --git a/chrome/browser/resources/safe_browsing/download_file_types.asciipb b/chrome/browser/resources/safe_browsing/download_file_types.asciipb
index ec8d9de..445cb89d 100644
--- a/chrome/browser/resources/safe_browsing/download_file_types.asciipb
+++ b/chrome/browser/resources/safe_browsing/download_file_types.asciipb
@@ -8,7 +8,7 @@
 ##
 ## Top level settings
 ##
-version_id: 20
+version_id: 21
 sampled_ping_probability: 0.01
 max_archived_binaries_to_report: 10
 default_file_type {
@@ -822,6 +822,17 @@
   uma_value: 302
   ping_setting: FULL_PING
 }
+file_types {
+  # OpenOffice extension, can execute arbitrary code.
+  # https://crbug.com/862163
+  extension: "oxt"
+  uma_value: 317
+  ping_setting: FULL_PING
+  platform_settings {
+    danger_level: ALLOW_ON_USER_GESTURE
+    auto_open_hint: DISALLOW_AUTO_OPEN
+  }
+}
 
 ##
 ## Windows-specific files
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index b12bf90..4097de8 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -354,6 +354,7 @@
         <settings-subpage
             associated-control="[[$$('#sync-status')]]"
             page-title="$i18n{syncPageTitle}"
+            learn-more-url="$i18n{privacyLearnMoreURL}"
             no-search$="[[!isAdvancedSyncSettingsVisible_(syncStatus,
                 unifiedConsentEnabled_)]]">
           <settings-sync-page
diff --git a/chrome/browser/signin/chrome_signin_client.cc b/chrome/browser/signin/chrome_signin_client.cc
index 441613a6..e555fe0 100644
--- a/chrome/browser/signin/chrome_signin_client.cc
+++ b/chrome/browser/signin/chrome_signin_client.cc
@@ -427,8 +427,9 @@
 std::unique_ptr<GaiaAuthFetcher> ChromeSigninClient::CreateGaiaAuthFetcher(
     GaiaAuthConsumer* consumer,
     const std::string& source,
-    net::URLRequestContextGetter* getter) {
-  return std::make_unique<GaiaAuthFetcher>(consumer, source, getter);
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+  return std::make_unique<GaiaAuthFetcher>(consumer, source,
+                                           url_loader_factory);
 }
 
 void ChromeSigninClient::VerifySyncToken() {
diff --git a/chrome/browser/signin/chrome_signin_client.h b/chrome/browser/signin/chrome_signin_client.h
index 2c19d5a..c8c74d1 100644
--- a/chrome/browser/signin/chrome_signin_client.h
+++ b/chrome/browser/signin/chrome_signin_client.h
@@ -64,7 +64,8 @@
   std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
       GaiaAuthConsumer* consumer,
       const std::string& source,
-      net::URLRequestContextGetter* getter) override;
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+      override;
 
   // Returns a string describing the chrome version environment. Version format:
   // <Build Info> <OS> <Version number> (<Last change>)<channel or "-devel">
diff --git a/chrome/browser/signin/dice_response_handler.cc b/chrome/browser/signin/dice_response_handler.cc
index da4fb3c..a77f7faa 100644
--- a/chrome/browser/signin/dice_response_handler.cc
+++ b/chrome/browser/signin/dice_response_handler.cc
@@ -184,8 +184,7 @@
   account_reconcilor_lock_ =
       std::make_unique<AccountReconcilor::Lock>(account_reconcilor);
   gaia_auth_fetcher_ = signin_client->CreateGaiaAuthFetcher(
-      this, GaiaConstants::kChromeSource,
-      signin_client->GetURLRequestContext());
+      this, GaiaConstants::kChromeSource, signin_client->GetURLLoaderFactory());
   VLOG(1) << "Start fetching token for account: " << email;
   gaia_auth_fetcher_->StartAuthCodeForOAuth2TokenExchange(authorization_code_);
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
diff --git a/chrome/browser/signin/dice_response_handler_unittest.cc b/chrome/browser/signin/dice_response_handler_unittest.cc
index 534c0e9..7cee70c 100644
--- a/chrome/browser/signin/dice_response_handler_unittest.cc
+++ b/chrome/browser/signin/dice_response_handler_unittest.cc
@@ -35,6 +35,7 @@
 #include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -60,14 +61,16 @@
   std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
       GaiaAuthConsumer* consumer,
       const std::string& source,
-      net::URLRequestContextGetter* getter) override {
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+      override {
     DCHECK(!consumer_ || (consumer_ == consumer));
     consumer_ = consumer;
 
     // Pass |this| as a dummy consumer to CreateGaiaAuthFetcher().
     // Since DiceTestSigninClient does not overrides any consumer method,
     // everything will be dropped on the floor.
-    return TestSigninClient::CreateGaiaAuthFetcher(this, source, getter);
+    return TestSigninClient::CreateGaiaAuthFetcher(this, source,
+                                                   url_loader_factory);
   }
 
   GaiaAuthConsumer* consumer_;
@@ -119,8 +122,7 @@
         request_context_getter_(
             new net::TestURLRequestContextGetter(task_runner_)),
         signin_client_(&pref_service_),
-        token_service_(std::make_unique<FakeOAuth2TokenServiceDelegate>(
-            request_context_getter_.get())),
+        token_service_(std::make_unique<FakeOAuth2TokenServiceDelegate>()),
         signin_error_controller_(
             SigninErrorController::AccountMode::PRIMARY_ACCOUNT),
         signin_manager_(&signin_client_,
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
index 9c4985cf..9751c77 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.cc
@@ -27,7 +27,6 @@
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher_immediate_error.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace {
@@ -251,7 +250,7 @@
     : token_service_delegate_(token_service_delegate),
       fetcher_(this,
                GaiaConstants::kChromeSource,
-               token_service_delegate_->GetRequestContext()),
+               token_service_delegate_->GetURLLoaderFactory()),
       weak_ptr_factory_(this) {
   RecordRefreshTokenRevocationRequestEvent(
       TokenRevocationRequestProgress::kRequestCreated);
@@ -387,7 +386,6 @@
 OAuth2AccessTokenFetcher*
 MutableProfileOAuth2TokenServiceDelegate::CreateAccessTokenFetcher(
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     OAuth2AccessTokenConsumer* consumer) {
   ValidateAccountId(account_id);
@@ -479,11 +477,6 @@
   return account_ids;
 }
 
-net::URLRequestContextGetter*
-MutableProfileOAuth2TokenServiceDelegate::GetRequestContext() const {
-  return client_->GetURLRequestContext();
-}
-
 scoped_refptr<network::SharedURLLoaderFactory>
 MutableProfileOAuth2TokenServiceDelegate::GetURLLoaderFactory() const {
   return client_->GetURLLoaderFactory();
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h
index a0b69e504..9df7cd20e 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate.h
@@ -43,7 +43,6 @@
   // OAuth2TokenServiceDelegate overrides.
   OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       OAuth2AccessTokenConsumer* consumer) override;
 
@@ -56,7 +55,6 @@
   GoogleServiceAuthError GetAuthError(
       const std::string& account_id) const override;
   std::vector<std::string> GetAccounts() override;
-  net::URLRequestContextGetter* GetRequestContext() const override;
   scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory()
       const override;
 
diff --git a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
index d7f6045..d5776b5 100644
--- a/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
+++ b/chrome/browser/signin/mutable_profile_oauth2_token_service_delegate_unittest.cc
@@ -87,8 +87,7 @@
       public OAuth2TokenService::Observer {
  public:
   MutableProfileOAuth2TokenServiceDelegateTest()
-      : factory_(NULL),
-        signin_error_controller_(
+      : signin_error_controller_(
             SigninErrorController::AccountMode::ANY_ACCOUNT),
         access_token_success_count_(0),
         access_token_failure_count_(0),
@@ -104,9 +103,6 @@
   void SetUp() override {
     OSCryptMocker::SetUp();
 
-    factory_.SetFakeResponse(GaiaUrls::GetInstance()->oauth2_revoke_url(), "",
-                             net::HTTP_OK, net::URLRequestStatus::SUCCESS);
-
     MutableProfileOAuth2TokenServiceDelegate::RegisterProfilePrefs(
         pref_service_.registry());
     pref_service_.registry()->RegisterListPref(
@@ -221,7 +217,6 @@
 
  protected:
   base::MessageLoop message_loop_;
-  net::FakeURLFetcherFactory factory_;
   std::unique_ptr<TestSigninClient> client_;
   std::unique_ptr<MutableProfileOAuth2TokenServiceDelegate>
       oauth2_service_delegate_;
@@ -943,8 +938,7 @@
   scope_list.push_back("scope");
   std::unique_ptr<OAuth2AccessTokenFetcher> fetcher(
       oauth2_service_delegate_->CreateAccessTokenFetcher(
-          kEmail, oauth2_service_delegate_->GetRequestContext(),
-          oauth2_service_delegate_->GetURLLoaderFactory(), this));
+          kEmail, oauth2_service_delegate_->GetURLLoaderFactory(), this));
   fetcher->Start("foo", "bar", scope_list);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(0, access_token_success_count_);
@@ -976,8 +970,7 @@
   scope_list.push_back("scope");
   std::unique_ptr<OAuth2AccessTokenFetcher> fetcher1(
       oauth2_service_delegate_->CreateAccessTokenFetcher(
-          kEmail, oauth2_service_delegate_->GetRequestContext(),
-          oauth2_service_delegate_->GetURLLoaderFactory(), this));
+          kEmail, oauth2_service_delegate_->GetURLLoaderFactory(), this));
   fetcher1->Start("foo", "bar", scope_list);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(0, access_token_success_count_);
@@ -991,8 +984,7 @@
       base::TimeTicks());
   std::unique_ptr<OAuth2AccessTokenFetcher> fetcher2(
       oauth2_service_delegate_->CreateAccessTokenFetcher(
-          kEmail, oauth2_service_delegate_->GetRequestContext(),
-          oauth2_service_delegate_->GetURLLoaderFactory(), this));
+          kEmail, oauth2_service_delegate_->GetURLLoaderFactory(), this));
   fetcher2->Start("foo", "bar", scope_list);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1, access_token_success_count_);
@@ -1024,8 +1016,7 @@
   scope_list.push_back("scope");
   std::unique_ptr<OAuth2AccessTokenFetcher> fetcher1(
       oauth2_service_delegate_->CreateAccessTokenFetcher(
-          kEmail, oauth2_service_delegate_->GetRequestContext(),
-          oauth2_service_delegate_->GetURLLoaderFactory(), this));
+          kEmail, oauth2_service_delegate_->GetURLLoaderFactory(), this));
   fetcher1->Start("foo", "bar", scope_list);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(0, access_token_success_count_);
@@ -1036,8 +1027,7 @@
       network::mojom::ConnectionType::CONNECTION_WIFI);
   std::unique_ptr<OAuth2AccessTokenFetcher> fetcher2(
       oauth2_service_delegate_->CreateAccessTokenFetcher(
-          kEmail, oauth2_service_delegate_->GetRequestContext(),
-          oauth2_service_delegate_->GetURLLoaderFactory(), this));
+          kEmail, oauth2_service_delegate_->GetURLLoaderFactory(), this));
   fetcher2->Start("foo", "bar", scope_list);
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(1, access_token_success_count_);
diff --git a/chrome/browser/signin/oauth2_token_service_delegate_android.cc b/chrome/browser/signin/oauth2_token_service_delegate_android.cc
index 992b64f..fabf6f1 100644
--- a/chrome/browser/signin/oauth2_token_service_delegate_android.cc
+++ b/chrome/browser/signin/oauth2_token_service_delegate_android.cc
@@ -260,7 +260,6 @@
 OAuth2AccessTokenFetcher*
 OAuth2TokenServiceDelegateAndroid::CreateAccessTokenFetcher(
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_factory,
     OAuth2AccessTokenConsumer* consumer) {
   DVLOG(1) << "OAuth2TokenServiceDelegateAndroid::CreateAccessTokenFetcher"
diff --git a/chrome/browser/signin/oauth2_token_service_delegate_android.h b/chrome/browser/signin/oauth2_token_service_delegate_android.h
index 5dd1f08..cb9b817f 100644
--- a/chrome/browser/signin/oauth2_token_service_delegate_android.h
+++ b/chrome/browser/signin/oauth2_token_service_delegate_android.h
@@ -98,7 +98,6 @@
  protected:
   OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_factory,
       OAuth2AccessTokenConsumer* consumer) override;
 
diff --git a/chrome/browser/signin/token_revoker_test_utils.cc b/chrome/browser/signin/token_revoker_test_utils.cc
index b93cf77e..880863c 100644
--- a/chrome/browser/signin/token_revoker_test_utils.cc
+++ b/chrome/browser/signin/token_revoker_test_utils.cc
@@ -2,8 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/signin/token_revoker_test_utils.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/net/system_network_context_manager.h"
 #include "content/public/test/test_utils.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 #include "google_apis/gaia/gaia_constants.h"
@@ -13,8 +14,8 @@
 RefreshTokenRevoker::RefreshTokenRevoker()
     : gaia_fetcher_(this,
                     GaiaConstants::kChromeSource,
-                    g_browser_process->system_request_context()) {
-}
+                    g_browser_process->system_network_context_manager()
+                        ->GetSharedURLLoaderFactory()) {}
 
 RefreshTokenRevoker::~RefreshTokenRevoker() {
 }
diff --git a/chrome/browser/storage/durable_storage_permission_context_unittest.cc b/chrome/browser/storage/durable_storage_permission_context_unittest.cc
index 27380c3..62641cba2 100644
--- a/chrome/browser/storage/durable_storage_permission_context_unittest.cc
+++ b/chrome/browser/storage/durable_storage_permission_context_unittest.cc
@@ -20,7 +20,7 @@
 #include "components/bookmarks/test/bookmark_test_helpers.h"
 #include "components/content_settings/core/browser/cookie_settings.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/browser/sync_file_system/drive_backend/sync_engine.h b/chrome/browser/sync_file_system/drive_backend/sync_engine.h
index 1830a21..0c23742 100644
--- a/chrome/browser/sync_file_system/drive_backend/sync_engine.h
+++ b/chrome/browser/sync_file_system/drive_backend/sync_engine.h
@@ -10,6 +10,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/sync_file_system/drive_backend/callback_tracker.h"
@@ -21,6 +22,7 @@
 #include "components/drive/service/drive_service_interface.h"
 #include "components/signin/core/browser/signin_manager_base.h"
 #include "content/public/browser/network_connection_tracker.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 class OAuth2TokenService;
 
diff --git a/chrome/browser/ui/app_list/test/fake_profile.cc b/chrome/browser/ui/app_list/test/fake_profile.cc
index 1f462d7..1037031 100644
--- a/chrome/browser/ui/app_list/test/fake_profile.cc
+++ b/chrome/browser/ui/app_list/test/fake_profile.cc
@@ -61,7 +61,8 @@
   return nullptr;
 }
 
-content::PermissionManager* FakeProfile::GetPermissionManager() {
+content::PermissionControllerDelegate*
+FakeProfile::GetPermissionControllerDelegate() {
   return nullptr;
 }
 
diff --git a/chrome/browser/ui/app_list/test/fake_profile.h b/chrome/browser/ui/app_list/test/fake_profile.h
index ad723ee..49d647a 100644
--- a/chrome/browser/ui/app_list/test/fake_profile.h
+++ b/chrome/browser/ui/app_list/test/fake_profile.h
@@ -44,7 +44,8 @@
   storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
   content::PushMessagingService* GetPushMessagingService() override;
   content::SSLHostStateDelegate* GetSSLHostStateDelegate() override;
-  content::PermissionManager* GetPermissionManager() override;
+  content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+      override;
   content::BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
   content::BackgroundSyncController* GetBackgroundSyncController() override;
   content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index 9cbfc3f..ec738c3 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -18,6 +18,7 @@
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/tabs/tab_strip.h"
+#include "chrome/common/chrome_features.h"
 #include "chrome/grit/theme_resources.h"
 #include "components/signin/core/browser/profile_management_switches.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -189,7 +190,8 @@
   // The special color we use won't be visible if there's a frame image, but
   // since it's used to determine constrast of other UI elements, the theme
   // color should be used instead.
-  return MD::IsRefreshUi() && ShouldPaintAsActive() && GetFrameImage().isNull();
+  return base::FeatureList::IsEnabled(features::kSingleTabMode) &&
+         MD::IsRefreshUi() && ShouldPaintAsActive() && GetFrameImage().isNull();
 }
 
 bool BrowserNonClientFrameView::ShouldPaintAsSingleTabMode() const {
diff --git a/chrome/browser/ui/views/media_router/media_remoting_dialog_view.cc b/chrome/browser/ui/views/media_router/media_remoting_dialog_view.cc
index f3a7541..678cb9a6 100644
--- a/chrome/browser/ui/views/media_router/media_remoting_dialog_view.cc
+++ b/chrome/browser/ui/views/media_router/media_remoting_dialog_view.cc
@@ -32,7 +32,7 @@
           ->GetPrefs();
   DCHECK(pref_service);
   const PrefService::Preference* pref =
-      pref_service->FindPreference(prefs::kMediaRouterMediaRemotingEnabled);
+      pref_service->FindPreference(::prefs::kMediaRouterMediaRemotingEnabled);
   if (pref && !pref->IsDefaultValue()) {
     std::move(callback).Run(pref->GetValue()->GetBool());
     return;
@@ -157,8 +157,10 @@
 void MediaRemotingDialogView::ReportPermission(bool allowed) {
   DCHECK(remember_choice_checkbox_);
   DCHECK(permission_callback_);
-  if (remember_choice_checkbox_->checked())
-    pref_service_->SetBoolean(prefs::kMediaRouterMediaRemotingEnabled, allowed);
+  if (remember_choice_checkbox_->checked()) {
+    pref_service_->SetBoolean(::prefs::kMediaRouterMediaRemotingEnabled,
+                              allowed);
+  }
   std::move(permission_callback_).Run(allowed);
 }
 
diff --git a/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc
index c2f0900..c78d555 100644
--- a/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc
+++ b/chrome/browser/ui/views/media_router/media_router_ui_browsertest.cc
@@ -282,7 +282,15 @@
   SetAlwaysShowActionPref(false);
 }
 
-IN_PROC_BROWSER_TEST_F(MediaRouterUIBrowserTest, OpenDialogsInMultipleTabs) {
+#if defined(MEMORY_SANITIZER)
+// Flaky crashes. crbug.com/863945
+#define MAYBE_OpenDialogsInMultipleTabs DISABLED_OpenDialogsInMultipleTabs
+#else
+#define MAYBE_OpenDialogsInMultipleTabs OpenDialogsInMultipleTabs
+#endif
+  
+IN_PROC_BROWSER_TEST_F(MediaRouterUIBrowserTest,
+                       MAYBE_OpenDialogsInMultipleTabs) {
   // Start with two tabs.
   chrome::NewTab(browser());
   ASSERT_EQ(2, browser()->tab_strip_model()->count());
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index 79d68e7..611b221 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -45,7 +45,7 @@
 
 // Colors for the control buttons.
 SkColor kBgColor = SK_ColorWHITE;
-SkColor kControlIconColor = gfx::kChromeIconGrey;
+SkColor kControlIconColor = SK_ColorBLACK;
 }  // namespace
 
 // OverlayWindow implementation of NonClientFrameView.
@@ -494,35 +494,6 @@
   // does not trigger this function. http://crbug.com/819673
 }
 
-void OverlayWindowViews::OnKeyEvent(ui::KeyEvent* event) {
-  if (event->type() != ui::ET_KEY_RELEASED)
-    return;
-
-  if (event->key_code() == ui::VKEY_TAB) {
-    // Switch the control that is currently focused. When the window
-    // is focused, |focused_control_button_| resets to CONTROL_PLAY_PAUSE.
-    if (focused_control_button_ == CONTROL_PLAY_PAUSE)
-      focused_control_button_ = CONTROL_CLOSE;
-    else
-      focused_control_button_ = CONTROL_PLAY_PAUSE;
-
-    // The controls may be hidden after the window is already in focus, e.g.
-    // mouse exits the window space. If they are already shown, this is a
-    // no-op.
-    UpdateControlsVisibility(true);
-
-    event->SetHandled();
-  } else if (event->key_code() == ui::VKEY_RETURN) {
-    if (focused_control_button_ == CONTROL_PLAY_PAUSE) {
-      TogglePlayPause();
-    } else /* CONTROL_CLOSE */ {
-      controller_->Close(true /* should_pause_video */);
-    }
-
-    event->SetHandled();
-  }
-}
-
 void OverlayWindowViews::OnMouseEvent(ui::MouseEvent* event) {
   switch (event->type()) {
     // Only show the media controls when the mouse is hovering over the window.
@@ -589,9 +560,6 @@
     should_show_controls_ = true;
   }
 
-  // Reset the first focused control to the play/pause button. This will
-  // always be called before key events can be handled.
-  focused_control_button_ = CONTROL_PLAY_PAUSE;
   views::Widget::OnNativeFocus();
 }
 
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h
index fe49175..abac8a3b 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -19,12 +19,6 @@
 // implemented in views, which will support all desktop platforms.
 class OverlayWindowViews : public content::OverlayWindow, public views::Widget {
  public:
-  // The list of control buttons that appear on the window.
-  enum ControlButton {
-    CONTROL_PLAY_PAUSE,
-    CONTROL_CLOSE,
-  };
-
   explicit OverlayWindowViews(
       content::PictureInPictureWindowController* controller);
   ~OverlayWindowViews() override;
@@ -48,7 +42,6 @@
   gfx::Size GetMinimumSize() const override;
   gfx::Size GetMaximumSize() const override;
   void OnNativeWidgetWorkspaceChanged() override;
-  void OnKeyEvent(ui::KeyEvent* event) override;
   void OnMouseEvent(ui::MouseEvent* event) override;
   void OnGestureEvent(ui::GestureEvent* event) override;
 
@@ -133,10 +126,6 @@
   // ensuring factors such as aspect ratio is maintained.
   gfx::Size natural_size_;
 
-  // The currently focused button on the window. This is used for keeping
-  // track of focus on the window while tabbing.
-  ControlButton focused_control_button_;
-
   // Views to be shown.
   std::unique_ptr<views::View> window_background_view_;
   std::unique_ptr<views::View> video_view_;
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 91746ea5..9d53835 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -1143,7 +1143,9 @@
 
 // static
 int Tab::GetStandardWidth() {
-  constexpr int kLayoutWidth[] = {193, 193, 245, 240, 240};
+  constexpr int kRefreshTabWidth = 240 - kSeparatorThickness;
+  constexpr int kLayoutWidth[] = {193, 193, 245, kRefreshTabWidth,
+                                  kRefreshTabWidth};
   return GetOverlap() + kLayoutWidth[MD::GetMode()];
 }
 
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index dff9f24d..c19d94a 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -540,7 +540,7 @@
   DCHECK(source_tabstrip_);
   old_focused_view_tracker_->SetView(
       source_tabstrip_->GetFocusManager()->GetFocusedView());
-  source_tabstrip_->GetFocusManager()->SetFocusedView(source_tabstrip_);
+  source_tabstrip_->GetFocusManager()->ClearFocus();
   // WARNING: we may have been deleted.
 }
 
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index bb2ab80c..d67c6445 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -2656,7 +2656,7 @@
     TabStrip* attached_tab_strip) {
   ASSERT_TRUE(attached_tab_strip->IsDragSessionActive());
   ASSERT_TRUE(TabDragController::IsActive());
-  EXPECT_TRUE(attached_tab_strip->HasFocus());
+  EXPECT_TRUE(attached_tab_strip->GetWidget()->GetNativeWindow()->HasFocus());
 
   // Put the attached window in overview to simulate the "drop on the new
   // selector item" scenario.
diff --git a/chrome/browser/ui/webui/identity_internals_ui.cc b/chrome/browser/ui/webui/identity_internals_ui.cc
index ecd1b1f..5e038250 100644
--- a/chrome/browser/ui/webui/identity_internals_ui.cc
+++ b/chrome/browser/ui/webui/identity_internals_ui.cc
@@ -276,8 +276,9 @@
     const std::string& access_token,
     Profile* profile,
     IdentityInternalsUIMessageHandler* consumer)
-    : fetcher_(this, GaiaConstants::kChromeSource,
-               profile->GetRequestContext()),
+    : fetcher_(this,
+               GaiaConstants::kChromeSource,
+               profile->GetURLLoaderFactory()),
       extension_id_(extension_id),
       access_token_(access_token),
       consumer_(consumer) {
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index c867dfa9..50d1344 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -1974,6 +1974,7 @@
                             arraysize(conditional_localized_strings));
   }
 
+  html_source->AddString("privacyLearnMoreURL", chrome::kPrivacyLearnMoreURL);
   html_source->AddString(
       "improveBrowsingExperience",
       l10n_util::GetStringFUTF16(
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
index ab54d09..1f6891a 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_chromeos.cc
@@ -9,6 +9,7 @@
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/account_tracker_service_factory.h"
 #include "chrome/browser/ui/webui/signin/inline_login_handler.h"
@@ -17,7 +18,7 @@
 #include "components/signin/core/browser/account_tracker_service.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
-#include "net/url_request/url_request_context_getter.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace chromeos {
 namespace {
@@ -30,18 +31,19 @@
 // itself after its work is complete.
 class SigninHelper : public GaiaAuthConsumer {
  public:
-  SigninHelper(Profile* profile,
-               chromeos::AccountManager* account_manager,
-               net::URLRequestContextGetter* request_context,
-               const std::string& gaia_id,
-               const std::string& email,
-               const std::string& auth_code)
+  SigninHelper(
+      Profile* profile,
+      chromeos::AccountManager* account_manager,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      const std::string& gaia_id,
+      const std::string& email,
+      const std::string& auth_code)
       : profile_(profile),
         account_manager_(account_manager),
         email_(email),
         gaia_auth_fetcher_(this,
                            GaiaConstants::kChromeSource,
-                           request_context) {
+                           url_loader_factory) {
     account_key_ = chromeos::AccountManager::AccountKey{
         gaia_id, chromeos::account_manager::AccountType::ACCOUNT_TYPE_GAIA};
 
@@ -120,6 +122,10 @@
   const std::string& email = auth_data->FindKey("email")->GetString();
   CHECK(!email.empty());
 
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory =
+      g_browser_process->system_network_context_manager()
+          ->GetSharedURLLoaderFactory();
+
   // TODO(sinhak): Do not depend on Profile unnecessarily.
   Profile* profile = Profile::FromWebUI(web_ui());
 
@@ -132,8 +138,7 @@
           ->GetAccountManager(profile->GetPath().value());
 
   // SigninHelper deletes itself after its work is done.
-  new SigninHelper(profile, account_manager,
-                   account_manager->GetUrlRequestContext(), gaia_id, email,
+  new SigninHelper(profile, account_manager, url_loader_factory, gaia_id, email,
                    auth_code);
 }
 
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
index 689f05ec..b9b1305bb 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -159,7 +159,7 @@
 
 InlineSigninHelper::InlineSigninHelper(
     base::WeakPtr<InlineLoginHandlerImpl> handler,
-    net::URLRequestContextGetter* getter,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     Profile* profile,
     Profile::CreateStatus create_status,
     const GURL& current_url,
@@ -172,7 +172,9 @@
     bool choose_what_to_sync,
     bool confirm_untrusted_signin,
     bool is_force_sign_in_with_usermanager)
-    : gaia_auth_fetcher_(this, GaiaConstants::kChromeSource, getter),
+    : gaia_auth_fetcher_(this,
+                         GaiaConstants::kChromeSource,
+                         url_loader_factory),
       handler_(handler),
       profile_(profile),
       create_status_(create_status),
@@ -724,8 +726,9 @@
 
   // InlineSigninHelper will delete itself.
   new InlineSigninHelper(
-      handler_weak_ptr, params.partition->GetURLRequestContext(), profile,
-      status, params.url, params.email, params.gaia_id, params.password,
+      handler_weak_ptr,
+      params.partition->GetURLLoaderFactoryForBrowserProcess(), profile, status,
+      params.url, params.email, params.gaia_id, params.password,
       params.session_index, params.auth_code, signin_scoped_device_id,
       params.choose_what_to_sync, params.confirm_untrusted_signin,
       params.is_force_sign_in_with_usermanager);
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
index 5ee5ba8..fb2d86f 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
@@ -11,6 +11,7 @@
 #include "base/files/file_path.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/sync/one_click_signin_sync_starter.h"
 #include "chrome/browser/ui/webui/signin/inline_login_handler.h"
@@ -18,6 +19,10 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
 
+namespace network {
+class SharedURLLoaderFactory;
+}
+
 // Implementation for the inline login WebUI handler on desktop Chrome. Once
 // CrOS migrates to the same webview approach as desktop Chrome, much of the
 // code in this class should move to its base class |InlineLoginHandler|.
@@ -122,22 +127,26 @@
 // InlineLoginHandlerImpl is destryed once the UI is closed.
 class InlineSigninHelper : public GaiaAuthConsumer {
  public:
-  InlineSigninHelper(base::WeakPtr<InlineLoginHandlerImpl> handler,
-                     net::URLRequestContextGetter* getter,
-                     Profile* profile,
-                     Profile::CreateStatus create_status,
-                     const GURL& current_url,
-                     const std::string& email,
-                     const std::string& gaia_id,
-                     const std::string& password,
-                     const std::string& session_index,
-                     const std::string& auth_code,
-                     const std::string& signin_scoped_device_id,
-                     bool choose_what_to_sync,
-                     bool confirm_untrusted_signin,
-                     bool is_force_sign_in_with_usermanager);
+  InlineSigninHelper(
+      base::WeakPtr<InlineLoginHandlerImpl> handler,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      Profile* profile,
+      Profile::CreateStatus create_status,
+      const GURL& current_url,
+      const std::string& email,
+      const std::string& gaia_id,
+      const std::string& password,
+      const std::string& session_index,
+      const std::string& auth_code,
+      const std::string& signin_scoped_device_id,
+      bool choose_what_to_sync,
+      bool confirm_untrusted_signin,
+      bool is_force_sign_in_with_usermanager);
   ~InlineSigninHelper() override;
 
+ protected:
+  GaiaAuthFetcher* GetGaiaAuthFetcherForTest() { return &gaia_auth_fetcher_; }
+
  private:
   // Handles cross account sign in error. If the supplied |email| does not match
   // the last signed in email of the current profile, then Chrome will show a
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc b/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc
index 0a14718..6e672bea 100644
--- a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc
@@ -58,7 +58,9 @@
 #include "google_apis/gaia/gaia_switches.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "net/base/url_util.h"
+#include "net/dns/mock_host_resolver.h"
 #include "net/http/http_response_headers.h"
+#include "net/test/embedded_test_server/controllable_http_response.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
@@ -153,7 +155,7 @@
  public:
   MockInlineSigninHelper(
       base::WeakPtr<InlineLoginHandlerImpl> handler,
-      net::URLRequestContextGetter* getter,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       Profile* profile,
       const GURL& current_url,
       const std::string& email,
@@ -175,13 +177,15 @@
                     OneClickSigninSyncStarter::StartSyncMode,
                     OneClickSigninSyncStarter::ConfirmationRequired));
 
+  GaiaAuthFetcher* GetGaiaAuthFetcher() { return GetGaiaAuthFetcherForTest(); }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(MockInlineSigninHelper);
 };
 
 MockInlineSigninHelper::MockInlineSigninHelper(
     base::WeakPtr<InlineLoginHandlerImpl> handler,
-    net::URLRequestContextGetter* getter,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     Profile* profile,
     const GURL& current_url,
     const std::string& email,
@@ -193,7 +197,7 @@
     bool choose_what_to_sync,
     bool confirm_untrusted_signin)
     : InlineSigninHelper(handler,
-                         getter,
+                         url_loader_factory,
                          profile,
                          Profile::CreateStatus::CREATE_STATUS_INITIALIZED,
                          current_url,
@@ -213,7 +217,7 @@
  public:
   MockSyncStarterInlineSigninHelper(
       base::WeakPtr<InlineLoginHandlerImpl> handler,
-      net::URLRequestContextGetter* getter,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       Profile* profile,
       const GURL& current_url,
       const std::string& email,
@@ -240,7 +244,7 @@
 
 MockSyncStarterInlineSigninHelper::MockSyncStarterInlineSigninHelper(
     base::WeakPtr<InlineLoginHandlerImpl> handler,
-    net::URLRequestContextGetter* getter,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     Profile* profile,
     const GURL& current_url,
     const std::string& email,
@@ -253,7 +257,7 @@
     bool confirm_untrusted_signin,
     bool is_force_sign_in_with_usermanager)
     : InlineSigninHelper(handler,
-                         getter,
+                         url_loader_factory,
                          profile,
                          Profile::CreateStatus::CREATE_STATUS_INITIALIZED,
                          current_url,
@@ -454,7 +458,7 @@
 
 class InlineLoginHelperBrowserTest : public InProcessBrowserTest {
  public:
-  InlineLoginHelperBrowserTest() {}
+  InlineLoginHelperBrowserTest() = default;
 
   void SetUpInProcessBrowserTestFixture() override {
     will_create_browser_context_services_subscription_ =
@@ -475,7 +479,42 @@
         context, &BuildFakeProfileOAuth2TokenService);
   }
 
+  void SetUp() override {
+    // Don't spin up the IO thread yet since no threads are allowed while
+    // spawning sandbox host process. See crbug.com/322732.
+    ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
+
+    InProcessBrowserTest::SetUp();
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    const GURL& base_url = embedded_test_server()->base_url();
+    command_line->AppendSwitchASCII(::switches::kGaiaUrl, base_url.spec());
+    command_line->AppendSwitchASCII(::switches::kLsoUrl, base_url.spec());
+    command_line->AppendSwitchASCII(::switches::kGoogleApisUrl,
+                                    base_url.spec());
+  }
+
   void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+
+    host_resolver()->AddRule("*", "127.0.0.1");
+
+    deprecated_client_login_to_oauth2_response_ =
+        std::make_unique<net::test_server::ControllableHttpResponse>(
+            embedded_test_server(),
+            GaiaUrls::GetInstance()
+                ->deprecated_client_login_to_oauth2_url()
+                .path(),
+            /*relative_url_is_prefix=*/true);
+    oauth2_token_exchange_success_ =
+        std::make_unique<net::test_server::ControllableHttpResponse>(
+            embedded_test_server(),
+            GaiaUrls::GetInstance()->oauth2_token_url().path(),
+            /*relative_url_is_prefix=*/true);
+
+    embedded_test_server()->StartAcceptingConnections();
+
     // Grab references to the fake signin manager and token service.
     Profile* profile = browser()->profile();
     signin_manager_ = static_cast<FakeSigninManagerForTesting*>(
@@ -487,27 +526,20 @@
     ASSERT_TRUE(token_service_);
   }
 
-    void SimulateStartCookieForOAuthLoginTokenExchangeSuccess(
+  void SimulateStartCookieForOAuthLoginTokenExchangeSuccess(
       const std::string& cookie_string) {
-    net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
-    ASSERT_TRUE(fetcher);
-    scoped_refptr<net::HttpResponseHeaders> reponse_headers =
-        new net::HttpResponseHeaders("");
-    reponse_headers->AddCookie(cookie_string);
-    fetcher->set_status(net::URLRequestStatus());
-    fetcher->set_response_code(net::HTTP_OK);
-    fetcher->set_response_headers(reponse_headers);
-    fetcher->delegate()->OnURLFetchComplete(fetcher);
+    deprecated_client_login_to_oauth2_response_->WaitForRequest();
+    deprecated_client_login_to_oauth2_response_->Send(
+        net::HTTP_OK, "text/html; charset=utf-8", "", {cookie_string});
+    deprecated_client_login_to_oauth2_response_->Done();
   }
 
   void SimulateStartAuthCodeForOAuth2TokenExchangeSuccess(
       const std::string& json_response) {
-    net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
-    ASSERT_TRUE(fetcher);
-    fetcher->set_status(net::URLRequestStatus());
-    fetcher->set_response_code(net::HTTP_OK);
-    fetcher->SetResponseString(json_response);
-    fetcher->delegate()->OnURLFetchComplete(fetcher);
+    oauth2_token_exchange_success_->WaitForRequest();
+    oauth2_token_exchange_success_->Send(
+        net::HTTP_OK, "application/json; charset=utf-8", json_response);
+    oauth2_token_exchange_success_->Done();
   }
 
   void SimulateOnClientOAuthSuccess(GaiaAuthConsumer* consumer,
@@ -519,9 +551,19 @@
 
   FakeSigninManagerForTesting* signin_manager() { return signin_manager_; }
   FakeProfileOAuth2TokenService* token_service() { return token_service_; }
+  scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory() {
+    return content::BrowserContext::GetDefaultStoragePartition(
+               browser()->profile())
+        ->GetURLLoaderFactoryForBrowserProcess();
+  }
+
+ protected:
+  std::unique_ptr<net::test_server::ControllableHttpResponse>
+      deprecated_client_login_to_oauth2_response_;
+  std::unique_ptr<net::test_server::ControllableHttpResponse>
+      oauth2_token_exchange_success_;
 
  private:
-  net::TestURLFetcherFactory url_fetcher_factory_;
   FakeSigninManagerForTesting* signin_manager_;
   FakeProfileOAuth2TokenService* token_service_;
   std::unique_ptr<
@@ -531,52 +573,57 @@
   DISALLOW_COPY_AND_ASSIGN(InlineLoginHelperBrowserTest);
 };
 
-// Test signin helper calls correct fetcher methods when called with a
-// session index.
+// Test signin helper calls correct fetcher methods when called with a session
+// index.
 IN_PROC_BROWSER_TEST_F(InlineLoginHelperBrowserTest, WithSessionIndex) {
   base::WeakPtr<InlineLoginHandlerImpl> handler;
-  MockInlineSigninHelper helper(handler,
-                                browser()->profile()->GetRequestContext(),
-                                browser()->profile(),
-                                GURL(),
-                                "foo@gmail.com",
-                                "gaiaid-12345",
-                                "password",
-                                "0",  // session index from above
+  MockInlineSigninHelper helper(handler, test_shared_loader_factory(),
+                                browser()->profile(), GURL(), "foo@gmail.com",
+                                "gaiaid-12345", "password",
+                                "0",            // session index from above
                                 std::string(),  // auth code
                                 std::string(),
-                                false,  // choose what to sync
+                                false,   // choose what to sync
                                 false);  // confirm untrusted signin
-  EXPECT_CALL(helper, OnClientOAuthSuccess(_));
+  base::RunLoop run_loop;
+  EXPECT_CALL(helper, OnClientOAuthSuccess(_))
+      .WillOnce(testing::InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); }));
 
   SimulateStartCookieForOAuthLoginTokenExchangeSuccess(
-      "secure; httponly; oauth_code=code");
+      "oauth_code=code; secure; httponly");
+
   SimulateStartAuthCodeForOAuth2TokenExchangeSuccess(
-      "{\"access_token\": \"access_token\", \"expires_in\": 1234567890,"
-      " \"refresh_token\": \"refresh_token\"}");
+      R"({
+           "access_token": "access_token",
+           "expires_in": 1234567890,
+           "refresh_token": "refresh_token"
+         })");
+  run_loop.Run();
 }
 
 // Test signin helper calls correct fetcher methods when called with an
 // auth code.
 IN_PROC_BROWSER_TEST_F(InlineLoginHelperBrowserTest, WithAuthCode) {
   base::WeakPtr<InlineLoginHandlerImpl> handler;
-  MockInlineSigninHelper helper(handler,
-                                browser()->profile()->GetRequestContext(),
-                                browser()->profile(),
-                                GURL(),
-                                "foo@gmail.com",
-                                "gaiaid-12345",
-                                "password",
-                                "",  // session index
+  MockInlineSigninHelper helper(handler, test_shared_loader_factory(),
+                                browser()->profile(), GURL(), "foo@gmail.com",
+                                "gaiaid-12345", "password",
+                                "",           // session index
                                 "auth_code",  // auth code
                                 std::string(),
-                                false,  // choose what to sync
+                                false,   // choose what to sync
                                 false);  // confirm untrusted signin
-  EXPECT_CALL(helper, OnClientOAuthSuccess(_));
+  base::RunLoop run_loop;
+  EXPECT_CALL(helper, OnClientOAuthSuccess(_))
+      .WillOnce(testing::InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); }));
 
   SimulateStartAuthCodeForOAuth2TokenExchangeSuccess(
-      "{\"access_token\": \"access_token\", \"expires_in\": 1234567890,"
-      " \"refresh_token\": \"refresh_token\"}");
+      R"({
+           "access_token": "access_token",
+           "expires_in": 1234567890,
+           "refresh_token": "refresh_token"
+         })");
+  run_loop.Run();
 }
 
 // Test signin helper creates sync starter with correct confirmation when
@@ -592,7 +639,10 @@
   // do need the RunUntilIdle() at the end.
   MockSyncStarterInlineSigninHelper* helper =
       new MockSyncStarterInlineSigninHelper(
-          handler, browser()->profile()->GetRequestContext(),
+          handler,
+          content::BrowserContext::GetDefaultStoragePartition(
+              browser()->profile())
+              ->GetURLLoaderFactoryForBrowserProcess(),
           browser()->profile(), url, "foo@gmail.com", "gaiaid-12345",
           "password",
           "",           // session index
@@ -637,9 +687,8 @@
   // do need the RunUntilIdle() at the end.
   MockSyncStarterInlineSigninHelper* helper =
       new MockSyncStarterInlineSigninHelper(
-          handler, browser()->profile()->GetRequestContext(),
-          browser()->profile(), url, "foo@gmail.com", "gaiaid-12345",
-          "password",
+          handler, test_shared_loader_factory(), browser()->profile(), url,
+          "foo@gmail.com", "gaiaid-12345", "password",
           "",           // session index
           "auth_code",  // auth code
           std::string(),
@@ -669,9 +718,8 @@
   // do need the RunUntilIdle() at the end.
   MockSyncStarterInlineSigninHelper* helper =
       new MockSyncStarterInlineSigninHelper(
-          handler, browser()->profile()->GetRequestContext(),
-          browser()->profile(), url, "foo@gmail.com", "gaiaid-12345",
-          "password",
+          handler, test_shared_loader_factory(), browser()->profile(), url,
+          "foo@gmail.com", "gaiaid-12345", "password",
           "",           // session index
           "auth_code",  // auth code
           std::string(),
@@ -702,9 +750,8 @@
   // do need the RunUntilIdle() at the end.
   MockSyncStarterInlineSigninHelper* helper =
       new MockSyncStarterInlineSigninHelper(
-          handler, browser()->profile()->GetRequestContext(),
-          browser()->profile(), url, "foo@gmail.com", "gaiaid-12345",
-          "password",
+          handler, test_shared_loader_factory(), browser()->profile(), url,
+          "foo@gmail.com", "gaiaid-12345", "password",
           "",           // session index
           "auth_code",  // auth code
           std::string(),
@@ -733,7 +780,7 @@
   // possible values of access_point=, reason=.
   GURL url("chrome://chrome-signin/?access_point=3&reason=2");
   base::WeakPtr<InlineLoginHandlerImpl> handler;
-  InlineSigninHelper helper(handler, browser()->profile()->GetRequestContext(),
+  InlineSigninHelper helper(handler, test_shared_loader_factory(),
                             browser()->profile(),
                             Profile::CreateStatus::CREATE_STATUS_INITIALIZED,
                             url, "foo@gmail.com", "gaiaid-12345", "password",
@@ -758,7 +805,7 @@
   // possible values of access_point=, reason=.
   GURL url("chrome://chrome-signin/?access_point=10&reason=1");
   base::WeakPtr<InlineLoginHandlerImpl> handler;
-  InlineSigninHelper helper(handler, browser()->profile()->GetRequestContext(),
+  InlineSigninHelper helper(handler, test_shared_loader_factory(),
                             browser()->profile(),
                             Profile::CreateStatus::CREATE_STATUS_INITIALIZED,
                             url, "foo@gmail.com", "gaiaid-12345", "password",
@@ -782,9 +829,9 @@
   // do need the RunUntilIdle() at the end.
   MockSyncStarterInlineSigninHelper* helper =
       new MockSyncStarterInlineSigninHelper(
-          handler, browser()->profile()->GetRequestContext(),
-          browser()->profile(), url, "foo@gmail.com", "gaiaid-12345",
-          "password", "", "auth_code", std::string(), false, false, true);
+          handler, test_shared_loader_factory(), browser()->profile(), url,
+          "foo@gmail.com", "gaiaid-12345", "password", "", "auth_code",
+          std::string(), false, false, true);
   EXPECT_CALL(
       *helper,
       CreateSyncStarter(_, _, "refresh_token",
diff --git a/chrome/browser/vr/BUILD.gn b/chrome/browser/vr/BUILD.gn
index 8f8a592..2994d9a9 100644
--- a/chrome/browser/vr/BUILD.gn
+++ b/chrome/browser/vr/BUILD.gn
@@ -314,7 +314,6 @@
     "gesture_detector_unittest.cc",
     "model/text_input_info_unittest.cc",
     "platform_ui_input_delegate_unittest.cc",
-    "pose_util_unittest.cc",
     "service/vr_device_manager_unittest.cc",
     "sliding_average_unittest.cc",
     "speech_recognizer_unittest.cc",
diff --git a/chrome/browser/vr/model/controller_model.cc b/chrome/browser/vr/model/controller_model.cc
index 407e8a7..1a443b6 100644
--- a/chrome/browser/vr/model/controller_model.cc
+++ b/chrome/browser/vr/model/controller_model.cc
@@ -16,7 +16,6 @@
       app_button_state(other.app_button_state),
       home_button_state(other.home_button_state),
       opacity(other.opacity),
-      quiescent(other.quiescent),
       resting_in_viewport(other.resting_in_viewport),
       handedness(other.handedness),
       battery_level(other.battery_level) {}
diff --git a/chrome/browser/vr/model/controller_model.h b/chrome/browser/vr/model/controller_model.h
index 7198b00c..4ab3f82b 100644
--- a/chrome/browser/vr/model/controller_model.h
+++ b/chrome/browser/vr/model/controller_model.h
@@ -32,7 +32,6 @@
   bool touching_touchpad = false;
   gfx::PointF touchpad_touch_position;
   float opacity = 1.0f;
-  bool quiescent = false;
   bool resting_in_viewport = false;
   bool recentered = false;
   bool app_button_long_pressed = false;
diff --git a/chrome/browser/vr/pose_util.cc b/chrome/browser/vr/pose_util.cc
index 1d395489..98fca87 100644
--- a/chrome/browser/vr/pose_util.cc
+++ b/chrome/browser/vr/pose_util.cc
@@ -4,8 +4,6 @@
 
 #include "chrome/browser/vr/pose_util.h"
 
-#include <cmath>
-
 #include "ui/gfx/transform.h"
 
 namespace vr {
@@ -25,22 +23,4 @@
                         head_pose.matrix().get(1, 2));
 }
 
-bool HeadMoveExceedsThreshold(const gfx::Transform& old_pose,
-                              const gfx::Transform& new_pose,
-                              float angular_threshold_degrees) {
-  gfx::Vector3dF old_forward_vector = GetForwardVector(old_pose);
-  gfx::Vector3dF new_forward_vector = GetForwardVector(new_pose);
-  float angle =
-      gfx::AngleBetweenVectorsInDegrees(new_forward_vector, old_forward_vector);
-
-  if (std::abs(angle) > angular_threshold_degrees)
-    return true;
-
-  gfx::Vector3dF old_up_vector = GetUpVector(old_pose);
-  gfx::Vector3dF new_up_vector = GetUpVector(new_pose);
-  angle = gfx::AngleBetweenVectorsInDegrees(new_up_vector, old_up_vector);
-
-  return std::abs(angle) > angular_threshold_degrees;
-}
-
 }  // namespace vr
diff --git a/chrome/browser/vr/pose_util.h b/chrome/browser/vr/pose_util.h
index d8d7653b..0aaad867 100644
--- a/chrome/browser/vr/pose_util.h
+++ b/chrome/browser/vr/pose_util.h
@@ -20,13 +20,6 @@
 // Returns a vector heading upward from the viewer's head.
 gfx::Vector3dF GetUpVector(const gfx::Transform& head_pose);
 
-// Returns true if either the change is gaze direction (via GetForwardVector
-// above) exceeds the angular threshold, or if the change in up vector exceeds
-// this same threshold.
-VR_EXPORT bool HeadMoveExceedsThreshold(const gfx::Transform& old_pose,
-                                        const gfx::Transform& new_pose,
-                                        float angular_threshold_degrees);
-
 }  // namespace vr
 
 #endif  //  CHROME_BROWSER_VR_POSE_UTIL_H_
diff --git a/chrome/browser/vr/pose_util_unittest.cc b/chrome/browser/vr/pose_util_unittest.cc
deleted file mode 100644
index 3710c069..0000000
--- a/chrome/browser/vr/pose_util_unittest.cc
+++ /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.
-
-#include "chrome/browser/vr/pose_util.h"
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/transform.h"
-
-namespace vr {
-
-TEST(PoseUtil, HeadMoveDetection) {
-  const float angular_threshold_degrees = 2.5f;
-
-  gfx::Transform neutral;
-  gfx::Transform within_gaze_threshold;
-  within_gaze_threshold.RotateAboutYAxis(1.0f);
-
-  EXPECT_FALSE(HeadMoveExceedsThreshold(neutral, within_gaze_threshold,
-                                        angular_threshold_degrees));
-
-  gfx::Transform beyond_gaze_threshold;
-  within_gaze_threshold.RotateAboutYAxis(3.0f);
-
-  EXPECT_TRUE(HeadMoveExceedsThreshold(neutral, within_gaze_threshold,
-                                       angular_threshold_degrees));
-
-  gfx::Transform within_tilt_threshold;
-  within_tilt_threshold.RotateAboutZAxis(1.0f);
-
-  EXPECT_FALSE(HeadMoveExceedsThreshold(neutral, within_tilt_threshold,
-                                        angular_threshold_degrees));
-
-  gfx::Transform beyond_tilt_threshold;
-  within_tilt_threshold.RotateAboutZAxis(3.0f);
-
-  EXPECT_TRUE(HeadMoveExceedsThreshold(neutral, within_tilt_threshold,
-                                       angular_threshold_degrees));
-}
-
-}  // namespace vr
diff --git a/chrome/browser/vr/service/browser_xr_device.cc b/chrome/browser/vr/service/browser_xr_device.cc
index 40dfbdb9..0c95f94 100644
--- a/chrome/browser/vr/service/browser_xr_device.cc
+++ b/chrome/browser/vr/service/browser_xr_device.cc
@@ -43,9 +43,9 @@
   }
 }
 
-void BrowserXrDevice::StopExclusiveSession() {
-  if (exclusive_session_controller_) {
-    exclusive_session_controller_ = nullptr;
+void BrowserXrDevice::StopImmersiveSession() {
+  if (immersive_session_controller_) {
+    immersive_session_controller_ = nullptr;
     presenting_display_host_ = nullptr;
   }
 }
@@ -94,7 +94,7 @@
 
 void BrowserXrDevice::ExitPresent(VRDisplayHost* display) {
   if (display == presenting_display_host_) {
-    StopExclusiveSession();
+    StopImmersiveSession();
   }
 }
 
@@ -113,11 +113,11 @@
     device::mojom::XRDeviceRuntimeSessionOptionsPtr options,
     device::mojom::VRDisplayHost::RequestSessionCallback callback,
     device::mojom::XRPresentationConnectionPtr connection,
-    device::mojom::XRSessionControllerPtr exclusive_session_controller) {
+    device::mojom::XRSessionControllerPtr immersive_session_controller) {
   if (connection && (displays_.find(display) != displays_.end())) {
-    if (options->exclusive) {
+    if (options->immersive) {
       presenting_display_host_ = display;
-      exclusive_session_controller_ = std::move(exclusive_session_controller);
+      immersive_session_controller_ = std::move(immersive_session_controller);
     }
     std::move(callback).Run(std::move(connection));
   } else {
@@ -125,8 +125,8 @@
     if (connection) {
       // The device has been removed, but we still got a connection, so make
       // sure to clean up this weird state.
-      exclusive_session_controller_ = std::move(exclusive_session_controller);
-      StopExclusiveSession();
+      immersive_session_controller_ = std::move(immersive_session_controller);
+      StopImmersiveSession();
     }
   }
 }
diff --git a/chrome/browser/vr/service/browser_xr_device.h b/chrome/browser/vr/service/browser_xr_device.h
index 03ada27..7b8aacb 100644
--- a/chrome/browser/vr/service/browser_xr_device.h
+++ b/chrome/browser/vr/service/browser_xr_device.h
@@ -55,17 +55,17 @@
 
   void OnInitialDevicePropertiesReceived(
       device::mojom::VRDisplayInfoPtr display_info);
-  void StopExclusiveSession();
+  void StopImmersiveSession();
   void OnListeningForActivate(bool is_listening);
   void OnRequestSessionResult(
       VRDisplayHost* display,
       device::mojom::XRDeviceRuntimeSessionOptionsPtr options,
       device::mojom::VRDisplayHost::RequestSessionCallback callback,
       device::mojom::XRPresentationConnectionPtr connection,
-      device::mojom::XRSessionControllerPtr exclusive_session_controller);
+      device::mojom::XRSessionControllerPtr immersive_session_controller);
 
   device::mojom::XRRuntimePtr device_;
-  device::mojom::XRSessionControllerPtr exclusive_session_controller_;
+  device::mojom::XRSessionControllerPtr immersive_session_controller_;
 
   std::set<VRDisplayHost*> displays_;
   device::mojom::VRDisplayInfoPtr display_info_;
diff --git a/chrome/browser/vr/service/vr_display_host.cc b/chrome/browser/vr/service/vr_display_host.cc
index ed9787b..7aa883f 100644
--- a/chrome/browser/vr/service/vr_display_host.cc
+++ b/chrome/browser/vr/service/vr_display_host.cc
@@ -41,7 +41,7 @@
     device::mojom::XRSessionOptions* options) {
   device::mojom::XRDeviceRuntimeSessionOptionsPtr runtime_options =
       device::mojom::XRDeviceRuntimeSessionOptions::New();
-  runtime_options->exclusive = options->exclusive;
+  runtime_options->immersive = options->immersive;
   runtime_options->has_user_activation = options->has_user_activation;
   runtime_options->use_legacy_webvr_render_path =
       options->use_legacy_webvr_render_path;
@@ -119,9 +119,9 @@
   runtime_options->render_frame_id =
       render_frame_host_ ? render_frame_host_->GetRoutingID() : -1;
 
-  // AR currently uses a non-exclusive session but we still want to call request
+  // AR currently uses a non-immersive session but we still want to call request
   // session on it.
-  if (runtime_options->exclusive ||
+  if (runtime_options->immersive ||
       base::FeatureList::IsEnabled(features::kWebXrHitTest)) {
     if (!triggered_by_displayactive) {
       ReportRequestPresent();
@@ -140,7 +140,7 @@
     connection->provider = provider.PassInterface();
     connection->transport_options =
         device::mojom::VRDisplayFrameTransportOptions::New();
-    // Non exclusive session setup happens on device initialization, so we don't
+    // Non immersive session setup happens on device initialization, so we don't
     // need to do anything further.
     std::move(callback).Run(std::move(connection));
   }
@@ -153,7 +153,7 @@
 
 bool VRDisplayHost::InternalSupportsSession(
     device::mojom::XRSessionOptions* options) {
-  if (options->exclusive) {
+  if (options->immersive) {
     return browser_device_->GetVRDisplayInfo()->capabilities->canPresent;
   }
 
diff --git a/chrome/browser/vr/test/vr_xr_browser_test.h b/chrome/browser/vr/test/vr_xr_browser_test.h
index 67bae166..b128bb50 100644
--- a/chrome/browser/vr/test/vr_xr_browser_test.h
+++ b/chrome/browser/vr/test/vr_xr_browser_test.h
@@ -114,7 +114,7 @@
       const std::string& js_expression,
       content::WebContents* web_contents);
 
-  // Enters either WebVR presentation or WebXR presentation (exclusive session).
+  // Enters either WebVR presentation or WebXR presentation (immersive session).
   virtual void EnterPresentation(content::WebContents* web_contents) = 0;
 
   // Enters either WebVR presentation or WebXR presentation and waits for the
@@ -125,7 +125,7 @@
   // it is not able to.
   virtual void EnterPresentationOrFail(content::WebContents* web_contents) = 0;
 
-  // Exits either WebVR presentation or WebXR presentation (exclusive session).
+  // Exits either WebVR presentation or WebXR presentation (immersive session).
   virtual void ExitPresentation(content::WebContents* web_contents) = 0;
 
   // Exits either WebVR presentation or WebXR presentation and waits for the
diff --git a/chrome/browser/vr/test/xr_browser_test.cc b/chrome/browser/vr/test/xr_browser_test.cc
index 2c17fda1..fbd0aff60 100644
--- a/chrome/browser/vr/test/xr_browser_test.cc
+++ b/chrome/browser/vr/test/xr_browser_test.cc
@@ -25,21 +25,21 @@
     content::WebContents* web_contents) {
   EnterPresentation(web_contents);
   EXPECT_TRUE(PollJavaScriptBoolean(
-      "sessionInfos[sessionTypes.EXCLUSIVE].currentSession != null",
+      "sessionInfos[sessionTypes.IMMERSIVE].currentSession != null",
       kPollTimeoutLong, web_contents));
 }
 
 void XrBrowserTestBase::ExitPresentation(content::WebContents* web_contents) {
   EXPECT_TRUE(content::ExecuteScript(
       web_contents,
-      "sessionInfos[sessionTypes.EXCLUSIVE].currentSession.end()"));
+      "sessionInfos[sessionTypes.IMMERSIVE].currentSession.end()"));
 }
 
 void XrBrowserTestBase::ExitPresentationOrFail(
     content::WebContents* web_contents) {
   ExitPresentation(web_contents);
   EXPECT_TRUE(PollJavaScriptBoolean(
-      "sessionInfos[sessionTypes.EXCLUSIVE].currentSession == null",
+      "sessionInfos[sessionTypes.IMMERSIVE].currentSession == null",
       kPollTimeoutLong, web_contents));
 }
 
diff --git a/chrome/browser/vr/ui.cc b/chrome/browser/vr/ui.cc
index 8d0c110..4f7c6896 100644
--- a/chrome/browser/vr/ui.cc
+++ b/chrome/browser/vr/ui.cc
@@ -411,7 +411,6 @@
                              const ReticleModel& reticle_model) {
   model_->controller = controller_model;
   model_->reticle = reticle_model;
-  model_->controller.quiescent = input_manager_->controller_quiescent();
   model_->controller.resting_in_viewport =
       input_manager_->controller_resting_in_viewport();
 }
@@ -536,8 +535,6 @@
   }
 
   model_->browsing_disabled = ui_initial_state.browsing_disabled;
-  model_->skips_redraw_when_not_dirty =
-      ui_initial_state.skips_redraw_when_not_dirty;
   model_->waiting_for_background = ui_initial_state.assets_supported;
   model_->supports_selection = ui_initial_state.supports_selection;
   model_->needs_keyboard_update = ui_initial_state.needs_keyboard_update;
diff --git a/chrome/browser/vr/ui.h b/chrome/browser/vr/ui.h
index 5d96f545..b2f88e2 100644
--- a/chrome/browser/vr/ui.h
+++ b/chrome/browser/vr/ui.h
@@ -48,7 +48,6 @@
   bool web_vr_autopresentation_expected = false;
   bool browsing_disabled = false;
   bool has_or_can_request_audio_permission = true;
-  bool skips_redraw_when_not_dirty = false;
   bool assets_supported = false;
   bool supports_selection = true;
   bool needs_keyboard_update = false;
diff --git a/chrome/browser/vr/ui_input_manager.cc b/chrome/browser/vr/ui_input_manager.cc
index fd57134..d2b7c32 100644
--- a/chrome/browser/vr/ui_input_manager.cc
+++ b/chrome/browser/vr/ui_input_manager.cc
@@ -25,8 +25,6 @@
     gfx::PointF(std::numeric_limits<float>::max(),
                 std::numeric_limits<float>::max());
 
-constexpr float kControllerQuiescenceAngularThresholdDegrees = 3.5f;
-constexpr float kControllerQuiescenceTemporalThresholdSeconds = 1.2f;
 constexpr float kControllerFocusThresholdSeconds = 1.0f;
 
 bool IsCentroidInViewport(const gfx::Transform& view_proj_matrix,
@@ -86,7 +84,6 @@
                                  const ControllerModel& controller_model,
                                  ReticleModel* reticle_model,
                                  InputEventList* input_event_list) {
-  UpdateQuiescenceState(current_time, controller_model);
   UpdateControllerFocusState(current_time, render_info, controller_model);
   reticle_model->target_element_id = 0;
   reticle_model->target_local_point = kInvalidTargetPoint;
@@ -352,36 +349,6 @@
   return target_element;
 }
 
-void UiInputManager::UpdateQuiescenceState(
-    base::TimeTicks current_time,
-    const ControllerModel& controller_model) {
-  // Update quiescence state.
-  gfx::Point3F old_position;
-  gfx::Point3F old_forward_position(0, 0, -1);
-  last_significant_controller_transform_.TransformPoint(&old_position);
-  last_significant_controller_transform_.TransformPoint(&old_forward_position);
-  gfx::Vector3dF old_forward = old_forward_position - old_position;
-  old_forward.GetNormalized(&old_forward);
-  gfx::Point3F new_position;
-  gfx::Point3F new_forward_position(0, 0, -1);
-  controller_model.transform.TransformPoint(&new_position);
-  controller_model.transform.TransformPoint(&new_forward_position);
-  gfx::Vector3dF new_forward = new_forward_position - new_position;
-  new_forward.GetNormalized(&new_forward);
-
-  float angle = AngleBetweenVectorsInDegrees(old_forward, new_forward);
-  if (angle > kControllerQuiescenceAngularThresholdDegrees || in_click_ ||
-      in_scroll_) {
-    controller_quiescent_ = false;
-    last_significant_controller_transform_ = controller_model.transform;
-    last_significant_controller_update_time_ = current_time;
-  } else if ((current_time - last_significant_controller_update_time_)
-                 .InSecondsF() >
-             kControllerQuiescenceTemporalThresholdSeconds) {
-    controller_quiescent_ = true;
-  }
-}
-
 void UiInputManager::UpdateControllerFocusState(
     base::TimeTicks current_time,
     const RenderInfo& render_info,
diff --git a/chrome/browser/vr/ui_input_manager.h b/chrome/browser/vr/ui_input_manager.h
index 3338891..cafd730 100644
--- a/chrome/browser/vr/ui_input_manager.h
+++ b/chrome/browser/vr/ui_input_manager.h
@@ -62,7 +62,6 @@
   void OnInputCommitted(const EditedText& info);
   void OnKeyboardHidden();
 
-  bool controller_quiescent() const { return controller_quiescent_; }
   bool controller_resting_in_viewport() const {
     return controller_resting_in_viewport_;
   }
@@ -104,8 +103,6 @@
   UiElement* GetTargetElement(const ControllerModel& controller_model,
                               ReticleModel* reticle_model,
                               const InputEventList& input_event_list) const;
-  void UpdateQuiescenceState(base::TimeTicks current_time,
-                             const ControllerModel& controller_model);
   void UpdateControllerFocusState(base::TimeTicks current_time,
                                   const RenderInfo& render_info,
                                   const ControllerModel& controller_model);
@@ -130,10 +127,6 @@
 
   ButtonState previous_button_state_ = ButtonState::UP;
 
-  base::TimeTicks last_significant_controller_update_time_;
-  gfx::Transform last_significant_controller_transform_;
-  bool controller_quiescent_ = false;
-
   base::TimeTicks last_controller_outside_viewport_time_;
   bool controller_resting_in_viewport_ = false;
 };
diff --git a/chrome/browser/vr/ui_scene_creator.cc b/chrome/browser/vr/ui_scene_creator.cc
index 87a65492..c74706b 100644
--- a/chrome/browser/vr/ui_scene_creator.cc
+++ b/chrome/browser/vr/ui_scene_creator.cc
@@ -1923,20 +1923,6 @@
 
   auto group = std::make_unique<UiElement>();
   group->SetName(kControllerGroup);
-  group->SetTransitionedProperties({OPACITY});
-  group->AddBinding(std::make_unique<Binding<bool>>(
-      VR_BIND_LAMBDA(
-          [](Model* m) {
-            return !m->controller.quiescent || !m->skips_redraw_when_not_dirty;
-          },
-          base::Unretained(model_)),
-      VR_BIND_LAMBDA(
-          [](UiElement* e, const bool& visible) {
-            e->SetTransitionDuration(base::TimeDelta::FromMilliseconds(
-                visible ? kControllerFadeInMs : kControllerFadeOutMs));
-            e->SetVisible(visible);
-          },
-          base::Unretained(group.get()))));
   scene_->AddUiElement(kControllerRoot, std::move(group));
 
   auto controller = CreateControllerElement(model_);
diff --git a/chrome/browser/vr/ui_unittest.cc b/chrome/browser/vr/ui_unittest.cc
index 8ad6bcca..787f2a0 100644
--- a/chrome/browser/vr/ui_unittest.cc
+++ b/chrome/browser/vr/ui_unittest.cc
@@ -958,31 +958,6 @@
   ClickElement(suggestion);
 }
 
-TEST_F(UiTest, ControllerQuiescence) {
-  CreateScene(kNotInWebVr);
-  OnBeginFrame();
-  EXPECT_TRUE(IsVisible(kControllerGroup));
-  model_->skips_redraw_when_not_dirty = true;
-  model_->controller.quiescent = true;
-
-  UiElement* controller_group = scene_->GetUiElementByName(kControllerGroup);
-  EXPECT_TRUE(RunForMs(100));
-  EXPECT_LT(0.0f, controller_group->computed_opacity());
-  EXPECT_TRUE(RunForMs(500));
-  EXPECT_EQ(0.0f, controller_group->computed_opacity());
-
-  model_->controller.quiescent = false;
-  EXPECT_TRUE(RunForMs(100));
-  EXPECT_GT(1.0f, controller_group->computed_opacity());
-  EXPECT_TRUE(RunForMs(150));
-  EXPECT_EQ(1.0f, controller_group->computed_opacity());
-
-  model_->skips_redraw_when_not_dirty = false;
-  model_->controller.quiescent = true;
-  EXPECT_FALSE(RunForMs(1000));
-  EXPECT_TRUE(IsVisible(kControllerGroup));
-}
-
 TEST_F(UiTest, CloseButtonColorBindings) {
   CreateScene(kNotInWebVr);
   ui_->SetFullscreen(true);
diff --git a/chrome/browser/vr/webvr_frame_pose_browser_test.cc b/chrome/browser/vr/webvr_frame_pose_browser_test.cc
index ec4de4d..62ac0845 100644
--- a/chrome/browser/vr/webvr_frame_pose_browser_test.cc
+++ b/chrome/browser/vr/webvr_frame_pose_browser_test.cc
@@ -48,7 +48,7 @@
   }
 
   std::vector<Frame> submitted_frames;
-  device::PoseFrameData last_exclusive_frame_data = {};
+  device::PoseFrameData last_immersive_frame_data = {};
 
  private:
   // Set to null on background thread after calling Quit(), so we can ensure we
@@ -58,7 +58,7 @@
   int wait_frame_count_ = 0;
   int num_frames_submitted_ = 0;
 
-  bool has_last_exclusive_frame_data_ = false;
+  bool has_last_immersive_frame_data_ = false;
   int frame_id_ = 0;
 };
 
@@ -74,7 +74,7 @@
   DLOG(ERROR) << "Frame Submitted: " << num_frames_submitted_ << " "
               << frame_id;
   submitted_frames.push_back(
-      {frame_data, last_exclusive_frame_data, WaitGetDeviceConfig()});
+      {frame_data, last_immersive_frame_data, WaitGetDeviceConfig()});
 
   num_frames_submitted_++;
   if (num_frames_submitted_ >= wait_frame_count_ && wait_frame_count_ > 0 &&
@@ -83,12 +83,12 @@
     wait_loop_ = nullptr;
   }
 
-  EXPECT_TRUE(has_last_exclusive_frame_data_);
+  EXPECT_TRUE(has_last_immersive_frame_data_);
 
   // We expect a waitGetPoses, then 2 submits (one for each eye), so after 2
   // submitted frames don't use the same frame_data again.
   if (num_frames_submitted_ % 2 == 0)
-    has_last_exclusive_frame_data_ = false;
+    has_last_immersive_frame_data_ = false;
 }
 
 device::PoseFrameData MyOpenVRMock::WaitGetMagicWindowPose() {
@@ -118,9 +118,9 @@
   // to identify what the expected pose is.
   pose.device_to_origin[3] = frame_id_;
 
-  has_last_exclusive_frame_data_ = true;
+  has_last_immersive_frame_data_ = true;
   frame_id_++;
-  last_exclusive_frame_data = pose;
+  last_immersive_frame_data = pose;
 
   return pose;
 }
diff --git a/chrome/browser/vr/webvr_transition_browser_test.cc b/chrome/browser/vr/webvr_transition_browser_test.cc
index d217c37f..97dc5b69 100644
--- a/chrome/browser/vr/webvr_transition_browser_test.cc
+++ b/chrome/browser/vr/webvr_transition_browser_test.cc
@@ -97,27 +97,27 @@
 }
 
 // Tests that window.requestAnimationFrame continues to fire when we have a
-// non-exclusive WebXR session
+// non-immersive WebXR session
 IN_PROC_BROWSER_TEST_F(
     XrBrowserTestStandard,
-    REQUIRES_GPU(TestWindowRafFiresDuringNonExclusiveSession)) {
+    REQUIRES_GPU(TestWindowRafFiresDuringNonImmersiveSession)) {
   LoadUrlAndAwaitInitialization(
-      GetHtmlTestFile("test_window_raf_fires_during_non_exclusive_session"));
+      GetHtmlTestFile("test_window_raf_fires_during_non_immersive_session"));
   WaitOnJavaScriptStep(GetFirstTabWebContents());
   EndTest(GetFirstTabWebContents());
 }
 
-// Tests that non-exclusive sessions stop receiving rAFs during an exclusive
-// session, but resume once the exclusive session ends.
+// Tests that non-immersive sessions stop receiving rAFs during an immersive
+// session, but resume once the immersive session ends.
 IN_PROC_BROWSER_TEST_F(XrBrowserTestStandard,
-                       REQUIRES_GPU(TestNonExclusiveStopsDuringExclusive)) {
+                       REQUIRES_GPU(TestNonImmersiveStopsDuringImmersive)) {
   LoadUrlAndAwaitInitialization(
-      GetHtmlTestFile("test_non_exclusive_stops_during_exclusive"));
-  ExecuteStepAndWait("stepBeforeExclusive()", GetFirstTabWebContents());
+      GetHtmlTestFile("test_non_immersive_stops_during_immersive"));
+  ExecuteStepAndWait("stepBeforeImmersive()", GetFirstTabWebContents());
   EnterPresentationOrFail(GetFirstTabWebContents());
-  ExecuteStepAndWait("stepDuringExclusive()", GetFirstTabWebContents());
+  ExecuteStepAndWait("stepDuringImmersive()", GetFirstTabWebContents());
   ExitPresentationOrFail(GetFirstTabWebContents());
-  ExecuteStepAndWait("stepAfterExclusive()", GetFirstTabWebContents());
+  ExecuteStepAndWait("stepAfterImmersive()", GetFirstTabWebContents());
   EndTest(GetFirstTabWebContents());
 }
 
diff --git a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
index 458483e..02c0f9d 100644
--- a/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
+++ b/chrome/browser/webauthn/chrome_authenticator_request_delegate.cc
@@ -139,9 +139,9 @@
     return;
   }
 
-  // This does not use content::PermissionManager because that only works with
-  // content settings, while this permission is a non-persisted, per-attested-
-  // registration consent.
+  // This does not use content::PermissionControllerDelegate because that only
+  // works with content settings, while this permission is a non-persisted,
+  // per-attested- registration consent.
   auto* permission_request_manager = PermissionRequestManager::FromWebContents(
       content::WebContents::FromRenderFrameHost(render_frame_host()));
   if (!permission_request_manager) {
diff --git a/chrome/chrome_cleaner/os/disk_util.cc b/chrome/chrome_cleaner/os/disk_util.cc
index 371a37a..5e0534a 100644
--- a/chrome/chrome_cleaner/os/disk_util.cc
+++ b/chrome/chrome_cleaner/os/disk_util.cc
@@ -752,41 +752,6 @@
   return ok != FALSE;
 }
 
-bool VerifyAuthenticodeSignature(const base::FilePath& signed_file) {
-  // Don't pop up any windows
-  const HWND window_mode = reinterpret_cast<HWND>(INVALID_HANDLE_VALUE);
-
-  // Verify file & certificates using the Microsoft Authenticode Policy
-  // Provider.
-  GUID verification_type = WINTRUST_ACTION_GENERIC_VERIFY_V2;
-
-  // Info for the file we're going to verify.
-  WINTRUST_FILE_INFO file_info = {};
-  file_info.cbStruct = sizeof(file_info);
-  file_info.pcwszFilePath = signed_file.value().c_str();
-
-  // Info for request to WinVerifyTrust.
-  WINTRUST_DATA trust_data = {};
-  trust_data.cbStruct = sizeof(trust_data);
-  trust_data.dwUIChoice = WTD_UI_NONE;               // no graphics
-  trust_data.fdwRevocationChecks = WTD_REVOKE_NONE;  // no revocation checking
-  trust_data.dwUnionChoice = WTD_CHOICE_FILE;        // check a file
-  trust_data.pFile = &file_info;                     // check this file
-  trust_data.dwProvFlags = WTD_REVOCATION_CHECK_NONE;
-
-  // From the WinVerifyTrust documentation:
-  //   http://msdn2.microsoft.com/en-us/library/aa388208.aspx:
-  //   "If the trust provider verifies that the subject is trusted
-  //   for the specified action, the return value is zero. No other
-  //   value besides zero should be considered a successful return."
-  LONG result = ::WinVerifyTrust(window_mode, &verification_type, &trust_data);
-  if (result) {
-    LOG(ERROR) << "WinVerifyTrust failed: '" << SanitizePath(signed_file)
-               << "'. " << result;
-  }
-  return !result;
-}
-
 bool ShortPathContainsCaseInsensitive(const base::string16& value,
                                       const base::string16& substring) {
   DWORD long_value_len = ::GetLongPathName(value.c_str(), nullptr, 0);
diff --git a/chrome/chrome_cleaner/os/disk_util.h b/chrome/chrome_cleaner/os/disk_util.h
index d9b5c506..201c5dcc 100644
--- a/chrome/chrome_cleaner/os/disk_util.h
+++ b/chrome/chrome_cleaner/os/disk_util.h
@@ -138,11 +138,6 @@
                                uint32_t delay_before_delete_ms,
                                base::win::ScopedHandle* process_handle);
 
-// Verifies that |signed_file| has a valid signature from a trusted software
-// publisher. The signing certificate must be valid for code signing, and must
-// be issued by a trusted certificate authority (e.g., VeriSign, Inc).
-bool VerifyAuthenticodeSignature(const base::FilePath& signed_file);
-
 // Return true when string |value| contains an occurrence of |substring|,
 // ignoring the string case and taking into account that |value| might be a
 // shortened path (with it's tail replaced by ~N).
diff --git a/chrome/chrome_cleaner/test/BUILD.gn b/chrome/chrome_cleaner/test/BUILD.gn
index f9d0201..0815762 100644
--- a/chrome/chrome_cleaner/test/BUILD.gn
+++ b/chrome/chrome_cleaner/test/BUILD.gn
@@ -2,6 +2,32 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+shared_library("empty_dll") {
+  sources = [
+    "empty_dll.cc",
+  ]
+}
+
+source_set("scoped_file") {
+  sources = [
+    "scoped_file.cc",
+    "scoped_file.h",
+  ]
+
+  deps = [
+    "//base:base",
+  ]
+}
+
+source_set("test_strings") {
+  testonly = true
+
+  sources = [
+    "test_strings.cc",
+    "test_strings.h",
+  ]
+}
+
 static_library("test_util") {
   testonly = true
 
diff --git a/chrome/chrome_cleaner/test/empty_dll.cc b/chrome/chrome_cleaner/test/empty_dll.cc
new file mode 100644
index 0000000..3a32091
--- /dev/null
+++ b/chrome/chrome_cleaner/test/empty_dll.cc
@@ -0,0 +1,9 @@
+// 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.
+
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
+  return TRUE;
+}
diff --git a/chrome/chrome_cleaner/test/scoped_file.cc b/chrome/chrome_cleaner/test/scoped_file.cc
new file mode 100644
index 0000000..052c1034
--- /dev/null
+++ b/chrome/chrome_cleaner/test/scoped_file.cc
@@ -0,0 +1,35 @@
+// 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.
+
+#include "chrome/chrome_cleaner/test/scoped_file.h"
+
+#include "base/base_paths_win.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+
+// static
+std::unique_ptr<ScopedFile> ScopedFile::Create(const base::FilePath& dir,
+                                               const base::string16& file_name,
+                                               const std::string& contents) {
+  base::FilePath file_path = dir.Append(file_name);
+  CHECK(base::PathExists(file_path.DirName()));
+  CHECK_LE(contents.length(),
+           static_cast<size_t>(std::numeric_limits<int>::max()));
+  base::WriteFile(file_path, contents.c_str(),
+                  static_cast<int>(contents.length()));
+  return std::make_unique<ScopedFile>(file_path);
+}
+
+ScopedFile::ScopedFile(const base::FilePath& file_path)
+    : file_path_(file_path) {}
+
+ScopedFile::~ScopedFile() {
+  if (base::PathExists(file_path_))
+    PCHECK(base::DeleteFile(file_path_, false /*recursive*/));
+}
+
+const base::FilePath& ScopedFile::file_path() {
+  return file_path_;
+}
diff --git a/chrome/chrome_cleaner/test/scoped_file.h b/chrome/chrome_cleaner/test/scoped_file.h
new file mode 100644
index 0000000..69ef7aa
--- /dev/null
+++ b/chrome/chrome_cleaner/test/scoped_file.h
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef CHROME_CHROME_CLEANER_TEST_SCOPED_FILE_H_
+#define CHROME_CHROME_CLEANER_TEST_SCOPED_FILE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/files/file_path.h"
+#include "base/strings/string16.h"
+
+// Holds the path for a file that gets deleted on destruction.
+class ScopedFile {
+ public:
+  static std::unique_ptr<ScopedFile> Create(const base::FilePath& dir,
+                                            const base::string16& file_name,
+                                            const std::string& contents);
+
+  explicit ScopedFile(const base::FilePath& file_path);
+
+  // Deletes the file with path |file_path_| if it exists. If the file doesn't
+  // exist on destruction (which can be the case for tests involving UwS
+  // removals), the destructor is a no-op.
+  ~ScopedFile();
+
+  const base::FilePath& file_path();
+
+ private:
+  base::FilePath file_path_;
+};
+
+#endif  // CHROME_CHROME_CLEANER_TEST_SCOPED_FILE_H_
diff --git a/chrome/chrome_cleaner/test/test_strings.cc b/chrome/chrome_cleaner/test/test_strings.cc
new file mode 100644
index 0000000..3734e56
--- /dev/null
+++ b/chrome/chrome_cleaner/test/test_strings.cc
@@ -0,0 +1,45 @@
+// 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.
+
+#include "chrome/chrome_cleaner/test/test_strings.h"
+
+namespace chrome_cleaner {
+
+// Command line switches.
+const char kTestSleepMinutesSwitch[] = "test-sleep-minutes";
+const char kTestEventToSignal[] = "test-event-to-signal";
+const char kTestForceOverwriteZoneIdentifier[] =
+    "test-force-overwrite-zone-identifier";
+
+// Test service properties
+const wchar_t kServiceName[] = L"CCT_TestService";
+const wchar_t kServiceDescription[] = L"Chrome Cleanup Tool (test)";
+const unsigned int kServiceQueryWaitTimeMs = 250;
+const int kServiceQueryRetry = 5;
+
+// Test file names.
+const wchar_t kValidUtf8Name[] = L"unicode_file_\u79c1.exe";
+const wchar_t kInvalidUtf8Name[] = L"unicode_file_\xd800.exe";
+
+// File content data.
+const char kFileContent[] = "This is the file content.";
+
+// GUIDs for tests.
+const GUID kGUID1 = {0x7698f759,
+                     0xf5b0,
+                     0x4328,
+                     {0x92, 0x38, 0xbd, 0x70, 0x8a, 0x6d, 0xc9, 0x63}};
+const GUID kGUID2 = {0xe2a9ee7b,
+                     0x456a,
+                     0x485f,
+                     {0xa3, 0xf2, 0x5e, 0x7c, 0x59, 0x6b, 0xa7, 0xe5}};
+const GUID kGUID3 = {0x61956963,
+                     0x386,
+                     0x437b,
+                     {0x86, 0x5e, 0xaf, 0xad, 0x63, 0x7e, 0x3f, 0x16}};
+const wchar_t kGUID1Str[] = L"{7698F759-F5B0-4328-9238-BD708A6DC963}";
+const wchar_t kGUID2Str[] = L"{E2A9EE7B-456A-485F-A3F2-5E7C596BA7E5}";
+const wchar_t kGUID3Str[] = L"{61956963-0386-437B-865E-AFAD637E3F16}";
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/test/test_strings.h b/chrome/chrome_cleaner/test/test_strings.h
new file mode 100644
index 0000000..4206e29
--- /dev/null
+++ b/chrome/chrome_cleaner/test/test_strings.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef CHROME_CHROME_CLEANER_TEST_TEST_STRINGS_H_
+#define CHROME_CHROME_CLEANER_TEST_TEST_STRINGS_H_
+
+#include <windows.h>
+
+namespace chrome_cleaner {
+
+// Command line switches.
+
+// The switch to activate the sleeping action for specified delay in minutes
+// before killing the process.
+extern const char kTestSleepMinutesSwitch[];
+
+// The switch to signal the event with the name given as a switch value.
+extern const char kTestEventToSignal[];
+
+// Test the overwrite of the ZoneIdentifier.
+extern const char kTestForceOverwriteZoneIdentifier[];
+
+// Test service properties.
+
+// The name of the service used for tests.
+extern const wchar_t kServiceName[];
+// The description of the service used for tests.
+extern const wchar_t kServiceDescription[];
+
+// The sleep time in ms between each poll attempt to get information about a
+// service.
+extern const unsigned int kServiceQueryWaitTimeMs;
+// The number of attempts to contact a service.
+extern const int kServiceQueryRetry;
+
+// A valid uft8 name for a file.
+extern const wchar_t kValidUtf8Name[];
+
+// An invalid uft8 name for a file.
+extern const wchar_t kInvalidUtf8Name[];
+
+// The test data written to file.
+const int kFileContentSize = 26;
+extern const char kFileContent[kFileContentSize];
+
+// GUIDs for tests.
+extern const GUID kGUID1;
+extern const GUID kGUID2;
+extern const GUID kGUID3;
+extern const wchar_t kGUID1Str[];
+extern const wchar_t kGUID2Str[];
+extern const wchar_t kGUID3Str[];
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_TEST_TEST_STRINGS_H_
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 5a02f5ad..1256315 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -262,9 +262,6 @@
     "ExternalExtensionDefaultButtonControl", base::FEATURE_DISABLED_BY_DEFAULT};
 
 #if BUILDFLAG(ENABLE_VR)
-// Controls experimental rendering features for VR browsing.
-const base::Feature kVrBrowsingExperimentalRendering{
-    "VrBrowsingExperimentalRendering", base::FEATURE_DISABLED_BY_DEFAULT};
 
 #if BUILDFLAG(ENABLE_OCULUS_VR)
 // Controls Oculus support.
@@ -539,6 +536,10 @@
 const base::Feature kNativeSmb{"NativeSmb", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_CHROMEOS)
 
+// Enables a special visual treatment for windows with a single tab.
+const base::Feature kSingleTabMode{"SingleTabMode",
+                                   base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Enables or disables the ability to use the sound content setting to mute a
 // website.
 const base::Feature kSoundContentSetting{"SoundContentSetting",
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index 6da7ce57..17a7798e 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -284,6 +284,8 @@
 extern const base::Feature kNativeSmb;
 #endif
 
+extern const base::Feature kSingleTabMode;
+
 extern const base::Feature kSoundContentSetting;
 
 #if defined(OS_MACOSX)
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 4717691..32cc1b75 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2537,6 +2537,7 @@
     "../browser/permissions/permission_request_manager_unittest.cc",
     "../browser/permissions/permission_util_unittest.cc",
     "../browser/plugins/pdf_iframe_navigation_throttle_unittest.cc",
+    "../browser/policy/browser_dm_token_storage_unittest.cc",
     "../browser/policy/browser_dm_token_storage_win_unittest.cc",
     "../browser/policy/cloud/cloud_policy_invalidator_unittest.cc",
     "../browser/policy/cloud/cloud_policy_test_utils.cc",
diff --git a/chrome/test/base/in_process_browser_test.cc b/chrome/test/base/in_process_browser_test.cc
index 62ac2df2..5aba7401 100644
--- a/chrome/test/base/in_process_browser_test.cc
+++ b/chrome/test/base/in_process_browser_test.cc
@@ -67,6 +67,7 @@
 #include "ui/display/display_switches.h"
 
 #if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
 #include "base/mac/scoped_nsautorelease_pool.h"
 #include "chrome/test/base/scoped_bundle_swizzler_mac.h"
 #endif
@@ -123,6 +124,8 @@
 #endif  // OS_MACOSX
 {
 #if defined(OS_MACOSX)
+  base::mac::SetOverrideAmIBundled(true);
+
   // TODO(phajdan.jr): Make browser_tests self-contained on Mac, remove this.
   // Before we run the browser, we have to hack the path to the exe to match
   // what it would be if Chrome was running, because it is used to fork renderer
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index dc8fb0b7..8ee890e 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -845,6 +845,11 @@
   return extensions_request_context_.get();
 }
 
+scoped_refptr<network::SharedURLLoaderFactory>
+TestingProfile::GetURLLoaderFactory() {
+  return nullptr;
+}
+
 content::ResourceContext* TestingProfile::GetResourceContext() {
   if (!resource_context_)
     resource_context_ = new content::MockResourceContext();
@@ -914,7 +919,8 @@
   return NULL;
 }
 
-content::PermissionManager* TestingProfile::GetPermissionManager() {
+content::PermissionControllerDelegate*
+TestingProfile::GetPermissionControllerDelegate() {
   return NULL;
 }
 
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index 00302b12..9d73150 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -243,7 +243,8 @@
   storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
   content::PushMessagingService* GetPushMessagingService() override;
   content::SSLHostStateDelegate* GetSSLHostStateDelegate() override;
-  content::PermissionManager* GetPermissionManager() override;
+  content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+      override;
   content::BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
   content::BackgroundSyncController* GetBackgroundSyncController() override;
   content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
@@ -309,6 +310,8 @@
 #endif  // !defined(OS_ANDROID)
   net::URLRequestContextGetter* GetRequestContext() override;
   net::URLRequestContextGetter* GetRequestContextForExtensions() override;
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
+
   void set_last_session_exited_cleanly(bool value) {
     last_session_exited_cleanly_ = value;
   }
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index 9436c48f..74b88e16 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -120,12 +120,12 @@
   return Status(kOk);
 }
 
-Status PrepareCommandLine(const Capabilities& capabilities,
-                          base::CommandLine* prepared_command,
-                          base::ScopedTempDir* user_data_dir_temp_dir,
-                          base::ScopedTempDir* extension_dir,
-                          std::vector<std::string>* extension_bg_pages,
-                          base::FilePath* user_data_dir) {
+Status PrepareDesktopCommandLine(const Capabilities& capabilities,
+                                 base::CommandLine* prepared_command,
+                                 base::ScopedTempDir* user_data_dir_temp_dir,
+                                 base::ScopedTempDir* extension_dir,
+                                 std::vector<std::string>* extension_bg_pages,
+                                 base::FilePath* user_data_dir) {
   base::FilePath program = capabilities.binary;
   if (program.empty()) {
     if (!FindChrome(&program))
@@ -146,14 +146,15 @@
     switches.RemoveSwitch(excluded_switch);
   }
   switches.SetFromSwitches(capabilities.switches);
-  if (switches.HasSwitch("remote-debugging-port")) {
-    return Status(kUnknownError,
-                  "Argument 'remote-debugging-port' is not allowed. "
-                  "You must let Chrome pick a remote debug port for you.");
+  if (!switches.HasSwitch("remote-debugging-port")) {
+    switches.SetSwitch("remote-debugging-port", "0");
   }
-  switches.SetSwitch("remote-debugging-port", "0");
-  if (capabilities.exclude_switches.count("user-data-dir") > 0)
+  if (capabilities.exclude_switches.count("user-data-dir") > 0) {
     LOG(WARNING) << "excluding user-data-dir switch is not supported";
+  }
+  if (capabilities.exclude_switches.count("remote-debugging-port") > 0) {
+    LOG(WARNING) << "excluding remote-debugging-port switch is not supported";
+  }
   if (switches.HasSwitch("user-data-dir")) {
     *user_data_dir =
         base::FilePath(switches.GetSwitchValueNative("user-data-dir"));
@@ -345,17 +346,29 @@
   base::ScopedTempDir extension_dir;
   Status status = Status(kOk);
   std::vector<std::string> extension_bg_pages;
+  int devtools_port = 0;
 
-  if (capabilities.switches.HasSwitch("user-data-dir")) {
+  if (capabilities.switches.HasSwitch("remote-debugging-port")) {
+    std::string port_switch =
+        capabilities.switches.GetSwitchValue("remote-debugging-port");
+    bool conversion_result = base::StringToInt(port_switch, &devtools_port);
+    if (!conversion_result || devtools_port < 0 || 65535 < devtools_port) {
+      return Status(
+          kUnknownError,
+          "remote-debugging-port flag has invalid value: " + port_switch);
+    }
+  }
+
+  if (!devtools_port && capabilities.switches.HasSwitch("user-data-dir")) {
     status = internal::RemoveOldDevToolsActivePortFile(base::FilePath(
         capabilities.switches.GetSwitchValueNative("user-data-dir")));
     if (status.IsError()) {
       return status;
     }
   }
-  status =
-      PrepareCommandLine(capabilities, &command, &user_data_dir_temp_dir,
-                         &extension_dir, &extension_bg_pages, &user_data_dir);
+  status = PrepareDesktopCommandLine(capabilities, &command,
+                                     &user_data_dir_temp_dir, &extension_dir,
+                                     &extension_bg_pages, &user_data_dir);
   if (status.IsError())
     return status;
 
@@ -417,15 +430,18 @@
   // Attempt to connect to devtools in order to send commands to Chrome. If
   // attempts fail, check if Chrome has crashed and return error.
   std::unique_ptr<DevToolsHttpClient> devtools_http_client;
-  int devtools_port;
   int exit_code;
   base::TerminationStatus chrome_status =
       base::TERMINATION_STATUS_STILL_RUNNING;
   base::TimeTicks deadline =
       base::TimeTicks::Now() + base::TimeDelta::FromSeconds(60);
   while (base::TimeTicks::Now() < deadline) {
-    status =
-        internal::ParseDevToolsActivePortFile(user_data_dir, &devtools_port);
+    if (!devtools_port) {
+      status =
+          internal::ParseDevToolsActivePortFile(user_data_dir, &devtools_port);
+    } else {
+      status = Status(kOk);
+    }
     if (status.IsOk()) {
       status = WaitForDevToolsAndCheckVersion(
           NetAddress(devtools_port), context_getter, socket_factory,
@@ -434,6 +450,7 @@
     if (status.IsOk()) {
       break;
     }
+    // Check to see if Chrome has crashed.
     chrome_status = base::GetTerminationStatus(process.Handle(), &exit_code);
     if (chrome_status != base::TERMINATION_STATUS_STILL_RUNNING) {
       std::string termination_reason =
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index a635c10..a0f20dc 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -18,7 +18,6 @@
 import os
 import re
 import shutil
-import socket
 import subprocess
 import sys
 import tempfile
@@ -2063,21 +2062,25 @@
         None,
         driver.ExecuteScript('return window.domAutomationController'))
 
-  def testRemoteDebugPortSwitchError(self):
-    """Tests that passing --remote-debugging-port through capabilities raises a
-    ChromeDriver error."""
-    exception_raised = False
-    try:
-      driver = self.CreateDriver(chrome_switches=['remote-debugging-port=5'])
-    except Exception as e:
-      self.assertIn(
-          '\'remote-debugging-port\' is not allowed', e.message,
-          'ChromeDriver should provide a useful error message for '
-          'remote-debugging-port users.')
-      exception_raised = True
-    self.assertTrue(
-        exception_raised,
-        'ChromeDriver should not allow the --remote-debugging-port flag.')
+  def testRemoteDebuggingPort(self):
+    """Tests that passing --remote-debugging-port through capabilities works.
+    """
+    # Must use retries since there is an inherent race condition in port
+    # selection.
+    ports_generator = util.FindProbableFreePorts()
+    for _ in range(3):
+      port = ports_generator.next()
+      port_flag = 'remote-debugging-port=%s' % port
+      try:
+        driver = self.CreateDriver(chrome_switches=[port_flag])
+      except:
+        continue
+      driver.Load('chrome:version')
+      command_line = driver.FindElement('id', 'command_line').GetText()
+      self.assertIn(port_flag, command_line)
+      break
+    else:  # Else clause gets invoked if "break" never happens.
+      raise  # This re-raises the most recent exception.
 
 
 class ChromeDesiredCapabilityTest(ChromeDriverBaseTest):
@@ -2645,30 +2648,40 @@
                     'must supply a chrome binary arg')
 
   def testConnectToRemoteBrowser(self):
-    port = self.FindFreePort()
-    temp_dir = util.MakeTempDir()
-    print 'temp dir is ' + temp_dir
-    cmd = [_CHROME_BINARY,
-           '--remote-debugging-port=%d' % port,
-           '--user-data-dir=%s' % temp_dir,
-           '--use-mock-keychain']
-    process = subprocess.Popen(cmd)
-    if process is None:
-      raise RuntimeError('Chrome could not be started with debugging port')
-    try:
-      driver = self.CreateDriver(debugger_address='localhost:%d' % port)
-      driver.ExecuteScript('console.info("%s")' % 'connecting at %d!' % port)
-      driver.Quit()
-    finally:
-      process.terminate()
-
-  def FindFreePort(self):
-    for port in range(10000, 10100):
+    # Must use retries since there is an inherent race condition in port
+    # selection.
+    ports_generator = util.FindProbableFreePorts()
+    for _ in range(3):
+      port = ports_generator.next()
+      temp_dir = util.MakeTempDir()
+      print 'temp dir is ' + temp_dir
+      cmd = [_CHROME_BINARY,
+             '--remote-debugging-port=%d' % port,
+             '--user-data-dir=%s' % temp_dir,
+             '--use-mock-keychain']
+      process = subprocess.Popen(cmd)
       try:
-        socket.create_connection(('127.0.0.1', port), 0.2).close()
-      except socket.error:
-        return port
-    raise RuntimeError('Cannot find open port')
+        driver = self.CreateDriver(debugger_address='localhost:%d' % port)
+        driver.ExecuteScript('console.info("%s")' % 'connecting at %d!' % port)
+        driver.Quit()
+      except:
+        continue
+      finally:
+        if process.poll() is None:
+          process.terminate()
+          # Wait for Chrome to exit here to prevent a race with Chrome to
+          # delete/modify the temporary user-data-dir.
+          # Maximum wait ~1 second.
+          for _ in range(20):
+            if process.poll() is not None:
+              break
+            print 'continuing to wait for Chrome to exit'
+            time.sleep(.05)
+          else:
+            process.kill()
+      break
+    else:  # Else clause gets invoked if "break" never happens.
+      raise  # This re-raises the most recent exception.
 
 
 class LaunchDesktopTest(ChromeDriverBaseTest):
diff --git a/chrome/test/chromedriver/util.py b/chrome/test/chromedriver/util.py
index 382212d..e78da7b 100644
--- a/chrome/test/chromedriver/util.py
+++ b/chrome/test/chromedriver/util.py
@@ -8,7 +8,9 @@
 import httplib
 import os
 import platform
+import random
 import signal
+import socket
 import stat
 import subprocess
 import sys
@@ -74,7 +76,11 @@
 
 
 def _DeleteDir(path):
-  """Deletes a directory recursively, which must exist."""
+  """Deletes a directory recursively, which must exist.
+
+  Note that this function can fail and raise OSError if another process is
+  making changes to the directory at the same time.
+  """
   # Don't use shutil.rmtree because it can't delete read-only files on Win.
   for root, dirs, files in os.walk(path, topdown=False):
     for name in files:
@@ -225,3 +231,25 @@
     url: A string of the URL.
   """
   print '@@@STEP_LINK@%s@%s@@@' % (label, url)
+
+
+def FindProbableFreePorts():
+  """Get an generator returning random free ports on the system.
+
+  Note that this function has an inherent race condition: some other process
+  may bind to the port after we return it, so it may no longer be free by then.
+  The workaround is to do this inside a retry loop. Do not use this function
+  if there is any alternative.
+  """
+  # This is the range of dynamic ports. See RFC6335 page 10.
+  dynamic_ports = range(49152, 65535)
+  random.shuffle(dynamic_ports)
+
+  for port in dynamic_ports:
+    try:
+      socket.create_connection(('127.0.0.1', port), 0.2).close()
+    except socket.error:
+      # If we can't connect to the port, then clearly nothing is listening on
+      # it.
+      yield port
+  raise RuntimeError('Cannot find open port')
diff --git a/chrome/test/data/password/done_redirect_parent.html b/chrome/test/data/password/done_redirect_parent.html
deleted file mode 100644
index 573728c..0000000
--- a/chrome/test/data/password/done_redirect_parent.html
+++ /dev/null
@@ -1,19 +0,0 @@
-<html>
-<body>
-
-<script>
-  if (!window.location.origin) {
-      window.location.origin = window.location.protocol + "//" + window.location.hostname;
-  }
-
-  var loc = window.location;
-  var locOrigin = loc.origin;
-  loc.href='about:blank';
-
-  window.parent.postMessage("done", locOrigin);
-</script>
-
-This html posts a message to window.parent.
-
-</body>
-</html>
diff --git a/chrome/test/data/password/iframe_target.html b/chrome/test/data/password/iframe_target.html
deleted file mode 100644
index 3236f3c4..0000000
--- a/chrome/test/data/password/iframe_target.html
+++ /dev/null
@@ -1,31 +0,0 @@
-<html>
-<body>
-
-<script>
-  function receiveMessage(event){
-    if (event.data == "done") {
-      // Modify the form so it will POST as usual.
-      form = document.getElementById("testform");
-      form.action = "done.html";
-      form.target = "";
-
-      // Remove the password field so Password Manager will ignore the form.
-      form.removeChild(document.getElementById("password_field"));
-
-      // Submit the form.
-      document.getElementById("testform").submit();
-    }
-  }
-  window.addEventListener("message", receiveMessage, false);
-</script>
-
-<form method="POST" action="done_redirect_parent.html" id="testform" target="iframe">
-  <input type="text" id="username_field" name="username_field">
-  <input type="password" id="password_field" name="password_field">
-  <input type="submit" id="input_submit_button" name="input_submit_button">
-</form>
-
-<iframe name="iframe" src="about:blank"></iframe>
-
-</body>
-</html>
diff --git a/chrome/test/data/password/no_form_elements_with_additional_form.html b/chrome/test/data/password/no_form_elements_with_additional_form.html
deleted file mode 100644
index 04e6ff9..0000000
--- a/chrome/test/data/password/no_form_elements_with_additional_form.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<html>
-<body>
-
-<input type="text" id="username">
-<input type="password" id="password">
-
-<form method="POST" action="done.html" id="search_form">
-  <input type="text" id="search_field">
-  <input type="submit" id="submit_search_button">
-</form>
-
-</body>
-</html>
diff --git a/chrome/test/data/password/password_form_with_simple_form.html b/chrome/test/data/password/password_form_with_simple_form.html
deleted file mode 100644
index 7aaf523..0000000
--- a/chrome/test/data/password/password_form_with_simple_form.html
+++ /dev/null
@@ -1,16 +0,0 @@
-<html>
-<body>
-
-<form method="POST" action="done.html" id="testform">
-  <input type="text" id="username_field" name="username_field">
-  <input type="password" id="password_field" name="password_field">
-  <input type="submit" id="input_submit_button" name="input_submit_button">
-</form>
-
-<form method="POST" action="done.html" id="search_form">
-  <input type="text" id="search_field">
-  <input type="submit" id="submit_search_button">
-</form>
-
-</body>
-</html>
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_non_exclusive_stops_during_exclusive.html b/chrome/test/data/xr/e2e_test_files/html/test_non_immersive_stops_during_immersive.html
similarity index 62%
rename from chrome/test/data/xr/e2e_test_files/html/test_non_exclusive_stops_during_exclusive.html
rename to chrome/test/data/xr/e2e_test_files/html/test_non_immersive_stops_during_immersive.html
index b80bf11..cd55563 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_non_exclusive_stops_during_exclusive.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_non_immersive_stops_during_immersive.html
@@ -1,6 +1,6 @@
 <!doctype html>
 <!--
-Tests that a non-exclusive session's rAF stops firing when an exclusive session
+Tests that a non-immersive session's rAF stops firing when an immersive session
 is active, but resumes afterwards.
 -->
 <html>
@@ -13,18 +13,18 @@
     <script src="../resources/webxr_e2e.js"></script>
     <script src="../resources/webxr_boilerplate.js"></script>
     <script>
-      var t = async_test("Non-exclusive rAF stops during exclusive session");
+      var t = async_test("Non-immersive rAF stops during immersive session");
       let counter = 0;
 
-      function stepBeforeExclusive() {
+      function stepBeforeImmersive() {
         onMagicWindowXRFrameCallback = function() {
           // Verify that we call a rAF once, then make sure any subsequent calls
-          // are not done while there is an exclusive session.
+          // are not done while there is an immersive session.
           onMagicWindowXRFrameCallback = function() {
-            if (sessionInfos[sessionTypes.EXCLUSIVE].currentSession !== null) {
+            if (sessionInfos[sessionTypes.IMMERSIVE].currentSession !== null) {
               t.step( () => {
                 assert_unreached(
-                    "Non-exclusive rAF called during exclusive session");
+                    "Non-immersive rAF called during immersive session");
               });
             }
           }
@@ -32,22 +32,22 @@
         };
       }
 
-      function stepDuringExclusive() {
-        // Let the exclusive session run for a bit so the non-exclusive rAF
+      function stepDuringImmersive() {
+        // Let the immersive session run for a bit so the non-immersive rAF
         // can fire if it's going to.
-        onExclusiveXRFrameCallback = function() {
+        onImmersiveXRFrameCallback = function() {
           if (counter < 10) {
             counter++;
             return;
           }
 
-          onExclusiveXRFrameCallback = null;
+          onImmersiveXRFrameCallback = null;
           finishJavaScriptStep();
         };
       }
 
-      function stepAfterExclusive() {
-        // Make sure we fire at least once after exiting the exclusive session
+      function stepAfterImmersive() {
+        // Make sure we fire at least once after exiting the immersive session
         onMagicWindowXRFrameCallback = function() {
           t.done();
         };
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_webxr_capabilities.html b/chrome/test/data/xr/e2e_test_files/html/test_webxr_capabilities.html
index 275209e..4b0697d 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_webxr_capabilities.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_webxr_capabilities.html
@@ -14,8 +14,8 @@
     <script>
       var expectations = {
         "Daydream": {
-          "exclusive": true,
-          "non-exclusive": true,
+          "immersive": true,
+          "non-immersive": true,
         }
       };
       var t = async_test("XRDevice capabilities match expectations");
@@ -29,25 +29,25 @@
         }
 
         let expected = expectations[device];
-        var supportsNonExclusive;
-        var supportsExclusive;
+        var supportsNonImmersive;
+        var supportsImmersive;
         var ctx = webglCanvas.getContext("xrpresent");
         xrDevice.supportsSession(
-            {exclusive: false, outputContext: ctx}).then( () => {
-          supportsNonExclusive = true;
+            {immersive: false, outputContext: ctx}).then( () => {
+          supportsNonImmersive = true;
         }, () => {
-          supportsNonExclusive = false;
+          supportsNonImmersive = false;
         }).then( () => {
-          xrDevice.supportsSession({exclusive: true}).then( () => {
-            supportsExclusive = true;
+          xrDevice.supportsSession({immersive: true}).then( () => {
+            supportsImmersive = true;
           }, () => {
-            supportsExclusive = false;
+            supportsImmersive = false;
           }).then( () => {
             t.step( () => {
-              assert_equals(supportsNonExclusive, expected["non-exclusive"],
-                  'Device supports non-exclusive sessions');
-              assert_equals(supportsExclusive, expected["exclusive"],
-                  'Device supports exclusive sessions');
+              assert_equals(supportsNonImmersive, expected["non-immersive"],
+                  'Device supports non-immersive sessions');
+              assert_equals(supportsImmersive, expected["immersive"],
+                  'Device supports immersive sessions');
             });
             t.done();
           });
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_webxr_input.html b/chrome/test/data/xr/e2e_test_files/html/test_webxr_input.html
index 16a707d..01c4e78 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_webxr_input.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_webxr_input.html
@@ -13,7 +13,7 @@
     <script src="../resources/webxr_e2e.js"></script>
     <script src="../resources/webxr_boilerplate.js"></script>
     <script>
-      var t = async_test("Screen taps/clicks registered as input when in WebXR exclusive session");
+      var t = async_test("Screen taps/clicks registered as input when in WebXR immersive session");
 
       var selectStartCount = 0;
       var selectEndCount = 0;
@@ -62,7 +62,7 @@
 
       function stepSetupListeners(numIterations) {
         iterations = numIterations;
-        let currentSession = sessionInfos[sessionTypes.EXCLUSIVE].currentSession;
+        let currentSession = sessionInfos[sessionTypes.IMMERSIVE].currentSession;
         currentSession.addEventListener('selectstart', onSelectStart, false);
         currentSession.addEventListener('selectend', onSelectEnd, false);
         currentSession.addEventListener('select', onSelect, false);
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_webxr_poses.html b/chrome/test/data/xr/e2e_test_files/html/test_webxr_poses.html
index fa4935d..9239fbd 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_webxr_poses.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_webxr_poses.html
@@ -62,11 +62,11 @@
         return MatrixCompare(pose.poseModelMatrix, expected);
       }
 
-      onExclusiveXRFrameCallback = function(session, frame, gl) {
+      onImmersiveXRFrameCallback = function(session, frame, gl) {
         // Encode an index into the clear color.
         frame_id++;
         frame_data_array[frame_id] = frame;
-        cached_frame_of_ref = sessionInfos[sessionTypes.EXCLUSIVE].currentFrameOfRef;
+        cached_frame_of_ref = sessionInfos[sessionTypes.IMMERSIVE].currentFrameOfRef;
 
         var encoded_frame_id = {};
         encoded_frame_id.r = frame_id % 256;
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_webxr_reentry_from_vr_browser.html b/chrome/test/data/xr/e2e_test_files/html/test_webxr_reentry_from_vr_browser.html
index 809299e..667351cf 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_webxr_reentry_from_vr_browser.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_webxr_reentry_from_vr_browser.html
@@ -16,8 +16,8 @@
       var t = async_test("rAFs continue to fire after presentation re-entry");
 
       function stepVerifyFirstPresent() {
-        onExclusiveXRFrameCallback = () => {
-          onExclusiveXRFrameCallback = null;
+        onImmersiveXRFrameCallback = () => {
+          onImmersiveXRFrameCallback = null;
           finishJavaScriptStep();
         };
       }
@@ -29,7 +29,7 @@
       }
 
       function stepVerifySecondPresent() {
-        onExclusiveXRFrameCallback = () => {
+        onImmersiveXRFrameCallback = () => {
           t.done();
         };
       }
diff --git a/chrome/test/data/xr/e2e_test_files/html/test_window_raf_fires_during_non_exclusive_session.html b/chrome/test/data/xr/e2e_test_files/html/test_window_raf_fires_during_non_immersive_session.html
similarity index 82%
rename from chrome/test/data/xr/e2e_test_files/html/test_window_raf_fires_during_non_exclusive_session.html
rename to chrome/test/data/xr/e2e_test_files/html/test_window_raf_fires_during_non_immersive_session.html
index 6161848..2c34f60a 100644
--- a/chrome/test/data/xr/e2e_test_files/html/test_window_raf_fires_during_non_exclusive_session.html
+++ b/chrome/test/data/xr/e2e_test_files/html/test_window_raf_fires_during_non_immersive_session.html
@@ -1,6 +1,6 @@
 <!doctype html>
 <!--
-Tests that window.rAF continues to fire during a non-exclusive session.
+Tests that window.rAF continues to fire during a non-immersive session.
 -->
 <html>
   <head>
@@ -12,7 +12,7 @@
     <script src="../resources/webxr_e2e.js"></script>
     <script src="../resources/webxr_boilerplate.js"></script>
     <script>
-      var t = async_test("window.rAF fires during a non-exclusive session");
+      var t = async_test("window.rAF fires during a non-immersive session");
 
       onMagicWindowXRFrameCallback = function() {
         window.requestAnimationFrame( () => {
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_page_submits_once.html b/chrome/test/data/xr/e2e_test_files/html/webxr_page_submits_once.html
index 691c0850..f2e3401 100644
--- a/chrome/test/data/xr/e2e_test_files/html/webxr_page_submits_once.html
+++ b/chrome/test/data/xr/e2e_test_files/html/webxr_page_submits_once.html
@@ -12,7 +12,7 @@
     <script src="../resources/webxr_boilerplate.js"></script>
     <script>
       var has_submitted = false;
-      onExclusiveXRFrameCallback = function() {
+      onImmersiveXRFrameCallback = function() {
         if (has_submitted) {
           shouldSubmitFrame = false;
           finishJavaScriptStep();
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_locks_focus.html b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_locks_focus.html
index b8c72d54..0c7bbb50 100644
--- a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_locks_focus.html
+++ b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_locks_focus.html
@@ -13,18 +13,18 @@
     <script src="../resources/webxr_e2e.js"></script>
     <script src="../resources/webxr_boilerplate.js"></script>
     <script>
-      var t = async_test("Focus is locked to exclusive session");
+      var t = async_test("Focus is locked to immersive session");
       var rafCount = 0;
 
       function stepSetupFocusLoss() {
-        onExclusiveXRFrameCallback = null;
+        onImmersiveXRFrameCallback = null;
         setTimeout(function() {
           document.getElementById('externalframe').contentWindow.focus();
         }, 1000);
       }
 
       window.onblur = function() {
-        onExclusiveXRFrameCallback = function() {
+        onImmersiveXRFrameCallback = function() {
           if (rafCount == 3) {
             t.done();
           }
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_don_canceled.html b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_don_canceled.html
index 5896f701..a20eb1fd 100644
--- a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_don_canceled.html
+++ b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_rejected_if_don_canceled.html
@@ -14,8 +14,8 @@
     <script src="../resources/webxr_boilerplate.js"></script>
     <script>
       var t = async_test("Presentation promise is rejected after DON canceled");
-      function onExclusiveRequestWithDon() {
-        xrDevice.requestSession({exclusive: true}).then( (session) => {
+      function onImmersiveRequestWithDon() {
+        xrDevice.requestSession({immersive: true}).then( (session) => {
           t.step( () => {
             assert_unreached("requestPresent promise resolved");
           });
@@ -25,7 +25,7 @@
           t.done();
         });
       }
-      webglCanvas.onclick = onExclusiveRequestWithDon;
+      webglCanvas.onclick = onImmersiveRequestWithDon;
     </script>
   </body>
 </html>
\ No newline at end of file
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_unresolved_during_don.html b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_unresolved_during_don.html
index cb6b8c6b..d8c3658e7 100644
--- a/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_unresolved_during_don.html
+++ b/chrome/test/data/xr/e2e_test_files/html/webxr_test_presentation_promise_unresolved_during_don.html
@@ -14,8 +14,8 @@
     <script src="../resources/webxr_boilerplate.js"></script>
     <script>
       var t = async_test("Presentation promise is unresolved during DON flow");
-      function onExclusiveRequestWithDon() {
-        xrDevice.requestSession({exclusive: true}).then( (session) => {
+      function onImmersiveRequestWithDon() {
+        xrDevice.requestSession({immersive: true}).then( (session) => {
           t.step( () => {
             assert_unreached("requestSession promise resolved");
           });
@@ -26,7 +26,7 @@
         });
         window.setTimeout( () => {t.done();}, 2000);
       }
-      webglCanvas.onclick = onExclusiveRequestWithDon;
+      webglCanvas.onclick = onImmersiveRequestWithDon;
     </script>
   </body>
 </html>
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_test_screen_taps_not_registered.html b/chrome/test/data/xr/e2e_test_files/html/webxr_test_screen_taps_not_registered.html
index e456030f..8535fb23 100644
--- a/chrome/test/data/xr/e2e_test_files/html/webxr_test_screen_taps_not_registered.html
+++ b/chrome/test/data/xr/e2e_test_files/html/webxr_test_screen_taps_not_registered.html
@@ -1,6 +1,6 @@
 <!doctype html>
 <!--
-Tests that screen taps aren't registered while in an exclusive WebXR session.
+Tests that screen taps aren't registered while in an immersive WebXR session.
 -->
 <html>
   <head>
@@ -12,7 +12,7 @@
     <script src="../resources/webxr_e2e.js"></script>
     <script src="../resources/webxr_boilerplate.js"></script>
     <script>
-      var t = async_test("Screen taps not registered when in exclusive session");
+      var t = async_test("Screen taps not registered when in immersive session");
       var numTaps = 0;
       webglCanvas.addEventListener("click", () => {numTaps++;}, false);
 
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_test_window_raf_fires_while_presenting.html b/chrome/test/data/xr/e2e_test_files/html/webxr_test_window_raf_fires_while_presenting.html
index f0c6924..cc689ca 100644
--- a/chrome/test/data/xr/e2e_test_files/html/webxr_test_window_raf_fires_while_presenting.html
+++ b/chrome/test/data/xr/e2e_test_files/html/webxr_test_window_raf_fires_while_presenting.html
@@ -1,7 +1,7 @@
 <!doctype html>
 <!--
 Tests that window.requestAnimationFrame continues to fire while in a WebXR
-exclusive session on Windows/desktop
+immersive session on Windows/desktop
 -->
 <html>
   <head>
@@ -13,7 +13,7 @@
     <script src="../resources/webxr_e2e.js"></script>
     <script src="../resources/webxr_boilerplate.js"></script>
     <script>
-      var t = async_test("window.rAF keeps firing while in exclusive session");
+      var t = async_test("window.rAF keeps firing while in immersive session");
 
       function stepVerifyBeforePresent() {
         window.requestAnimationFrame( () => {
diff --git a/chrome/test/data/xr/e2e_test_files/html/webxr_test_window_raf_stops_firing_during_exclusive_session.html b/chrome/test/data/xr/e2e_test_files/html/webxr_test_window_raf_stops_firing_during_immersive_session.html
similarity index 100%
rename from chrome/test/data/xr/e2e_test_files/html/webxr_test_window_raf_stops_firing_during_exclusive_session.html
rename to chrome/test/data/xr/e2e_test_files/html/webxr_test_window_raf_stops_firing_during_immersive_session.html
diff --git a/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js b/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js
index cee212b..ccd9294 100644
--- a/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js
+++ b/chrome/test/data/xr/e2e_test_files/resources/webxr_boilerplate.js
@@ -19,17 +19,17 @@
 var gl = null;
 var xrDevice = null;
 var onMagicWindowXRFrameCallback = null;
-var onExclusiveXRFrameCallback = null;
+var onImmersiveXRFrameCallback = null;
 var shouldSubmitFrame = true;
 var hasPresentedFrame = false;
 var arSessionRequestWouldTriggerPermissionPrompt = null;
 
 var sessionTypes = Object.freeze({
-  EXCLUSIVE: 1,
+  IMMERSIVE: 1,
   AR: 2,
   MAGIC_WINDOW: 3
 });
-var sessionTypeToRequest = sessionTypes.EXCLUSIVE;
+var sessionTypeToRequest = sessionTypes.IMMERSIVE;
 
 class SessionInfo {
   constructor() {
@@ -60,13 +60,13 @@
 }
 
 var sessionInfos = {}
-sessionInfos[sessionTypes.EXCLUSIVE] = new SessionInfo();
+sessionInfos[sessionTypes.IMMERSIVE] = new SessionInfo();
 sessionInfos[sessionTypes.AR] = new SessionInfo();
 sessionInfos[sessionTypes.MAGIC_WINDOW] = new SessionInfo();
 
 function getSessionType(session) {
-  if (session.exclusive) {
-    return sessionTypes.EXCLUSIVE;
+  if (session.immersive) {
+    return sessionTypes.IMMERSIVE;
   } else if (sessionInfos[sessionTypes.AR].currentSession == session) {
     // TODO(bsheedy): Replace this check if there's ever something like
     // session.ar for checking if the session is AR-capable.
@@ -78,9 +78,9 @@
 
 function onRequestSession() {
   switch (sessionTypeToRequest) {
-    case sessionTypes.EXCLUSIVE:
-      xrDevice.requestSession({exclusive: true}).then( (session) => {
-        sessionInfos[sessionTypes.EXCLUSIVE].currentSession = session;
+    case sessionTypes.IMMERSIVE:
+      xrDevice.requestSession({immersive: true}).then( (session) => {
+        sessionInfos[sessionTypes.IMMERSIVE].currentSession = session;
         onSessionStarted(session);
       });
       break;
@@ -144,14 +144,14 @@
 
   gl.bindFramebuffer(gl.FRAMEBUFFER, session.baseLayer.framebuffer);
 
-  // If in an exclusive session, set canvas to blue.
+  // If in an immersive session, set canvas to blue.
   // If in an AR session, just draw the camera.
   // Otherwise, red.
   switch (getSessionType(session)) {
-    case sessionTypes.EXCLUSIVE:
+    case sessionTypes.IMMERSIVE:
       gl.clearColor(0.0, 0.0, 1.0, 1.0);
-      if (onExclusiveXRFrameCallback) {
-        onExclusiveXRFrameCallback(session, frame, gl);
+      if (onImmersiveXRFrameCallback) {
+        onImmersiveXRFrameCallback(session, frame, gl);
       }
       gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
       break;
@@ -178,24 +178,24 @@
   });
 }
 
-// Try to get an XRDevice and set up a non-exclusive session with it
+// Try to get an XRDevice and set up a non-immersive session with it
 if (navigator.xr) {
   navigator.xr.requestDevice().then( (device) => {
     xrDevice = device;
     if (!device)
       return;
 
-    // Set up the device to have a non-exclusive session (magic window) drawing
+    // Set up the device to have a non-immersive session (magic window) drawing
     // into the full screen canvas on the page
     let ctx = webglCanvas.getContext('xrpresent');
-    // WebXR for VR tests want a non-exclusive session to be automatically
+    // WebXR for VR tests want a non-immersive session to be automatically
     // created on page load to reduce the amount of boilerplate code necessary.
     // However, doing so during AR tests currently fails due to AR sessions
     // always requiring a user gesture. So, allow a page to set a variable
     // before loading this JavaScript file if they wish to skip the automatic
-    // non-exclusive session creation.
-    if (typeof shouldAutoCreateNonExclusiveSession === 'undefined'
-        || shouldAutoCreateNonExclusiveSession === true) {
+    // non-immersive session creation.
+    if (typeof shouldAutoCreateNonImmersiveSession === 'undefined'
+        || shouldAutoCreateNonImmersiveSession === true) {
       device.requestSession({outputContext: ctx}).then( (session) => {
         onSessionStarted(session);
       }).then( () => {
diff --git a/chromecast/browser/cast_browser_context.cc b/chromecast/browser/cast_browser_context.cc
index 814a256..bec7475ac 100644
--- a/chromecast/browser/cast_browser_context.cc
+++ b/chromecast/browser/cast_browser_context.cc
@@ -132,7 +132,8 @@
   return nullptr;
 }
 
-content::PermissionManager* CastBrowserContext::GetPermissionManager() {
+content::PermissionControllerDelegate*
+CastBrowserContext::GetPermissionControllerDelegate() {
   if (!permission_manager_.get())
     permission_manager_.reset(new CastPermissionManager());
   return permission_manager_.get();
diff --git a/chromecast/browser/cast_browser_context.h b/chromecast/browser/cast_browser_context.h
index fbd3537..13c4bbf 100644
--- a/chromecast/browser/cast_browser_context.h
+++ b/chromecast/browser/cast_browser_context.h
@@ -37,7 +37,8 @@
   storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
   content::PushMessagingService* GetPushMessagingService() override;
   content::SSLHostStateDelegate* GetSSLHostStateDelegate() override;
-  content::PermissionManager* GetPermissionManager() override;
+  content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+      override;
   content::BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
   content::BackgroundSyncController* GetBackgroundSyncController() override;
   content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
@@ -67,7 +68,7 @@
   URLRequestContextFactory* const url_request_context_factory_;
   base::FilePath path_;
   std::unique_ptr<CastResourceContext> resource_context_;
-  std::unique_ptr<content::PermissionManager> permission_manager_;
+  std::unique_ptr<content::PermissionControllerDelegate> permission_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(CastBrowserContext);
 };
diff --git a/chromecast/browser/cast_permission_manager.h b/chromecast/browser/cast_permission_manager.h
index 15b36d1..82809fc 100644
--- a/chromecast/browser/cast_permission_manager.h
+++ b/chromecast/browser/cast_permission_manager.h
@@ -7,17 +7,17 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 
 namespace chromecast {
 namespace shell {
 
-class CastPermissionManager : public content::PermissionManager {
+class CastPermissionManager : public content::PermissionControllerDelegate {
  public:
   CastPermissionManager();
   ~CastPermissionManager() override;
 
-  // content::PermissionManager implementation:
+  // content::PermissionControllerDelegate implementation:
   int RequestPermission(
       content::PermissionType permission,
       content::RenderFrameHost* render_frame_host,
diff --git a/chromeos/BUILD.gn b/chromeos/BUILD.gn
index 307553cc..c0f8da9 100644
--- a/chromeos/BUILD.gn
+++ b/chromeos/BUILD.gn
@@ -698,7 +698,7 @@
     "//net",
     "//net:test_support",
     "//services/network:test_support",
-    "//services/network/public/cpp:cpp_base",
+    "//services/network/public/cpp",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/icu",
diff --git a/chromeos/account_manager/DEPS b/chromeos/account_manager/DEPS
new file mode 100644
index 0000000..0ebb5fbf
--- /dev/null
+++ b/chromeos/account_manager/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+  "account_manager_unittest.cc": [
+    "+services/network/test/test_url_loader_factory.h",
+  ]
+}
diff --git a/chromeos/account_manager/account_manager.cc b/chromeos/account_manager/account_manager.cc
index c294583..16278f3 100644
--- a/chromeos/account_manager/account_manager.cc
+++ b/chromeos/account_manager/account_manager.cc
@@ -20,7 +20,6 @@
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "third_party/protobuf/src/google/protobuf/message_lite.h"
 
@@ -98,7 +97,7 @@
 class AccountManager::GaiaTokenRevocationRequest : public GaiaAuthConsumer {
  public:
   GaiaTokenRevocationRequest(
-      net::URLRequestContextGetter* request_context,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       AccountManager::DelayNetworkCallRunner delay_network_call_runner,
       const std::string& refresh_token,
       base::WeakPtr<AccountManager> account_manager)
@@ -107,7 +106,7 @@
         weak_factory_(this) {
     DCHECK(!refresh_token_.empty());
     gaia_auth_fetcher_ = std::make_unique<GaiaAuthFetcher>(
-        this, GaiaConstants::kChromeOSSource, request_context);
+        this, GaiaConstants::kChromeOSSource, url_loader_factory);
     base::RepeatingClosure start_revoke_token = base::BindRepeating(
         &GaiaTokenRevocationRequest::Start, weak_factory_.GetWeakPtr());
     delay_network_call_runner.Run(start_revoke_token);
@@ -171,17 +170,17 @@
 
 void AccountManager::Initialize(
     const base::FilePath& home_dir,
-    net::URLRequestContextGetter* request_context,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     DelayNetworkCallRunner delay_network_call_runner) {
   Initialize(
-      home_dir, request_context, std::move(delay_network_call_runner),
+      home_dir, url_loader_factory, std::move(delay_network_call_runner),
       base::CreateSequencedTaskRunnerWithTraits(
           {base::TaskShutdownBehavior::BLOCK_SHUTDOWN, base::MayBlock()}));
 }
 
 void AccountManager::Initialize(
     const base::FilePath& home_dir,
-    net::URLRequestContextGetter* request_context,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     DelayNetworkCallRunner delay_network_call_runner,
     scoped_refptr<base::SequencedTaskRunner> task_runner) {
   VLOG(1) << "AccountManager::Initialize";
@@ -197,7 +196,7 @@
   }
 
   init_state_ = InitializationState::kInProgress;
-  request_context_ = request_context;
+  url_loader_factory_ = url_loader_factory;
   delay_network_call_runner_ = std::move(delay_network_call_runner);
   task_runner_ = task_runner;
   writer_ = std::make_unique<base::ImportantFileWriter>(
@@ -342,17 +341,6 @@
   observers_.RemoveObserver(observer);
 }
 
-net::URLRequestContextGetter* AccountManager::GetUrlRequestContext() {
-  // LSTs on Chrome are not channel/token bound for now and hence we can use
-  // the system request context.
-  // Note that we cannot use the Profile's request context since
-  // |AccountManager| acts outside the scope of Profiles.
-  // TODO(sinhak): Create a new |URLRequestContext| for |AccountManager| which
-  // conforms to token binding when those details are finalized.
-  DCHECK(request_context_);
-  return request_context_;
-}
-
 std::unique_ptr<OAuth2AccessTokenFetcher>
 AccountManager::CreateAccessTokenFetcher(
     const AccountKey& account_key,
@@ -400,7 +388,7 @@
 
   pending_token_revocation_requests_.emplace_back(
       std::make_unique<GaiaTokenRevocationRequest>(
-          GetUrlRequestContext(), delay_network_call_runner_, refresh_token,
+          url_loader_factory_, delay_network_call_runner_, refresh_token,
           weak_factory_.GetWeakPtr()));
 }
 
diff --git a/chromeos/account_manager/account_manager.h b/chromeos/account_manager/account_manager.h
index 1cd8aafe..85ecb93a 100644
--- a/chromeos/account_manager/account_manager.h
+++ b/chromeos/account_manager/account_manager.h
@@ -31,10 +31,6 @@
 class ImportantFileWriter;
 }  // namespace base
 
-namespace net {
-class URLRequestContextGetter;
-}
-
 namespace network {
 class SharedURLLoaderFactory;
 }
@@ -101,9 +97,10 @@
   // |chromeos::DelayNetworkCall|. Cannot use |chromeos::DelayNetworkCall| due
   // to linking/dependency constraints.
   // This method MUST be called at least once in the lifetime of AccountManager.
-  void Initialize(const base::FilePath& home_dir,
-                  net::URLRequestContextGetter* request_context,
-                  DelayNetworkCallRunner delay_network_call_runner);
+  void Initialize(
+      const base::FilePath& home_dir,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      DelayNetworkCallRunner delay_network_call_runner);
 
   // Gets (async) a list of account keys known to |AccountManager|.
   void GetAccounts(AccountListCallback callback);
@@ -128,9 +125,6 @@
   // not in the list of known observers.
   void RemoveObserver(Observer* observer);
 
-  // Gets AccountManager's URL Request Context.
-  net::URLRequestContextGetter* GetUrlRequestContext();
-
   // Creates and returns an |OAuth2AccessTokenFetcher| using the refresh token
   // stored for |account_key|. |IsTokenAvailable| should be |true| for
   // |account_key|, otherwise a |nullptr| is returned.
@@ -161,10 +155,11 @@
   FRIEND_TEST_ALL_PREFIXES(AccountManagerTest, TestInitialization);
 
   // Same as the public |Initialize| except for a |task_runner|.
-  void Initialize(const base::FilePath& home_dir,
-                  net::URLRequestContextGetter* request_context,
-                  DelayNetworkCallRunner delay_network_call_runner,
-                  scoped_refptr<base::SequencedTaskRunner> task_runner);
+  void Initialize(
+      const base::FilePath& home_dir,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      DelayNetworkCallRunner delay_network_call_runner,
+      scoped_refptr<base::SequencedTaskRunner> task_runner);
 
   // Reads tokens from |tokens| and inserts them in |tokens_| and runs all
   // callbacks waiting on |AccountManager| initialization.
@@ -216,9 +211,8 @@
   // Status of this object's initialization.
   InitializationState init_state_ = InitializationState::kNotStarted;
 
-  // All tokens, if channel bound, are bound to |request_context_|. This is a
-  // non-owning pointer.
-  net::URLRequestContextGetter* request_context_ = nullptr;
+  // All tokens, if channel bound, are bound to |url_loader_factory_|.
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
 
   // An indirect way to access |chromeos::DelayNetworkCall|. We cannot use
   // |chromeos::DelayNetworkCall| directly here due to linking/dependency
diff --git a/chromeos/account_manager/account_manager_unittest.cc b/chromeos/account_manager/account_manager_unittest.cc
index 308938d4..de36346 100644
--- a/chromeos/account_manager/account_manager_unittest.cc
+++ b/chromeos/account_manager/account_manager_unittest.cc
@@ -16,7 +16,8 @@
 #include "base/run_loop.h"
 #include "base/test/scoped_task_environment.h"
 #include "base/threading/sequenced_task_runner_handle.h"
-#include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -37,17 +38,20 @@
 
 class AccountManagerTest : public testing::Test {
  public:
-  AccountManagerTest() = default;
+  AccountManagerTest()
+      : test_shared_loader_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_)) {}
   ~AccountManagerTest() override {}
 
  protected:
   void SetUp() override {
     ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
-    request_context_ = new net::TestURLRequestContextGetter(
-        scoped_task_environment_.GetMainThreadTaskRunner());
     ResetAndInitializeAccountManager();
   }
 
+  void TearDown() override { test_shared_loader_factory_->Detach(); }
+
   // Gets the list of accounts stored in |account_manager_|.
   std::vector<AccountManager::AccountKey> GetAccountsBlocking() {
     std::vector<AccountManager::AccountKey> accounts;
@@ -70,16 +74,20 @@
   // parameters.
   void ResetAndInitializeAccountManager() {
     account_manager_ = std::make_unique<AccountManagerSpy>();
-    account_manager_->Initialize(tmp_dir_.GetPath(), request_context_.get(),
-                                 immediate_callback_runner_,
-                                 base::SequencedTaskRunnerHandle::Get());
+    account_manager_->Initialize(
+        tmp_dir_.GetPath(), test_shared_loader_factory_,
+        immediate_callback_runner_, base::SequencedTaskRunnerHandle::Get());
   }
 
   // Check base/test/scoped_task_environment.h. This must be the first member /
   // declared before any member that cares about tasks.
   base::test::ScopedTaskEnvironment scoped_task_environment_;
   base::ScopedTempDir tmp_dir_;
-  scoped_refptr<net::URLRequestContextGetter> request_context_;
+
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
+      test_shared_loader_factory_;
+
   std::unique_ptr<AccountManagerSpy> account_manager_;
   const AccountManager::AccountKey kAccountKey_{
       "111", account_manager::AccountType::ACCOUNT_TYPE_GAIA};
@@ -134,7 +142,7 @@
 
   EXPECT_EQ(account_manager.init_state_,
             AccountManager::InitializationState::kNotStarted);
-  account_manager.Initialize(tmp_dir_.GetPath(), request_context_.get(),
+  account_manager.Initialize(tmp_dir_.GetPath(), test_shared_loader_factory_,
                              immediate_callback_runner_,
                              base::SequencedTaskRunnerHandle::Get());
   scoped_task_environment_.RunUntilIdle();
diff --git a/chromeos/login/auth/login_performer.h b/chromeos/login/auth/login_performer.h
index fce862a..2478b31 100644
--- a/chromeos/login/auth/login_performer.h
+++ b/chromeos/login/auth/login_performer.h
@@ -10,6 +10,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "chromeos/chromeos_export.h"
 #include "chromeos/login/auth/auth_status_consumer.h"
@@ -24,8 +25,8 @@
 class TaskRunner;
 }
 
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
 }
 
 namespace content {
@@ -170,8 +171,9 @@
   // Look up browser context to use during signin.
   virtual content::BrowserContext* GetSigninContext() = 0;
 
-  // Get RequestContext used for sign in.
-  virtual net::URLRequestContextGetter* GetSigninRequestContext() = 0;
+  // Gets the SharedURLLoaderFactory used for sign in.
+  virtual scoped_refptr<network::SharedURLLoaderFactory>
+  GetSigninURLLoaderFactory() = 0;
 
   // Create authenticator implementation.
   virtual scoped_refptr<Authenticator> CreateAuthenticator() = 0;
diff --git a/components/autofill/content/renderer/form_tracker.cc b/components/autofill/content/renderer/form_tracker.cc
index 827c689d..f5d12ffb 100644
--- a/components/autofill/content/renderer/form_tracker.cc
+++ b/components/autofill/content/renderer/form_tracker.cc
@@ -186,12 +186,8 @@
   // (i.e. DidStartProvisionalLoad is called twice in this case).  The check for
   // kWebNavigationTypeLinkClicked is reliable only for content initiated
   // navigations.
-  // Don't handle kWebNavigationTypeFormSubmitted here, it is handled in
-  // WillSubmitForm().
   if (navigation_state->IsContentInitiated() &&
       document_loader->GetNavigationType() !=
-          blink::kWebNavigationTypeFormSubmitted &&
-      document_loader->GetNavigationType() !=
           blink::kWebNavigationTypeLinkClicked) {
     FireProbablyFormSubmitted();
   }
diff --git a/components/autofill/content/renderer/password_autofill_agent.cc b/components/autofill/content/renderer/password_autofill_agent.cc
index d58f611c..e0273b7 100644
--- a/components/autofill/content/renderer/password_autofill_agent.cc
+++ b/components/autofill/content/renderer/password_autofill_agent.cc
@@ -1077,12 +1077,6 @@
   return frame->GetSecurityOrigin().CanAccessPasswordManager();
 }
 
-bool PasswordAutofillAgent::
-    FrameCanAccessPasswordManagerWithoutAboutBlankCheck() {
-  blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
-  return frame->GetSecurityOrigin().CanAccessPasswordManager();
-}
-
 void PasswordAutofillAgent::OnDynamicFormsSeen() {
   SendPasswordForms(false /* only_visible */);
 }
@@ -1328,8 +1322,7 @@
           PasswordForm::SubmissionIndicatorEvent::HTML_FORM_SUBMISSION;
     }
 
-    if (FrameCanAccessPasswordManagerWithoutAboutBlankCheck() &&
-        !submitted_form->origin.IsAboutBlank()) {
+    if (FrameCanAccessPasswordManager()) {
       // Some observers depend on sending this information now instead of when
       // the frame starts loading. If there are redirects that cause a new
       // RenderView to be instantiated (such as redirects to the WebStore)
diff --git a/components/autofill/content/renderer/password_autofill_agent.h b/components/autofill/content/renderer/password_autofill_agent.h
index 2985ce8..48bd341 100644
--- a/components/autofill/content/renderer/password_autofill_agent.h
+++ b/components/autofill/content/renderer/password_autofill_agent.h
@@ -186,12 +186,6 @@
   // unique origins aren't allowed access.
   virtual bool FrameCanAccessPasswordManager();
 
-  // Determine whether the current frame is allowed to access the password
-  // manager without an additional check for about:blank. There is a valid
-  // usecase for about:blank iframe where a website POSTs a form to the empty
-  // iframe from the main frame.
-  virtual bool FrameCanAccessPasswordManagerWithoutAboutBlankCheck();
-
  private:
   // Ways to restrict which passwords are saved in ProvisionallySavePassword.
   enum ProvisionallySaveRestriction {
diff --git a/components/autofill/content/renderer/test_password_autofill_agent.cc b/components/autofill/content/renderer/test_password_autofill_agent.cc
index 1f331cf..560bbbc 100644
--- a/components/autofill/content/renderer/test_password_autofill_agent.cc
+++ b/components/autofill/content/renderer/test_password_autofill_agent.cc
@@ -17,9 +17,4 @@
   return true;
 }
 
-bool TestPasswordAutofillAgent::
-    FrameCanAccessPasswordManagerWithoutAboutBlankCheck() {
-  return true;
-}
-
 }  // namespace autofill
diff --git a/components/autofill/content/renderer/test_password_autofill_agent.h b/components/autofill/content/renderer/test_password_autofill_agent.h
index 28fe227..2f4add1 100644
--- a/components/autofill/content/renderer/test_password_autofill_agent.h
+++ b/components/autofill/content/renderer/test_password_autofill_agent.h
@@ -20,8 +20,6 @@
   // work with the password manager.
   // PasswordAutofillAgent:
   bool FrameCanAccessPasswordManager() override;
-
-  bool FrameCanAccessPasswordManagerWithoutAboutBlankCheck() override;
 };
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/autofill_profile.cc b/components/autofill/core/browser/autofill_profile.cc
index f96dba386..ede6790 100644
--- a/components/autofill/core/browser/autofill_profile.cc
+++ b/components/autofill/core/browser/autofill_profile.cc
@@ -36,6 +36,7 @@
 #include "components/autofill/core/browser/state_names.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/autofill_l10n_util.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/strings/grit/components_strings.h"
diff --git a/components/autofill/core/browser/autofill_profile_unittest.cc b/components/autofill/core/browser/autofill_profile_unittest.cc
index 2689031..276979c8 100644
--- a/components/autofill/core/browser/autofill_profile_unittest.cc
+++ b/components/autofill/core/browser/autofill_profile_unittest.cc
@@ -60,14 +60,14 @@
 // Based on existence of first name, last name, and address line 1.
 TEST(AutofillProfileTest, PreviewSummaryString) {
   // Case 0/null: ""
-  AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
   // Empty profile - nothing to update.
   base::string16 summary0 = GetLabel(&profile0);
   EXPECT_EQ(base::string16(), summary0);
 
   // Case 0a/empty name and address, so the first two fields of the rest of the
   // data is used: "Hollywood, CA"
-  AutofillProfile profile00(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile00(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile00, "", "", "",
       "johnwayne@me.xyz", "Fox", "", "", "Hollywood", "CA", "91601", "US",
       "16505678910");
@@ -75,7 +75,7 @@
   EXPECT_EQ(ASCIIToUTF16("Hollywood, CA"), summary00);
 
   // Case 1: "<address>" without line 2.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "", "", "",
       "johnwayne@me.xyz", "Fox", "123 Zoo St.", "", "Hollywood", "CA",
       "91601", "US", "16505678910");
@@ -83,7 +83,7 @@
   EXPECT_EQ(ASCIIToUTF16("123 Zoo St., Hollywood"), summary1);
 
   // Case 1a: "<address>" with line 2.
-  AutofillProfile profile1a(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile1a(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1a, "", "", "",
       "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
       "91601", "US", "16505678910");
@@ -91,7 +91,7 @@
   EXPECT_EQ(ASCIIToUTF16("123 Zoo St., unit 5"), summary1a);
 
   // Case 2: "<lastname>"
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "", "Mitchell",
       "Morrison", "johnwayne@me.xyz", "Fox", "", "", "Hollywood", "CA",
       "91601", "US", "16505678910");
@@ -100,7 +100,7 @@
   EXPECT_EQ(ASCIIToUTF16("Mitchell Morrison, Hollywood"), summary2);
 
   // Case 3: "<lastname>, <address>"
-  AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile3, "", "Mitchell",
       "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "",
       "Hollywood", "CA", "91601", "US", "16505678910");
@@ -108,7 +108,7 @@
   EXPECT_EQ(ASCIIToUTF16("Mitchell Morrison, 123 Zoo St."), summary3);
 
   // Case 4: "<firstname>"
-  AutofillProfile profile4(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile4, "Marion", "Mitchell", "",
       "johnwayne@me.xyz", "Fox", "", "", "Hollywood", "CA", "91601", "US",
       "16505678910");
@@ -116,7 +116,7 @@
   EXPECT_EQ(ASCIIToUTF16("Marion Mitchell, Hollywood"), summary4);
 
   // Case 5: "<firstname>, <address>"
-  AutofillProfile profile5(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile5(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile5, "Marion", "Mitchell", "",
       "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5", "Hollywood", "CA",
       "91601", "US", "16505678910");
@@ -124,7 +124,7 @@
   EXPECT_EQ(ASCIIToUTF16("Marion Mitchell, 123 Zoo St."), summary5);
 
   // Case 6: "<firstname> <lastname>"
-  AutofillProfile profile6(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile6(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile6, "Marion", "Mitchell",
       "Morrison", "johnwayne@me.xyz", "Fox", "", "", "Hollywood", "CA",
       "91601", "US", "16505678910");
@@ -133,7 +133,7 @@
             summary6);
 
   // Case 7: "<firstname> <lastname>, <address>"
-  AutofillProfile profile7(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile7(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile7, "Marion", "Mitchell",
       "Morrison", "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
       "Hollywood", "CA", "91601", "US", "16505678910");
@@ -142,7 +142,7 @@
 
   // Case 7a: "<firstname> <lastname>, <address>" - same as #7, except for
   // e-mail.
-  AutofillProfile profile7a(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile7a(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile7a, "Marion", "Mitchell",
     "Morrison", "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
     "Hollywood", "CA", "91601", "US", "16505678910");
@@ -162,8 +162,8 @@
 
 TEST(AutofillProfileTest, AdjustInferredLabels) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[0].get(), "John", "", "Doe",
                        "johndoe@hades.com", "Underworld", "666 Erebus St.", "",
                        "Elysium", "CA", "91111", "US", "16502111111");
@@ -215,8 +215,8 @@
   EXPECT_EQ(ASCIIToUTF16("Jane Doe, 123 Letha Shore."), labels[1]);
   EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., CO"), labels[2]);
 
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[3].get(), "John", "", "Doe",
                        "johndoe@hades.com", "Underworld", "666 Erebus St.", "",
                        "Elysium", "CO",  // State is different for some.
@@ -236,8 +236,8 @@
   EXPECT_EQ(ASCIIToUTF16("John Doe, 666 Erebus St., CO, 16504444444"),
             labels[3]);
 
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[4].get(), "John", "", "Doe",
                        "johndoe@styx.com",  // E-Mail is different for some.
                        "Underworld", "666 Erebus St.", "", "Elysium",
@@ -263,8 +263,8 @@
 
 TEST(AutofillProfileTest, CreateInferredLabelsI18n_CH) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles.back().get(), "H.", "R.", "Giger",
                        "hrgiger@beispiel.com", "Beispiel Inc",
                        "Brandschenkestrasse 110", "", "Zurich", "", "8002",
@@ -297,8 +297,8 @@
 
 TEST(AutofillProfileTest, CreateInferredLabelsI18n_FR) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles.back().get(), "Antoine", "", "de Saint-Exupéry",
                        "antoine@exemple.com", "Exemple Inc", "8 Rue de Londres",
                        "", "Paris", "", "75009", "FR", "+33 (0) 1 42 68 53 00");
@@ -335,8 +335,8 @@
 
 TEST(AutofillProfileTest, CreateInferredLabelsI18n_KR) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles.back().get(), "Park", "", "Jae-sang",
                        "park@yeleul.com", "Yeleul Inc",
                        "Gangnam Finance Center", "152 Teheran-ro", "Gangnam-Gu",
@@ -379,8 +379,8 @@
 
 TEST(AutofillProfileTest, CreateInferredLabelsI18n_JP_Latn) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles.back().get(), "Miku", "", "Hatsune",
                        "miku@rei.com", "Rei Inc", "Roppongi Hills Mori Tower",
                        "6-10-1 Roppongi", "Minato-ku", "Tokyo", "106-6126",
@@ -417,8 +417,8 @@
 
 TEST(AutofillProfileTest, CreateInferredLabelsI18n_JP_ja) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles.back().get(), "ミク", "", "初音",
                        "miku@rei.com", "例", "六本木ヒルズ森タワー",
                        "六本木 6-10-1", "港区", "東京都", "106-6126", "JP",
@@ -451,13 +451,13 @@
 
 TEST(AutofillProfileTest, CreateInferredLabels) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[0].get(), "John", "", "Doe",
                        "johndoe@hades.com", "Underworld", "666 Erebus St.", "",
                        "Elysium", "CA", "91111", "US", "16502111111");
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[1].get(), "Jane", "", "Doe",
                        "janedoe@tertium.com", "Pluto Inc.", "123 Letha Shore.",
                        "", "Dis", "CA", "91222", "US", "12345678910");
@@ -554,12 +554,12 @@
 // distinguishing fields, but only if it makes sense given the suggested fields.
 TEST(AutofillProfileTest, CreateInferredLabelsFallsBackToFullName) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[0].get(), "John", "", "Doe", "doe@example.com",
                        "", "88 Nowhere Ave.", "", "", "", "", "", "");
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[1].get(), "Johnny", "K", "Doe",
                        "doe@example.com", "", "88 Nowhere Ave.", "", "", "", "",
                        "", "");
@@ -591,12 +591,12 @@
 // Test that we do not show duplicate fields in the labels.
 TEST(AutofillProfileTest, CreateInferredLabelsNoDuplicatedFields) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[0].get(), "John", "", "Doe", "doe@example.com",
                        "", "88 Nowhere Ave.", "", "", "", "", "", "");
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[1].get(), "John", "", "Doe", "dojo@example.com",
                        "", "88 Nowhere Ave.", "", "", "", "", "", "");
 
@@ -618,16 +618,16 @@
 // Make sure that empty fields are not treated as distinguishing fields.
 TEST(AutofillProfileTest, CreateInferredLabelsSkipsEmptyFields) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[0].get(), "John", "", "Doe", "doe@example.com",
                        "Gogole", "", "", "", "", "", "", "");
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[1].get(), "John", "", "Doe", "doe@example.com",
                        "Ggoole", "", "", "", "", "", "", "");
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[2].get(), "John", "", "Doe",
                        "john.doe@example.com", "Goolge", "", "", "", "", "", "",
                        "");
@@ -655,8 +655,8 @@
 // Test that labels that would otherwise have multiline values are flattened.
 TEST(AutofillProfileTest, CreateInferredLabelsFlattensMultiLineValues) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles;
-  profiles.push_back(std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com/"));
+  profiles.push_back(std::make_unique<AutofillProfile>(base::GenerateGUID(),
+                                                       test::kEmptyOrigin));
   test::SetProfileInfo(profiles[0].get(), "John", "", "Doe", "doe@example.com",
                        "", "88 Nowhere Ave.", "Apt. 42", "", "", "", "", "");
 
@@ -677,10 +677,8 @@
   std::unique_ptr<AutofillProfile> a, b;
 
   // |a| is a subset of |b|.
-  a.reset(
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com/"));
-  b.reset(
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com/"));
+  a.reset(new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin));
+  b.reset(new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin));
   test::SetProfileInfo(a.get(), "Thomas", nullptr, "Jefferson",
                        "declaration_guy@gmail.com", nullptr, nullptr, nullptr,
                        nullptr, nullptr, nullptr, nullptr, nullptr);
@@ -697,10 +695,8 @@
   EXPECT_TRUE(a->IsSubsetOf(*a, "en-US"));
 
   // One field in |b| is different.
-  a.reset(
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com/"));
-  b.reset(
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com/"));
+  a.reset(new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin));
+  b.reset(new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin));
   test::SetProfileInfo(a.get(), "Thomas", nullptr, "Jefferson",
                        "declaration_guy@gmail.com", nullptr, nullptr, nullptr,
                        nullptr, nullptr, nullptr, nullptr, nullptr);
@@ -797,14 +793,14 @@
 }
 
 TEST(AutofillProfileTest, AssignmentOperator) {
-  AutofillProfile a(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile a(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&a, "Marion", "Mitchell", "Morrison",
                        "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
                        "Hollywood", "CA", "91601", "US",
                        "12345678910");
 
   // Result of assignment should be logically equal to the original profile.
-  AutofillProfile b(base::GenerateGUID(), "http://www.example.com/");
+  AutofillProfile b(base::GenerateGUID(), test::kEmptyOrigin);
   b = a;
   EXPECT_TRUE(a == b);
 
@@ -814,7 +810,7 @@
 }
 
 TEST(AutofillProfileTest, Copy) {
-  AutofillProfile a(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile a(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&a, "Marion", "Mitchell", "Morrison",
                        "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
                        "Hollywood", "CA", "91601", "US",
@@ -875,7 +871,7 @@
 }
 
 TEST(AutofillProfileTest, IsPresentButInvalid) {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
   EXPECT_FALSE(profile.IsPresentButInvalid(ADDRESS_HOME_STATE));
   EXPECT_FALSE(profile.IsPresentButInvalid(ADDRESS_HOME_ZIP));
   EXPECT_FALSE(profile.IsPresentButInvalid(PHONE_HOME_WHOLE_NUMBER));
@@ -905,7 +901,7 @@
 }
 
 TEST(AutofillProfileTest, SetRawInfoPreservesLineBreaks) {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
 
   profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
                      ASCIIToUTF16("123 Super St.\n"
@@ -916,7 +912,7 @@
 }
 
 TEST(AutofillProfileTest, SetInfoPreservesLineBreaks) {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
 
   profile.SetInfo(ADDRESS_HOME_STREET_ADDRESS,
                   ASCIIToUTF16("123 Super St.\n"
@@ -928,7 +924,7 @@
 }
 
 TEST(AutofillProfileTest, SetRawInfoDoesntTrimWhitespace) {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
 
   profile.SetRawInfo(EMAIL_ADDRESS, ASCIIToUTF16("\tuser@example.com    "));
   EXPECT_EQ(ASCIIToUTF16("\tuser@example.com    "),
@@ -936,7 +932,7 @@
 }
 
 TEST(AutofillProfileTest, SetInfoTrimsWhitespace) {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
 
   profile.SetInfo(EMAIL_ADDRESS, ASCIIToUTF16("\tuser@example.com    "),
                   "en-US");
@@ -945,7 +941,7 @@
 }
 
 TEST(AutofillProfileTest, FullAddress) {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
                        "marion@me.xyz", "Fox", "123 Zoo St.", "unit 5",
                        "Hollywood", "CA", "91601", "US",
diff --git a/components/autofill/core/browser/autofill_test_utils.cc b/components/autofill/core/browser/autofill_test_utils.cc
index 623cfe2..fcb9fa9 100644
--- a/components/autofill/core/browser/autofill_test_utils.cc
+++ b/components/autofill/core/browser/autofill_test_utils.cc
@@ -200,7 +200,7 @@
 }
 
 AutofillProfile GetFullValidProfileForCanada() {
-  AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
   SetProfileInfo(&profile, "Alice", "", "Wonderland", "alice@wonderland.ca",
                  "Fiction", "666 Notre-Dame Ouest", "Apt 8", "Montreal", "QC",
                  "H3B 2T9", "CA", "15141112233");
@@ -208,7 +208,7 @@
 }
 
 AutofillProfile GetFullValidProfileForChina() {
-  AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
   SetProfileInfo(&profile, "John", "H.", "Doe", "johndoe@google.cn", "Google",
                  "100 Century Avenue", "", "赫章县", "毕节地区", "贵州省",
                  "200120", "CN", "+86-21-6133-7666");
@@ -216,7 +216,7 @@
 }
 
 AutofillProfile GetFullProfile() {
-  AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
   SetProfileInfo(&profile,
                  "John",
                  "H.",
@@ -233,7 +233,7 @@
 }
 
 AutofillProfile GetFullProfile2() {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
   SetProfileInfo(&profile,
                  "Jane",
                  "A.",
@@ -250,7 +250,7 @@
 }
 
 AutofillProfile GetFullCanadianProfile() {
-  AutofillProfile profile(base::GenerateGUID(), "http://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
   SetProfileInfo(&profile, "Wayne", "", "Gretzky", "wayne@hockey.com", "NHL",
                  "123 Hockey rd.", "Apt 8", "Moncton", "New Brunswick",
                  "E1A 0A6", "CA", "15068531212");
@@ -258,7 +258,7 @@
 }
 
 AutofillProfile GetIncompleteProfile1() {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
   SetProfileInfo(&profile, "John", "H.", "Doe", "jsmith@example.com", "ACME",
                  "123 Main Street", "Unit 1", "Greensdale", "MI", "48838", "US",
                  "");
@@ -266,7 +266,7 @@
 }
 
 AutofillProfile GetIncompleteProfile2() {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com/");
+  AutofillProfile profile(base::GenerateGUID(), kEmptyOrigin);
   SetProfileInfo(&profile, "", "", "", "jsmith@example.com", "", "", "", "", "",
                  "", "", "");
   return profile;
@@ -285,14 +285,14 @@
 }
 
 CreditCard GetCreditCard() {
-  CreditCard credit_card(base::GenerateGUID(), "http://www.example.com");
+  CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin);
   SetCreditCardInfo(&credit_card, "Test User", "4111111111111111" /* Visa */,
                     "11", "2022", "1");
   return credit_card;
 }
 
 CreditCard GetCreditCard2() {
-  CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card(base::GenerateGUID(), kEmptyOrigin);
   SetCreditCardInfo(&credit_card, "Someone Else", "378282246310005" /* AmEx */,
                     "07", "2022", "1");
   return credit_card;
@@ -345,7 +345,7 @@
 
   CreditCard credit_card =
       (record_type == CreditCard::LOCAL_CARD)
-          ? CreditCard(base::GenerateGUID(), "http://www.example.com")
+          ? CreditCard(base::GenerateGUID(), kEmptyOrigin)
           : CreditCard(record_type, base::GenerateGUID().substr(24));
   test::SetCreditCardInfo(
       &credit_card, "Justin Thyme", GetRandomCardNumber().c_str(),
diff --git a/components/autofill/core/browser/autofill_test_utils.h b/components/autofill/core/browser/autofill_test_utils.h
index b512755..80af947 100644
--- a/components/autofill/core/browser/autofill_test_utils.h
+++ b/components/autofill/core/browser/autofill_test_utils.h
@@ -30,6 +30,8 @@
 // Common utilities shared amongst Autofill tests.
 namespace test {
 
+const char kEmptyOrigin[] = "";
+
 // The following methods return a PrefService that can be used for
 // Autofill-related testing in contexts where the PrefService would otherwise
 // have to be constructed manually (e.g., in unit tests within Autofill core
diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc
index d342a509..70f44e2 100644
--- a/components/autofill/core/browser/credit_card.cc
+++ b/components/autofill/core/browser/credit_card.cc
@@ -33,6 +33,7 @@
 #include "components/autofill/core/browser/autofill_type.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/autofill_regexes.h"
 #include "components/autofill/core/common/form_field_data.h"
 #include "components/grit/components_scaled_resources.h"
diff --git a/components/autofill/core/browser/credit_card_unittest.cc b/components/autofill/core/browser/credit_card_unittest.cc
index 53095cf8..4503172 100644
--- a/components/autofill/core/browser/credit_card_unittest.cc
+++ b/components/autofill/core/browser/credit_card_unittest.cc
@@ -219,18 +219,18 @@
 }
 
 TEST(CreditCardTest, AssignmentOperator) {
-  CreditCard a(base::GenerateGUID(), "some origin");
+  CreditCard a(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&a, "John Dillinger", "123456789012", "01", "2010",
                           "1");
 
   // Result of assignment should be logically equal to the original profile.
-  CreditCard b(base::GenerateGUID(), "some other origin");
+  CreditCard b(base::GenerateGUID(), test::kEmptyOrigin);
   b = a;
-  EXPECT_TRUE(a == b);
+  EXPECT_EQ(a, b);
 
   // Assignment to self should not change the profile value.
   a = *&a;  // The *& defeats Clang's -Wself-assign warning.
-  EXPECT_TRUE(a == b);
+  EXPECT_EQ(a, b);
 }
 
 struct SetExpirationYearFromStringTestCase {
@@ -318,7 +318,7 @@
         SetExpirationDateFromStringTestCase{"05_2045", 0, 0}));
 
 TEST(CreditCardTest, Copy) {
-  CreditCard a(base::GenerateGUID(), "https://www.example.com");
+  CreditCard a(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&a, "John Dillinger", "123456789012", "01", "2010",
                           base::GenerateGUID());
 
@@ -496,7 +496,7 @@
 }
 
 TEST(CreditCardTest, UpdateFromImportedCard) {
-  CreditCard original_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard original_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&original_card, "John Dillinger", "123456789012",
                           "09", "2017", "1");
 
@@ -505,14 +505,14 @@
   // The new card has a different name, expiration date, and origin.
   CreditCard b = a;
   b.set_guid(base::GenerateGUID());
-  b.set_origin("https://www.example.org");
+  b.set_origin(test::kEmptyOrigin);
   b.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("J. Dillinger"));
   b.SetRawInfo(CREDIT_CARD_EXP_MONTH, ASCIIToUTF16("08"));
   b.SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, ASCIIToUTF16("2019"));
 
   // |a| should be updated with the information from |b|.
   EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
-  EXPECT_EQ("https://www.example.org", a.origin());
+  EXPECT_EQ(test::kEmptyOrigin, a.origin());
   EXPECT_EQ(ASCIIToUTF16("J. Dillinger"), a.GetRawInfo(CREDIT_CARD_NAME_FULL));
   EXPECT_EQ(ASCIIToUTF16("08"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
   EXPECT_EQ(ASCIIToUTF16("2019"), a.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR));
@@ -524,7 +524,7 @@
   b.SetRawInfo(CREDIT_CARD_NAME_FULL, base::string16());
 
   EXPECT_TRUE(a.UpdateFromImportedCard(b, "en-US"));
-  EXPECT_EQ("https://www.example.org", a.origin());
+  EXPECT_EQ(test::kEmptyOrigin, a.origin());
   EXPECT_EQ(ASCIIToUTF16("John Dillinger"),
             a.GetRawInfo(CREDIT_CARD_NAME_FULL));
   EXPECT_EQ(ASCIIToUTF16("08"), a.GetRawInfo(CREDIT_CARD_EXP_MONTH));
diff --git a/components/autofill/core/browser/form_data_importer.cc b/components/autofill/core/browser/form_data_importer.cc
index d6cb0c5..43420f2 100644
--- a/components/autofill/core/browser/form_data_importer.cc
+++ b/components/autofill/core/browser/form_data_importer.cc
@@ -226,7 +226,6 @@
   // The candidate for profile import. There are many ways for the candidate to
   // be rejected (see everywhere this function returns false).
   AutofillProfile candidate_profile;
-  candidate_profile.set_origin(form.source_url().spec());
 
   // We only set complete phone, so aggregate phone parts in these vars and set
   // complete at the end.
@@ -413,7 +412,6 @@
   *has_duplicate_field_type = false;
 
   CreditCard candidate_credit_card;
-  candidate_credit_card.set_origin(form.source_url().spec());
 
   std::set<ServerFieldType> types_seen;
   for (const auto& field : form) {
diff --git a/components/autofill/core/browser/form_data_importer_unittest.cc b/components/autofill/core/browser/form_data_importer_unittest.cc
index 9001c9f9..d1f7062 100644
--- a/components/autofill/core/browser/form_data_importer_unittest.cc
+++ b/components/autofill/core/browser/form_data_importer_unittest.cc
@@ -196,7 +196,7 @@
         .WillOnce(QuitMessageLoop(&run_loop));
     run_loop.Run();
 
-    CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+    CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
     test::SetCreditCardInfo(&expected, exp_name, exp_cc_num, exp_cc_month,
                             exp_cc_year, "");
     const std::vector<CreditCard*>& results =
@@ -300,7 +300,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected, "George", nullptr, "Washington",
                        "theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
                        "San Francisco", "California", "94102", nullptr,
@@ -540,7 +540,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr,
                        nullptr, "21 Laussat St", nullptr, "San Francisco",
                        "California", "94102", nullptr, "(650) 555-0000");
@@ -580,7 +580,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected, "George", nullptr, "Washington",
                        "theprez@gmail.com", nullptr, "21 Laussat St",
                        "Apt. #42", "San Francisco", "California", "94102",
@@ -621,7 +621,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected, "George", nullptr, "Washington",
                        "theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
                        "San Francisco", "California", "94102", nullptr,
@@ -658,7 +658,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  AutofillProfile expected2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected2, "John", nullptr, "Adams", "second@gmail.com",
                        nullptr, "22 Laussat St", nullptr, "San Francisco",
                        "California", "94102", nullptr, nullptr);
@@ -716,12 +716,12 @@
 
   WaitForOnPersonalDataChanged();
 
-  AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected, "George", nullptr, "Washington",
                        "theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
                        "San Francisco", "California", "94102", nullptr,
                        nullptr);
-  AutofillProfile expected2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected2, "John", nullptr, "Adams", "second@gmail.com",
                        nullptr, "22 Laussat St", nullptr, "San Francisco",
                        "California", "94102", nullptr, nullptr);
@@ -791,7 +791,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected, "George", nullptr, "Washington",
                        "theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
                        "San Francisco", "California", "94102", nullptr,
@@ -875,12 +875,12 @@
   WaitForOnPersonalDataChanged();
 
   // Only two are saved.
-  AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected, "George", nullptr, "Washington",
                        "theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
                        "San Francisco", "California", "94102", nullptr,
                        nullptr);
-  AutofillProfile expected2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected2, "John", nullptr, "Adams", "second@gmail.com",
                        nullptr, "22 Laussat St", nullptr, "San Francisco",
                        "California", "94102", nullptr, nullptr);
@@ -929,7 +929,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected, "George", nullptr, "Washington",
                        "theprez@gmail.com", nullptr, "1600 Pennsylvania Avenue",
                        "Suite A", "San Francisco", "California", "94102",
@@ -1014,7 +1014,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected, "George", nullptr, "Washington", nullptr,
                        nullptr, "190 High Street", nullptr, "Philadelphia",
                        "Pennsylvania", "19106", nullptr, nullptr);
@@ -1054,7 +1054,7 @@
   const std::vector<AutofillProfile*>& results2 =
       personal_data_manager_->GetProfiles();
 
-  AutofillProfile expected2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected2, "George", nullptr, "Washington",
                        "theprez@gmail.com", nullptr, "190 High Street", nullptr,
                        "Philadelphia", "Pennsylvania", "19106", nullptr,
@@ -1096,7 +1096,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected, "George", nullptr, "Washington",
                        "theprez@gmail.com", "Government", "190 High Street",
                        nullptr, "Philadelphia", "Pennsylvania", "19106",
@@ -1327,7 +1327,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  AutofillProfile expected(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected, "George", nullptr, "Washington",
                        "theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
                        "San Francisco", "California", "94102", "MM", nullptr);
@@ -1404,7 +1404,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
                           "2999", "");  // Imported cards have no billing info.
   const std::vector<CreditCard*>& results =
@@ -1495,7 +1495,7 @@
   WaitForOnPersonalDataChanged();
 
   // See that the invalid option text was converted to the right value.
-  CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "02",
                           "2999", "");  // Imported cards have no billing info.
   const std::vector<CreditCard*>& results =
@@ -1520,7 +1520,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
                           "2999", "");  // Imported cards have no billing info.
   const std::vector<CreditCard*>& results =
@@ -1542,7 +1542,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected2, "", "5500000000000004", "02", "2999",
                           "");  // Imported cards have no billing info.
   std::vector<CreditCard*> cards;
@@ -1705,7 +1705,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
                           "2998", "");  // Imported cards have no billing info.
   const std::vector<CreditCard*>& results =
@@ -1730,7 +1730,7 @@
 
   // Expect that the newer information is saved.  In this case the year is
   // updated to "2999".
-  CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
                           "2999", "");  // Imported cards have no billing info.
   const std::vector<CreditCard*>& results2 =
@@ -1755,7 +1755,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
                           "2998", "");  // Imported cards have no billing info.
   const std::vector<CreditCard*>& results =
@@ -1783,7 +1783,7 @@
 
   // Expect that the newer information is saved.  In this case the year is
   // updated to "2999".
-  CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
                           "2999", "");  // Imported cards have no billing info.
   const std::vector<CreditCard*>& results2 =
@@ -1808,7 +1808,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
                           "2998", "");  // Imported cards have no billing info.
   const std::vector<CreditCard*>& results =
@@ -1834,7 +1834,7 @@
   ResetPersonalDataManager(USER_MODE_NORMAL);
 
   // No change is expected.
-  CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
                           "2998", "");
   const std::vector<CreditCard*>& results2 =
@@ -1859,7 +1859,7 @@
 
   WaitForOnPersonalDataChanged();
 
-  CreditCard expected(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected, "Biggie Smalls", "4111111111111111", "01",
                           "2999", "");
   const std::vector<CreditCard*>& results =
@@ -1885,7 +1885,7 @@
   ResetPersonalDataManager(USER_MODE_NORMAL);
 
   // No change is expected.
-  CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
                           "2999", "");
   const std::vector<CreditCard*>& results2 =
@@ -1912,7 +1912,7 @@
   ResetPersonalDataManager(USER_MODE_NORMAL);
 
   // No change is expected.
-  CreditCard expected3(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected3, "Biggie Smalls", "4111111111111111", "01",
                           "2999", "");
   const std::vector<CreditCard*>& results3 =
@@ -1924,7 +1924,7 @@
 TEST_F(FormDataImporterTest, ImportCreditCard_MissingInfoInOld) {
   // Start with a single valid credit card stored via the preferences.
   // Note the empty name.
-  CreditCard saved_credit_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard saved_credit_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&saved_credit_card, "", "4111111111111111" /* Visa */,
                           "01", "2998", "1");
   personal_data_manager_->AddCreditCard(saved_credit_card);
@@ -1953,7 +1953,7 @@
 
   // Expect that the newer information is saved.  In this case the year is
   // added to the existing credit card.
-  CreditCard expected2(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected2, "Biggie Smalls", "4111111111111111", "01",
                           "2999", "1");
   const std::vector<CreditCard*>& results2 =
@@ -1967,7 +1967,7 @@
 TEST_F(FormDataImporterTest, ImportCreditCard_SameCardWithSeparators) {
   // Start with a single valid credit card stored via the preferences.
   // Note the separators in the credit card number.
-  CreditCard saved_credit_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard saved_credit_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&saved_credit_card, "Biggie Smalls",
                           "4111 1111 1111 1111" /* Visa */, "01", "2999", "");
   personal_data_manager_->AddCreditCard(saved_credit_card);
@@ -2047,7 +2047,7 @@
 TEST_F(FormDataImporterTest,
        ImportFormData_SecondImportResetsCreditCardRecordType) {
   // Start with a single valid credit card stored via the preferences.
-  CreditCard saved_credit_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard saved_credit_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&saved_credit_card, "Biggie Smalls",
                           "4111 1111 1111 1111" /* Visa */, "01", "2999", "");
   personal_data_manager_->AddCreditCard(saved_credit_card);
@@ -2164,7 +2164,7 @@
 TEST_F(FormDataImporterTest,
        ImportFormData_ImportCreditCardRecordType_LocalCard) {
   // Start with a single valid credit card stored via the preferences.
-  CreditCard saved_credit_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard saved_credit_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&saved_credit_card, "Biggie Smalls",
                           "4111 1111 1111 1111" /* Visa */, "01", "2999", "");
   personal_data_manager_->AddCreditCard(saved_credit_card);
@@ -2398,8 +2398,7 @@
   WaitForOnPersonalDataChanged();
 
   // Test that the address has been saved.
-  AutofillProfile expected_address(base::GenerateGUID(),
-                                   "https://www.example.com");
+  AutofillProfile expected_address(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected_address, "George", nullptr, "Washington",
                        "theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
                        "San Francisco", "California", "94102", nullptr,
@@ -2410,7 +2409,7 @@
   EXPECT_EQ(0, expected_address.Compare(*results_addr[0]));
 
   // Test that the credit card has also been saved.
-  CreditCard expected_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected_card, "Biggie Smalls", "4111111111111111",
                           "01", "2999", "");
   const std::vector<CreditCard*>& results_cards =
@@ -2481,7 +2480,7 @@
   EXPECT_EQ(2U, personal_data_manager_->GetProfiles().size());
 
   // Test that the credit card has been saved.
-  CreditCard expected_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected_card, "Biggie Smalls", "4111111111111111",
                           "01", "2999", "");
   const std::vector<CreditCard*>& results =
@@ -2536,7 +2535,7 @@
   EXPECT_EQ(0U, personal_data_manager_->GetProfiles().size());
 
   // Test that the credit card has been saved.
-  CreditCard expected_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard expected_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&expected_card, "Biggie Smalls", "4111111111111111",
                           "01", "2999", "");
   const std::vector<CreditCard*>& results =
@@ -2588,8 +2587,7 @@
   WaitForOnPersonalDataChanged();
 
   // Test that the address has been saved.
-  AutofillProfile expected_address(base::GenerateGUID(),
-                                   "https://www.example.com");
+  AutofillProfile expected_address(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&expected_address, "George", nullptr, "Washington",
                        "theprez@gmail.com", nullptr, "21 Laussat St", nullptr,
                        "San Francisco", "California", "94102", nullptr,
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index a73a8539..9ccf695 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -38,6 +38,7 @@
 #include "components/autofill/core/browser/phone_number_i18n.h"
 #include "components/autofill/core/browser/validation.h"
 #include "components/autofill/core/common/autofill_clock.h"
+#include "components/autofill/core/common/autofill_constants.h"
 #include "components/autofill/core/common/autofill_features.h"
 #include "components/autofill/core/common/autofill_pref_names.h"
 #include "components/autofill/core/common/autofill_switches.h"
@@ -1299,6 +1300,40 @@
   }
 }
 
+void PersonalDataManager::ClearProfileNonSettingsOrigins() {
+  bool has_updated = false;
+
+  for (AutofillProfile* profile : GetProfiles()) {
+    if (profile->origin() != kSettingsOrigin && !profile->origin().empty()) {
+      profile->set_origin(std::string());
+      database_->UpdateAutofillProfile(*profile);
+      has_updated = true;
+    }
+  }
+
+  // Refresh the local cache and send notifications to observers if a changed
+  // was made.
+  if (has_updated)
+    Refresh();
+}
+
+void PersonalDataManager::ClearCreditCardNonSettingsOrigins() {
+  bool has_updated = false;
+
+  for (CreditCard* card : GetLocalCreditCards()) {
+    if (card->origin() != kSettingsOrigin && !card->origin().empty()) {
+      card->set_origin(std::string());
+      database_->UpdateCreditCard(*card);
+      has_updated = true;
+    }
+  }
+
+  // Refresh the local cache and send notifications to observers if a changed
+  // was made.
+  if (has_updated)
+    Refresh();
+}
+
 // TODO(crbug.com/618448): Refactor MergeProfile to not depend on class
 // variables.
 std::string PersonalDataManager::MergeProfile(
@@ -2295,15 +2330,17 @@
 }
 
 void PersonalDataManager::ApplyAddressFixesAndCleanups() {
-  RemoveOrphanAutofillTableRows();  // One-time fix, otherwise NOP.
-  ApplyDedupingRoutine();           // Once per major version, otherwise NOP.
-  DeleteDisusedAddresses();         // Once per major version, otherwise NOP.
-  MaybeCreateTestAddresses();       // Once per user profile startup.
+  RemoveOrphanAutofillTableRows();   // One-time fix, otherwise NOP.
+  ApplyDedupingRoutine();            // Once per major version, otherwise NOP.
+  DeleteDisusedAddresses();          // Once per major version, otherwise NOP.
+  MaybeCreateTestAddresses();        // Once per user profile startup.
+  ClearProfileNonSettingsOrigins();  // Ran everytime it is called.
 }
 
 void PersonalDataManager::ApplyCardFixesAndCleanups() {
   DeleteDisusedCreditCards();    // Once per major version, otherwise NOP.
   MaybeCreateTestCreditCards();  // Once per user profile startup.
+  ClearCreditCardNonSettingsOrigins();  // Ran everytime it is called.
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/personal_data_manager.h b/components/autofill/core/browser/personal_data_manager.h
index 759ece7..08153ba5c 100644
--- a/components/autofill/core/browser/personal_data_manager.h
+++ b/components/autofill/core/browser/personal_data_manager.h
@@ -391,6 +391,10 @@
                            GetCreditCardSuggestions_CreditCardAutofillDisabled);
   FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
                            GetCreditCardSuggestions_NoCardsLoadedIfDisabled);
+  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
+                           ClearProfileNonSettingsOrigins);
+  FRIEND_TEST_ALL_PREFIXES(PersonalDataManagerTest,
+                           ClearCreditCardNonSettingsOrigins);
 
   friend class autofill::AutofillInteractiveTest;
   friend class autofill::PersonalDataManagerFactory;
@@ -470,6 +474,11 @@
   // this class and must outlive |this|.
   void SetPrefService(PrefService* pref_service);
 
+  // Clears the value of the origin field of the autofill profiles or cards that
+  // were not created from the settings page.
+  void ClearProfileNonSettingsOrigins();
+  void ClearCreditCardNonSettingsOrigins();
+
   void set_database(scoped_refptr<AutofillWebDataService> database) {
     database_ = database;
   }
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index 5c5f80e..72057d6 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -147,7 +147,7 @@
   void SetUpReferenceProfile() {
     ASSERT_EQ(0U, personal_data_->GetProfiles().size());
 
-    AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+    AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
     test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
                          "johnwayne@me.xyz", "Fox", "123 Zoo St", "unit 5",
                          "Hollywood", "CA", "91601", "US", "12345678910");
@@ -168,7 +168,7 @@
     ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
 
     CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
-                            "https://www.example.com");
+                            test::kEmptyOrigin);
     test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
                             "378282246310005" /* American Express */, "04",
                             "2999", "1");
@@ -178,7 +178,7 @@
     personal_data_->AddCreditCard(credit_card0);
 
     CreditCard credit_card1("1141084B-72D7-4B73-90CF-3D6AC154673B",
-                            "https://www.example.com");
+                            test::kEmptyOrigin);
     credit_card1.set_use_count(300);
     credit_card1.set_use_date(AutofillClock::Now() -
                               base::TimeDelta::FromDays(10));
@@ -187,7 +187,7 @@
     personal_data_->AddCreditCard(credit_card1);
 
     CreditCard credit_card2("002149C1-EE28-4213-A3B9-DA243FFF021B",
-                            "https://www.example.com");
+                            test::kEmptyOrigin);
     credit_card2.set_use_count(1);
     credit_card2.set_use_date(AutofillClock::Now() -
                               base::TimeDelta::FromDays(1));
@@ -258,7 +258,7 @@
   // and has not been used in last 400 days. This card is supposed to be
   // deleted during a major version upgrade.
   void CreateDeletableExpiredAndDisusedCreditCard() {
-    CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+    CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
     test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
                             "378282246310005" /* American Express */, "04",
                             "1999", "1");
@@ -576,17 +576,17 @@
 }
 
 TEST_F(PersonalDataManagerTest, AddUpdateRemoveProfiles) {
-  AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
 
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "903 Apple Ct.", nullptr,
                        "Orlando", "FL", "32801", "US", "19482937549");
 
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "19482937549");
@@ -626,16 +626,16 @@
 
 TEST_F(PersonalDataManagerTest, AddUpdateRemoveCreditCards) {
   EnableWalletCardImport();
-  CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card0, "John Dillinger",
                           "4234567890123456" /* Visa */, "01", "2999", "1");
 
-  CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card1, "Bonnie Parker",
                           "5105105105105100" /* Mastercard */, "12", "2999",
                           "1");
 
-  CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card2, "Clyde Barrow",
                           "378282246310005" /* American Express */, "04",
                           "2999", "1");
@@ -676,7 +676,7 @@
   ExpectSameElements(cards, personal_data_->GetCreditCards());
 
   // Add a full server card.
-  CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card3, "Jane Doe",
                           "4111111111111111" /* Visa */, "04", "2999", "1");
   credit_card3.set_record_type(CreditCard::FULL_SERVER_CARD);
@@ -718,7 +718,7 @@
   test_clock.SetNow(kArbitraryTime);
 
   // Add a credit card to the database.
-  CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card, "John Dillinger",
                           "4234567890123456" /* Visa */, "01", "2999", "1");
   personal_data_->AddCreditCard(credit_card);
@@ -1037,21 +1037,21 @@
 }
 
 TEST_F(PersonalDataManagerTest, AddProfilesAndCreditCards) {
-  AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
 
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "903 Apple Ct.", nullptr,
                        "Orlando", "FL", "32801", "US", "19482937549");
 
-  CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card0, "John Dillinger",
                           "4234567890123456" /* Visa */, "01", "2999", "1");
 
-  CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card1, "Bonnie Parker",
                           "5105105105105100" /* Mastercard */, "12", "2999",
                           "1");
@@ -1091,7 +1091,7 @@
 // Test for http://crbug.com/50047. Makes sure that guids are populated
 // correctly on load.
 TEST_F(PersonalDataManagerTest, PopulateUniqueIDsOnLoad) {
-  AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile0, "y", "", "", "", "", "", "", "", "", "", "",
                        "");
 
@@ -1106,7 +1106,7 @@
   EXPECT_EQ(0, profile0.Compare(*results2[0]));
 
   // Add a new profile.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "z", "", "", "", "", "", "", "", "", "", "",
                        "");
   personal_data_->AddProfile(profile1);
@@ -1122,17 +1122,17 @@
 }
 
 TEST_F(PersonalDataManagerTest, SetUniqueCreditCardLabels) {
-  CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
   credit_card0.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("John"));
-  CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
   credit_card1.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Paul"));
-  CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
   credit_card2.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Ringo"));
-  CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
   credit_card3.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Other"));
-  CreditCard credit_card4(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card4(base::GenerateGUID(), test::kEmptyOrigin);
   credit_card4.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Ozzy"));
-  CreditCard credit_card5(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card5(base::GenerateGUID(), test::kEmptyOrigin);
   credit_card5.SetRawInfo(CREDIT_CARD_NAME_FULL, base::ASCIIToUTF16("Dio"));
 
   // Add the test credit cards to the database.
@@ -1159,7 +1159,7 @@
 }
 
 TEST_F(PersonalDataManagerTest, SetEmptyProfile) {
-  AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile0, "", "", "", "", "", "", "", "", "", "", "",
                        "");
 
@@ -1178,7 +1178,7 @@
 }
 
 TEST_F(PersonalDataManagerTest, SetEmptyCreditCard) {
-  CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card0, "", "", "", "", "");
 
   // Add the empty credit card to the database.
@@ -1196,12 +1196,12 @@
 }
 
 TEST_F(PersonalDataManagerTest, Refresh) {
-  AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile0, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
 
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "903 Apple Ct.", nullptr,
                        "Orlando", "FL", "32801", "US", "19482937549");
@@ -1217,7 +1217,7 @@
   profiles.push_back(&profile1);
   ExpectSameElements(profiles, personal_data_->GetProfiles());
 
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "19482937549");
@@ -1259,7 +1259,7 @@
 // overwriting existing unverified profiles.
 TEST_F(PersonalDataManagerTest, SaveImportedProfileWithVerifiedData) {
   // Start with an unverified profile.
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
@@ -1335,7 +1335,7 @@
   EXPECT_EQ(0U, non_empty_types.size());
 
   // Test with one profile stored.
-  AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile0, "Marion", nullptr, "Morrison",
                        "johnwayne@me.xyz", nullptr, "123 Zoo St.", nullptr,
                        "Hollywood", "CA", "91601", "US", "14155678910");
@@ -1365,12 +1365,12 @@
   EXPECT_TRUE(non_empty_types.count(PHONE_HOME_WHOLE_NUMBER));
 
   // Test with multiple profiles stored.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "903 Apple Ct.", nullptr,
                        "Orlando", "FL", "32801", "US", "16502937549");
 
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "16502937549");
@@ -1404,7 +1404,7 @@
   EXPECT_TRUE(non_empty_types.count(PHONE_HOME_WHOLE_NUMBER));
 
   // Test with credit card information also stored.
-  CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card, "John Dillinger",
                           "4234567890123456" /* Visa */, "01", "2999", "");
   personal_data_->AddCreditCard(credit_card);
@@ -1449,13 +1449,13 @@
   ASSERT_TRUE(personal_data_->GetProfiles().empty());
   ASSERT_TRUE(personal_data_->GetCreditCards().empty());
 
-  AutofillProfile steve_jobs(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile steve_jobs(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&steve_jobs, "Steven", "Paul", "Jobs", "sjobs@apple.com",
                        "Apple Computer, Inc.", "1 Infinite Loop", "",
                        "Cupertino", "CA", "95014", "US", "(800) 275-2273");
   personal_data_->AddProfile(steve_jobs);
 
-  CreditCard bill_gates(base::GenerateGUID(), "https://www.example.com");
+  CreditCard bill_gates(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&bill_gates, "William H. Gates", "5555555555554444",
                           "1", "2020", "1");
   personal_data_->AddCreditCard(bill_gates);
@@ -1472,7 +1472,7 @@
   // Add profiles or credit card shouldn't work.
   personal_data_->AddProfile(test::GetFullProfile());
 
-  CreditCard larry_page(base::GenerateGUID(), "https://www.example.com");
+  CreditCard larry_page(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&larry_page, "Lawrence Page", "4111111111111111",
                           "10", "2025", "1");
   personal_data_->AddCreditCard(larry_page);
@@ -1610,7 +1610,7 @@
 }
 
 TEST_F(PersonalDataManagerTest, UpdateLanguageCodeInProfile) {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox", "123 Zoo St.", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
@@ -1633,7 +1633,7 @@
 }
 
 TEST_F(PersonalDataManagerTest, GetProfileSuggestions) {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1650,7 +1650,7 @@
 }
 
 TEST_F(PersonalDataManagerTest, GetProfileSuggestions_PhoneSubstring) {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1666,7 +1666,7 @@
 }
 
 TEST_F(PersonalDataManagerTest, GetProfileSuggestions_HideSubsets) {
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1712,7 +1712,7 @@
   // De-duplication of suggestions takes noticeable time when there are more
   // than 15 or so suggestions. In that case, Auofill just shows them all to
   // the user.
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1744,7 +1744,7 @@
 TEST_F(PersonalDataManagerTest, GetProfileSuggestions_Ranking) {
   // Set up the profiles. They are named with number suffixes X so the X is the
   // order in which they should be ordered by frecency.
-  AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile3, "Marion3", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1753,7 +1753,7 @@
   profile3.set_use_count(5);
   personal_data_->AddProfile(profile3);
 
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1762,7 +1762,7 @@
   profile1.set_use_count(10);
   personal_data_->AddProfile(profile1);
 
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1784,21 +1784,21 @@
 // Tests that GetProfileSuggestions returns all profiles suggestions.
 TEST_F(PersonalDataManagerTest, GetProfileSuggestions_NumberOfSuggestions) {
   // Set up 3 different profiles.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
   personal_data_->AddProfile(profile1);
 
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
   personal_data_->AddProfile(profile2);
 
-  AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile3, "Marion3", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1819,7 +1819,7 @@
 TEST_F(PersonalDataManagerTest,
        GetProfileSuggestions_SuppressDisusedProfilesOnEmptyField) {
   // Set up 2 different profiles.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1827,7 +1827,7 @@
   profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(200));
   personal_data_->AddProfile(profile1);
 
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "456 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1898,7 +1898,7 @@
 // Tests that suggestions based on invalid data are handled correctly.
 TEST_F(PersonalDataManagerTest, GetProfileSuggestions_InvalidData) {
   // Set up 2 different profiles.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "123 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1907,7 +1907,7 @@
   profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(20));
   personal_data_->AddProfile(profile1);
 
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox",
                        "456 Zoo St.\nSecond Line\nThird line", "unit 5",
@@ -1952,8 +1952,7 @@
   const std::string kServerAddressId("server_address1");
 
   // Add two different profiles, a local and a server one.
-  AutofillProfile local_profile(base::GenerateGUID(),
-                                "https://www.example.com");
+  AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "19482937549");
@@ -1998,8 +1997,7 @@
   const std::string kServerAddressId("server_address1");
 
   // Add two different profiles, a local and a server one.
-  AutofillProfile local_profile(base::GenerateGUID(),
-                                "https://www.example.com");
+  AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "19482937549");
@@ -2049,8 +2047,7 @@
                                             false);
 
   // Add a local profile.
-  AutofillProfile local_profile(base::GenerateGUID(),
-                                "https://www.example.com");
+  AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "19482937549");
@@ -2103,7 +2100,7 @@
   EnableWalletCardImport();
   // Add a local card.
   CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
                           "4234 5678 9012 2110" /* Visa */, "04", "2999", "1");
   personal_data_->AddCreditCard(credit_card0);
@@ -2122,7 +2119,7 @@
   EnableWalletCardImport();
   // Add a local card.
   CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
                           "4234 5678 9012 2110" /* Visa */, "04", "2999", "1");
   personal_data_->AddCreditCard(credit_card0);
@@ -2142,7 +2139,7 @@
   EnableWalletCardImport();
   // Add a local card.
   CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
                           "4234 5678 9012 2110" /* Visa */, "04", "2999", "1");
   personal_data_->AddCreditCard(credit_card0);
@@ -2355,7 +2352,7 @@
 
   // Add a never used non expired credit card.
   CreditCard credit_card0("002149C1-EE28-4213-A3B9-DA243FFF021B",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card0, "Bonnie Parker",
                           "5105105105105100" /* Mastercard */, "04", "2999",
                           "1");
@@ -2363,7 +2360,7 @@
 
   // Add an expired card with a higher frecency score.
   CreditCard credit_card1("287151C8-6AB1-487C-9095-28E80BE5DA15",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
                           "378282246310005" /* American Express */, "04",
                           "1999", "1");
@@ -2374,7 +2371,7 @@
 
   // Add an expired card with a lower frecency score.
   CreditCard credit_card2("1141084B-72D7-4B73-90CF-3D6AC154673B",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   credit_card2.set_use_count(3);
   credit_card2.set_use_date(AutofillClock::Now() -
                             base::TimeDelta::FromDays(1));
@@ -2409,7 +2406,7 @@
 
   // Add a never used non expired local credit card.
   CreditCard credit_card0("002149C1-EE28-4213-A3B9-DA243FFF021B",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card0, "Bonnie Parker",
                           "5105105105105100" /* Mastercard */, "04", "2999",
                           "1");
@@ -2439,7 +2436,7 @@
 
   // Add an expired local card last used 180 days ago.
   CreditCard credit_card3("1141084B-72D7-4B73-90CF-3D6AC154673B",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   credit_card3.set_use_date(now - base::TimeDelta::FromDays(182));
   test::SetCreditCardInfo(&credit_card3, "John Dillinger",
                           "378282246310005" /* American Express */, "01",
@@ -2541,7 +2538,7 @@
   ASSERT_EQ(0U, personal_data_->GetCreditCards().size());
 
   CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
                           "378282246310005" /* American Express */, "04",
                           "2999", "1");
@@ -2551,7 +2548,7 @@
   personal_data_->AddCreditCard(credit_card0);
 
   CreditCard credit_card1("1141084B-72D7-4B73-90CF-3D6AC154673B",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   credit_card1.set_use_count(300);
   credit_card1.set_use_date(AutofillClock::Now() -
                             base::TimeDelta::FromDays(10));
@@ -2685,7 +2682,7 @@
   // Add a second dupe local card to make sure a full server card can be a dupe
   // of more than one local card.
   CreditCard credit_card3("4141084B-72D7-4B73-90CF-3D6AC154673B",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card3, "Clyde Barrow", "", "04", "", "");
   personal_data_->AddCreditCard(credit_card3);
 
@@ -2704,7 +2701,7 @@
 
   // Add a local card.
   CreditCard credit_card0("287151C8-6AB1-487C-9095-28E80BE5DA15",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card0, "Clyde Barrow",
                           "378282246310005" /* American Express */, "04",
                           "2999", "1");
@@ -2770,7 +2767,7 @@
 
   // Create 3 different local credit cards.
   CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
-                        "https://www.example.com");
+                        test::kEmptyOrigin);
   test::SetCreditCardInfo(&local_card, "Homer Simpson",
                           "4234567890123456" /* Visa */, "01", "2999", "1");
   local_card.set_use_count(3);
@@ -2799,7 +2796,7 @@
   std::list<CreditCard*> credit_cards;
 
   CreditCard local_card("1141084B-72D7-4B73-90CF-3D6AC154673B",
-                        "https://www.example.com");
+                        test::kEmptyOrigin);
   local_card.set_use_count(300);
   local_card.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(10));
   test::SetCreditCardInfo(&local_card, "Homer Simpson",
@@ -2856,7 +2853,7 @@
   std::list<CreditCard*> credit_cards;
 
   CreditCard credit_card2("002149C1-EE28-4213-A3B9-DA243FFF021B",
-                          "https://www.example.com");
+                          test::kEmptyOrigin);
   credit_card2.set_use_count(1);
   credit_card2.set_use_date(AutofillClock::Now() -
                             base::TimeDelta::FromDays(1));
@@ -2900,7 +2897,7 @@
   EXPECT_EQ(kArbitraryTime, profile.modification_date());
   personal_data_->AddProfile(profile);
 
-  CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card, "John Dillinger",
                           "4234567890123456" /* Visa */, "01", "2999", "1");
   EXPECT_EQ(1U, credit_card.use_count());
@@ -3190,7 +3187,7 @@
   // Set the time to a bigger value.
   test_clock.SetNow(kSomeLaterTime);
 
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Marion", "Mitchell", "Morrison",
                        "johnwayne@me.xyz", "Fox", "123 Zoo St", "unit 5",
                        "Hollywood", "CA", "91601", "US", "12345678910");
@@ -3505,12 +3502,12 @@
 TEST_F(PersonalDataManagerTest, MergeProfile_Frecency) {
   // Create two very similar profiles except with different company names.
   std::unique_ptr<AutofillProfile> profile1 = std::make_unique<AutofillProfile>(
-      base::GenerateGUID(), "https://www.example.com");
+      base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile1.get(), "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "12345678910");
   AutofillProfile* profile2 =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3524,8 +3521,7 @@
   existing_profiles.push_back(base::WrapUnique(profile2));
 
   // Create a new imported profile with no company name.
-  AutofillProfile imported_profile(base::GenerateGUID(),
-                                   "https://www.example.com");
+  AutofillProfile imported_profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&imported_profile, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
                        "Springfield", "IL", "91601", "US", "12345678910");
@@ -3555,7 +3551,7 @@
   // Create an initial profile with a use count of 10, an old use date and an
   // old modification date of 4 days ago.
   AutofillProfile* profile =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "SNP", "742 Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3571,8 +3567,7 @@
   test_clock.SetNow(kSomeLaterTime);
 
   // Create a new imported profile that will get merged with the existing one.
-  AutofillProfile imported_profile(base::GenerateGUID(),
-                                   "https://www.example.com");
+  AutofillProfile imported_profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&imported_profile, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
                        "Springfield", "IL", "91601", "US", "12345678910");
@@ -3603,7 +3598,7 @@
   // Create the profile for which to find duplicates. It has the highest
   // frecency.
   AutofillProfile* profile1 =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile1, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3611,7 +3606,7 @@
 
   // Create a different profile that should not be deduped (different address).
   AutofillProfile* profile2 =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "Fox", "1234 Other Street", "",
                        "Springfield", "IL", "91601", "US", "12345678910");
@@ -3619,7 +3614,7 @@
 
   // Create a profile similar to profile1 which should be deduped.
   AutofillProfile* profile3 =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile3, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
                        "Springfield", "IL", "91601", "US", "12345678910");
@@ -3628,7 +3623,7 @@
   // Create another different profile that should not be deduped (different
   // name).
   AutofillProfile* profile4 =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile4, "Marjorie", "Jacqueline", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3638,7 +3633,7 @@
   // frecency, the result of the merge should be in this profile at the end of
   // the test.
   AutofillProfile* profile5 =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile5, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3688,7 +3683,7 @@
   // Create the profile for which to find duplicates. It has the highest
   // frecency.
   AutofillProfile* profile1 =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile1, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3696,7 +3691,7 @@
 
   // Create a different profile that should not be deduped (different address).
   AutofillProfile* profile2 =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile2, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "Fox", "1234 Other Street", "",
                        "Springfield", "IL", "91601", "US", "12345678910");
@@ -3704,7 +3699,7 @@
 
   // Create a profile similar to profile1 which should be deduped.
   AutofillProfile* profile3 =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile3, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
                        "Springfield", "IL", "91601", "US", "12345678910");
@@ -3713,7 +3708,7 @@
   // Create another different profile that should not be deduped (different
   // name).
   AutofillProfile* profile4 =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile4, "Marjorie", "Jacqueline", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3723,7 +3718,7 @@
   // frecency, the result of the merge should be in this profile at the end of
   // the test.
   AutofillProfile* profile5 =
-      new AutofillProfile(base::GenerateGUID(), "https://www.example.com");
+      new AutofillProfile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(profile5, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "US", "12345678910");
@@ -3777,16 +3772,16 @@
 
   // Create cards that use A, D, E and F as their billing address id.
   CreditCard* credit_card1 =
-      new CreditCard(base::GenerateGUID(), "https://www.example.com");
+      new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
   credit_card1->set_billing_address_id("A");
   CreditCard* credit_card2 =
-      new CreditCard(base::GenerateGUID(), "https://www.example.com");
+      new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
   credit_card2->set_billing_address_id("D");
   CreditCard* credit_card3 =
-      new CreditCard(base::GenerateGUID(), "https://www.example.com");
+      new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
   credit_card3->set_billing_address_id("E");
   CreditCard* credit_card4 =
-      new CreditCard(base::GenerateGUID(), "https://www.example.com");
+      new CreditCard(base::GenerateGUID(), test::kEmptyOrigin);
   credit_card4->set_billing_address_id("F");
 
   // Add the credit cards to the database.
@@ -3823,7 +3818,7 @@
 
   // Create a set of 3 profiles to be merged together.
   // Create a profile with a higher frecency score.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "");
@@ -3831,7 +3826,7 @@
   profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1));
 
   // Create a profile with a medium frecency score.
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
                        "Springfield", "IL", "91601", "", "12345678910");
@@ -3839,7 +3834,7 @@
   profile2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3));
 
   // Create a profile with a lower frecency score.
-  AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
@@ -3848,7 +3843,7 @@
 
   // Create a set of two profiles to be merged together.
   // Create a profile with a higher frecency score.
-  AutofillProfile profile4(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile4, "Marge", "B", "Simpson",
                        "marge.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "");
@@ -3856,7 +3851,7 @@
   profile4.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1));
 
   // Create a profile with a lower frecency score.
-  AutofillProfile profile5(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile5(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile5, "Marge", "B", "Simpson",
                        "marge.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
@@ -3864,7 +3859,7 @@
   profile5.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3));
 
   // Create a unique profile.
-  AutofillProfile profile6(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile6(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile6, "Bart", "J", "Simpson",
                        "bart.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
@@ -3874,18 +3869,18 @@
   // Add three credit cards. Give them a frecency score so that they are
   // suggested in order (1, 2, 3). This will ensure a deterministic order for
   // verifying results.
-  CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card1, "Clyde Barrow",
                           "378282246310005" /* American Express */, "04",
                           "2999", "1");
   credit_card1.set_use_count(10);
 
-  CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card2, "John Dillinger",
                           "4234567890123456" /* Visa */, "01", "2999", "1");
   credit_card2.set_use_count(5);
 
-  CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card3, "Bonnie Parker",
                           "5105105105105100" /* Mastercard */, "12", "2999",
                           "1");
@@ -3954,7 +3949,7 @@
 // frecency score.
 TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MergedProfileValues) {
   // Create a profile with a higher frecency score.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "");
@@ -3962,7 +3957,7 @@
   profile1.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(1));
 
   // Create a profile with a medium frecency score.
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
                        "Springfield", "IL", "91601", "", "12345678910");
@@ -3970,7 +3965,7 @@
   profile2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3));
 
   // Create a profile with a lower frecency score.
-  AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
@@ -4052,7 +4047,7 @@
   profile1.set_use_date(kMuchLaterTime);
 
   // Create a similar non verified profile with a medium frecency score.
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "");
@@ -4060,7 +4055,7 @@
   profile2.set_use_date(kSomeLaterTime);
 
   // Create a similar non verified profile with a lower frecency score.
-  AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
@@ -4110,7 +4105,7 @@
 // frecency score.
 TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_VerifiedProfileLast) {
   // Create a profile to dedupe with a higher frecency score.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "");
@@ -4118,7 +4113,7 @@
   profile1.set_use_date(kMuchLaterTime);
 
   // Create a similar non verified profile with a medium frecency score.
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
@@ -4175,7 +4170,7 @@
 // a verified profile. Also tests that two verified profiles don't get merged.
 TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleVerifiedProfiles) {
   // Create a profile to dedupe with a higher frecency score.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "");
@@ -4251,7 +4246,7 @@
 TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_MultipleDedupes) {
   // Create a Homer home profile with a higher frecency score than other Homer
   // profiles.
-  AutofillProfile Homer1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile Homer1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&Homer1, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "");
@@ -4260,7 +4255,7 @@
 
   // Create a Homer home profile with a medium frecency score compared to other
   // Homer profiles.
-  AutofillProfile Homer2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile Homer2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&Homer2, "Homer", "Jay", "Simpson",
                        "homer.simpson@abc.com", "", "742 Evergreen Terrace", "",
                        "Springfield", "IL", "91601", "", "12345678910");
@@ -4269,7 +4264,7 @@
 
   // Create a Homer home profile with a lower frecency score than other Homer
   // profiles.
-  AutofillProfile Homer3(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile Homer3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&Homer3, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
@@ -4277,7 +4272,7 @@
   Homer3.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(5));
 
   // Create a Homer work profile (different address).
-  AutofillProfile Homer4(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile Homer4(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&Homer4, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "Fox", "12 Nuclear Plant.", "",
                        "Springfield", "IL", "91601", "US", "9876543");
@@ -4295,7 +4290,7 @@
 
   // Create a verified Marge home profile with a lower frecency score that the
   // other Marge profile.
-  AutofillProfile Marge2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile Marge2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&Marge2, "Marjorie", "Jacqueline", "Simpson",
                        "marge.simpson@abc.com", "", "742 Evergreen Terrace", "",
                        "Springfield", "IL", "91601", "", "12345678910");
@@ -4303,7 +4298,7 @@
   Marge2.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3));
 
   // Create a Barney profile (guest user).
-  AutofillProfile Barney(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile Barney(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&Barney, "Barney", "", "Gumble", "barney.gumble@abc.com",
                        "ABC", "123 Other Street", "", "Springfield", "IL",
                        "91601", "", "");
@@ -4390,13 +4385,13 @@
 // Tests that ApplyDedupingRoutine is not run if the feature is disabled.
 TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_FeatureDisabled) {
   // Create a profile to dedupe.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "");
 
   // Create a similar profile.
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
@@ -4424,7 +4419,7 @@
 
 TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_NopIfOneProfile) {
   // Create a profile to dedupe.
-  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "");
@@ -4444,13 +4439,13 @@
 // version.
 TEST_F(PersonalDataManagerTest, ApplyDedupingRoutine_OncePerVersion) {
   // Create a profile to dedupe.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "", "742. Evergreen Terrace",
                        "", "Springfield", "IL", "91601", "US", "");
 
   // Create a similar profile.
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
@@ -4475,7 +4470,7 @@
   EXPECT_EQ(1U, profiles.size());
 
   // Add another duplicate profile.
-  AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile3, "Homer", "J", "Simpson",
                        "homer.simpson@abc.com", "Fox", "742 Evergreen Terrace.",
                        "", "Springfield", "IL", "91601", "", "");
@@ -4548,7 +4543,7 @@
 
   // Create unverified/disused/not-used-by-valid-credit-card
   // address(deletable).
-  AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile0, "Alice", "", "Delete", "", "ACME",
                        "1234 Evergreen Terrace", "Bld. 6", "Springfield", "IL",
                        "32801", "US", "15151231234");
@@ -4556,12 +4551,12 @@
   personal_data_->AddProfile(profile0);
 
   // Create unverified/disused/used-by-expired-credit-card address(deletable).
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Bob", "", "Delete", "", "ACME",
                        "1234 Evergreen Terrace", "Bld. 7", "Springfield", "IL",
                        "32801", "US", "15151231234");
   profile1.set_use_date(now - base::TimeDelta::FromDays(400));
-  CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card0, "Bob",
                           "5105105105105100" /* Mastercard */, "04", "1999",
                           "1");
@@ -4572,7 +4567,7 @@
 
   // Create verified/disused/not-used-by-valid-credit-card address(not
   // deletable).
-  AutofillProfile profile2(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile2, "Charlie", "", "Keep", "", "ACME",
                        "1234 Evergreen Terrace", "Bld. 8", "Springfield", "IL",
                        "32801", "US", "15151231234");
@@ -4582,7 +4577,7 @@
 
   // Create unverified/recently-used/not-used-by-valid-credit-card address(not
   // deletable).
-  AutofillProfile profile3(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile3(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile3, "Dave", "", "Keep", "", "ACME",
                        "1234 Evergreen Terrace", "Bld. 9", "Springfield", "IL",
                        "32801", "US", "15151231234");
@@ -4590,7 +4585,7 @@
   personal_data_->AddProfile(profile3);
 
   // Create unverified/disused/used-by-valid-credit-card address(not deletable).
-  AutofillProfile profile4(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile4(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile4, "Emma", "", "Keep", "", "ACME",
                        "1234 Evergreen Terrace", "Bld. 10", "Springfield", "IL",
                        "32801", "US", "15151231234");
@@ -4675,7 +4670,7 @@
   auto now = AutofillClock::Now();
 
   // Create a recently used local card, it is expected to remain.
-  CreditCard credit_card1(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card1, "Alice",
                           "378282246310005" /* American Express */, "04",
                           "2999", "1");
@@ -4683,7 +4678,7 @@
 
   // Create a local card that was expired 400 days ago, but recently used.
   // It is expected to remain.
-  CreditCard credit_card2(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card2(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card2, "Bob",
                           "378282246310006" /* American Express */, "04",
                           "1999", "1");
@@ -4691,7 +4686,7 @@
 
   // Create a local card expired recently, and last used 400 days ago.
   // It is expected to remain.
-  CreditCard credit_card3(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card3(base::GenerateGUID(), test::kEmptyOrigin);
   base::Time expiry_date = now - base::TimeDelta::FromDays(32);
   base::Time::Exploded exploded;
   expiry_date.UTCExplode(&exploded);
@@ -4703,7 +4698,7 @@
 
   // Create a local card expired 400 days ago, and last used 400 days ago.
   // It is expected to be deleted.
-  CreditCard credit_card4(base::GenerateGUID(), "https://www.example.com");
+  CreditCard credit_card4(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&credit_card4, "David",
                           "5105105105105100" /* Mastercard */, "04", "1999",
                           "1");
@@ -4778,8 +4773,7 @@
   // Add two different profiles, a local and a server one. Set the use stats so
   // the server profile has a higher frecency, to have a predictable ordering to
   // validate results.
-  AutofillProfile local_profile(base::GenerateGUID(),
-                                "https://www.example.com");
+  AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&local_profile, "Josephine", "Alicia", "Saenz",
                        "joewayne@me.xyz", "Fox", "1212 Center.", "Bld. 5",
                        "Orlando", "FL", "32801", "US", "19482937549");
@@ -4803,7 +4797,7 @@
   // Add a server and a local card that have the server address as billing
   // address.
   CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
-                        "https://www.example.com");
+                        test::kEmptyOrigin);
   test::SetCreditCardInfo(&local_card, "Clyde Barrow",
                           "378282246310005" /* American Express */, "04",
                           "2999", "1");
@@ -4884,8 +4878,7 @@
   // the server card has a higher frecency, to have a predicatble ordering to
   // validate results.
   // Add a local profile.
-  AutofillProfile local_profile(base::GenerateGUID(),
-                                "https://www.example.com");
+  AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&local_profile, "John", "", "Doe", "john@doe.com", "",
                        "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US",
                        "19482937549");
@@ -4908,7 +4901,7 @@
   // Add a server and a local card that have the server address as billing
   // address.
   CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
-                        "https://www.example.com");
+                        test::kEmptyOrigin);
   test::SetCreditCardInfo(&local_card, "Clyde Barrow",
                           "378282246310005" /* American Express */, "04",
                           "2999", "1");
@@ -5039,8 +5032,7 @@
   // Add a unique local profile and two similar server profiles. Set the use
   // stats to have a predicatble ordering to validate results.
   // Add a local profile.
-  AutofillProfile local_profile(base::GenerateGUID(),
-                                "https://www.example.com");
+  AutofillProfile local_profile(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&local_profile, "Bob", "", "Doe", "", "Fox",
                        "1212 Center.", "Bld. 5", "Orlando", "FL", "32801", "US",
                        "19482937549");
@@ -5076,7 +5068,7 @@
   // Add a server and a local card that have the first and second Wallet address
   // as a billing address.
   CreditCard local_card("287151C8-6AB1-487C-9095-28E80BE5DA15",
-                        "https://www.example.com");
+                        test::kEmptyOrigin);
   test::SetCreditCardInfo(&local_card, "Clyde Barrow",
                           "378282246310005" /* American Express */, "04",
                           "2999", "1");
@@ -5262,16 +5254,16 @@
   std::vector<CreditCard> server_cards;
 
   // Add two different profiles
-  AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile0, "Bob", "", "Doe", "", "Fox", "1212 Center.",
                        "Bld. 5", "Orlando", "FL", "32801", "US", "19482937549");
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Seb", "", "Doe", "", "ACME",
                        "1234 Evergreen Terrace", "Bld. 5", "Springfield", "IL",
                        "32801", "US", "15151231234");
 
   // Add a local and a server card that have profile0 as their billing address.
-  CreditCard local_card0(base::GenerateGUID(), "https://www.example.com");
+  CreditCard local_card0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&local_card0, "John Dillinger",
                           "4111111111111111" /* Visa */, "01", "2999",
                           profile0.guid());
@@ -5282,7 +5274,7 @@
   server_cards.push_back(server_card0);
 
   // Do the same but for profile1.
-  CreditCard local_card1(base::GenerateGUID(), "https://www.example.com");
+  CreditCard local_card1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetCreditCardInfo(&local_card1, "Seb Dillinger",
                           "4111111111111111" /* Visa */, "01", "2999",
                           profile1.guid());
@@ -5351,14 +5343,14 @@
 
 TEST_F(PersonalDataManagerTest, LogStoredProfileMetrics) {
   // Add a recently used (3 days ago) profile.
-  AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile0(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile0, "Bob", "", "Doe", "", "Fox", "1212 Center.",
                        "Bld. 5", "Orlando", "FL", "32801", "US", "19482937549");
   profile0.set_use_date(AutofillClock::Now() - base::TimeDelta::FromDays(3));
   personal_data_->AddProfile(profile0);
 
   // Add a profile used a long time (200 days) ago.
-  AutofillProfile profile1(base::GenerateGUID(), "https://www.example.com");
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
   test::SetProfileInfo(&profile1, "Seb", "", "Doe", "", "ACME",
                        "1234 Evergreen Terrace", "Bld. 5", "Springfield", "IL",
                        "32801", "US", "15151231234");
@@ -6134,4 +6126,166 @@
 }
 #endif  // !defined(OS_ANDROID)
 
+// Tests that all the non settings origins of autofill profiles are cleared but
+// that the settings origins are untouched.
+TEST_F(PersonalDataManagerTest, ClearProfileNonSettingsOrigins) {
+  // Create three profile with a nonsettings, non-empty origin.
+  AutofillProfile profile0(base::GenerateGUID(), "https://www.example.com");
+  test::SetProfileInfo(&profile0, "Marion0", "Mitchell", "Morrison",
+                       "johnwayne@me.xyz", "Fox",
+                       "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+                       "Hollywood", "CA", "91601", "US", "12345678910");
+  profile0.set_use_count(10000);
+  personal_data_->AddProfile(profile0);
+
+  AutofillProfile profile1(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetProfileInfo(&profile1, "Marion1", "Mitchell", "Morrison",
+                       "johnwayne@me.xyz", "Fox",
+                       "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+                       "Hollywood", "CA", "91601", "US", "12345678910");
+  profile1.set_use_count(1000);
+  personal_data_->AddProfile(profile1);
+
+  AutofillProfile profile2(base::GenerateGUID(), "1234");
+  test::SetProfileInfo(&profile2, "Marion2", "Mitchell", "Morrison",
+                       "johnwayne@me.xyz", "Fox",
+                       "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+                       "Hollywood", "CA", "91601", "US", "12345678910");
+  profile2.set_use_count(100);
+  personal_data_->AddProfile(profile2);
+
+  // Create a profile with a settings origin.
+  AutofillProfile profile3(base::GenerateGUID(), kSettingsOrigin);
+  test::SetProfileInfo(&profile3, "Marion3", "Mitchell", "Morrison",
+                       "johnwayne@me.xyz", "Fox",
+                       "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+                       "Hollywood", "CA", "91601", "US", "12345678910");
+  profile3.set_use_count(10);
+  personal_data_->AddProfile(profile3);
+
+  WaitForOnPersonalDataChanged();
+  ASSERT_EQ(4U, personal_data_->GetProfiles().size());
+
+  personal_data_->ClearProfileNonSettingsOrigins();
+
+  WaitForOnPersonalDataChanged();
+  ASSERT_EQ(4U, personal_data_->GetProfiles().size());
+
+  // The first three profiles' origin should be cleared and the fourth one still
+  // be the settings origin.
+  EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[0]->origin().empty());
+  EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[1]->origin().empty());
+  EXPECT_TRUE(personal_data_->GetProfilesToSuggest()[2]->origin().empty());
+  EXPECT_EQ(kSettingsOrigin,
+            personal_data_->GetProfilesToSuggest()[3]->origin());
+}
+
+// Tests that all the non settings origins of autofill credit cards are cleared
+// but that the settings origins are untouched.
+TEST_F(PersonalDataManagerTest, ClearCreditCardNonSettingsOrigins) {
+  // Create three cards with a non settings origin.
+  CreditCard credit_card0(base::GenerateGUID(), "https://www.example.com");
+  test::SetCreditCardInfo(&credit_card0, "Bob0",
+                          "5105105105105100" /* Mastercard */, "04", "1999",
+                          "1");
+  credit_card0.set_use_count(10000);
+  personal_data_->AddCreditCard(credit_card0);
+
+  CreditCard credit_card1(base::GenerateGUID(), test::kEmptyOrigin);
+  test::SetCreditCardInfo(&credit_card1, "Bob1",
+                          "5105105105105101" /* Mastercard */, "04", "1999",
+                          "1");
+  credit_card1.set_use_count(1000);
+  personal_data_->AddCreditCard(credit_card1);
+
+  CreditCard credit_card2(base::GenerateGUID(), "1234");
+  test::SetCreditCardInfo(&credit_card2, "Bob2",
+                          "5105105105105102" /* Mastercard */, "04", "1999",
+                          "1");
+  credit_card2.set_use_count(100);
+  personal_data_->AddCreditCard(credit_card2);
+
+  // Create a card with a settings origin.
+  CreditCard credit_card3(base::GenerateGUID(), kSettingsOrigin);
+  test::SetCreditCardInfo(&credit_card3, "Bob3",
+                          "5105105105105103" /* Mastercard */, "04", "1999",
+                          "1");
+  credit_card3.set_use_count(10);
+  personal_data_->AddCreditCard(credit_card3);
+
+  WaitForOnPersonalDataChanged();
+  ASSERT_EQ(4U, personal_data_->GetCreditCards().size());
+
+  personal_data_->ClearCreditCardNonSettingsOrigins();
+
+  WaitForOnPersonalDataChanged();
+  ASSERT_EQ(4U, personal_data_->GetCreditCards().size());
+
+  // The first three profiles' origin should be cleared and the fourth one still
+  // be the settings origin.
+  EXPECT_TRUE(
+      personal_data_->GetCreditCardsToSuggest(false)[0]->origin().empty());
+  EXPECT_TRUE(
+      personal_data_->GetCreditCardsToSuggest(false)[1]->origin().empty());
+  EXPECT_TRUE(
+      personal_data_->GetCreditCardsToSuggest(false)[2]->origin().empty());
+  EXPECT_EQ(kSettingsOrigin,
+            personal_data_->GetCreditCardsToSuggest(false)[3]->origin());
+}
+
+// Tests that all the non settings origins of autofill profiles are cleared even
+// if Autofill is disabled.
+TEST_F(
+    PersonalDataManagerTest,
+    SyncServiceInitializedWithAutofillDisabled_ClearProfileNonSettingsOrigins) {
+  // Create a profile with a non-settings, non-empty origin.
+  AutofillProfile profile(base::GenerateGUID(), "https://www.example.com");
+  test::SetProfileInfo(&profile, "Marion0", "Mitchell", "Morrison",
+                       "johnwayne@me.xyz", "Fox",
+                       "123 Zoo St.\nSecond Line\nThird line", "unit 5",
+                       "Hollywood", "CA", "91601", "US", "12345678910");
+  personal_data_->AddProfile(profile);
+  WaitForOnPersonalDataChanged();
+
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+  prefs_->SetBoolean(prefs::kAutofillEnabled, false);
+
+  ASSERT_EQ(1U, personal_data_->GetProfiles().size());
+
+  personal_data_->OnSyncServiceInitialized(nullptr);
+
+  WaitForOnPersonalDataChanged();
+  ASSERT_EQ(1U, personal_data_->GetProfiles().size());
+
+  // The profile's origin should be cleared
+  EXPECT_TRUE(personal_data_->GetProfiles()[0]->origin().empty());
+}
+
+// Tests that all the non settings origins of autofill credit cards are cleared
+// even if Autofill is disabled.
+TEST_F(
+    PersonalDataManagerTest,
+    SyncServiceInitializedWithAutofillDisabled_ClearCreditCardNonSettingsOrigins) {
+  // Create a card with a non-settings, non-empty origin.
+  CreditCard credit_card(base::GenerateGUID(), "https://www.example.com");
+  test::SetCreditCardInfo(&credit_card, "Bob0",
+                          "5105105105105100" /* Mastercard */, "04", "1999",
+                          "1");
+  personal_data_->AddCreditCard(credit_card);
+  WaitForOnPersonalDataChanged();
+
+  EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged()).Times(1);
+  prefs_->SetBoolean(prefs::kAutofillEnabled, false);
+
+  ASSERT_EQ(1U, personal_data_->GetCreditCards().size());
+
+  personal_data_->OnSyncServiceInitialized(nullptr);
+
+  WaitForOnPersonalDataChanged();
+  ASSERT_EQ(1U, personal_data_->GetCreditCards().size());
+
+  // The card's origin should be cleared
+  EXPECT_TRUE(personal_data_->GetCreditCards()[0]->origin().empty());
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
index 349a5b9..c83262a 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.cc
@@ -21,6 +21,7 @@
 #include "components/autofill/core/browser/form_group.h"
 #include "components/autofill/core/browser/webdata/autofill_table.h"
 #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
+#include "components/autofill/core/common/autofill_constants.h"
 #include "components/sync/model/sync_error.h"
 #include "components/sync/model/sync_error_factory.h"
 #include "components/sync/protocol/sync.pb.h"
@@ -323,7 +324,10 @@
   bool diff = false;
   if (specifics.has_origin() && profile->origin() != specifics.origin()) {
     bool was_verified = profile->IsVerified();
-    profile->set_origin(specifics.origin());
+    // In this case, the local origin must be empty on the local |profile|, but
+    // the remote profile was verified.
+    if (specifics.origin() == kSettingsOrigin)
+      profile->set_origin(kSettingsOrigin);
     diff = true;
 
     // Verified profiles should never be overwritten by unverified ones.
diff --git a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
index 8566101..028b92f3 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
+++ b/components/autofill/core/browser/webdata/autofill_profile_syncable_service.h
@@ -128,6 +128,10 @@
                            MergeSimilarProfiles_DifferentNames);
   FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
                            MergeSimilarProfiles_NonZeroUseCounts);
+  FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
+                           OverwriteProfileWithServerData_NonSettingsOrigin);
+  FRIEND_TEST_ALL_PREFIXES(AutofillProfileSyncableServiceTest,
+                           OverwriteProfileWithServerData_SettingsOrigin);
 
   // The map of the guid to profiles owned by the |profiles_| vector.
   typedef std::map<std::string, AutofillProfile*> GUIDToProfileMap;
diff --git a/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc b/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
index 37f9c05..cf031298 100644
--- a/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_profile_syncable_service_unittest.cc
@@ -39,8 +39,7 @@
 const char kGuid2[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44C";
 const char kGuid3[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44D";
 const char kGuid4[] = "EDC609ED-7EEE-4F27-B00C-423242A9C44E";
-const char kHttpOrigin[] = "http://www.example.com/";
-const char kHttpsOrigin[] = "https://www.example.com/";
+const char kEmptyOrigin[] = "";
 const int kValidityStateBitfield = 1984;
 
 class MockAutofillProfileSyncableService
@@ -142,7 +141,7 @@
 // returned from ConstructCompleteSyncData().
 std::unique_ptr<AutofillProfile> ConstructCompleteProfile() {
   std::unique_ptr<AutofillProfile> profile(
-      new AutofillProfile(kGuid1, kHttpsOrigin));
+      new AutofillProfile(kGuid1, kSettingsOrigin));
 
   profile->set_use_count(7);
   profile->set_use_date(base::Time::FromTimeT(1423182152));
@@ -183,7 +182,7 @@
       entity_specifics.mutable_autofill_profile();
 
   specifics->set_guid(kGuid1);
-  specifics->set_origin(kHttpsOrigin);
+  specifics->set_origin(kSettingsOrigin);
   specifics->set_use_count(7);
   specifics->set_use_date(1423182152);
 
@@ -271,9 +270,9 @@
   std::string guid_present2 = kGuid2;
   std::string guid_synced1 = kGuid3;
   std::string guid_synced2 = kGuid4;
-  std::string origin_present1 = kHttpOrigin;
-  std::string origin_present2 = std::string();
-  std::string origin_synced1 = kHttpsOrigin;
+  std::string origin_present1 = kEmptyOrigin;
+  std::string origin_present2 = kEmptyOrigin;
+  std::string origin_synced1 = kEmptyOrigin;
   std::string origin_synced2 = kSettingsOrigin;
 
   profiles_from_web_db.push_back(
@@ -322,10 +321,10 @@
   std::string guid_present2 = kGuid2;
   std::string guid_synced1 = kGuid3;
   std::string guid_synced2 = kGuid4;
-  std::string origin_present1 = kHttpOrigin;
+  std::string origin_present1 = kEmptyOrigin;
   std::string origin_present2 = kSettingsOrigin;
-  std::string origin_synced1 = kHttpsOrigin;
-  std::string origin_synced2 = kHttpsOrigin;
+  std::string origin_synced1 = kEmptyOrigin;
+  std::string origin_synced2 = kEmptyOrigin;
 
   profiles_from_web_db.push_back(
       std::make_unique<AutofillProfile>(guid_present1, origin_present1));
@@ -376,10 +375,10 @@
   std::string guid_present2 = kGuid2;
   std::string guid_synced1 = kGuid3;
   std::string guid_synced2 = kGuid4;
-  std::string origin_present1 = kHttpOrigin;
+  std::string origin_present1 = kEmptyOrigin;
   std::string origin_present2 = kSettingsOrigin;
-  std::string origin_synced1 = kHttpsOrigin;
-  std::string origin_synced2 = kHttpsOrigin;
+  std::string origin_synced1 = kEmptyOrigin;
+  std::string origin_synced2 = kEmptyOrigin;
 
   profiles_from_web_db.push_back(
       std::make_unique<AutofillProfile>(guid_present1, origin_present1));
@@ -486,10 +485,10 @@
   std::string guid_present2 = kGuid2;
 
   profiles_from_web_db.push_back(
-      std::make_unique<AutofillProfile>(guid_present1, kHttpOrigin));
+      std::make_unique<AutofillProfile>(guid_present1, kEmptyOrigin));
   profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
   profiles_from_web_db.push_back(
-      std::make_unique<AutofillProfile>(guid_present2, kHttpsOrigin));
+      std::make_unique<AutofillProfile>(guid_present2, kEmptyOrigin));
   profiles_from_web_db.back()->SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
 
   syncer::SyncChangeList expected_change_list;
@@ -515,8 +514,8 @@
   ASSERT_EQ(2U, data.size());
   EXPECT_EQ(guid_present1, data[0].GetSpecifics().autofill_profile().guid());
   EXPECT_EQ(guid_present2, data[1].GetSpecifics().autofill_profile().guid());
-  EXPECT_EQ(kHttpOrigin, data[0].GetSpecifics().autofill_profile().origin());
-  EXPECT_EQ(kHttpsOrigin, data[1].GetSpecifics().autofill_profile().origin());
+  EXPECT_EQ(kEmptyOrigin, data[0].GetSpecifics().autofill_profile().origin());
+  EXPECT_EQ(kEmptyOrigin, data[1].GetSpecifics().autofill_profile().origin());
 
   autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
 }
@@ -527,14 +526,14 @@
   std::string guid_synced = kGuid2;
 
   syncer::SyncChangeList change_list;
-  AutofillProfile profile(guid_synced, kHttpOrigin);
+  AutofillProfile profile(guid_synced, kEmptyOrigin);
   profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
   change_list.push_back(
       syncer::SyncChange(
           FROM_HERE,
           syncer::SyncChange::ACTION_ADD,
           MockAutofillProfileSyncableService::CreateData(profile)));
-  AutofillProfile empty_profile(guid_present, kHttpsOrigin);
+  AutofillProfile empty_profile(guid_present, kEmptyOrigin);
   change_list.push_back(
       syncer::SyncChange(
           FROM_HERE,
@@ -563,7 +562,7 @@
   TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
   autofill_syncable_service_.set_sync_processor(sync_change_processor);
 
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Jane"));
   AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile);
   autofill_syncable_service_.AutofillProfileChanged(change);
@@ -575,7 +574,7 @@
   sync_pb::AutofillProfileSpecifics specifics =
       result.sync_data().GetSpecifics().autofill_profile();
   EXPECT_EQ(kGuid1, specifics.guid());
-  EXPECT_EQ(kHttpsOrigin, specifics.origin());
+  EXPECT_EQ(kEmptyOrigin, specifics.origin());
   EXPECT_THAT(specifics.name_first(), testing::ElementsAre("Jane"));
 }
 
@@ -616,10 +615,10 @@
 // |from_profile| into |into_profile| but not the other way around.
 TEST_F(AutofillProfileSyncableServiceTest,
        MergeSimilarProfiles_AdditionalInfoInBothProfiles) {
-  AutofillProfile into_profile(kGuid1, kHttpOrigin);
+  AutofillProfile into_profile(kGuid1, kEmptyOrigin);
   into_profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("111 First St."));
 
-  AutofillProfile from_profile(kGuid2, kHttpsOrigin);
+  AutofillProfile from_profile(kGuid2, kEmptyOrigin);
   from_profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("111 First St."));
 
   from_profile.set_use_count(0);
@@ -644,7 +643,7 @@
       from_profile, &into_profile, "en-US"));
   EXPECT_EQ(ASCIIToUTF16("650234567"),
             into_profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER));
-  EXPECT_EQ(kHttpsOrigin, into_profile.origin());
+  EXPECT_EQ(kEmptyOrigin, into_profile.origin());
 
   // Make sure that the language code of |into_profile| was not added to
   // |from_profile|.
@@ -656,8 +655,8 @@
 TEST_F(AutofillProfileSyncableServiceTest,
        MergeSimilarProfiles_DifferentUseDates) {
   // Different guids, same origin.
-  AutofillProfile into_profile(kGuid1, kHttpOrigin);
-  AutofillProfile from_profile(kGuid2, kHttpOrigin);
+  AutofillProfile into_profile(kGuid1, kEmptyOrigin);
+  AutofillProfile from_profile(kGuid2, kEmptyOrigin);
 
   from_profile.set_use_count(0);
   into_profile.set_use_count(0);
@@ -687,8 +686,8 @@
 TEST_F(AutofillProfileSyncableServiceTest,
        MergeSimilarProfiles_NonZeroUseCounts) {
   // Different guids, same origin, same use date.
-  AutofillProfile into_profile(kGuid1, kHttpOrigin);
-  AutofillProfile from_profile(kGuid2, kHttpOrigin);
+  AutofillProfile into_profile(kGuid1, kEmptyOrigin);
+  AutofillProfile from_profile(kGuid2, kEmptyOrigin);
   from_profile.set_use_date(base::Time::FromTimeT(1234));
   into_profile.set_use_date(base::Time::FromTimeT(1234));
 
@@ -759,7 +758,7 @@
   sync_pb::AutofillProfileSpecifics* autofill_specifics =
       specifics.mutable_autofill_profile();
   autofill_specifics->set_guid(kGuid1);
-  autofill_specifics->set_origin(kHttpsOrigin);
+  autofill_specifics->set_origin(kEmptyOrigin);
   autofill_specifics->add_name_first(std::string());
   autofill_specifics->add_name_middle(std::string());
   autofill_specifics->add_name_last(std::string());
@@ -777,7 +776,7 @@
   // Set up expectations: Full street address takes precedence over address
   // lines.
   syncer::SyncChangeList expected_change_list;
-  AutofillProfile expected_profile(kGuid1, kHttpsOrigin);
+  AutofillProfile expected_profile(kGuid1, kEmptyOrigin);
   expected_profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
                               ASCIIToUTF16("456 El Camino Real\n"
                                            "Suite #1337"));
@@ -804,7 +803,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Create a profile with the street address set.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.SetRawInfo(ADDRESS_HOME_STREET_ADDRESS,
                      ASCIIToUTF16("123 Example St.\n"
                                   "Apt. 42"));
@@ -851,7 +850,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has an origin.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
 
   // Remote data does not have an origin value.
@@ -886,12 +885,53 @@
   autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
 }
 
+// Sync data without origin should not overwrite existing origin in local
+// autofill profile.
+TEST_F(AutofillProfileSyncableServiceTest,
+       NonSettingsOriginFromSyncIsIgnored_Merge) {
+  std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
+
+  // Remote data has no origin value.
+  AutofillProfile profile(kGuid1, std::string());
+  profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
+
+  // Remote data has a non-settings origin value.
+  sync_pb::EntitySpecifics specifics;
+  sync_pb::AutofillProfileSpecifics* autofill_specifics =
+      specifics.mutable_autofill_profile();
+  autofill_specifics->set_guid(profile.guid());
+  autofill_specifics->set_origin("www.example.com");
+  autofill_specifics->add_name_first("John");
+  autofill_specifics->add_name_middle(std::string());
+  autofill_specifics->add_name_last(std::string());
+  autofill_specifics->add_name_full(std::string());
+  autofill_specifics->add_email_address(std::string());
+  autofill_specifics->add_phone_home_whole_number(std::string());
+
+  syncer::SyncDataList data_list;
+  data_list.push_back(syncer::SyncData::CreateLocalData(
+      profile.guid(), profile.guid(), specifics));
+
+  // Expect the local autofill profile to still have an origin after sync.
+  MockAutofillProfileSyncableService::DataBundle expected_bundle;
+  AutofillProfile expected_profile(profile.guid(), profile.origin());
+  expected_profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  expected_bundle.profiles_to_update.push_back(&expected_profile);
+
+  // Expect no sync events to add origin to the remote data.
+  syncer::SyncChangeList expected_empty_change_list;
+
+  MergeDataAndStartSyncing(std::move(profiles_from_web_db), data_list,
+                           expected_bundle, expected_empty_change_list);
+  autofill_syncable_service_.StopSyncing(syncer::AUTOFILL_PROFILE);
+}
+
 // Missing language code field should not generate sync events.
 TEST_F(AutofillProfileSyncableServiceTest, NoLanguageCodeNoSync) {
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has an empty language code.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   EXPECT_TRUE(profile.language_code().empty());
   profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
 
@@ -930,7 +970,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has an empty language code.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   EXPECT_TRUE(profile.language_code().empty());
   profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
 
@@ -956,7 +996,7 @@
 
   // Expect the local autofill profile to have "en" language code after sync.
   MockAutofillProfileSyncableService::DataBundle expected_bundle;
-  AutofillProfile expected_profile(kGuid1, kHttpsOrigin);
+  AutofillProfile expected_profile(kGuid1, kEmptyOrigin);
   expected_profile.set_language_code("en");
   expected_bundle.profiles_to_update.push_back(&expected_profile);
 
@@ -973,7 +1013,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has "de" language code.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.set_language_code("de");
   profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
 
@@ -999,7 +1039,7 @@
 
   // Expect the local autofill profile to have "en" language code after sync.
   MockAutofillProfileSyncableService::DataBundle expected_bundle;
-  AutofillProfile expected_profile(kGuid1, kHttpsOrigin);
+  AutofillProfile expected_profile(kGuid1, kEmptyOrigin);
   expected_profile.set_language_code("en");
   expected_bundle.profiles_to_update.push_back(&expected_profile);
 
@@ -1017,7 +1057,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has "en" language code.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.set_language_code("en");
   profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
 
@@ -1060,7 +1100,7 @@
   TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
   autofill_syncable_service_.set_sync_processor(sync_change_processor);
 
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.set_language_code("en");
   AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile);
   autofill_syncable_service_.AutofillProfileChanged(change);
@@ -1072,7 +1112,7 @@
   sync_pb::AutofillProfileSpecifics specifics =
       result.sync_data().GetSpecifics().autofill_profile();
   EXPECT_EQ(kGuid1, specifics.guid());
-  EXPECT_EQ(kHttpsOrigin, specifics.origin());
+  EXPECT_EQ(kEmptyOrigin, specifics.origin());
   EXPECT_EQ("en", specifics.address_home_language_code());
 }
 
@@ -1081,7 +1121,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has a default validity state bitfield.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   EXPECT_EQ(0, profile.GetValidityBitfieldValue());
   profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
 
@@ -1119,7 +1159,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has a default validity state.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   EXPECT_EQ(0, profile.GetValidityBitfieldValue());
   profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
 
@@ -1145,7 +1185,7 @@
   // Expect the local autofill profile to have the non default validity state
   // bitfield after sync.
   MockAutofillProfileSyncableService::DataBundle expected_bundle;
-  AutofillProfile expected_profile(kGuid1, kHttpsOrigin);
+  AutofillProfile expected_profile(kGuid1, kEmptyOrigin);
   expected_profile.SetValidityFromBitfieldValue(kValidityStateBitfield);
   expected_bundle.profiles_to_update.push_back(&expected_profile);
 
@@ -1162,7 +1202,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has a non default validity state bitfield value.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.SetValidityFromBitfieldValue(kValidityStateBitfield + 1);
   profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
 
@@ -1188,7 +1228,7 @@
   // Expect the local autofill profile to have the remote validity state
   // bitfield value after sync.
   MockAutofillProfileSyncableService::DataBundle expected_bundle;
-  AutofillProfile expected_profile(kGuid1, kHttpsOrigin);
+  AutofillProfile expected_profile(kGuid1, kEmptyOrigin);
   expected_profile.SetValidityFromBitfieldValue(kValidityStateBitfield);
   expected_bundle.profiles_to_update.push_back(&expected_profile);
 
@@ -1207,7 +1247,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has a non default validity state bitfield value.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.SetValidityFromBitfieldValue(kValidityStateBitfield);
   profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
 
@@ -1250,7 +1290,7 @@
   TestSyncChangeProcessor* sync_change_processor = new TestSyncChangeProcessor;
   autofill_syncable_service_.set_sync_processor(sync_change_processor);
 
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.SetValidityFromBitfieldValue(kValidityStateBitfield);
   AutofillProfileChange change(AutofillProfileChange::ADD, kGuid1, &profile);
   autofill_syncable_service_.AutofillProfileChanged(change);
@@ -1262,7 +1302,7 @@
   sync_pb::AutofillProfileSpecifics specifics =
       result.sync_data().GetSpecifics().autofill_profile();
   EXPECT_EQ(kGuid1, specifics.guid());
-  EXPECT_EQ(kHttpsOrigin, specifics.origin());
+  EXPECT_EQ(kEmptyOrigin, specifics.origin());
   EXPECT_EQ(kValidityStateBitfield, specifics.validity_state_bitfield());
 }
 
@@ -1271,7 +1311,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has an empty full name.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
   profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
 
@@ -1307,7 +1347,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has a full name.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.SetRawInfo(NAME_FULL, ASCIIToUTF16("John Jacob Smith, Jr"));
   profiles_from_web_db.push_back(std::make_unique<AutofillProfile>(profile));
 
@@ -1347,7 +1387,7 @@
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
   // Local autofill profile has 0 for use_count/use_date.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.set_language_code("en");
   profile.set_use_count(0);
   profile.set_use_date(base::Time());
@@ -1447,7 +1487,7 @@
   SetUp();
   std::vector<std::unique_ptr<AutofillProfile>> profiles_from_web_db;
 
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.set_language_code("en");
   profile.set_use_count(test_case.local_use_count);
   profile.set_use_date(test_case.local_use_date);
@@ -1515,7 +1555,7 @@
   sync_pb::AutofillProfileSpecifics* autofill_specifics =
       specifics.mutable_autofill_profile();
   autofill_specifics->set_guid(kGuid1);
-  autofill_specifics->set_origin(kHttpsOrigin);
+  autofill_specifics->set_origin(kEmptyOrigin);
   autofill_specifics->add_name_first(std::string());
   autofill_specifics->add_name_middle(std::string());
   autofill_specifics->add_name_last(std::string());
@@ -1528,8 +1568,7 @@
 
   syncer::SyncDataList data_list;
   data_list.push_back(
-      syncer::SyncData::CreateLocalData(
-          kGuid1, kHttpsOrigin, specifics));
+      syncer::SyncData::CreateLocalData(kGuid1, kEmptyOrigin, specifics));
 
   EXPECT_CALL(autofill_syncable_service_, LoadAutofillData(_))
       .Times(1)
@@ -1545,7 +1584,7 @@
           new syncer::SyncErrorFactoryMock()));
 
   // Update to the usage stats for that profile.
-  AutofillProfile profile(kGuid1, kHttpsOrigin);
+  AutofillProfile profile(kGuid1, kEmptyOrigin);
   profile.set_language_code("en");
   profile.set_use_count(10U);
   profile.set_use_date(base::Time::FromTimeT(30));
@@ -1586,4 +1625,74 @@
       AutofillProfileChange::UPDATE, server_profile.guid(), &server_profile));
 }
 
+// Tests that a non-settings origin from the server is never set to the local
+// profile.
+TEST_F(AutofillProfileSyncableServiceTest,
+       OverwriteProfileWithServerData_NonSettingsOrigin) {
+  // Create a profile with an empty origin.
+  AutofillProfile profile(kGuid1, std::string());
+  profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 1st st"));
+
+  // Create a Sync profile with a non-settings origin.
+  sync_pb::EntitySpecifics specifics;
+  sync_pb::AutofillProfileSpecifics* autofill_specifics =
+      specifics.mutable_autofill_profile();
+  autofill_specifics->set_guid(profile.guid());
+  autofill_specifics->set_origin("https://www.example.com");
+  autofill_specifics->add_name_first("John");
+  autofill_specifics->add_name_middle(std::string());
+  autofill_specifics->add_name_last(std::string());
+  autofill_specifics->add_name_full(std::string());
+  autofill_specifics->add_email_address(std::string());
+  autofill_specifics->add_phone_home_whole_number(std::string());
+  autofill_specifics->set_address_home_line1("1 1st st");
+  autofill_specifics->set_use_count(profile.use_count());
+  autofill_specifics->set_use_date(profile.use_date().ToTimeT());
+
+  // Expect that the empty origin is not overwritten.
+  autofill_syncable_service_.OverwriteProfileWithServerData(*autofill_specifics,
+                                                            &profile);
+  EXPECT_TRUE(profile.origin().empty());
+
+  // Set the local origin to settings.
+  profile.set_origin(kSettingsOrigin);
+
+  // Expect that the settings origin is not overwritten.
+  autofill_syncable_service_.OverwriteProfileWithServerData(*autofill_specifics,
+                                                            &profile);
+  EXPECT_EQ(kSettingsOrigin, profile.origin());
+}
+
+// Tests that a non-settings origin from the server is not set to the local
+// profile.
+TEST_F(AutofillProfileSyncableServiceTest,
+       OverwriteProfileWithServerData_SettingsOrigin) {
+  // Create a profile with an empty origin.
+  AutofillProfile profile(kGuid1, std::string());
+  profile.SetRawInfo(NAME_FIRST, ASCIIToUTF16("John"));
+  profile.SetRawInfo(ADDRESS_HOME_LINE1, ASCIIToUTF16("1 1st st"));
+
+  // Create a Sync profile with a non-settings origin.
+  sync_pb::EntitySpecifics specifics;
+  sync_pb::AutofillProfileSpecifics* autofill_specifics =
+      specifics.mutable_autofill_profile();
+  autofill_specifics->set_guid(profile.guid());
+  autofill_specifics->set_origin(kSettingsOrigin);
+  autofill_specifics->add_name_first("John");
+  autofill_specifics->add_name_middle(std::string());
+  autofill_specifics->add_name_last(std::string());
+  autofill_specifics->add_name_full(std::string());
+  autofill_specifics->add_email_address(std::string());
+  autofill_specifics->add_phone_home_whole_number(std::string());
+  autofill_specifics->set_address_home_line1("1 1st st");
+  autofill_specifics->set_use_count(profile.use_count());
+  autofill_specifics->set_use_date(profile.use_date().ToTimeT());
+
+  // Expect that the settings origin replaced the empty origin.
+  autofill_syncable_service_.OverwriteProfileWithServerData(*autofill_specifics,
+                                                            &profile);
+  EXPECT_EQ(kSettingsOrigin, profile.origin());
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/browser/webdata/web_data_service_unittest.cc b/components/autofill/core/browser/webdata/web_data_service_unittest.cc
index 528064c..9058c7e 100644
--- a/components/autofill/core/browser/webdata/web_data_service_unittest.cc
+++ b/components/autofill/core/browser/webdata/web_data_service_unittest.cc
@@ -332,10 +332,10 @@
 TEST_F(WebDataServiceAutofillTest, ProfileUpdate) {
   // The GUIDs are alphabetical for easier testing.
   AutofillProfile profile1("6141084B-72D7-4B73-90CF-3D6AC154673B",
-                           "http://example.com");
+                           std::string());
   profile1.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Abe"));
   AutofillProfile profile2("087151C8-6AB1-487C-9095-28E80BE5DA15",
-                           "http://example.com");
+                           std::string());
   profile2.SetRawInfo(NAME_FIRST, ASCIIToUTF16("Alice"));
 
   EXPECT_CALL(observer_, AutofillProfileChanged(_))
@@ -422,11 +422,9 @@
 }
 
 TEST_F(WebDataServiceAutofillTest, CreditUpdate) {
-  CreditCard card1("E4D2662E-5E16-44F3-AF5A-5A77FAE4A6F3",
-                   "https://ejemplo.mx");
+  CreditCard card1("E4D2662E-5E16-44F3-AF5A-5A77FAE4A6F3", std::string());
   card1.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Abe"));
-  CreditCard card2("B9C52112-BD5F-4080-84E1-C651D2CB90E2",
-                   "https://example.com");
+  CreditCard card2("B9C52112-BD5F-4080-84E1-C651D2CB90E2", std::string());
   card2.SetRawInfo(CREDIT_CARD_NAME_FULL, ASCIIToUTF16("Alice"));
 
   wds_->AddCreditCard(card1);
diff --git a/components/domain_reliability/service_unittest.cc b/components/domain_reliability/service_unittest.cc
index f8fa192..a115f15 100644
--- a/components/domain_reliability/service_unittest.cc
+++ b/components/domain_reliability/service_unittest.cc
@@ -13,7 +13,7 @@
 #include "components/domain_reliability/test_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/permission_controller.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -28,7 +28,7 @@
 
 namespace {
 
-class TestPermissionManager : public content::PermissionManager {
+class TestPermissionManager : public content::PermissionControllerDelegate {
  public:
   TestPermissionManager() : get_permission_status_count_(0) {}
 
@@ -147,7 +147,7 @@
             content::BrowserThread::IO);
     url_request_context_getter_ =
         new net::TestURLRequestContextGetter(network_task_runner);
-    browser_context_.SetPermissionManager(
+    browser_context_.SetPermissionControllerDelegate(
         base::WrapUnique(permission_manager_));
     service_ = base::WrapUnique(DomainReliabilityService::Create(
         upload_reporter_string_, &browser_context_));
diff --git a/components/download/internal/common/OWNERS b/components/download/internal/common/OWNERS
new file mode 100644
index 0000000..42c52dc
--- /dev/null
+++ b/components/download/internal/common/OWNERS
@@ -0,0 +1,2 @@
+# For adding new file types
+per-file download_stats.cc=file://chrome/browser/resources/safe_browsing/OWNERS
diff --git a/components/download/internal/common/download_stats.cc b/components/download/internal/common/download_stats.cc
index e27afc3b..96a21a2e 100644
--- a/components/download/internal/common/download_stats.cc
+++ b/components/download/internal/common/download_stats.cc
@@ -239,7 +239,7 @@
     FILE_PATH_LITERAL(".applescript"), FILE_PATH_LITERAL(".scpt"),       // 311
     FILE_PATH_LITERAL(".scptd"),       FILE_PATH_LITERAL(".seplugin"),   // 313
     FILE_PATH_LITERAL(".osas"),        FILE_PATH_LITERAL(".osax"),       // 315
-    FILE_PATH_LITERAL(".settingcontent-ms"),                             // 316
+    FILE_PATH_LITERAL(".settingcontent-ms"), FILE_PATH_LITERAL(".oxt"),  // 317
     // NOTE! When you add a type here, please add the UMA value as a comment.
     // These must all match DownloadItem.DangerousFileType in
     // enums.xml. From 263 onward, they should also match
diff --git a/components/drive/DEPS b/components/drive/DEPS
index effd9116..dfd2734 100644
--- a/components/drive/DEPS
+++ b/components/drive/DEPS
@@ -7,6 +7,7 @@
   "+mojo/public/cpp/bindings/interface_request.h",
   "+net",
   "+services/device/public/mojom",
+  "+services/network",
   "+third_party/leveldatabase",
   "+third_party/re2",
   "+services/network/public/cpp",
diff --git a/components/drive/service/drive_api_service.cc b/components/drive/service/drive_api_service.cc
index b00195c..ae7ff1cd 100644
--- a/components/drive/service/drive_api_service.cc
+++ b/components/drive/service/drive_api_service.cc
@@ -305,7 +305,6 @@
 
   sender_ = std::make_unique<RequestSender>(
       new google_apis::AuthService(oauth2_token_service_, account_id,
-                                   url_request_context_getter_.get(),
                                    url_loader_factory_, scopes),
       url_request_context_getter_.get(), blocking_task_runner_.get(),
       custom_user_agent_, traffic_annotation_);
diff --git a/components/feature_engagement/README.md b/components/feature_engagement/README.md
index 5e8d5cd0..ea4a5711 100644
--- a/components/feature_engagement/README.md
+++ b/components/feature_engagement/README.md
@@ -241,17 +241,18 @@
 1.  Add feature to the histogram suffix `IPHFeatures` in:
     `//tools/metrics/histograms/histograms.xml`.
     *   The suffix must match the `base::Feature` `name` member of your feature.
-1.  Add feature to the actions file (actions do not support automatic suffixes):
-    `//tools/metrics/actions/actions.xml`.
+1.  Add feature to the actions file at: `//tools/metrics/actions/actions.xml`.
     *   The suffix must match the `base::Feature` `name` member.
-    *   Use an old example to ensure you configure and describe it correctly.
-    *   For `IPH_MyFunFeature` it would look like this:
-        *   `<action name="InProductHelp.NotifyEvent.IPH_MyFunFeature">`
-        *   `<action name="InProductHelp.NotifyUsedEvent.IPH_MyFunFeature">`
-        *   `<action name="InProductHelp.ShouldTriggerHelpUI.IPH_MyFunFeature">`
-        *   `<action name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_MyFunFeature">`
-        *   `<action name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_MyFunFeature">`
-        *   `<action name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_MyFunFeature">`
+    *   Find the `<action-suffix>` entry at the end of the file, where the
+        following `<affected-action>`s are listed:
+        *   `InProductHelp.NotifyEvent.IPH`
+        *   `InProductHelp.NotifyUsedEvent.IPH`
+        *   `InProductHelp.ShouldTriggerHelpUI.IPH`
+        *   `InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH`
+        *   `InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH`
+        *   `InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH`
+    *   Add an alphebetically sorted entry to the list of `<suffix>`es like:
+        `<suffix name="MyFunFeature" label="For MyFunFeature feature."/>`
 
 ### Adding a local field trial testing configuration
 
diff --git a/components/gcm_driver/gcm_client_impl.cc b/components/gcm_driver/gcm_client_impl.cc
index be04384..45c5cb4 100644
--- a/components/gcm_driver/gcm_client_impl.cc
+++ b/components/gcm_driver/gcm_client_impl.cc
@@ -695,14 +695,11 @@
                                            device_checkin_info_.account_tokens,
                                            gservices_settings_.digest(),
                                            chrome_build_proto);
-  checkin_request_.reset(
-      new CheckinRequest(gservices_settings_.GetCheckinURL(),
-                         request_info,
-                         GetGCMBackoffPolicy(),
-                         base::Bind(&GCMClientImpl::OnCheckinCompleted,
-                                    weak_ptr_factory_.GetWeakPtr()),
-                         url_request_context_getter_.get(),
-                         &recorder_));
+  checkin_request_.reset(new CheckinRequest(
+      gservices_settings_.GetCheckinURL(), request_info, GetGCMBackoffPolicy(),
+      base::Bind(&GCMClientImpl::OnCheckinCompleted,
+                 weak_ptr_factory_.GetWeakPtr()),
+      url_loader_factory_, &recorder_));
   // Taking a snapshot of the accounts count here, as there might be an asynch
   // update of the account tokens while checkin is in progress.
   device_checkin_info_.SnapshotCheckinAccounts();
@@ -1162,7 +1159,7 @@
           std::move(request_handler), GetGCMBackoffPolicy(),
           base::Bind(&GCMClientImpl::OnUnregisterCompleted,
                      weak_ptr_factory_.GetWeakPtr(), registration_info),
-          kMaxUnregistrationRetries, url_request_context_getter_, &recorder_,
+          kMaxUnregistrationRetries, url_loader_factory_, &recorder_,
           source_to_record));
   unregistration_request->Start();
   pending_unregistration_requests_.insert(
diff --git a/components/gcm_driver/gcm_client_impl_unittest.cc b/components/gcm_driver/gcm_client_impl_unittest.cc
index b9a3411..a2895c0e 100644
--- a/components/gcm_driver/gcm_client_impl_unittest.cc
+++ b/components/gcm_driver/gcm_client_impl_unittest.cc
@@ -566,11 +566,10 @@
   std::string response_string;
   response.SerializeToString(&response_string);
 
-  net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher);
-  fetcher->set_response_code(response_code);
-  fetcher->SetResponseString(response_string);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
+  EXPECT_TRUE(url_loader_factory()->SimulateResponseForPendingRequest(
+      gservices_settings().GetCheckinURL(),
+      network::URLLoaderCompletionStatus(net::OK),
+      network::CreateResourceResponseHead(response_code), response_string));
   // Give a chance for GCMStoreImpl::Backend to finish persisting data.
   PumpLoopUntilIdle();
 }
@@ -592,11 +591,11 @@
     const std::string& app_id) {
   std::string response(kUnregistrationResponsePrefix);
   response.append(app_id);
-  net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher);
-  fetcher->set_response_code(net::HTTP_OK);
-  fetcher->SetResponseString(response);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+  EXPECT_TRUE(url_loader_factory()->SimulateResponseForPendingRequest(
+      GURL(kRegisterUrl), network::URLLoaderCompletionStatus(net::OK),
+      network::CreateResourceResponseHead(net::HTTP_OK), response));
+
   // Give a chance for GCMStoreImpl::Backend to finish persisting data.
   PumpLoopUntilIdle();
 }
@@ -1705,11 +1704,11 @@
 
 void GCMClientInstanceIDTest::CompleteDeleteToken() {
   std::string response(kDeleteTokenResponse);
-  net::TestURLFetcher* fetcher = url_fetcher_factory()->GetFetcherByID(0);
-  ASSERT_TRUE(fetcher);
-  fetcher->set_response_code(net::HTTP_OK);
-  fetcher->SetResponseString(response);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+  EXPECT_TRUE(url_loader_factory()->SimulateResponseForPendingRequest(
+      GURL(kRegisterUrl), network::URLLoaderCompletionStatus(net::OK),
+      network::CreateResourceResponseHead(net::HTTP_OK), response));
+
   // Give a chance for GCMStoreImpl::Backend to finish persisting data.
   PumpLoopUntilIdle();
 }
diff --git a/components/omnibox/browser/BUILD.gn b/components/omnibox/browser/BUILD.gn
index 0bc863c..1325b60 100644
--- a/components/omnibox/browser/BUILD.gn
+++ b/components/omnibox/browser/BUILD.gn
@@ -242,6 +242,8 @@
     "test_omnibox_client.h",
     "test_omnibox_edit_controller.cc",
     "test_omnibox_edit_controller.h",
+    "test_omnibox_edit_model.cc",
+    "test_omnibox_edit_model.h",
     "test_omnibox_view.cc",
     "test_omnibox_view.h",
     "test_scheme_classifier.cc",
@@ -344,7 +346,7 @@
     "//sql:test_support",
     "//testing/gmock",
     "//testing/gtest",
-    "//ui/base:base",
+    "//ui/base:test_support",
     "//url",
   ]
 }
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index 59fc322..e9b00583 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -282,10 +282,6 @@
   return !AutocompleteMatch::IsSearchType(CurrentMatch(nullptr).type);
 }
 
-AutocompleteMatch::Type OmniboxEditModel::CurrentTextType() const {
-  return CurrentMatch(nullptr).type;
-}
-
 void OmniboxEditModel::AdjustTextForCopy(int sel_min,
                                          base::string16* text,
                                          GURL* url_from_text,
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h
index 445d76f..a41aebe6 100644
--- a/components/omnibox/browser/omnibox_edit_model.h
+++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -136,9 +136,6 @@
   // URL/navigation, as opposed to a search.
   bool CurrentTextIsURL() const;
 
-  // Returns the match type for the current edit contents.
-  AutocompleteMatch::Type CurrentTextType() const;
-
   // Invoked to adjust the text before writting to the clipboard for a copy
   // (e.g. by adding 'http' to the front). |sel_min| gives the minimum position
   // of the selection e.g. min(selection_start, selection_end). |text| is the
diff --git a/components/omnibox/browser/omnibox_edit_model_unittest.cc b/components/omnibox/browser/omnibox_edit_model_unittest.cc
index 9a6f88f2..cfc8ddba 100644
--- a/components/omnibox/browser/omnibox_edit_model_unittest.cc
+++ b/components/omnibox/browser/omnibox_edit_model_unittest.cc
@@ -17,41 +17,11 @@
 #include "components/omnibox/browser/search_provider.h"
 #include "components/omnibox/browser/test_omnibox_client.h"
 #include "components/omnibox/browser/test_omnibox_edit_controller.h"
+#include "components/omnibox/browser/test_omnibox_edit_model.h"
 #include "components/omnibox/browser/test_omnibox_view.h"
 #include "components/toolbar/test_toolbar_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-namespace {
-
-class TestOmniboxEditModel : public OmniboxEditModel {
- public:
-  TestOmniboxEditModel(OmniboxView* view, OmniboxEditController* controller)
-      : OmniboxEditModel(view,
-                         controller,
-                         std::make_unique<TestOmniboxClient>()),
-        popup_is_open_(false) {}
-
-  bool PopupIsOpen() const override { return popup_is_open_; };
-
-  AutocompleteMatch CurrentMatch(GURL*) const override {
-    return current_match_;
-  };
-
-  void SetPopupIsOpen(bool open) { popup_is_open_ = open; }
-
-  void SetCurrentMatch(const AutocompleteMatch& match) {
-    current_match_ = match;
-  }
-
- private:
-  bool popup_is_open_;
-  AutocompleteMatch current_match_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestOmniboxEditModel);
-};
-
-}  // namespace
-
 class OmniboxEditModelTest : public testing::Test {
  public:
   void SetUp() override {
diff --git a/components/omnibox/browser/omnibox_view.cc b/components/omnibox/browser/omnibox_view.cc
index ea7e0a12..b8bed1f 100644
--- a/components/omnibox/browser/omnibox_view.cc
+++ b/components/omnibox/browser/omnibox_view.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "components/bookmarks/browser/bookmark_model.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/omnibox_edit_controller.h"
 #include "components/omnibox/browser/omnibox_edit_model.h"
@@ -114,25 +115,46 @@
         controller_->GetToolbarModel()->GetVectorIcon(), dip_size, color);
   }
 
-  // For Material Refresh, display the favicon of the default search engine.
-  const auto type = model_ ? model_->CurrentTextType()
-                           : AutocompleteMatchType::URL_WHAT_YOU_TYPED;
-  if (ui::MaterialDesignController::IsNewerMaterialUi() &&
-      AutocompleteMatch::IsSearchType(type)) {
-    gfx::Image favicon = model_->client()->GetFaviconForDefaultSearchProvider(
-        std::move(on_icon_fetched));
+  // For tests, model_ will be null.
+  if (!model_) {
+    const gfx::VectorIcon& vector_icon = AutocompleteMatch::TypeToVectorIcon(
+        AutocompleteMatchType::URL_WHAT_YOU_TYPED, false /*is_bookmark*/,
+        false /*is_tab_match*/);
+    return gfx::CreateVectorIcon(vector_icon, dip_size, color);
+  }
+
+  AutocompleteMatch match = model_->CurrentMatch(nullptr);
+  bool is_bookmarked = false;
+
+  if (ui::MaterialDesignController::IsNewerMaterialUi()) {
+    gfx::Image favicon;
+
+    if (AutocompleteMatch::IsSearchType(match.type)) {
+      // For search queries, display default search engine's favicon.
+      favicon = model_->client()->GetFaviconForDefaultSearchProvider(
+          std::move(on_icon_fetched));
+
+    } else if (OmniboxFieldTrial::IsShowSuggestionFaviconsEnabled()) {
+      // For site suggestions, display site's favicon.
+      favicon = model_->client()->GetFaviconForPageUrl(
+          match.destination_url, std::move(on_icon_fetched));
+    }
+
     if (!favicon.IsEmpty())
       return favicon.AsImageSkia();
-
     // If the client returns an empty favicon, fall through to provide the
     // generic vector icon. |on_icon_fetched| may or may not be called later.
     // If it's never called, the vector icon we provide below should remain.
+
+    // For bookmarked suggestions, display bookmark icon.
+    bookmarks::BookmarkModel* bookmark_model =
+        model_->client()->GetBookmarkModel();
+    is_bookmarked =
+        bookmark_model && bookmark_model->IsBookmarked(match.destination_url);
   }
 
-  const gfx::VectorIcon& vector_icon =
-      AutocompleteMatch::TypeToVectorIcon(type,
-                                          /*is_bookmark=*/false,
-                                          /*is_tab_match=*/false);
+  const gfx::VectorIcon& vector_icon = AutocompleteMatch::TypeToVectorIcon(
+      match.type, is_bookmarked, false /*is_tab_match*/);
   return gfx::CreateVectorIcon(vector_icon, dip_size, color);
 #endif  // defined(OS_IOS)
 }
diff --git a/components/omnibox/browser/omnibox_view.h b/components/omnibox/browser/omnibox_view.h
index 0da2e692..b8c0795 100644
--- a/components/omnibox/browser/omnibox_view.h
+++ b/components/omnibox/browser/omnibox_view.h
@@ -289,6 +289,7 @@
 
  private:
   friend class OmniboxViewMacTest;
+  friend class TestOmniboxView;
 
   // |model_| can be NULL in tests.
   std::unique_ptr<OmniboxEditModel> model_;
diff --git a/components/omnibox/browser/omnibox_view_unittest.cc b/components/omnibox/browser/omnibox_view_unittest.cc
index b9cadd6..495e953 100644
--- a/components/omnibox/browser/omnibox_view_unittest.cc
+++ b/components/omnibox/browser/omnibox_view_unittest.cc
@@ -3,20 +3,72 @@
 // found in the LICENSE file.
 
 #include <stddef.h>
+#include <utility>
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
+#include "build/build_config.h"
+#include "components/bookmarks/browser/bookmark_model.h"
+#include "components/bookmarks/test/test_bookmark_client.h"
+#include "components/omnibox/browser/autocomplete_match.h"
+#include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/omnibox/browser/omnibox_view.h"
+#include "components/omnibox/browser/test_omnibox_client.h"
+#include "components/omnibox/browser/test_omnibox_edit_controller.h"
+#include "components/omnibox/browser/test_omnibox_edit_model.h"
+#include "components/omnibox/browser/test_omnibox_view.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
+#include "ui/base/test/material_design_controller_test_api.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/favicon_size.h"
+#include "ui/gfx/paint_vector_icon.h"
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+#include "components/omnibox/browser/vector_icons.h"  // nogncheck
+#include "components/vector_icons/vector_icons.h"     // nogncheck
+#endif
 
 using base::ASCIIToUTF16;
 
 namespace {
 
-class OmniboxViewTest : public PlatformTest {
+class OmniboxViewTest : public testing::Test {
+ public:
+  OmniboxViewTest() {
+    controller_ = std::make_unique<TestOmniboxEditController>();
+    view_ = std::make_unique<TestOmniboxView>(controller_.get());
+
+    model_ = new TestOmniboxEditModel(view_.get(), controller_.get());
+    view_->SetModel(model_);
+
+    bookmark_model_ = bookmarks::TestBookmarkClient::CreateModel();
+    client()->SetBookmarkModel(bookmark_model_.get());
+
+    material_design_ =
+        std::make_unique<ui::test::MaterialDesignControllerTestAPI>(
+            ui::MaterialDesignController::MATERIAL_REFRESH);
+  }
+
+  TestOmniboxView* view() { return view_.get(); }
+
+  TestOmniboxEditModel* model() { return model_; }
+
+  TestOmniboxClient* client() {
+    return static_cast<TestOmniboxClient*>(model()->client());
+  }
+
+  bookmarks::BookmarkModel* bookmark_model() { return bookmark_model_.get(); }
+
+ private:
+  base::test::ScopedTaskEnvironment task_environment_;
+  std::unique_ptr<ui::test::MaterialDesignControllerTestAPI> material_design_;
+  std::unique_ptr<TestOmniboxEditController> controller_;
+  std::unique_ptr<TestOmniboxView> view_;
+  TestOmniboxEditModel* model_;
+  std::unique_ptr<bookmarks::BookmarkModel> bookmark_model_;
 };
 
 TEST_F(OmniboxViewTest, TestStripSchemasUnsafeForPaste) {
@@ -93,4 +145,57 @@
             OmniboxView::SanitizeTextForPaste(kSafeJavaScriptUrl));
 }
 
+#if !defined(OS_ANDROID) && !defined(OS_IOS)
+// Tests GetIcon returns the default search icon when the match is a search
+// query.
+TEST_F(OmniboxViewTest, GetIcon_Default) {
+  gfx::ImageSkia expected_icon = gfx::CreateVectorIcon(
+      vector_icons::kSearchIcon, gfx::kFaviconSize, gfx::kPlaceholderColor);
+
+  gfx::ImageSkia icon = view()->GetIcon(
+      gfx::kFaviconSize, gfx::kPlaceholderColor, base::DoNothing());
+
+  EXPECT_EQ(icon.bitmap(), expected_icon.bitmap());
+}
+
+// Tests GetIcon returns the bookmark icon when the match is bookmarked.
+TEST_F(OmniboxViewTest, GetIcon_BookmarkIcon) {
+  const GURL kUrl("https://bookmarks.com");
+
+  AutocompleteMatch match;
+  match.destination_url = kUrl;
+  model()->SetCurrentMatch(match);
+
+  bookmark_model()->AddURL(bookmark_model()->bookmark_bar_node(), 0,
+                           base::ASCIIToUTF16("a bookmark"), kUrl);
+
+  gfx::ImageSkia expected_icon =
+      gfx::CreateVectorIcon(omnibox::kTouchableBookmarkIcon, gfx::kFaviconSize,
+                            gfx::kPlaceholderColor);
+
+  gfx::ImageSkia icon = view()->GetIcon(
+      gfx::kFaviconSize, gfx::kPlaceholderColor, base::DoNothing());
+
+  EXPECT_EQ(icon.bitmap(), expected_icon.bitmap());
+}
+
+// Tests GetIcon returns the website's favicon when the match is a website.
+TEST_F(OmniboxViewTest, GetIcon_Favicon) {
+  const GURL kUrl("https://woahDude.com");
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+  scoped_feature_list_.InitAndEnableFeature(
+      omnibox::kUIExperimentShowSuggestionFavicons);
+
+  AutocompleteMatch match;
+  match.type = AutocompleteMatchType::URL_WHAT_YOU_TYPED;
+  match.destination_url = kUrl;
+  model()->SetCurrentMatch(match);
+
+  view()->GetIcon(gfx::kFaviconSize, gfx::kPlaceholderColor, base::DoNothing());
+
+  EXPECT_EQ(client()->GetPageUrlForLastFaviconRequest(), kUrl);
+}
+#endif  // !defined(OS_IOS)
+
 }  // namespace
diff --git a/components/omnibox/browser/test_omnibox_client.cc b/components/omnibox/browser/test_omnibox_client.cc
index 67ffc32..d9a2bdf 100644
--- a/components/omnibox/browser/test_omnibox_client.cc
+++ b/components/omnibox/browser/test_omnibox_client.cc
@@ -22,6 +22,7 @@
 
 TestOmniboxClient::TestOmniboxClient()
     : session_id_(SessionID::FromSerializedValue(1)),
+      bookmark_model_(nullptr),
       autocomplete_classifier_(
           std::make_unique<AutocompleteController>(
               CreateAutocompleteProviderClient(),
@@ -69,6 +70,15 @@
   return session_id_;
 }
 
+void TestOmniboxClient::SetBookmarkModel(
+    bookmarks::BookmarkModel* bookmark_model) {
+  bookmark_model_ = bookmark_model;
+}
+
+bookmarks::BookmarkModel* TestOmniboxClient::GetBookmarkModel() {
+  return bookmark_model_;
+}
+
 const AutocompleteSchemeClassifier& TestOmniboxClient::GetSchemeClassifier()
     const {
   return scheme_classifier_;
@@ -85,3 +95,14 @@
   bitmap.allocN32Pixels(16, 16);
   return gfx::Image(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
 }
+
+gfx::Image TestOmniboxClient::GetFaviconForPageUrl(
+    const GURL& page_url,
+    FaviconFetchedCallback on_favicon_fetched) {
+  page_url_for_last_favicon_request_ = page_url;
+  return gfx::Image();
+}
+
+GURL TestOmniboxClient::GetPageUrlForLastFaviconRequest() const {
+  return page_url_for_last_favicon_request_;
+}
diff --git a/components/omnibox/browser/test_omnibox_client.h b/components/omnibox/browser/test_omnibox_client.h
index e7ac3bb9..f50aed29 100644
--- a/components/omnibox/browser/test_omnibox_client.h
+++ b/components/omnibox/browser/test_omnibox_client.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "components/bookmarks/browser/bookmark_model.h"
 #include "components/omnibox/browser/autocomplete_classifier.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_provider_client.h"
@@ -36,16 +37,25 @@
       const AutocompleteMatch& alternate_nav_match) override;
   bool IsPasteAndGoEnabled() const override;
   const SessionID& GetSessionID() const override;
+  void SetBookmarkModel(bookmarks::BookmarkModel* bookmark_model);
+  bookmarks::BookmarkModel* GetBookmarkModel() override;
   const AutocompleteSchemeClassifier& GetSchemeClassifier() const override;
   AutocompleteClassifier* GetAutocompleteClassifier() override;
   gfx::Image GetSizedIcon(const gfx::VectorIcon& vector_icon_type,
                           SkColor vector_icon_color) const override;
+  gfx::Image GetFaviconForPageUrl(
+      const GURL& page_url,
+      FaviconFetchedCallback on_favicon_fetched) override;
+
+  GURL GetPageUrlForLastFaviconRequest() const;
 
  private:
   AutocompleteMatch alternate_nav_match_;
   SessionID session_id_;
+  bookmarks::BookmarkModel* bookmark_model_;
   TestSchemeClassifier scheme_classifier_;
   AutocompleteClassifier autocomplete_classifier_;
+  GURL page_url_for_last_favicon_request_;
 
   DISALLOW_COPY_AND_ASSIGN(TestOmniboxClient);
 };
diff --git a/components/omnibox/browser/test_omnibox_edit_model.cc b/components/omnibox/browser/test_omnibox_edit_model.cc
new file mode 100644
index 0000000..a754c8bc
--- /dev/null
+++ b/components/omnibox/browser/test_omnibox_edit_model.cc
@@ -0,0 +1,29 @@
+// 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.
+
+#include <memory>
+
+#include "components/omnibox/browser/test_omnibox_client.h"
+#include "components/omnibox/browser/test_omnibox_edit_model.h"
+
+TestOmniboxEditModel::TestOmniboxEditModel(OmniboxView* view,
+                                           OmniboxEditController* controller)
+    : OmniboxEditModel(view, controller, std::make_unique<TestOmniboxClient>()),
+      popup_is_open_(false) {}
+
+bool TestOmniboxEditModel::PopupIsOpen() const {
+  return popup_is_open_;
+}
+
+AutocompleteMatch TestOmniboxEditModel::CurrentMatch(GURL*) const {
+  return current_match_;
+}
+
+void TestOmniboxEditModel::SetPopupIsOpen(bool open) {
+  popup_is_open_ = open;
+}
+
+void TestOmniboxEditModel::SetCurrentMatch(const AutocompleteMatch& match) {
+  current_match_ = match;
+}
diff --git a/components/omnibox/browser/test_omnibox_edit_model.h b/components/omnibox/browser/test_omnibox_edit_model.h
new file mode 100644
index 0000000..98efbcc
--- /dev/null
+++ b/components/omnibox/browser/test_omnibox_edit_model.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_MODEL_H_
+#define COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_MODEL_H_
+
+#include "components/omnibox/browser/omnibox_edit_model.h"
+
+class TestOmniboxEditModel : public OmniboxEditModel {
+ public:
+  TestOmniboxEditModel(OmniboxView* view, OmniboxEditController* controller);
+
+  // OmniboxEditModel:
+  bool PopupIsOpen() const override;
+  AutocompleteMatch CurrentMatch(GURL*) const override;
+
+  void SetPopupIsOpen(bool open);
+
+  void SetCurrentMatch(const AutocompleteMatch& match);
+
+ private:
+  bool popup_is_open_;
+  AutocompleteMatch current_match_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestOmniboxEditModel);
+};
+
+#endif  // COMPONENTS_OMNIBOX_BROWSER_TEST_OMNIBOX_EDIT_MODEL_H_
diff --git a/components/omnibox/browser/test_omnibox_view.cc b/components/omnibox/browser/test_omnibox_view.cc
index 67c9815..507bcbc2 100644
--- a/components/omnibox/browser/test_omnibox_view.cc
+++ b/components/omnibox/browser/test_omnibox_view.cc
@@ -73,3 +73,7 @@
 int TestOmniboxView::GetOmniboxTextLength() const {
   return 0;
 }
+
+void TestOmniboxView::SetModel(OmniboxEditModel* model) {
+  model_.reset(model);
+}
diff --git a/components/omnibox/browser/test_omnibox_view.h b/components/omnibox/browser/test_omnibox_view.h
index 45f82e1..2b29397 100644
--- a/components/omnibox/browser/test_omnibox_view.h
+++ b/components/omnibox/browser/test_omnibox_view.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "components/omnibox/browser/omnibox_edit_model.h"
 #include "components/omnibox/browser/omnibox_view.h"
 
 struct AutocompleteMatch;
@@ -65,6 +66,7 @@
   void EmphasizeURLComponents() override {}
   void SetEmphasis(bool emphasize, const gfx::Range& range) override {}
   void UpdateSchemeStyle(const gfx::Range& range) override {}
+  void SetModel(OmniboxEditModel* model);
 
  private:
   base::string16 text_;
diff --git a/components/previews/content/previews_ui_service.cc b/components/previews/content/previews_ui_service.cc
index 81cf8af..0ff68ee 100644
--- a/components/previews/content/previews_ui_service.cc
+++ b/components/previews/content/previews_ui_service.cc
@@ -99,6 +99,26 @@
   logger_->OnIgnoreBlacklistDecisionStatusChanged(ignored);
 }
 
+void PreviewsUIService::SetResourceLoadingHintsResourcePatternsToBlock(
+    const GURL& document_gurl,
+    const std::vector<std::string>& patterns) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  resource_loading_hints_document_gurl_ = document_gurl;
+  resource_loading_hints_patterns_to_block_ = patterns;
+}
+
+std::vector<std::string>
+PreviewsUIService::GetResourceLoadingHintsResourcePatternsToBlock(
+    const GURL& document_gurl) const {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // TODO(tbansal): https://crbug.com/856243. Read patterns from the proto
+  // optimizations file from the disk, and populate the return value.
+  if (document_gurl != resource_loading_hints_document_gurl_)
+    return std::vector<std::string>();
+  return resource_loading_hints_patterns_to_block_;
+}
+
 PreviewsLogger* PreviewsUIService::previews_logger() const {
   DCHECK(thread_checker_.CalledOnValidThread());
   return logger_.get();
diff --git a/components/previews/content/previews_ui_service.h b/components/previews/content/previews_ui_service.h
index 3613c89a..0c4ffdb2 100644
--- a/components/previews/content/previews_ui_service.h
+++ b/components/previews/content/previews_ui_service.h
@@ -6,6 +6,7 @@
 #define COMPONENTS_PREVIEWS_CONTENT_PREVIEWS_UI_SERVICE_H_
 
 #include <string>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -105,6 +106,23 @@
       std::vector<PreviewsEligibilityReason>&& passed_reasons,
       uint64_t page_id);
 
+  // Returns the vector of subresource patterns whose loading should be blocked
+  // when loading |document_gurl|. The pattern may be a single substring to
+  // match against the URL or it may be an ordered set of substrings to match
+  // where the substrings are separated by the ‘*’ wildcard character (with an
+  // implicit ‘*’ at the beginning and end).
+  std::vector<std::string> GetResourceLoadingHintsResourcePatternsToBlock(
+      const GURL& document_gurl) const;
+
+  // Sets the vector of subresource patterns whose loading should be blocked
+  // when loading |document_gurl| to |patterns|. The pattern may be a single
+  // substring to match against the URL or it may be an ordered set of
+  // substrings to match where the substrings are separated by the ‘*’ wildcard
+  // character (with an implicit ‘*’ at the beginning and end).
+  void SetResourceLoadingHintsResourcePatternsToBlock(
+      const GURL& document_gurl,
+      const std::vector<std::string>& patterns);
+
   // Expose the pointer to PreviewsLogger to extract logging messages. This
   // pointer's life time is the same as of |this|, and it is guaranteed to not
   // return null.
@@ -119,6 +137,14 @@
   // The IO thread task runner. Used to post tasks to |previews_decider_impl_|.
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
 
+  // |resource_loading_hints_patterns_| are the set of subresource patterns
+  // whose loading should be blocked. The hints apply to subresources when
+  // fetching |resource_loading_hints_document_gurl_|.
+  // TODO(tbansal): https://crbug.com/856243. Consider storing this
+  // data in a map or an LRU cache.
+  GURL resource_loading_hints_document_gurl_;
+  std::vector<std::string> resource_loading_hints_patterns_to_block_;
+
   // A log object to keep track of events such as previews navigations,
   // blacklist actions, etc.
   std::unique_ptr<PreviewsLogger> logger_;
diff --git a/components/signin/core/browser/BUILD.gn b/components/signin/core/browser/BUILD.gn
index 75e815a..726dab6 100644
--- a/components/signin/core/browser/BUILD.gn
+++ b/components/signin/core/browser/BUILD.gn
@@ -148,6 +148,7 @@
     "//components/pref_registry",
     "//components/webdata/common",
     "//crypto",
+    "//services/network/public/cpp",
     "//skia",
     "//sql",
     "//third_party/icu",
diff --git a/components/signin/core/browser/account_fetcher_service.cc b/components/signin/core/browser/account_fetcher_service.cc
index 00cef45..66dc8bee 100644
--- a/components/signin/core/browser/account_fetcher_service.cc
+++ b/components/signin/core/browser/account_fetcher_service.cc
@@ -222,7 +222,7 @@
     const std::string& account_id) {
   child_info_request_ = ChildAccountInfoFetcher::CreateFrom(
       child_request_account_id_, this, token_service_,
-      signin_client_->GetURLRequestContext(), invalidation_service_);
+      signin_client_->GetURLLoaderFactory(), invalidation_service_);
 }
 
 void AccountFetcherService::ResetChildInfo() {
diff --git a/components/signin/core/browser/account_reconcilor_unittest.cc b/components/signin/core/browser/account_reconcilor_unittest.cc
index 42e98f09..e79b9e6 100644
--- a/components/signin/core/browser/account_reconcilor_unittest.cc
+++ b/components/signin/core/browser/account_reconcilor_unittest.cc
@@ -113,7 +113,7 @@
 // Introduce a dummy class creating the delegate internally, to avoid the move.
 class DummyAccountReconcilorWithDelegate : public AccountReconcilor {
  public:
-  explicit DummyAccountReconcilorWithDelegate(
+  DummyAccountReconcilorWithDelegate(
       ProfileOAuth2TokenService* token_service,
       SigninManagerBase* signin_manager,
       SigninClient* client,
@@ -132,7 +132,7 @@
 
   // Takes ownership of |delegate|.
   // gmock can't work with move only parameters.
-  explicit DummyAccountReconcilorWithDelegate(
+  DummyAccountReconcilorWithDelegate(
       ProfileOAuth2TokenService* token_service,
       SigninManagerBase* signin_manager,
       SigninClient* client,
diff --git a/components/signin/core/browser/child_account_info_fetcher.cc b/components/signin/core/browser/child_account_info_fetcher.cc
index c5af00f71..bc8e267 100644
--- a/components/signin/core/browser/child_account_info_fetcher.cc
+++ b/components/signin/core/browser/child_account_info_fetcher.cc
@@ -6,6 +6,7 @@
 
 #include "build/build_config.h"
 
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 #if defined(OS_ANDROID)
 #include "components/signin/core/browser/child_account_info_fetcher_android.h"
 #else
@@ -17,13 +18,13 @@
     const std::string& account_id,
     AccountFetcherService* fetcher_service,
     OAuth2TokenService* token_service,
-    net::URLRequestContextGetter* request_context_getter,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     invalidation::InvalidationService* invalidation_service) {
 #if defined(OS_ANDROID)
   return ChildAccountInfoFetcherAndroid::Create(fetcher_service, account_id);
 #else
   return std::make_unique<ChildAccountInfoFetcherImpl>(
-      account_id, fetcher_service, token_service, request_context_getter,
+      account_id, fetcher_service, token_service, url_loader_factory,
       invalidation_service);
 #endif
 }
diff --git a/components/signin/core/browser/child_account_info_fetcher.h b/components/signin/core/browser/child_account_info_fetcher.h
index 0b3623d..f5891f5c 100644
--- a/components/signin/core/browser/child_account_info_fetcher.h
+++ b/components/signin/core/browser/child_account_info_fetcher.h
@@ -8,6 +8,7 @@
 #include <memory>
 #include <string>
 
+#include "base/memory/ref_counted.h"
 #include "build/build_config.h"
 
 #if defined(OS_ANDROID)
@@ -17,8 +18,8 @@
 namespace invalidation {
 class InvalidationService;
 }
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
 }
 class AccountFetcherService;
 class OAuth2TokenService;
@@ -31,7 +32,7 @@
       const std::string& account_id,
       AccountFetcherService* fetcher_service,
       OAuth2TokenService* token_service,
-      net::URLRequestContextGetter* request_context_getter,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       invalidation::InvalidationService* invalidation_service);
   virtual ~ChildAccountInfoFetcher();
 
diff --git a/components/signin/core/browser/child_account_info_fetcher_impl.cc b/components/signin/core/browser/child_account_info_fetcher_impl.cc
index 64bdd2b..0fb277d6 100644
--- a/components/signin/core/browser/child_account_info_fetcher_impl.cc
+++ b/components/signin/core/browser/child_account_info_fetcher_impl.cc
@@ -16,6 +16,7 @@
 #include "google/cacheinvalidation/types.pb.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 #include "google_apis/gaia/gaia_constants.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 // TODO(maroun): Remove this file.
 
@@ -48,11 +49,11 @@
     const std::string& account_id,
     AccountFetcherService* fetcher_service,
     OAuth2TokenService* token_service,
-    net::URLRequestContextGetter* request_context_getter,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     invalidation::InvalidationService* invalidation_service)
     : OAuth2TokenService::Consumer(kFetcherId),
       token_service_(token_service),
-      request_context_getter_(request_context_getter),
+      url_loader_factory_(url_loader_factory),
       fetcher_service_(fetcher_service),
       invalidation_service_(invalidation_service),
       account_id_(account_id),
@@ -100,7 +101,7 @@
   DCHECK_EQ(request, login_token_request_.get());
 
   gaia_auth_fetcher_ = fetcher_service_->signin_client_->CreateGaiaAuthFetcher(
-      this, GaiaConstants::kChromeSource, request_context_getter_);
+      this, GaiaConstants::kChromeSource, url_loader_factory_);
   gaia_auth_fetcher_->StartOAuthLogin(access_token,
                                       GaiaConstants::kGaiaService);
 }
diff --git a/components/signin/core/browser/child_account_info_fetcher_impl.h b/components/signin/core/browser/child_account_info_fetcher_impl.h
index 9046a40..7b352cbb 100644
--- a/components/signin/core/browser/child_account_info_fetcher_impl.h
+++ b/components/signin/core/browser/child_account_info_fetcher_impl.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/threading/thread_checker.h"
 #include "base/timer/timer.h"
 #include "components/invalidation/public/invalidation_handler.h"
@@ -18,6 +19,10 @@
 
 // TODO(maroun): Remove this file.
 
+namespace network {
+class SharedURLLoaderFactory;
+}
+
 class GaiaAuthFetcher;
 
 class ChildAccountInfoFetcherImpl : public ChildAccountInfoFetcher,
@@ -29,7 +34,7 @@
       const std::string& account_id,
       AccountFetcherService* fetcher_service,
       OAuth2TokenService* token_service,
-      net::URLRequestContextGetter* request_context_getter,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       invalidation::InvalidationService* invalidation_service);
   ~ChildAccountInfoFetcherImpl() override;
 
@@ -58,7 +63,7 @@
   std::string GetOwnerName() const override;
 
   OAuth2TokenService* token_service_;
-  net::URLRequestContextGetter* request_context_getter_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   AccountFetcherService* fetcher_service_;
   invalidation::InvalidationService* invalidation_service_;
   const std::string account_id_;
diff --git a/components/signin/core/browser/fake_gaia_cookie_manager_service.cc b/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
index 2289d9eb..88e6a51 100644
--- a/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/fake_gaia_cookie_manager_service.cc
@@ -10,33 +10,43 @@
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "net/url_request/test_url_fetcher_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
 
 FakeGaiaCookieManagerService::FakeGaiaCookieManagerService(
     OAuth2TokenService* token_service,
     const std::string& source,
     SigninClient* client,
-    bool use_fake_url_fetcher)
+    bool use_fake_url_loader)
     : GaiaCookieManagerService(token_service, source, client) {
-  if (use_fake_url_fetcher) {
-    url_fetcher_factory_ = std::make_unique<net::FakeURLFetcherFactory>(
-        /*default_factory=*/nullptr);
+  if (use_fake_url_loader) {
+    test_url_loader_factory_ =
+        std::make_unique<network::TestURLLoaderFactory>();
+    shared_loader_factory_ =
+        base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+            test_url_loader_factory_.get());
   }
 }
 
-FakeGaiaCookieManagerService::~FakeGaiaCookieManagerService() = default;
+FakeGaiaCookieManagerService::~FakeGaiaCookieManagerService() {
+  if (shared_loader_factory_)
+    shared_loader_factory_->Detach();
+}
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseHttpNotFound() {
-  url_fetcher_factory_->SetFakeResponse(
-      GaiaUrls::GetInstance()->ListAccountsURLWithSource(
-          GaiaConstants::kChromeSource),
-      "", net::HTTP_NOT_FOUND, net::URLRequestStatus::SUCCESS);
+  test_url_loader_factory_->AddResponse(
+      GaiaUrls::GetInstance()
+          ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
+          .spec(),
+      /*content=*/"", net::HTTP_NOT_FOUND);
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseWebLoginRequired() {
-  url_fetcher_factory_->SetFakeResponse(
-      GaiaUrls::GetInstance()->ListAccountsURLWithSource(
-          GaiaConstants::kChromeSource),
-      "Info=WebLoginRequired", net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+  test_url_loader_factory_->AddResponse(
+      GaiaUrls::GetInstance()
+          ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
+          .spec(),
+      "Info=WebLoginRequired");
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseWithParams(
@@ -55,11 +65,11 @@
     response_body.push_back(response_part);
   }
 
-  url_fetcher_factory_->SetFakeResponse(
-      GaiaUrls::GetInstance()->ListAccountsURLWithSource(
-          GaiaConstants::kChromeSource),
-      std::string("[\"f\", [") + base::JoinString(response_body, ", ") + "]]",
-      net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+  test_url_loader_factory_->AddResponse(
+      GaiaUrls::GetInstance()
+          ->ListAccountsURLWithSource(GaiaConstants::kChromeSource)
+          .spec(),
+      std::string("[\"f\", [") + base::JoinString(response_body, ", ") + "]]");
 }
 
 void FakeGaiaCookieManagerService::SetListAccountsResponseNoAccounts() {
@@ -105,3 +115,10 @@
   // be able to find the URLs.
   return GaiaConstants::kChromeSource;
 }
+
+scoped_refptr<network::SharedURLLoaderFactory>
+FakeGaiaCookieManagerService::GetURLLoaderFactory() {
+  return shared_loader_factory_
+             ? shared_loader_factory_
+             : GaiaCookieManagerService::GetURLLoaderFactory();
+}
diff --git a/components/signin/core/browser/fake_gaia_cookie_manager_service.h b/components/signin/core/browser/fake_gaia_cookie_manager_service.h
index c2550fc..40ba7bb1 100644
--- a/components/signin/core/browser/fake_gaia_cookie_manager_service.h
+++ b/components/signin/core/browser/fake_gaia_cookie_manager_service.h
@@ -8,10 +8,12 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
 
-namespace net {
-class FakeURLFetcherFactory;
+namespace network {
+class TestURLLoaderFactory;
+class WeakWrapperSharedURLLoaderFactory;
 }
 
 class FakeGaiaCookieManagerService : public GaiaCookieManagerService {
@@ -50,9 +52,12 @@
   std::string GetSourceForRequest(
       const GaiaCookieManagerService::GaiaCookieRequest& request) override;
   std::string GetDefaultSourceForRequest() override;
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
 
   // Provide a fake response for calls to /ListAccounts.
-  std::unique_ptr<net::FakeURLFetcherFactory> url_fetcher_factory_;
+  std::unique_ptr<network::TestURLLoaderFactory> test_url_loader_factory_;
+  scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
+      shared_loader_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeGaiaCookieManagerService);
 };
diff --git a/components/signin/core/browser/fake_profile_oauth2_token_service.cc b/components/signin/core/browser/fake_profile_oauth2_token_service.cc
index e7a6cc2..bdbf33bc 100644
--- a/components/signin/core/browser/fake_profile_oauth2_token_service.cc
+++ b/components/signin/core/browser/fake_profile_oauth2_token_service.cc
@@ -21,7 +21,7 @@
 
 FakeProfileOAuth2TokenService::FakeProfileOAuth2TokenService()
     : FakeProfileOAuth2TokenService(
-          std::make_unique<FakeOAuth2TokenServiceDelegate>(nullptr)) {}
+          std::make_unique<FakeOAuth2TokenServiceDelegate>()) {}
 
 FakeProfileOAuth2TokenService::FakeProfileOAuth2TokenService(
     std::unique_ptr<OAuth2TokenServiceDelegate> delegate)
@@ -122,7 +122,6 @@
 void FakeProfileOAuth2TokenService::FetchOAuth2Token(
     RequestImpl* request,
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::string& client_id,
     const std::string& client_secret,
diff --git a/components/signin/core/browser/fake_profile_oauth2_token_service.h b/components/signin/core/browser/fake_profile_oauth2_token_service.h
index f8f0d18..ea6feaf 100644
--- a/components/signin/core/browser/fake_profile_oauth2_token_service.h
+++ b/components/signin/core/browser/fake_profile_oauth2_token_service.h
@@ -90,7 +90,6 @@
   void FetchOAuth2Token(
       RequestImpl* request,
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const std::string& client_id,
       const std::string& client_secret,
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.cc b/components/signin/core/browser/gaia_cookie_manager_service.cc
index 11a2730..8cbd84e3 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -131,7 +131,8 @@
   CleanupTransientState();
   results_.clear();
   helper_->gaia_auth_fetcher_ = helper_->signin_client_->CreateGaiaAuthFetcher(
-      this, helper_->GetDefaultSourceForRequest(), helper_->request_context());
+      this, helper_->GetDefaultSourceForRequest(),
+      helper_->GetURLLoaderFactory());
   helper_->gaia_auth_fetcher_->StartGetCheckConnectionInfo();
 
   // Some fetches may timeout.  Start a timer to decide when the result fetcher
@@ -767,11 +768,10 @@
 void GaiaCookieManagerService::StartFetchingUbertoken() {
   VLOG(1) << "GaiaCookieManagerService::StartFetchingUbertoken account_id="
           << requests_.front().account_id();
-  uber_token_fetcher_.reset(new UbertokenFetcher(
-      token_service_, this, GetDefaultSourceForRequest(),
-      signin_client_->GetURLRequestContext(),
+  uber_token_fetcher_ = std::make_unique<UbertokenFetcher>(
+      token_service_, this, GetDefaultSourceForRequest(), GetURLLoaderFactory(),
       base::Bind(&SigninClient::CreateGaiaAuthFetcher,
-                 base::Unretained(signin_client_))));
+                 base::Unretained(signin_client_)));
   if (access_token_.empty()) {
     uber_token_fetcher_->StartFetchingToken(requests_.front().account_id());
   } else {
@@ -783,8 +783,7 @@
 void GaiaCookieManagerService::StartFetchingMergeSession() {
   DCHECK(!uber_token_.empty());
   gaia_auth_fetcher_ = signin_client_->CreateGaiaAuthFetcher(
-      this, GetSourceForRequest(requests_.front()),
-      signin_client_->GetURLRequestContext());
+      this, GetSourceForRequest(requests_.front()), GetURLLoaderFactory());
 
   gaia_auth_fetcher_->StartMergeSession(uber_token_,
       external_cc_result_fetcher_.GetExternalCcResult());
@@ -800,8 +799,7 @@
 
 void GaiaCookieManagerService::StartFetchingLogOut() {
   gaia_auth_fetcher_ = signin_client_->CreateGaiaAuthFetcher(
-      this, GetSourceForRequest(requests_.front()),
-      signin_client_->GetURLRequestContext());
+      this, GetSourceForRequest(requests_.front()), GetURLLoaderFactory());
   gaia_auth_fetcher_->StartLogOut();
 }
 
@@ -809,8 +807,7 @@
   VLOG(1) << "GaiaCookieManagerService::ListAccounts";
 
   gaia_auth_fetcher_ = signin_client_->CreateGaiaAuthFetcher(
-      this, GetSourceForRequest(requests_.front()),
-      signin_client_->GetURLRequestContext());
+      this, GetSourceForRequest(requests_.front()), GetURLLoaderFactory());
   gaia_auth_fetcher_->StartListAccounts();
 }
 
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.h b/components/signin/core/browser/gaia_cookie_manager_service.h
index a7d75f1..218b1b1 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.h
+++ b/components/signin/core/browser/gaia_cookie_manager_service.h
@@ -232,13 +232,14 @@
     return &fetcher_backoff_;
   }
 
+  // Can be overridden by tests.
+  virtual scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory();
+
  private:
   net::URLRequestContextGetter* request_context() {
     return signin_client_->GetURLRequestContext();
   }
 
-  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory();
-
   // Returns the source value to use for GaiaFetcher requests.  This is
   // virtual to allow tests and fake classes to override.
   virtual std::string GetSourceForRequest(
@@ -295,8 +296,8 @@
   std::unique_ptr<UbertokenFetcher> uber_token_fetcher_;
   ExternalCcResultFetcher external_cc_result_fetcher_;
 
-  // If the GaiaAuthFetcher or URLFetcher fails, retry with exponential backoff
-  // and network delay.
+  // If the GaiaAuthFetcher or SimpleURLLoader fails, retry with exponential
+  // backoff and network delay.
   net::BackoffEntry fetcher_backoff_;
   base::OneShotTimer fetcher_timer_;
   int fetcher_retries_;
diff --git a/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc b/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
index 1c47d2f20..917dcb9 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service_unittest.cc
@@ -26,8 +26,6 @@
 #include "google_apis/gaia/fake_oauth2_token_service.h"
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/gaia_urls.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_test_util.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -162,12 +160,13 @@
     consumer->OnLogOutFailure(error);
   }
 
-  void SimulateGetCheckConnctionInfoSuccess(net::TestURLFetcher* fetcher,
-                                            const std::string& data) {
-    fetcher->set_status(net::URLRequestStatus());
-    fetcher->set_response_code(200);
-    fetcher->SetResponseString(data);
-    fetcher->delegate()->OnURLFetchComplete(fetcher);
+  void SimulateGetCheckConnectionInfoSuccess(const std::string& data) {
+    signin_client_->test_url_loader_factory()->AddResponse(
+        GaiaUrls::GetInstance()
+            ->GetCheckConnectionInfoURLWithSource(GaiaConstants::kChromeSource)
+            .spec(),
+        data);
+    base::RunLoop().RunUntilIdle();
   }
 
   void SimulateGetCheckConnectionInfoResult(const std::string& url,
@@ -181,15 +180,20 @@
         GURL(url).spec());
   }
 
+  bool IsLoadPending() {
+    return signin_client_->test_url_loader_factory()->NumPending() > 0;
+  }
+
   const GoogleServiceAuthError& no_error() { return no_error_; }
   const GoogleServiceAuthError& error() { return error_; }
   const GoogleServiceAuthError& canceled() { return canceled_; }
 
-  net::TestURLFetcherFactory* factory() { return &factory_; }
+  scoped_refptr<network::SharedURLLoaderFactory> factory() const {
+    return signin_client_->GetURLLoaderFactory();
+  }
 
  private:
   base::MessageLoop message_loop_;
-  net::TestURLFetcherFactory factory_;
   FakeOAuth2TokenService token_service_;
   GoogleServiceAuthError no_error_;
   GoogleServiceAuthError error_;
@@ -734,10 +738,7 @@
   result_fetcher.Start();
 
   // Simulate a successful completion of GetCheckConnctionInfo.
-  net::TestURLFetcher* fetcher = factory()->GetFetcherByID(0);
-  ASSERT_TRUE(nullptr != fetcher);
-  SimulateGetCheckConnctionInfoSuccess(
-      fetcher,
+  SimulateGetCheckConnectionInfoSuccess(
       "[{\"carryBackToken\": \"yt\", \"url\": \"http://www.yt.com\"},"
       " {\"carryBackToken\": \"bl\", \"url\": \"http://www.bl.com\"}]");
 
@@ -762,10 +763,7 @@
   result_fetcher.Start();
 
   // Simulate a successful completion of GetCheckConnctionInfo.
-  net::TestURLFetcher* fetcher = factory()->GetFetcherByID(0);
-  ASSERT_TRUE(nullptr != fetcher);
-  SimulateGetCheckConnctionInfoSuccess(
-      fetcher,
+  SimulateGetCheckConnectionInfoSuccess(
       "[{\"carryBackToken\": \"yt\", \"url\": \"http://www.yt.com\"},"
       " {\"carryBackToken\": \"bl\", \"url\": \"http://www.bl.com\"}]");
 
@@ -794,10 +792,7 @@
   result_fetcher.Start();
 
   // Simulate a successful completion of GetCheckConnctionInfo.
-  net::TestURLFetcher* fetcher = factory()->GetFetcherByID(0);
-  ASSERT_TRUE(nullptr != fetcher);
-  SimulateGetCheckConnctionInfoSuccess(
-      fetcher,
+  SimulateGetCheckConnectionInfoSuccess(
       "[{\"carryBackToken\": \"yt\", \"url\": \"http://www.yt.com\"}]");
 
   GaiaCookieManagerService::ExternalCcResultFetcher::LoaderToToken loaders =
@@ -817,14 +812,11 @@
   EXPECT_CALL(helper, StartFetchingUbertoken());
   helper.AddAccountToCookie("acc1@gmail.com", GaiaConstants::kChromeSource);
 
-  ASSERT_FALSE(factory()->GetFetcherByID(0));
+  ASSERT_FALSE(IsLoadPending());
   SimulateUbertokenSuccess(&helper, "token");
 
   // Check there is now a fetcher that belongs to the ExternalCCResultFetcher.
-  net::TestURLFetcher* fetcher = factory()->GetFetcherByID(0);
-  ASSERT_TRUE(nullptr != fetcher);
-  SimulateGetCheckConnctionInfoSuccess(
-      fetcher,
+  SimulateGetCheckConnectionInfoSuccess(
       "[{\"carryBackToken\": \"bl\", \"url\": \"http://www.bl.com\"}]");
   GaiaCookieManagerService::ExternalCcResultFetcher* result_fetcher =
       helper.external_cc_result_fetcher_for_testing();
diff --git a/components/signin/core/browser/signin_client.h b/components/signin/core/browser/signin_client.h
index 6027db2f..44a648b2 100644
--- a/components/signin/core/browser/signin_client.h
+++ b/components/signin/core/browser/signin_client.h
@@ -139,7 +139,7 @@
   virtual std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
       GaiaAuthConsumer* consumer,
       const std::string& source,
-      net::URLRequestContextGetter* getter) = 0;
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) = 0;
 
   // Called once the credentials has been copied to another SigninManager.
   virtual void AfterCredentialsCopied() {}
diff --git a/components/signin/core/browser/test_signin_client.cc b/components/signin/core/browser/test_signin_client.cc
index fd438b5..76f6f6e 100644
--- a/components/signin/core/browser/test_signin_client.cc
+++ b/components/signin/core/browser/test_signin_client.cc
@@ -127,8 +127,9 @@
 std::unique_ptr<GaiaAuthFetcher> TestSigninClient::CreateGaiaAuthFetcher(
     GaiaAuthConsumer* consumer,
     const std::string& source,
-    net::URLRequestContextGetter* getter) {
-  return std::make_unique<GaiaAuthFetcher>(consumer, source, getter);
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+  return std::make_unique<GaiaAuthFetcher>(consumer, source,
+                                           url_loader_factory);
 }
 
 void TestSigninClient::PreGaiaLogout(base::OnceClosure callback) {
diff --git a/components/signin/core/browser/test_signin_client.h b/components/signin/core/browser/test_signin_client.h
index 5596c4eb..8e487d6 100644
--- a/components/signin/core/browser/test_signin_client.h
+++ b/components/signin/core/browser/test_signin_client.h
@@ -107,7 +107,8 @@
   std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
       GaiaAuthConsumer* consumer,
       const std::string& source,
-      net::URLRequestContextGetter* getter) override;
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+      override;
   void PreGaiaLogout(base::OnceClosure callback) override;
 
   // Loads the token database.
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
index 5a298de..1f13b5dc 100644
--- a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
+++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.h
@@ -28,7 +28,6 @@
 
   OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       OAuth2AccessTokenConsumer* consumer) override;
 
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
index 5d620896..d7a52008 100644
--- a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
+++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate.mm
@@ -300,7 +300,6 @@
 OAuth2AccessTokenFetcher*
 ProfileOAuth2TokenServiceIOSDelegate::CreateAccessTokenFetcher(
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     OAuth2AccessTokenConsumer* consumer) {
   AccountInfo account_info =
diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
index f14ece7c..f36924c 100644
--- a/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
+++ b/components/signin/ios/browser/profile_oauth2_token_service_ios_delegate_unittest.mm
@@ -261,8 +261,8 @@
   scopes.push_back("scope");
   std::unique_ptr<OAuth2AccessTokenFetcher> fetcher1(
       oauth2_delegate_->CreateAccessTokenFetcher(
-          GetAccountId(account1), oauth2_delegate_->GetRequestContext(),
-          oauth2_delegate_->GetURLLoaderFactory(), this));
+          GetAccountId(account1), oauth2_delegate_->GetURLLoaderFactory(),
+          this));
   fetcher1->Start("foo", "bar", scopes);
   EXPECT_EQ(0, access_token_success_);
   EXPECT_EQ(0, access_token_failure_);
@@ -285,8 +285,8 @@
   scopes.push_back("scope");
   std::unique_ptr<OAuth2AccessTokenFetcher> fetcher1(
       oauth2_delegate_->CreateAccessTokenFetcher(
-          GetAccountId(account1), oauth2_delegate_->GetRequestContext(),
-          oauth2_delegate_->GetURLLoaderFactory(), this));
+          GetAccountId(account1), oauth2_delegate_->GetURLLoaderFactory(),
+          this));
   fetcher1->Start("foo", "bar", scopes);
   EXPECT_EQ(0, access_token_success_);
   EXPECT_EQ(0, access_token_failure_);
diff --git a/components/subresource_filter/content/common/ad_delay_throttle.cc b/components/subresource_filter/content/common/ad_delay_throttle.cc
index e638d8a9..d3bb807 100644
--- a/components/subresource_filter/content/common/ad_delay_throttle.cc
+++ b/components/subresource_filter/content/common/ad_delay_throttle.cc
@@ -26,7 +26,7 @@
 namespace {
 
 void LogSecureInfo(AdDelayThrottle::SecureInfo info) {
-  UMA_HISTOGRAM_ENUMERATION("SubresourceFilter.AdDelay.SecureInfo", info);
+  UMA_HISTOGRAM_ENUMERATION("Ads.Features.ResourceIsSecure", info);
 }
 
 class InsecureCondition : public AdDelayThrottle::DeferCondition {
@@ -65,7 +65,7 @@
   ~NonIsolatedCondition() override {
     if (provider()->IsAdRequest()) {
       UMA_HISTOGRAM_ENUMERATION(
-          "SubresourceFilter.AdDelay.IsolatedInfo",
+          "Ads.Features.AdResourceIsIsolated",
           was_condition_ever_satisfied()
               ? AdDelayThrottle::IsolatedInfo::kNonIsolatedAd
               : AdDelayThrottle::IsolatedInfo::kIsolatedAd);
diff --git a/components/subresource_filter/content/common/ad_delay_throttle_unittest.cc b/components/subresource_filter/content/common/ad_delay_throttle_unittest.cc
index 6255a3a..b2775d57c 100644
--- a/components/subresource_filter/content/common/ad_delay_throttle_unittest.cc
+++ b/components/subresource_filter/content/common/ad_delay_throttle_unittest.cc
@@ -448,7 +448,7 @@
   loader_factory_.AddResponse(insecure_url.spec(), "foo");
   loader_factory_.AddResponse(secure_url.spec(), "foo");
 
-  const char kSecureHistogram[] = "SubresourceFilter.AdDelay.SecureInfo";
+  const char kSecureHistogram[] = "Ads.Features.ResourceIsSecure";
   {
     base::HistogramTester histograms;
     {
@@ -510,7 +510,7 @@
   const GURL url("https://example.test/ad.js");
   loader_factory_.AddResponse(url.spec(), "foo");
 
-  const char kIsolatedHistogram[] = "SubresourceFilter.AdDelay.IsolatedInfo";
+  const char kIsolatedHistogram[] = "Ads.Features.AdResourceIsIsolated";
   {
     base::HistogramTester histograms;
     {
diff --git a/components/sync/android/java/src/org/chromium/components/sync/PassphraseType.java b/components/sync/android/java/src/org/chromium/components/sync/PassphraseType.java
index b1da1056..0bc2063 100644
--- a/components/sync/android/java/src/org/chromium/components/sync/PassphraseType.java
+++ b/components/sync/android/java/src/org/chromium/components/sync/PassphraseType.java
@@ -23,17 +23,18 @@
     FROZEN_IMPLICIT_PASSPHRASE(2), // Frozen GAIA passphrase.
     CUSTOM_PASSPHRASE(3); // User-provided passphrase.
 
-    public static Parcelable.Creator CREATOR = new Parcelable.Creator<PassphraseType>() {
-        @Override
-        public PassphraseType createFromParcel(Parcel parcel) {
-            return fromInternalValue(parcel.readInt());
-        }
+    public static final Parcelable.Creator<PassphraseType> CREATOR =
+            new Parcelable.Creator<PassphraseType>() {
+                @Override
+                public PassphraseType createFromParcel(Parcel parcel) {
+                    return fromInternalValue(parcel.readInt());
+                }
 
-        @Override
-        public PassphraseType[] newArray(int size) {
-            return new PassphraseType[size];
-        }
-    };
+                @Override
+                public PassphraseType[] newArray(int size) {
+                    return new PassphraseType[size];
+                }
+            };
 
     public static PassphraseType fromInternalValue(int value) {
         for (PassphraseType type : values()) {
diff --git a/components/sync/driver/sync_service.cc b/components/sync/driver/sync_service.cc
index ee753cea..cb0573c 100644
--- a/components/sync/driver/sync_service.cc
+++ b/components/sync/driver/sync_service.cc
@@ -14,13 +14,7 @@
 }
 
 bool SyncService::CanSyncStart() const {
-  int disable_reasons = GetDisableReasons();
-  // An unrecoverable error is currently *not* considered a start-preventing
-  // disable reason, because it occurs after Sync has already started.
-  // TODO(crbug.com/839834): Consider changing this, since Sync shuts down and
-  // won't start up again after an unrecoverable error.
-  disable_reasons = disable_reasons & ~DISABLE_REASON_UNRECOVERABLE_ERROR;
-  return disable_reasons == DISABLE_REASON_NONE;
+  return GetDisableReasons() == DISABLE_REASON_NONE;
 }
 
 bool SyncService::IsSyncAllowed() const {
diff --git a/components/sync/driver/sync_service.h b/components/sync/driver/sync_service.h
index b568996e..5ec33f8 100644
--- a/components/sync/driver/sync_service.h
+++ b/components/sync/driver/sync_service.h
@@ -231,9 +231,8 @@
   virtual void OnDataTypeRequestsSyncStartup(ModelType type) = 0;
 
   // DEPRECATED! Use GetDisableReasons/HasDisableReason instead.
-  // Equivalent to having no disable reasons except UNRECOVERABLE_ERROR, i.e.
-  // "(GetDisableReasons() & ~DISABLE_REASON_UNRECOVERABLE_ERROR) ==
-  // DISABLE_REASON_NONE".
+  // Equivalent to having no disable reasons, i.e.
+  // "GetDisableReasons() == DISABLE_REASON_NONE".
   bool CanSyncStart() const;
 
   // Stops sync at the user's request. |data_fate| controls whether the sync
diff --git a/components/toolbar/toolbar_model.h b/components/toolbar/toolbar_model.h
index 299a910d..0866ef20 100644
--- a/components/toolbar/toolbar_model.h
+++ b/components/toolbar/toolbar_model.h
@@ -51,7 +51,7 @@
   // Returns the id of the icon to show to the left of the address, based on the
   // current URL.  When search term replacement is active, this returns a search
   // icon.  This doesn't cover specialized icons while the user is editing; see
-  // OmniboxView::GetVectorIcon().
+  // OmniboxView::GetIcon().
   virtual const gfx::VectorIcon& GetVectorIcon() const = 0;
 
   // Returns text for the omnibox secure verbose chip.
diff --git a/content/browser/background_sync/background_sync_manager_unittest.cc b/content/browser/background_sync/background_sync_manager_unittest.cc
index 0c5b7b46..077a39c 100644
--- a/content/browser/background_sync/background_sync_manager_unittest.cc
+++ b/content/browser/background_sync/background_sync_manager_unittest.cc
@@ -109,7 +109,7 @@
     ON_CALL(*mock_permission_manager,
             GetPermissionStatus(PermissionType::BACKGROUND_SYNC, _, _))
         .WillByDefault(Return(blink::mojom::PermissionStatus::GRANTED));
-    helper_->browser_context()->SetPermissionManager(
+    helper_->browser_context()->SetPermissionControllerDelegate(
         std::move(mock_permission_manager));
 
     // Create a StoragePartition with the correct BrowserContext so that the
@@ -264,9 +264,9 @@
     return callback_status_ == BACKGROUND_SYNC_STATUS_OK;
   }
 
-  MockPermissionManager* GetPermissionManager() {
+  MockPermissionManager* GetPermissionControllerDelegate() {
     return static_cast<MockPermissionManager*>(
-        helper_->browser_context()->GetPermissionManager());
+        helper_->browser_context()->GetPermissionControllerDelegate());
   }
 
   bool GetRegistration(
@@ -484,7 +484,8 @@
 
 TEST_F(BackgroundSyncManagerTest, RegisterPermissionDenied) {
   GURL expected_origin = GURL(kPattern1).GetOrigin();
-  MockPermissionManager* mock_permission_manager = GetPermissionManager();
+  MockPermissionManager* mock_permission_manager =
+      GetPermissionControllerDelegate();
 
   EXPECT_CALL(*mock_permission_manager,
               GetPermissionStatus(PermissionType::BACKGROUND_SYNC,
@@ -495,7 +496,8 @@
 
 TEST_F(BackgroundSyncManagerTest, RegisterPermissionGranted) {
   GURL expected_origin = GURL(kPattern1).GetOrigin();
-  MockPermissionManager* mock_permission_manager = GetPermissionManager();
+  MockPermissionManager* mock_permission_manager =
+      GetPermissionControllerDelegate();
 
   EXPECT_CALL(*mock_permission_manager,
               GetPermissionStatus(PermissionType::BACKGROUND_SYNC,
diff --git a/content/browser/background_sync/background_sync_service_impl_unittest.cc b/content/browser/background_sync/background_sync_service_impl_unittest.cc
index c58cd84f..4f6d1aa 100644
--- a/content/browser/background_sync/background_sync_service_impl_unittest.cc
+++ b/content/browser/background_sync/background_sync_service_impl_unittest.cc
@@ -128,7 +128,7 @@
             GetPermissionStatus(PermissionType::BACKGROUND_SYNC, _, _))
         .WillByDefault(
             testing::Return(blink::mojom::PermissionStatus::GRANTED));
-    embedded_worker_helper_->browser_context()->SetPermissionManager(
+    embedded_worker_helper_->browser_context()->SetPermissionControllerDelegate(
         std::move(mock_permission_manager));
   }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 7013b4b..9cc32b63 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -137,6 +137,7 @@
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/common/url_utils.h"
+#include "device/gamepad/gamepad_monitor.h"
 #include "device/vr/public/mojom/vr_service.mojom.h"
 #include "media/audio/audio_manager.h"
 #include "media/base/media_switches.h"
@@ -3398,6 +3399,8 @@
   registry_->AddInterface(base::Bind(&SharedWorkerConnectorImpl::Create,
                                      process_->GetID(), routing_id_));
 
+  registry_->AddInterface(base::BindRepeating(&device::GamepadMonitor::Create));
+
   registry_->AddInterface<device::mojom::VRService>(base::Bind(
       &WebvrServiceProvider::BindWebvrService, base::Unretained(this)));
 
diff --git a/content/browser/geolocation/geolocation_service_impl_unittest.cc b/content/browser/geolocation/geolocation_service_impl_unittest.cc
index 6f2230c..bb1ec33 100644
--- a/content/browser/geolocation/geolocation_service_impl_unittest.cc
+++ b/content/browser/geolocation/geolocation_service_impl_unittest.cc
@@ -84,7 +84,7 @@
     RenderViewHostImplTestHarness::SetUp();
     NavigateAndCommit(kMainUrl);
     browser_context_.reset(new content::TestBrowserContext());
-    browser_context_->SetPermissionManager(
+    browser_context_->SetPermissionControllerDelegate(
         std::make_unique<TestPermissionManager>());
     permission_controller_.reset(
         new PermissionControllerImpl(browser_context_.get()));
@@ -133,7 +133,7 @@
 
   TestPermissionManager* permission_manager() {
     return static_cast<TestPermissionManager*>(
-        browser_context_->GetPermissionManager());
+        browser_context_->GetPermissionControllerDelegate());
   }
 
  private:
diff --git a/content/browser/notifications/blink_notification_service_impl_unittest.cc b/content/browser/notifications/blink_notification_service_impl_unittest.cc
index c26cf4b..618c7bd 100644
--- a/content/browser/notifications/blink_notification_service_impl_unittest.cc
+++ b/content/browser/notifications/blink_notification_service_impl_unittest.cc
@@ -118,7 +118,7 @@
         mojo::MakeRequest(&notification_service_ptr));
 
     // Provide a mock permission manager to the |browser_context_|.
-    browser_context_.SetPermissionManager(
+    browser_context_.SetPermissionControllerDelegate(
         std::make_unique<testing::NiceMock<MockPermissionManager>>());
   }
 
@@ -300,7 +300,7 @@
   void SetPermissionStatus(blink::mojom::PermissionStatus permission_status) {
     MockPermissionManager* mock_permission_manager =
         static_cast<MockPermissionManager*>(
-            browser_context_.GetPermissionManager());
+            browser_context_.GetPermissionControllerDelegate());
 
     ON_CALL(*mock_permission_manager,
             GetPermissionStatus(PermissionType::NOTIFICATIONS, _, _))
diff --git a/content/browser/payments/payment_app_provider_impl.cc b/content/browser/payments/payment_app_provider_impl.cc
index 7ef9019..011ba40 100644
--- a/content/browser/payments/payment_app_provider_impl.cc
+++ b/content/browser/payments/payment_app_provider_impl.cc
@@ -575,13 +575,15 @@
   DCHECK(manifest_url.is_valid() && sw_js_url.is_valid() &&
          sw_scope.is_valid());
 
-  // TODO(crbug.com/853924): Unify duplicated code between here and
-  // ServiceWorkerProviderHost::IsValidRegisterMessage.
-  if (ServiceWorkerUtils::ContainsDisallowedCharacter(sw_js_url, sw_scope,
-                                                      error_message)) {
+  // Scope will be checked against service worker js url when registering, but
+  // we check it here earlier to avoid presenting unusable payment handlers.
+  if (!ServiceWorkerUtils::IsPathRestrictionSatisfiedWithoutHeader(
+          sw_scope, sw_js_url, error_message)) {
     return false;
   }
 
+  // TODO(crbug.com/855312): Unify duplicated code between here and
+  // ServiceWorkerProviderHost::IsValidRegisterMessage.
   std::vector<GURL> urls = {manifest_url, sw_js_url, sw_scope};
   if (!ServiceWorkerUtils::AllOriginsMatchAndCanAccessServiceWorkers(urls)) {
     *error_message =
diff --git a/content/browser/payments/payment_app_provider_impl_unittest.cc b/content/browser/payments/payment_app_provider_impl_unittest.cc
index 6143488..13b87020 100644
--- a/content/browser/payments/payment_app_provider_impl_unittest.cc
+++ b/content/browser/payments/payment_app_provider_impl_unittest.cc
@@ -65,7 +65,7 @@
         .WillByDefault(
             testing::Return(blink::mojom::PermissionStatus::GRANTED));
     static_cast<TestBrowserContext*>(browser_context())
-        ->SetPermissionManager(std::move(mock_permission_manager));
+        ->SetPermissionControllerDelegate(std::move(mock_permission_manager));
   }
   ~PaymentAppProviderTest() override {}
 
diff --git a/content/browser/permissions/permission_controller_impl.cc b/content/browser/permissions/permission_controller_impl.cc
index 5c2a3a2..75ccdf0 100644
--- a/content/browser/permissions/permission_controller_impl.cc
+++ b/content/browser/permissions/permission_controller_impl.cc
@@ -8,7 +8,7 @@
 #include "content/browser/permissions/permission_controller_impl.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_context.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 #include "third_party/blink/public/platform/modules/permissions/permission_status.mojom.h"
 
 class GURL;
@@ -34,7 +34,8 @@
     const GURL& requesting_origin,
     bool user_gesture,
     const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
-  PermissionManager* delegate = browser_context_->GetPermissionManager();
+  PermissionControllerDelegate* delegate =
+      browser_context_->GetPermissionControllerDelegate();
   if (!delegate) {
     callback.Run(blink::mojom::PermissionStatus::DENIED);
     return kNoPendingOperation;
@@ -50,7 +51,8 @@
     bool user_gesture,
     const base::Callback<
         void(const std::vector<blink::mojom::PermissionStatus>&)>& callback) {
-  PermissionManager* delegate = browser_context_->GetPermissionManager();
+  PermissionControllerDelegate* delegate =
+      browser_context_->GetPermissionControllerDelegate();
   if (!delegate) {
     std::vector<blink::mojom::PermissionStatus> result(
         permissions.size(), blink::mojom::PermissionStatus::DENIED);
@@ -66,7 +68,8 @@
     PermissionType permission,
     const GURL& requesting_origin,
     const GURL& embedding_origin) {
-  PermissionManager* delegate = browser_context_->GetPermissionManager();
+  PermissionControllerDelegate* delegate =
+      browser_context_->GetPermissionControllerDelegate();
   if (!delegate)
     return blink::mojom::PermissionStatus::DENIED;
   return delegate->GetPermissionStatus(permission, requesting_origin,
@@ -78,7 +81,8 @@
     PermissionType permission,
     RenderFrameHost* render_frame_host,
     const GURL& requesting_origin) {
-  PermissionManager* delegate = browser_context_->GetPermissionManager();
+  PermissionControllerDelegate* delegate =
+      browser_context_->GetPermissionControllerDelegate();
   if (!delegate)
     return blink::mojom::PermissionStatus::DENIED;
   return delegate->GetPermissionStatusForFrame(permission, render_frame_host,
@@ -88,7 +92,8 @@
 void PermissionControllerImpl::ResetPermission(PermissionType permission,
                                                const GURL& requesting_origin,
                                                const GURL& embedding_origin) {
-  PermissionManager* delegate = browser_context_->GetPermissionManager();
+  PermissionControllerDelegate* delegate =
+      browser_context_->GetPermissionControllerDelegate();
   if (!delegate)
     return;
   delegate->ResetPermission(permission, requesting_origin, embedding_origin);
@@ -99,7 +104,8 @@
     const GURL& requesting_origin,
     const GURL& embedding_origin,
     const base::Callback<void(blink::mojom::PermissionStatus)>& callback) {
-  PermissionManager* delegate = browser_context_->GetPermissionManager();
+  PermissionControllerDelegate* delegate =
+      browser_context_->GetPermissionControllerDelegate();
   if (!delegate)
     return kNoPendingOperation;
   return delegate->SubscribePermissionStatusChange(
@@ -108,7 +114,8 @@
 
 void PermissionControllerImpl::UnsubscribePermissionStatusChange(
     int subscription_id) {
-  PermissionManager* delegate = browser_context_->GetPermissionManager();
+  PermissionControllerDelegate* delegate =
+      browser_context_->GetPermissionControllerDelegate();
   if (!delegate)
     return;
   delegate->UnsubscribePermissionStatusChange(subscription_id);
diff --git a/content/browser/picture_in_picture/overlay_surface_embedder.cc b/content/browser/picture_in_picture/overlay_surface_embedder.cc
index 9032c88..6b8c3c7 100644
--- a/content/browser/picture_in_picture/overlay_surface_embedder.cc
+++ b/content/browser/picture_in_picture/overlay_surface_embedder.cc
@@ -51,6 +51,7 @@
 
 void OverlaySurfaceEmbedder::UpdateLayerBounds() {
   // Update the size of window background.
+  window_background_layer_ = window_->GetWindowBackgroundLayer();
   window_background_layer_->SetBounds(
       gfx::Rect(gfx::Point(0, 0), window_->GetBounds().size()));
 
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index 4fc50411..6a145b45 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -402,13 +402,8 @@
 }
 
 void DelegatedFrameHost::EvictDelegatedFrame() {
-  // It is possible that we are embedding the contents of previous
-  // DelegatedFrameHost. In this case, HasSavedFrame() will return false but we
-  // still need to clear the layer.
-  if (HasFallbackSurface()) {
-    client_->DelegatedFrameHostGetLayer()->SetFallbackSurfaceId(
-        viz::SurfaceId());
-  }
+  // Replaces the SurfaceLayer with a SolidColorLayer.
+  client_->DelegatedFrameHostGetLayer()->SetShowSolidColorContent();
 
   if (!HasSavedFrame())
     return;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 0aa51e4..19ee3f9 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -171,7 +171,6 @@
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_constants.h"
 #include "device/gamepad/gamepad_haptics_manager.h"
-#include "device/gamepad/gamepad_monitor.h"
 #include "gpu/GLES2/gl2extchromium.h"
 #include "gpu/command_buffer/client/gpu_switches.h"
 #include "gpu/command_buffer/common/context_creation_attribs.h"
@@ -1978,8 +1977,6 @@
 
   registry->AddInterface(base::Bind(&device::GamepadHapticsManager::Create));
 
-  registry->AddInterface(base::Bind(&device::GamepadMonitor::Create));
-
   registry->AddInterface(
       base::Bind(&PushMessagingManager::BindRequest,
                  base::Unretained(push_messaging_manager_.get())));
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 3ec98f60..6f457e9 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -1763,8 +1763,9 @@
   scroll_observer->Wait();
 }
 
-#if defined(OS_CHROMEOS)
+#if defined(OS_CHROMEOS) || defined(OS_MACOSX)
 // Flaky: https://crbug.com/836200.
+// Flaky timeouts on Mac: https://crbug.com/863971.
 #define MAYBE_ScrollBubblingFromOOPIFWithBodyOverflowHidden \
   DISABLED_ScrollBubblingFromOOPIFWithBodyOverflowHidden
 #else
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index 57daaba..7537896e 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -1236,8 +1236,15 @@
   RunTest(PinchGoesToMainFrame);
 }
 
+#if defined(OS_CHROMEOS)
+// Flaky timeouts: https://crbug.com/833380
+#define MAYBE_EmulatedGestureScrollBubbles DISABLED_EmulatedGestureScrollBubbles
+#else
+#define MAYBE_EmulatedGestureScrollBubbles EmulatedGestureScrollBubbles
+#endif
+
 IN_PROC_BROWSER_TEST_P(SitePerProcessEmulatedTouchBrowserTest,
-                       EmulatedGestureScrollBubbles) {
+                       MAYBE_EmulatedGestureScrollBubbles) {
   RunTest(TouchActionBubbling);
 }
 
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index d588ea5..1fdc0255 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -1197,6 +1197,10 @@
   }
 }
 
+void StoragePartitionImpl::ResetURLLoaderFactoryForBrowserProcessForTesting() {
+  url_loader_factory_for_browser_process_.reset();
+}
+
 BrowserContext* StoragePartitionImpl::browser_context() const {
   return browser_context_;
 }
diff --git a/content/browser/storage_partition_impl.h b/content/browser/storage_partition_impl.h
index 18c46a2..e79f8775 100644
--- a/content/browser/storage_partition_impl.h
+++ b/content/browser/storage_partition_impl.h
@@ -132,6 +132,7 @@
   void ClearBluetoothAllowedDevicesMapForTesting() override;
   void FlushNetworkInterfaceForTesting() override;
   void WaitForDeletionTasksForTesting() override;
+  void ResetURLLoaderFactoryForBrowserProcessForTesting() override;
 
   BackgroundFetchContext* GetBackgroundFetchContext();
   BackgroundSyncContext* GetBackgroundSyncContext();
diff --git a/content/browser/storage_partition_impl_browsertest.cc b/content/browser/storage_partition_impl_browsertest.cc
index 2df5d01..a1f42c9 100644
--- a/content/browser/storage_partition_impl_browsertest.cc
+++ b/content/browser/storage_partition_impl_browsertest.cc
@@ -70,7 +70,7 @@
   request->url = url;
   std::unique_ptr<network::SimpleURLLoader> url_loader =
       network::SimpleURLLoader::Create(std::move(request),
-                                       NO_TRAFFIC_ANNOTATION_YET);
+                                       TRAFFIC_ANNOTATION_FOR_TESTS);
   SimpleURLLoaderTestHelper url_loader_helper;
   url_loader->DownloadToString(
       partition->GetURLLoaderFactoryForBrowserProcess().get(),
diff --git a/content/browser/webauth/authenticator_impl_unittest.cc b/content/browser/webauth/authenticator_impl_unittest.cc
index af18137..503271d 100644
--- a/content/browser/webauth/authenticator_impl_unittest.cc
+++ b/content/browser/webauth/authenticator_impl_unittest.cc
@@ -877,7 +877,8 @@
   base::RunLoop().RunUntilIdle();
   task_runner->FastForwardBy(base::TimeDelta::FromMinutes(1));
   callback_receiver.WaitForCallback();
-  EXPECT_EQ(AuthenticatorStatus::NOT_ALLOWED_ERROR, callback_receiver.status());
+  EXPECT_EQ(AuthenticatorStatus::CREDENTIAL_NOT_RECOGNIZED,
+            callback_receiver.status());
 }
 
 TEST_F(AuthenticatorImplTest, MakeCredentialAlreadyRegistered) {
diff --git a/content/browser/webauth/webauth_browsertest.cc b/content/browser/webauth/webauth_browsertest.cc
index 36fff588..a3b8c26 100644
--- a/content/browser/webauth/webauth_browsertest.cc
+++ b/content/browser/webauth/webauth_browsertest.cc
@@ -67,6 +67,10 @@
     "webauth: NotAllowedError: The operation either timed out or was not "
     "allowed. See: https://w3c.github.io/webauthn/#sec-assertion-privacy.";
 
+constexpr char kInvalidStateErrorMessage[] =
+    "webauth: InvalidStateError: The user attempted to use an authenticator "
+    "that recognized none of the provided credentials.";
+
 constexpr char kRelyingPartySecurityErrorMessage[] =
     "webauth: SecurityError: The relying party ID 'localhost' is not a "
     "registrable domain suffix of, nor equal to 'https://www.acme.com";
@@ -803,7 +807,7 @@
   ASSERT_TRUE(content::ExecuteScriptAndExtractString(
       shell()->web_contents()->GetMainFrame(),
       BuildGetCallWithParameters(parameters), &result));
-  ASSERT_EQ(kTimeoutErrorMessage, result);
+  ASSERT_EQ(kInvalidStateErrorMessage, result);
 }
 
 // WebAuthBrowserBleDisabledTest
diff --git a/content/common/service_worker/service_worker_utils.cc b/content/common/service_worker/service_worker_utils.cc
index 2f53613..5abbb6e9 100644
--- a/content/common/service_worker/service_worker_utils.cc
+++ b/content/common/service_worker/service_worker_utils.cc
@@ -53,6 +53,27 @@
     const GURL& script_url,
     const std::string* service_worker_allowed_header_value,
     std::string* error_message) {
+  return IsPathRestrictionSatisfiedInternal(scope, script_url, true,
+                                            service_worker_allowed_header_value,
+                                            error_message);
+}
+
+// static
+bool ServiceWorkerUtils::IsPathRestrictionSatisfiedWithoutHeader(
+    const GURL& scope,
+    const GURL& script_url,
+    std::string* error_message) {
+  return IsPathRestrictionSatisfiedInternal(scope, script_url, false, nullptr,
+                                            error_message);
+}
+
+// static
+bool ServiceWorkerUtils::IsPathRestrictionSatisfiedInternal(
+    const GURL& scope,
+    const GURL& script_url,
+    bool service_worker_allowed_header_supported,
+    const std::string* service_worker_allowed_header_value,
+    std::string* error_message) {
   DCHECK(scope.is_valid());
   DCHECK(!scope.has_ref());
   DCHECK(script_url.is_valid());
@@ -63,7 +84,8 @@
     return false;
 
   std::string max_scope_string;
-  if (service_worker_allowed_header_value) {
+  if (service_worker_allowed_header_value &&
+      service_worker_allowed_header_supported) {
     GURL max_scope = script_url.Resolve(*service_worker_allowed_header_value);
     if (!max_scope.is_valid()) {
       *error_message = "An invalid Service-Worker-Allowed header value ('";
@@ -82,13 +104,19 @@
     *error_message = "The path of the provided scope ('";
     error_message->append(scope_string);
     error_message->append("') is not under the max scope allowed (");
-    if (service_worker_allowed_header_value)
+    if (service_worker_allowed_header_value &&
+        service_worker_allowed_header_supported)
       error_message->append("set by Service-Worker-Allowed: ");
     error_message->append("'");
     error_message->append(max_scope_string);
-    error_message->append(
-        "'). Adjust the scope, move the Service Worker script, or use the "
-        "Service-Worker-Allowed HTTP header to allow the scope.");
+    if (service_worker_allowed_header_supported) {
+      error_message->append(
+          "'). Adjust the scope, move the Service Worker script, or use the "
+          "Service-Worker-Allowed HTTP header to allow the scope.");
+    } else {
+      error_message->append(
+          "'). Adjust the scope or move the Service Worker script.");
+    }
     return false;
   }
   return true;
diff --git a/content/common/service_worker/service_worker_utils.h b/content/common/service_worker/service_worker_utils.h
index 0a47484..62606881 100644
--- a/content/common/service_worker/service_worker_utils.h
+++ b/content/common/service_worker/service_worker_utils.h
@@ -39,6 +39,13 @@
       const std::string* service_worker_allowed_header_value,
       std::string* error_message);
 
+  // Same as above IsPathRestrictionSatisfied, but without considering
+  // 'Service-Worker-Allowed' header.
+  CONTENT_EXPORT static bool IsPathRestrictionSatisfiedWithoutHeader(
+      const GURL& scope,
+      const GURL& script_url,
+      std::string* error_message);
+
   static bool ContainsDisallowedCharacter(const GURL& scope,
                                           const GURL& script_url,
                                           std::string* error_message);
@@ -74,6 +81,14 @@
   static bool ShouldBypassCacheDueToUpdateViaCache(
       bool is_main_script,
       blink::mojom::ServiceWorkerUpdateViaCache cache_mode);
+
+ private:
+  static bool IsPathRestrictionSatisfiedInternal(
+      const GURL& scope,
+      const GURL& script_url,
+      bool service_worker_allowed_header_supported,
+      const std::string* service_worker_allowed_header_value,
+      std::string* error_message);
 };
 
 class CONTENT_EXPORT LongestScopeMatcher {
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index fdaaa086..a332235 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -60,7 +60,6 @@
           "content.mojom.WorkerURLLoaderFactoryProvider",
           "device.mojom.BatteryMonitor",
           "device.mojom.GamepadHapticsManager",
-          "device.mojom.GamepadMonitor",
           "discardable_memory.mojom.DiscardableSharedMemoryManager",
           "media.mojom.KeySystemSupport",
           "media.mojom.VideoCaptureHost",
@@ -181,6 +180,7 @@
           "content.mojom.RendererAudioInputStreamFactory",
           "content.mojom.RendererAudioOutputStreamFactory",
           "content.mojom.SharedWorkerConnector",
+          "device.mojom.GamepadMonitor",
           "device.mojom.Geolocation",
           "device.mojom.NFC",
           "device.mojom.SensorProvider",
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index 1847f77..cb9b7ba 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -201,7 +201,7 @@
     "pepper_flash_settings_helper.h",
     "pepper_vpn_provider_resource_host_proxy.h",
     "permission_controller.h",
-    "permission_manager.h",
+    "permission_controller_delegate.h",
     "permission_type.h",
     "picture_in_picture_window_controller.h",
     "platform_notification_context.h",
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index b833886..4f794e2 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -68,7 +68,7 @@
 class DownloadManager;
 class DownloadManagerDelegate;
 class PermissionController;
-class PermissionManager;
+class PermissionControllerDelegate;
 struct PushEventPayload;
 class PushMessagingService;
 class ResourceContext;
@@ -261,15 +261,12 @@
   // return nullptr, implementing the default exception storage strategy.
   virtual SSLHostStateDelegate* GetSSLHostStateDelegate() = 0;
 
-  // Returns the PermissionManager associated with this context if
+  // Returns the PermissionControllerDelegate associated with this context if
   // any, nullptr otherwise.
   //
   // Note: if you want to check a permission status, you probably need
   // BrowserContext::GetPermissionController() instead.
-  //
-  // TODO(lushnikov): This should be renamed into
-  // GetPermissionControllerDelegate().
-  virtual PermissionManager* GetPermissionManager() = 0;
+  virtual PermissionControllerDelegate* GetPermissionControllerDelegate() = 0;
 
   // Returns the BackgroundFetchDelegate associated with that context if any,
   // nullptr otherwise.
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
index 32b99c73..d765060 100644
--- a/content/public/browser/content_browser_client.h
+++ b/content/public/browser/content_browser_client.h
@@ -37,6 +37,7 @@
 #include "media/mojo/interfaces/remoting.mojom.h"
 #include "net/base/mime_util.h"
 #include "net/cookies/canonical_cookie.h"
+#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/mojom/network_context.mojom.h"
 #include "services/network/public/mojom/websocket.mojom.h"
 #include "services/service_manager/embedder/embedded_service_info.h"
@@ -104,7 +105,6 @@
 class SSLInfo;
 class URLRequest;
 class URLRequestContext;
-class URLRequestContextGetter;
 }  // namespace net
 
 namespace network {
diff --git a/content/public/browser/permission_controller.h b/content/public/browser/permission_controller.h
index e018eb7..de585e5 100644
--- a/content/public/browser/permission_controller.h
+++ b/content/public/browser/permission_controller.h
@@ -16,7 +16,7 @@
 class RenderFrameHost;
 
 // This class allows the content layer to manipulate permissions. It's behavior
-// is defined by the embedder via PermissionManager implementation.
+// is defined by the embedder via PermissionControllerDelegate implementation.
 class CONTENT_EXPORT PermissionController
     : public base::SupportsUserData::Data {
  public:
diff --git a/content/public/browser/permission_manager.h b/content/public/browser/permission_controller_delegate.h
similarity index 92%
rename from content/public/browser/permission_manager.h
rename to content/public/browser/permission_controller_delegate.h
index 487b0c80..2a81ed3 100644
--- a/content/public/browser/permission_manager.h
+++ b/content/public/browser/permission_controller_delegate.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_PUBLIC_BROWSER_PERMISSION_MANAGER_H_
-#define CONTENT_PUBLIC_BROWSER_PERMISSION_MANAGER_H_
+#ifndef CONTENT_PUBLIC_BROWSER_PERMISSION_CONTROLLER_DELEGATE_H_
+#define CONTENT_PUBLIC_BROWSER_PERMISSION_CONTROLLER_DELEGATE_H_
 
 #include "content/common/content_export.h"
 #include "third_party/blink/public/platform/modules/permissions/permission_status.mojom.h"
@@ -14,9 +14,9 @@
 enum class PermissionType;
 class RenderFrameHost;
 
-class CONTENT_EXPORT PermissionManager {
+class CONTENT_EXPORT PermissionControllerDelegate {
  public:
-  virtual ~PermissionManager() = default;
+  virtual ~PermissionControllerDelegate() = default;
 
   // Requests a permission on behalf of a frame identified by
   // render_frame_host.
@@ -96,4 +96,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_PUBLIC_BROWSER_PERMISSION_MANAGER_H_
+#endif  // CONTENT_PUBLIC_BROWSER_PERMISSION_CONTROLLER_DELEGATE_H_
diff --git a/content/public/browser/storage_partition.h b/content/public/browser/storage_partition.h
index 28e2c25..fe4b7cc8 100644
--- a/content/public/browser/storage_partition.h
+++ b/content/public/browser/storage_partition.h
@@ -224,6 +224,10 @@
   // Wait until all deletions tasks are finished. For test use only.
   virtual void WaitForDeletionTasksForTesting() = 0;
 
+  // Used in tests to force the cached SharedURLLoaderFactory to be dropped, as
+  // a way to work-around https://crbug.com/857577.
+  virtual void ResetURLLoaderFactoryForBrowserProcessForTesting() {}
+
  protected:
   virtual ~StoragePartition() {}
 };
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index c0bfbccc..1357447d 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -56,10 +56,6 @@
 #include "base/process/process_handle.h"
 #endif
 
-#if defined(OS_MACOSX)
-#include "base/mac/foundation_util.h"
-#endif
-
 #if defined(USE_AURA)
 #include "content/browser/compositor/image_transport_factory.h"
 #include "ui/aura/test/event_generator_delegate_aura.h"  // nogncheck
@@ -132,10 +128,6 @@
       use_software_compositing_(false),
       set_up_called_(false),
       disable_io_checks_(false) {
-#if defined(OS_MACOSX)
-  base::mac::SetOverrideAmIBundled(true);
-#endif
-
   ui::test::EnableTestConfigForPlatformWindows();
 
 #if defined(OS_POSIX)
diff --git a/content/public/test/content_browser_test.cc b/content/public/test/content_browser_test.cc
index 183c757f..9c1304b 100644
--- a/content/public/test/content_browser_test.cc
+++ b/content/public/test/content_browser_test.cc
@@ -25,6 +25,10 @@
 #include "content/shell/app/shell_main_delegate.h"
 #endif
 
+#if defined(OS_MACOSX)
+#include "base/mac/foundation_util.h"
+#endif
+
 #if !defined(OS_CHROMEOS) && defined(OS_LINUX)
 #include "ui/base/ime/input_method_initializer.h"
 #endif
@@ -37,6 +41,8 @@
 
 ContentBrowserTest::ContentBrowserTest() {
 #if defined(OS_MACOSX)
+  base::mac::SetOverrideAmIBundled(true);
+
   // See comment in InProcessBrowserTest::InProcessBrowserTest().
   base::FilePath content_shell_path;
   CHECK(base::PathService::Get(base::FILE_EXE, &content_shell_path));
diff --git a/content/public/test/mock_permission_manager.h b/content/public/test/mock_permission_manager.h
index ec5535d..b140a499 100644
--- a/content/public/test/mock_permission_manager.h
+++ b/content/public/test/mock_permission_manager.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_PUBLIC_TEST_MOCK_PERMISSION_MANAGER_H_
 #define CONTENT_PUBLIC_TEST_MOCK_PERMISSION_MANAGER_H_
 
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "url/gurl.h"
 
@@ -16,7 +16,7 @@
 enum class PermissionType;
 
 // Mock of the permission manager for unit tests.
-class MockPermissionManager : public PermissionManager {
+class MockPermissionManager : public PermissionControllerDelegate {
  public:
   MockPermissionManager();
 
diff --git a/content/public/test/test_browser_context.cc b/content/public/test/test_browser_context.cc
index 1ff07fb..e61da8ba 100644
--- a/content/public/test/test_browser_context.cc
+++ b/content/public/test/test_browser_context.cc
@@ -11,7 +11,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/test/null_task_runner.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 #include "content/public/test/mock_resource_context.h"
 #include "content/test/mock_background_sync_controller.h"
 #include "content/test/mock_ssl_host_state_delegate.h"
@@ -81,9 +81,9 @@
   special_storage_policy_ = policy;
 }
 
-void TestBrowserContext::SetPermissionManager(
-    std::unique_ptr<PermissionManager> permission_manager) {
-  permission_manager_ = std::move(permission_manager);
+void TestBrowserContext::SetPermissionControllerDelegate(
+    std::unique_ptr<PermissionControllerDelegate> delegate) {
+  permission_controller_delegate_ = std::move(delegate);
 }
 
 net::URLRequestContextGetter* TestBrowserContext::GetRequestContext() {
@@ -137,8 +137,9 @@
   return ssl_host_state_delegate_.get();
 }
 
-PermissionManager* TestBrowserContext::GetPermissionManager() {
-  return permission_manager_.get();
+PermissionControllerDelegate*
+TestBrowserContext::GetPermissionControllerDelegate() {
+  return permission_controller_delegate_.get();
 }
 
 BackgroundFetchDelegate* TestBrowserContext::GetBackgroundFetchDelegate() {
diff --git a/content/public/test/test_browser_context.h b/content/public/test/test_browser_context.h
index 9d54726a..7a231877 100644
--- a/content/public/test/test_browser_context.h
+++ b/content/public/test/test_browser_context.h
@@ -34,8 +34,8 @@
   base::FilePath TakePath();
 
   void SetSpecialStoragePolicy(storage::SpecialStoragePolicy* policy);
-  void SetPermissionManager(
-      std::unique_ptr<PermissionManager> permission_manager);
+  void SetPermissionControllerDelegate(
+      std::unique_ptr<PermissionControllerDelegate> delegate);
   net::URLRequestContextGetter* GetRequestContext();
 
   // Allow clients to make this an incognito context.
@@ -56,7 +56,7 @@
   storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
   PushMessagingService* GetPushMessagingService() override;
   SSLHostStateDelegate* GetSSLHostStateDelegate() override;
-  PermissionManager* GetPermissionManager() override;
+  PermissionControllerDelegate* GetPermissionControllerDelegate() override;
   BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
   BackgroundSyncController* GetBackgroundSyncController() override;
   BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate() override;
@@ -81,7 +81,7 @@
   std::unique_ptr<MockResourceContext> resource_context_;
   scoped_refptr<storage::SpecialStoragePolicy> special_storage_policy_;
   std::unique_ptr<MockSSLHostStateDelegate> ssl_host_state_delegate_;
-  std::unique_ptr<PermissionManager> permission_manager_;
+  std::unique_ptr<PermissionControllerDelegate> permission_controller_delegate_;
   std::unique_ptr<MockBackgroundSyncController> background_sync_controller_;
   bool is_off_the_record_ = false;
 
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index 4e2c42a..063b4077 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -125,8 +125,6 @@
     "frame_blame_context.h",
     "frame_owner_properties.cc",
     "frame_owner_properties.h",
-    "gamepad_shared_memory_reader.cc",
-    "gamepad_shared_memory_reader.h",
     "gpu/actions_parser.cc",
     "gpu/actions_parser.h",
     "gpu/compositor_dependencies.h",
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 7337264..e4d0c25 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -5937,6 +5937,13 @@
                             ->navigation_state()
                             ->IsContentInitiated()
                       : !IsBrowserInitiated(pending_navigation_params_.get());
+  // TODO(dgozman): clean this up after some Canary coverage.
+  CHECK(!pending_navigation_params_);
+  if (info.extra_data) {
+    CHECK(static_cast<DocumentState*>(info.extra_data)
+              ->navigation_state()
+              ->IsContentInitiated());
+  }
 
   // Webkit is asking whether to navigate to a new URL.
   // This is fine normally, except if we're showing UI from one security
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 1fdb7cc..89580c7 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -503,7 +503,7 @@
   webview()->SetShowFPSCounter(
       command_line.HasSwitch(cc::switches::kShowFPSCounter));
 
-  ApplyWebPreferencesInternal(webkit_preferences_, webview(), compositor_deps_);
+  ApplyWebPreferencesInternal(webkit_preferences_, webview());
 
   if (switches::IsTouchDragDropEnabled())
     webview()->GetSettings()->SetTouchDragDropEnabled(true);
@@ -1217,10 +1217,8 @@
   frames_with_pending_state_.clear();
 }
 
-void RenderViewImpl::ApplyWebPreferencesInternal(
-    const WebPreferences& prefs,
-    blink::WebView* web_view,
-    CompositorDependencies* compositor_deps) {
+void RenderViewImpl::ApplyWebPreferencesInternal(const WebPreferences& prefs,
+                                                 blink::WebView* web_view) {
   ApplyWebPreferences(prefs, web_view);
 }
 
@@ -1833,7 +1831,7 @@
 
 void RenderViewImpl::OnUpdateWebPreferences(const WebPreferences& prefs) {
   webkit_preferences_ = prefs;
-  ApplyWebPreferencesInternal(webkit_preferences_, webview(), compositor_deps_);
+  ApplyWebPreferencesInternal(webkit_preferences_, webview());
 }
 
 void RenderViewImpl::OnEnumerateDirectoryResponse(
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index d66cad7f..442475b 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -493,8 +493,7 @@
       blink::WebNavigationPolicy policy);
 
   void ApplyWebPreferencesInternal(const WebPreferences& prefs,
-                                   blink::WebView* web_view,
-                                   CompositorDependencies* compositor_deps);
+                                   blink::WebView* web_view);
 
   // IPC message handlers ------------------------------------------------------
   //
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index e586e93..12ce92d 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -50,7 +50,6 @@
 #include "content/renderer/dom_storage/webstoragenamespace_impl.h"
 #include "content/renderer/file_info_util.h"
 #include "content/renderer/fileapi/webfilesystem_impl.h"
-#include "content/renderer/gamepad_shared_memory_reader.h"
 #include "content/renderer/image_capture/image_capture_frame_grabber.h"
 #include "content/renderer/indexed_db/webidbfactory_impl.h"
 #include "content/renderer/loader/child_url_loader_factory_bundle.h"
@@ -778,8 +777,6 @@
 //------------------------------------------------------------------------------
 
 void RendererBlinkPlatformImpl::SampleGamepads(device::Gamepads& gamepads) {
-  if (gamepad_shared_memory_reader_)
-    gamepad_shared_memory_reader_->SampleGamepads(gamepads);
 }
 
 //------------------------------------------------------------------------------
@@ -1071,25 +1068,11 @@
 void RendererBlinkPlatformImpl::StartListening(
     blink::WebPlatformEventType type,
     blink::WebPlatformEventListener* listener) {
-  if (type == blink::kWebPlatformEventTypeGamepad) {
-    if (!gamepad_shared_memory_reader_) {
-      gamepad_shared_memory_reader_ =
-          std::make_unique<GamepadSharedMemoryReader>();
-    }
-    gamepad_shared_memory_reader_->Start(
-        static_cast<blink::WebGamepadListener*>(listener));
-  } else {
-    DVLOG(1) << "RendererBlinkPlatformImpl::startListening() with "
-                "unknown type.";
-  }
+
 }
 
 void RendererBlinkPlatformImpl::StopListening(
     blink::WebPlatformEventType type) {
-  if (type == blink::kWebPlatformEventTypeGamepad) {
-    if (gamepad_shared_memory_reader_)
-      gamepad_shared_memory_reader_->Stop();
-  }
 }
 
 //------------------------------------------------------------------------------
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h
index 11a3acd6..4c09b20 100644
--- a/content/renderer/renderer_blink_platform_impl.h
+++ b/content/renderer/renderer_blink_platform_impl.h
@@ -51,17 +51,12 @@
 class WebSecurityOrigin;
 }  // namespace blink
 
-namespace device {
-class Gamepads;
-}
-
 namespace network {
 class SharedURLLoaderFactory;
 }
 
 namespace content {
 class BlinkInterfaceProviderImpl;
-class GamepadSharedMemoryReader;
 class ChildURLLoaderFactoryBundle;
 class LocalStorageCachedAreas;
 class PlatformEventObserverBase;
@@ -307,10 +302,6 @@
   base::IDMap<std::unique_ptr<PlatformEventObserverBase>>
       platform_event_observers_;
 
-  // TODO(crbug.com/612330): Remove when GamepadSharedMemoryReader class is
-  // moved to blink
-  std::unique_ptr<GamepadSharedMemoryReader> gamepad_shared_memory_reader_;
-
   // NOT OWNED
   blink::scheduler::WebThreadScheduler* main_thread_scheduler_;
 
diff --git a/content/shell/browser/layout_test/layout_test_browser_context.cc b/content/shell/browser/layout_test/layout_test_browser_context.cc
index 0d6bdef6..f4b5a62 100644
--- a/content/shell/browser/layout_test/layout_test_browser_context.cc
+++ b/content/shell/browser/layout_test/layout_test_browser_context.cc
@@ -75,7 +75,8 @@
   return push_messaging_service_.get();
 }
 
-PermissionManager* LayoutTestBrowserContext::GetPermissionManager() {
+PermissionControllerDelegate*
+LayoutTestBrowserContext::GetPermissionControllerDelegate() {
   if (!permission_manager_.get())
     permission_manager_.reset(new LayoutTestPermissionManager());
   return permission_manager_.get();
@@ -90,7 +91,8 @@
 
 LayoutTestPermissionManager*
 LayoutTestBrowserContext::GetLayoutTestPermissionManager() {
-  return static_cast<LayoutTestPermissionManager*>(GetPermissionManager());
+  return static_cast<LayoutTestPermissionManager*>(
+      GetPermissionControllerDelegate());
 }
 
 }  // namespace content
diff --git a/content/shell/browser/layout_test/layout_test_browser_context.h b/content/shell/browser/layout_test/layout_test_browser_context.h
index 338b416..28c1a70 100644
--- a/content/shell/browser/layout_test/layout_test_browser_context.h
+++ b/content/shell/browser/layout_test/layout_test_browser_context.h
@@ -23,7 +23,7 @@
 class DownloadManagerDelegate;
 class LayoutTestPermissionManager;
 class LayoutTestPushMessagingService;
-class PermissionManager;
+class PermissionControllerDelegate;
 class PushMessagingService;
 
 class LayoutTestBrowserContext final : public ShellBrowserContext {
@@ -34,7 +34,7 @@
   // BrowserContext implementation.
   DownloadManagerDelegate* GetDownloadManagerDelegate() override;
   PushMessagingService* GetPushMessagingService() override;
-  PermissionManager* GetPermissionManager() override;
+  PermissionControllerDelegate* GetPermissionControllerDelegate() override;
   BackgroundSyncController* GetBackgroundSyncController() override;
 
   LayoutTestPermissionManager* GetLayoutTestPermissionManager();
@@ -46,7 +46,7 @@
 
  private:
   std::unique_ptr<LayoutTestPushMessagingService> push_messaging_service_;
-  std::unique_ptr<PermissionManager> permission_manager_;
+  std::unique_ptr<PermissionControllerDelegate> permission_manager_;
   std::unique_ptr<BackgroundSyncController> background_sync_controller_;
   std::unique_ptr<device::ScopedGeolocationOverrider> geolocation_overrider_;
 
diff --git a/content/shell/browser/layout_test/layout_test_permission_manager.cc b/content/shell/browser/layout_test/layout_test_permission_manager.cc
index 995219b..7cccc6f 100644
--- a/content/shell/browser/layout_test/layout_test_permission_manager.cc
+++ b/content/shell/browser/layout_test/layout_test_permission_manager.cc
@@ -57,7 +57,7 @@
 }
 
 LayoutTestPermissionManager::LayoutTestPermissionManager()
-    : PermissionManager() {}
+    : PermissionControllerDelegate() {}
 
 LayoutTestPermissionManager::~LayoutTestPermissionManager() {
 }
diff --git a/content/shell/browser/layout_test/layout_test_permission_manager.h b/content/shell/browser/layout_test/layout_test_permission_manager.h
index 474abd2..a54e80f 100644
--- a/content/shell/browser/layout_test/layout_test_permission_manager.h
+++ b/content/shell/browser/layout_test/layout_test_permission_manager.h
@@ -12,12 +12,12 @@
 #include "base/containers/id_map.h"
 #include "base/macros.h"
 #include "base/synchronization/lock.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 #include "url/gurl.h"
 
 namespace content {
 
-class LayoutTestPermissionManager : public PermissionManager {
+class LayoutTestPermissionManager : public PermissionControllerDelegate {
  public:
   LayoutTestPermissionManager();
   ~LayoutTestPermissionManager() override;
diff --git a/content/shell/browser/layout_test/layout_test_push_messaging_service.cc b/content/shell/browser/layout_test/layout_test_push_messaging_service.cc
index 8014580f..f54ca8d 100644
--- a/content/shell/browser/layout_test/layout_test_push_messaging_service.cc
+++ b/content/shell/browser/layout_test/layout_test_push_messaging_service.cc
@@ -75,7 +75,7 @@
   blink::mojom::PermissionStatus permission_status =
       LayoutTestContentBrowserClient::Get()
           ->browser_context()
-          ->GetPermissionManager()
+          ->GetPermissionControllerDelegate()
           ->GetPermissionStatus(PermissionType::NOTIFICATIONS,
                                 requesting_origin, requesting_origin);
 
diff --git a/content/shell/browser/shell_browser_context.cc b/content/shell/browser/shell_browser_context.cc
index 361ad8e..06fc3546 100644
--- a/content/shell/browser/shell_browser_context.cc
+++ b/content/shell/browser/shell_browser_context.cc
@@ -226,7 +226,8 @@
   return nullptr;
 }
 
-PermissionManager* ShellBrowserContext::GetPermissionManager() {
+PermissionControllerDelegate*
+ShellBrowserContext::GetPermissionControllerDelegate() {
   if (!permission_manager_.get())
     permission_manager_.reset(new ShellPermissionManager());
   return permission_manager_.get();
diff --git a/content/shell/browser/shell_browser_context.h b/content/shell/browser/shell_browser_context.h
index 1cd7107..f3af162 100644
--- a/content/shell/browser/shell_browser_context.h
+++ b/content/shell/browser/shell_browser_context.h
@@ -25,7 +25,7 @@
 
 class BackgroundSyncController;
 class DownloadManagerDelegate;
-class PermissionManager;
+class PermissionControllerDelegate;
 class ShellDownloadManagerDelegate;
 #if !defined(OS_ANDROID)
 class ZoomLevelDelegate;
@@ -58,7 +58,7 @@
   storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
   PushMessagingService* GetPushMessagingService() override;
   SSLHostStateDelegate* GetSSLHostStateDelegate() override;
-  PermissionManager* GetPermissionManager() override;
+  PermissionControllerDelegate* GetPermissionControllerDelegate() override;
   BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
   BackgroundSyncController* GetBackgroundSyncController() override;
   BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate() override;
@@ -113,7 +113,7 @@
 
   std::unique_ptr<ShellResourceContext> resource_context_;
   std::unique_ptr<ShellDownloadManagerDelegate> download_manager_delegate_;
-  std::unique_ptr<PermissionManager> permission_manager_;
+  std::unique_ptr<PermissionControllerDelegate> permission_manager_;
   std::unique_ptr<BackgroundSyncController> background_sync_controller_;
 
  private:
diff --git a/content/shell/browser/shell_permission_manager.h b/content/shell/browser/shell_permission_manager.h
index 0772718..b054b925 100644
--- a/content/shell/browser/shell_permission_manager.h
+++ b/content/shell/browser/shell_permission_manager.h
@@ -7,11 +7,11 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 
 namespace content {
 
-class ShellPermissionManager : public PermissionManager {
+class ShellPermissionManager : public PermissionControllerDelegate {
  public:
   ShellPermissionManager();
   ~ShellPermissionManager() override;
diff --git a/content/shell/test_runner/gamepad_controller.cc b/content/shell/test_runner/gamepad_controller.cc
index b0d7b65d..444cb1c 100644
--- a/content/shell/test_runner/gamepad_controller.cc
+++ b/content/shell/test_runner/gamepad_controller.cc
@@ -8,12 +8,13 @@
 
 #include "base/macros.h"
 #include "content/public/common/service_names.mojom.h"
+#include "content/public/renderer/render_frame.h"
 #include "content/shell/test_runner/web_test_delegate.h"
 #include "gin/arguments.h"
 #include "gin/handle.h"
 #include "gin/object_template_builder.h"
 #include "gin/wrappable.h"
-#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/platform/web_gamepad_listener.h"
 #include "third_party/blink/public/web/blink.h"
 #include "third_party/blink/public/web/web_local_frame.h"
@@ -170,14 +171,17 @@
 }
 
 void GamepadController::Install(blink::WebLocalFrame* frame) {
-  service_manager::Connector::TestApi connector_test_api(
-      blink::Platform::Current()->GetConnector());
-  connector_test_api.OverrideBinderForTesting(
-      service_manager::Identity(content::mojom::kBrowserServiceName),
+  content::RenderFrame* render_frame =
+      content::RenderFrame::FromWebFrame(frame);
+  if (!render_frame)
+    return;
+
+  service_manager::InterfaceProvider::TestApi connector_test_api(
+      render_frame->GetRemoteInterfaces());
+  connector_test_api.SetBinderForName(
       device::mojom::GamepadMonitor::Name_,
       base::BindRepeating(&GamepadController::OnInterfaceRequest,
                           base::Unretained(this)));
-
   GamepadControllerBindings::Install(weak_factory_.GetWeakPtr(), frame);
 }
 
diff --git a/content/test/gpu/gpu_tests/context_lost_expectations.py b/content/test/gpu/gpu_tests/context_lost_expectations.py
index 3e81777..b40a798 100644
--- a/content/test/gpu/gpu_tests/context_lost_expectations.py
+++ b/content/test/gpu/gpu_tests/context_lost_expectations.py
@@ -44,9 +44,9 @@
 
     # There are probably multiple race conditions in the renderer
     # process related to context loss, but they're happening most
-    # often on the Mac ASAN bot.
+    # often on the Mac bots.
     self.Flaky('GpuCrash_GPUProcessCrashesExactlyOncePerVisitToAboutGpuCrash',
-               ['mac', 'asan'], bug=861956)
+               ['mac'], bug=861956)
 
     # 'Browser must support tab control' raised on Android
     self.Skip('GpuCrash_GPUProcessCrashesExactlyOncePerVisitToAboutGpuCrash',
diff --git a/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py b/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py
index c3328e6..29e5fcf 100644
--- a/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py
+++ b/content/test/gpu/gpu_tests/screenshot_sync_integration_test.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import math
 import os
 import random
 import sys
@@ -119,9 +120,17 @@
         "window.draw({{ red }}, {{ green }}, {{ blue }});",
         red=canvasRGB.r, green=canvasRGB.g, blue=canvasRGB.b)
     screenshot = tab.Screenshot(10)
+    # Avoid checking along antialiased boundary due to limited Adreno 3xx
+    # interpolation precision (crbug.com/847984). We inset by one CSS pixel
+    # adjusted by the device pixel ratio.
+    inset = int(math.ceil(tab.EvaluateJavaScript('window.devicePixelRatio')))
+    # It seems that we should be able to set start_x to 2 * inset (one to
+    # account for the inner div having left=1 and one to avoid sampling the
+    # aa edge). For reasons not fully understood this is insufficent on
+    # several bots (N9, 6P, mac_chromium_rel_ng).
     start_x = 10
-    start_y = 0
-    outer_size = 256
+    start_y = inset
+    outer_size = 256 - inset
     skip = 10
     for y in range(start_y, outer_size, skip):
       for x in range(start_x, outer_size, skip):
diff --git a/device/fido/get_assertion_task.cc b/device/fido/get_assertion_task.cc
index de7aa61..7cae6313 100644
--- a/device/fido/get_assertion_task.cc
+++ b/device/fido/get_assertion_task.cc
@@ -71,8 +71,10 @@
 }
 
 void GetAssertionTask::U2fSign() {
+  DCHECK(!device()->device_info());
   device()->set_supported_protocol(ProtocolVersion::kU2f);
-  if (!IsConvertibleToU2fSignCommand(request_)) {
+
+  if (!CheckUserVerificationCompatible()) {
     std::move(callback_).Run(CtapDeviceResponseCode::kCtap2ErrOther,
                              base::nullopt);
     return;
diff --git a/device/fido/get_assertion_task_unittest.cc b/device/fido/get_assertion_task_unittest.cc
index d01b4da5..fbc5792 100644
--- a/device/fido/get_assertion_task_unittest.cc
+++ b/device/fido/get_assertion_task_unittest.cc
@@ -341,6 +341,9 @@
   auto device = std::make_unique<MockFidoDevice>();
   device->ExpectCtap2CommandAndRespondWith(
       CtapRequestCommand::kAuthenticatorGetInfo, base::nullopt);
+  device->ExpectRequestAndRespondWith(
+      test_data::kU2fFakeRegisterCommand,
+      test_data::kApduEncodedNoErrorSignResponse);
 
   auto task = std::make_unique<GetAssertionTask>(
       device.get(), std::move(request),
@@ -348,7 +351,7 @@
 
   get_assertion_callback_receiver().WaitForCallback();
   EXPECT_EQ(device->supported_protocol(), ProtocolVersion::kU2f);
-  EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrOther,
+  EXPECT_EQ(CtapDeviceResponseCode::kCtap2ErrCredentialNotValid,
             get_assertion_callback_receiver().status());
   EXPECT_FALSE(get_assertion_callback_receiver().value());
 }
diff --git a/device/fido/mac/get_assertion_operation.h b/device/fido/mac/get_assertion_operation.h
index 3b4efd5..3146c8f 100644
--- a/device/fido/mac/get_assertion_operation.h
+++ b/device/fido/mac/get_assertion_operation.h
@@ -40,7 +40,7 @@
 
  private:
   const std::string& RpId() const override;
-  void PromptTouchIdDone(bool success, NSError* err) override;
+  void PromptTouchIdDone(bool success) override;
 
   DISALLOW_COPY_AND_ASSIGN(GetAssertionOperation);
 };
diff --git a/device/fido/mac/get_assertion_operation.mm b/device/fido/mac/get_assertion_operation.mm
index e778cd1..4f1bec16 100644
--- a/device/fido/mac/get_assertion_operation.mm
+++ b/device/fido/mac/get_assertion_operation.mm
@@ -52,11 +52,8 @@
   PromptTouchId("sign in to " + RpId());
 }
 
-void GetAssertionOperation::PromptTouchIdDone(bool success, NSError* err) {
+void GetAssertionOperation::PromptTouchIdDone(bool success) {
   if (!success) {
-    // err is autoreleased.
-    CHECK(err != nil);
-    DVLOG(1) << "Touch ID prompt failed: " << base::mac::NSToCFCast(err);
     std::move(callback())
         .Run(CtapDeviceResponseCode::kCtap2ErrOperationDenied, base::nullopt);
     return;
diff --git a/device/fido/mac/make_credential_operation.h b/device/fido/mac/make_credential_operation.h
index f30ce14..4f9f78c 100644
--- a/device/fido/mac/make_credential_operation.h
+++ b/device/fido/mac/make_credential_operation.h
@@ -58,7 +58,7 @@
  private:
   // OperationBase:
   const std::string& RpId() const override;
-  void PromptTouchIdDone(bool success, NSError* err) override;
+  void PromptTouchIdDone(bool success) override;
 
   base::Optional<std::vector<uint8_t>> GenerateCredentialIdForRequest() const;
 };
diff --git a/device/fido/mac/make_credential_operation.mm b/device/fido/mac/make_credential_operation.mm
index 0081e96..51f598dd 100644
--- a/device/fido/mac/make_credential_operation.mm
+++ b/device/fido/mac/make_credential_operation.mm
@@ -70,11 +70,8 @@
   PromptTouchId("register with " + RpId());
 }
 
-void MakeCredentialOperation::PromptTouchIdDone(bool success, NSError* err) {
+void MakeCredentialOperation::PromptTouchIdDone(bool success) {
   if (!success) {
-    // err is autoreleased.
-    CHECK(err != nil);
-    DVLOG(1) << "Touch ID prompt failed: " << base::mac::NSToCFCast(err);
     std::move(callback())
         .Run(CtapDeviceResponseCode::kCtap2ErrOperationDenied, base::nullopt);
     return;
diff --git a/device/fido/mac/operation_base.h b/device/fido/mac/operation_base.h
index 6f030be..5452520 100644
--- a/device/fido/mac/operation_base.h
+++ b/device/fido/mac/operation_base.h
@@ -65,8 +65,8 @@
                                           base::Unretained(this)));
   }
 
-  // Callback for |PromptTouchId|. Any NSError that gets passed is autoreleased.
-  virtual void PromptTouchIdDone(bool success, NSError* err) = 0;
+  // Callback for |PromptTouchId|.
+  virtual void PromptTouchIdDone(bool success) = 0;
 
   // Subclasses override RpId to return the RP ID from the type-specific
   // request.
diff --git a/device/fido/mac/touch_id_context.h b/device/fido/mac/touch_id_context.h
index 29133b4..e54f64d 100644
--- a/device/fido/mac/touch_id_context.h
+++ b/device/fido/mac/touch_id_context.h
@@ -23,9 +23,8 @@
 class API_AVAILABLE(macosx(10.12.2)) TouchIdContext {
  public:
   // The callback is invoked when the Touch ID prompt completes. It receives a
-  // boolean indicating success and an autoreleased NSError if the prompt was
-  // denied or failed.
-  using Callback = base::OnceCallback<void(bool, NSError*)>;
+  // boolean indicating whether obtaining the fingerprint was successful.
+  using Callback = base::OnceCallback<void(bool)>;
 
   TouchIdContext();
   ~TouchIdContext();
@@ -44,6 +43,8 @@
   SecAccessControlRef access_control() const { return access_control_; }
 
  private:
+  void RunCallback(bool success);
+
   base::scoped_nsobject<LAContext> context_;
   base::ScopedCFTypeRef<SecAccessControlRef> access_control_;
   Callback callback_;
diff --git a/device/fido/mac/touch_id_context.mm b/device/fido/mac/touch_id_context.mm
index 8a31f2bc..f372a44f 100644
--- a/device/fido/mac/touch_id_context.mm
+++ b/device/fido/mac/touch_id_context.mm
@@ -6,7 +6,12 @@
 
 #import <Foundation/Foundation.h>
 
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/sequenced_task_runner.h"
 #include "base/strings/sys_string_conversions.h"
+#include "base/threading/sequenced_task_runner_handle.h"
 
 namespace device {
 namespace fido {
@@ -33,6 +38,8 @@
 
 void TouchIdContext::PromptTouchId(std::string reason, Callback callback) {
   callback_ = std::move(callback);
+  scoped_refptr<base::SequencedTaskRunner> runner =
+      base::SequencedTaskRunnerHandle::Get();
   auto weak_self = weak_ptr_factory_.GetWeakPtr();
   // If evaluation succeeds (i.e. user provides a fingerprint), |context_| can
   // be used for one signing operation. N.B. even in |MakeCredentialOperation|,
@@ -42,13 +49,35 @@
                         operation:LAAccessControlOperationUseKeySign
                   localizedReason:base::SysUTF8ToNSString(reason)
                             reply:^(BOOL success, NSError* error) {
-                              if (!weak_self) {
-                                return;
+                              // The reply block is invoked in a separate
+                              // thread. We want to invoke the callback in the
+                              // original thread, so we post it onto the
+                              // originating runner. The weak_self and runner
+                              // variables inside the block are const-copies of
+                              // the ones in the enclosing scope (c.f.
+                              // http://clang.llvm.org/docs/Block-ABI-Apple.html#imported-variables).
+                              if (!success) {
+                                // |error| is autoreleased in this block. It
+                                // is not currently passed onto the other
+                                // thread running the callback; but if it
+                                // were, it would have to be retained first
+                                // (and probably captured in a
+                                // scoped_nsobject<NSError>).
+                                DCHECK(error != nil);
+                                DVLOG(1) << "Touch ID prompt failed: "
+                                         << base::mac::NSToCFCast(error);
                               }
-                              std::move(callback_).Run(success, error);
+                              runner->PostTask(
+                                  FROM_HERE,
+                                  base::BindOnce(&TouchIdContext::RunCallback,
+                                                 weak_self, success));
                             }];
 }
 
+void TouchIdContext::RunCallback(bool success) {
+  std::move(callback_).Run(success);
+}
+
 }  // namespace mac
 }  // namespace fido
 }  // namespace device
diff --git a/device/fido/mac/util.mm b/device/fido/mac/util.mm
index 0ce6571f8..ea14dace 100644
--- a/device/fido/mac/util.mm
+++ b/device/fido/mac/util.mm
@@ -103,6 +103,7 @@
   std::array<uint8_t, 2> encoded_credential_id_length = {
       0, static_cast<uint8_t>(credential_id.size())};
   constexpr uint8_t flags =
+      static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserPresence) |
       static_cast<uint8_t>(AuthenticatorData::Flag::kTestOfUserVerification) |
       static_cast<uint8_t>(AuthenticatorData::Flag::kAttestation);
   return AuthenticatorData(
diff --git a/device/fido/u2f_sign_operation.cc b/device/fido/u2f_sign_operation.cc
index a9ae882..2331918c 100644
--- a/device/fido/u2f_sign_operation.cc
+++ b/device/fido/u2f_sign_operation.cc
@@ -27,15 +27,30 @@
 U2fSignOperation::~U2fSignOperation() = default;
 
 void U2fSignOperation::Start() {
-  // Non-empty allow list in |request_| is checked from above
-  // IsConvertibleToU2fSignCommand().
-  auto it = request().allow_list()->cbegin();
+  const auto& allow_list = request().allow_list();
+  if (allow_list && !allow_list->empty()) {
+    const auto it = allow_list->cbegin();
+    DispatchDeviceRequest(
+        ConvertToU2fSignCommand(request(), ApplicationParameterType::kPrimary,
+                                it->id(), true /* is_check_only */),
+        base::BindOnce(&U2fSignOperation::OnCheckForKeyHandlePresence,
+                       weak_factory_.GetWeakPtr(),
+                       ApplicationParameterType::kPrimary, it));
+  } else {
+    // In order to make U2F authenticators blink on sign request with an empty
+    // allow list, we send fake enrollment to the device and error out if the
+    // user has provided user presence.
+    SendFakeEnrollment();
+  }
+}
+
+void U2fSignOperation::SendFakeEnrollment() {
   DispatchDeviceRequest(
-      ConvertToU2fSignCommand(request(), ApplicationParameterType::kPrimary,
-                              it->id(), true /* is_check_only */),
-      base::BindOnce(&U2fSignOperation::OnCheckForKeyHandlePresence,
-                     weak_factory_.GetWeakPtr(),
-                     ApplicationParameterType::kPrimary, it));
+      ConstructBogusU2fRegistrationCommand(),
+      base::BindOnce(&U2fSignOperation::OnSignResponseReceived,
+                     weak_factory_.GetWeakPtr(), true /* is_fake_enrollment */,
+                     ApplicationParameterType::kPrimary,
+                     std::vector<uint8_t>()));
 }
 
 void U2fSignOperation::RetrySign(
@@ -160,13 +175,9 @@
       } else {
         // No provided key was accepted by this device. Send registration
         // (Fake enroll) request to device.
-        DispatchDeviceRequest(
-            ConstructBogusU2fRegistrationCommand(),
-            base::BindOnce(
-                &U2fSignOperation::OnSignResponseReceived,
-                weak_factory_.GetWeakPtr(), true /* is_fake_enrollment */,
-                ApplicationParameterType::kPrimary, std::vector<uint8_t>()));
+        SendFakeEnrollment();
       }
+
       break;
     }
     default:
diff --git a/device/fido/u2f_sign_operation.h b/device/fido/u2f_sign_operation.h
index 190a51e..f303ae48 100644
--- a/device/fido/u2f_sign_operation.h
+++ b/device/fido/u2f_sign_operation.h
@@ -46,6 +46,7 @@
   using AllowedListIterator =
       std::vector<PublicKeyCredentialDescriptor>::const_iterator;
 
+  void SendFakeEnrollment();
   void RetrySign(bool is_fake_enrollment,
                  ApplicationParameterType application_parameter_type,
                  const std::vector<uint8_t>& key_handle);
diff --git a/device/gamepad/gamepad_provider.cc b/device/gamepad/gamepad_provider.cc
index 1487c46..a567c17c 100644
--- a/device/gamepad/gamepad_provider.cc
+++ b/device/gamepad/gamepad_provider.cc
@@ -11,7 +11,6 @@
 #include <vector>
 
 #include "base/bind.h"
-#include "base/command_line.h"
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
@@ -25,18 +24,11 @@
 #include "device/gamepad/gamepad_data_fetcher.h"
 #include "device/gamepad/gamepad_data_fetcher_manager.h"
 #include "device/gamepad/gamepad_user_gesture.h"
-#include "device/gamepad/public/cpp/gamepad_switches.h"
+#include "device/gamepad/public/cpp/gamepad_features.h"
 #include "mojo/public/cpp/system/platform_handle.h"
 
 namespace device {
 
-namespace {
-
-const size_t kPollingIntervalMillisecondsMin = 4;   // ~250 Hz
-const size_t kPollingIntervalMillisecondsMax = 16;  // ~62.5 Hz
-
-}  // namespace
-
 GamepadProvider::ClosureAndThread::ClosureAndThread(
     const base::Closure& c,
     const scoped_refptr<base::SingleThreadTaskRunner>& m)
@@ -195,21 +187,8 @@
 }
 
 void GamepadProvider::Initialize(std::unique_ptr<GamepadDataFetcher> fetcher) {
-  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
-  size_t interval_millis = kPollingIntervalMillisecondsMax;
-  if (command_line &&
-      command_line->HasSwitch(switches::kGamepadPollingInterval)) {
-    std::string string_value =
-        command_line->GetSwitchValueASCII(switches::kGamepadPollingInterval);
-    size_t int_value;
-    if (base::StringToSizeT(string_value, &int_value)) {
-      // Clamp interval duration to valid range.
-      int_value = std::max(int_value, kPollingIntervalMillisecondsMin);
-      int_value = std::min(int_value, kPollingIntervalMillisecondsMax);
-      interval_millis = int_value;
-    }
-  }
-  sampling_interval_delta_ = base::TimeDelta::FromMilliseconds(interval_millis);
+  sampling_interval_delta_ =
+      base::TimeDelta::FromMilliseconds(features::GetGamepadPollingInterval());
 
   base::SystemMonitor* monitor = base::SystemMonitor::Get();
   if (monitor)
diff --git a/device/gamepad/public/cpp/BUILD.gn b/device/gamepad/public/cpp/BUILD.gn
index 7b44b38..26af5f7 100644
--- a/device/gamepad/public/cpp/BUILD.gn
+++ b/device/gamepad/public/cpp/BUILD.gn
@@ -44,7 +44,13 @@
 
 static_library("switches") {
   sources = [
+    "gamepad_features.cc",
+    "gamepad_features.h",
     "gamepad_switches.cc",
     "gamepad_switches.h",
   ]
+
+  public_deps = [
+    "//base",
+  ]
 }
diff --git a/device/gamepad/public/cpp/gamepad_features.cc b/device/gamepad/public/cpp/gamepad_features.cc
new file mode 100644
index 0000000..75dfa02
--- /dev/null
+++ b/device/gamepad/public/cpp/gamepad_features.cc
@@ -0,0 +1,63 @@
+// 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.
+
+#include "device/gamepad/public/cpp/gamepad_features.h"
+
+#include <algorithm>
+
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "device/gamepad/public/cpp/gamepad_switches.h"
+
+namespace features {
+
+namespace {
+
+const size_t kPollingIntervalMillisecondsMin = 4;   // ~250 Hz
+const size_t kPollingIntervalMillisecondsMax = 16;  // ~62.5 Hz
+
+size_t OverrideIntervalIfValid(base::StringPiece param_value,
+                               size_t default_interval) {
+  size_t interval;
+  if (param_value.empty() || !base::StringToSizeT(param_value, &interval))
+    return default_interval;
+  // Clamp interval duration to valid range.
+  interval = std::max(interval, kPollingIntervalMillisecondsMin);
+  interval = std::min(interval, kPollingIntervalMillisecondsMax);
+  return interval;
+}
+
+}  // namespace
+
+const base::Feature kGamepadPollingInterval{"GamepadPollingInterval",
+                                            base::FEATURE_DISABLED_BY_DEFAULT};
+
+const char kGamepadPollingIntervalParamKey[] = "interval-ms";
+
+size_t GetGamepadPollingInterval() {
+  size_t polling_interval = kPollingIntervalMillisecondsMax;
+
+  // Check if the polling interval is overridden by a field trial.
+  if (base::FeatureList::IsEnabled(kGamepadPollingInterval)) {
+    std::string param_value = base::GetFieldTrialParamValueByFeature(
+        kGamepadPollingInterval, kGamepadPollingIntervalParamKey);
+    polling_interval = OverrideIntervalIfValid(param_value, polling_interval);
+  }
+
+  // Check if the polling interval is overridden by a command-line flag.
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line &&
+      command_line->HasSwitch(switches::kGamepadPollingInterval)) {
+    std::string switch_value =
+        command_line->GetSwitchValueASCII(switches::kGamepadPollingInterval);
+    polling_interval = OverrideIntervalIfValid(switch_value, polling_interval);
+  }
+
+  return polling_interval;
+}
+
+}  // namespace features
diff --git a/device/gamepad/public/cpp/gamepad_features.h b/device/gamepad/public/cpp/gamepad_features.h
new file mode 100644
index 0000000..462c501e
--- /dev/null
+++ b/device/gamepad/public/cpp/gamepad_features.h
@@ -0,0 +1,19 @@
+// 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.
+
+#ifndef DEVICE_GAMEPAD_PUBLIC_CPP_GAMEPAD_FEATURES_H_
+#define DEVICE_GAMEPAD_PUBLIC_CPP_GAMEPAD_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace features {
+
+extern const base::Feature kGamepadPollingInterval;
+extern const char kGamepadPollingIntervalParamKey[];
+
+size_t GetGamepadPollingInterval();
+
+}  // namespace features
+
+#endif  // DEVICE_GAMEPAD_PUBLIC_CPP_GAMEPAD_FEATURES_H_
diff --git a/device/vr/android/gvr/gvr_device.cc b/device/vr/android/gvr/gvr_device.cc
index 93cae2b4..de2c12bc 100644
--- a/device/vr/android/gvr/gvr_device.cc
+++ b/device/vr/android/gvr/gvr_device.cc
@@ -185,19 +185,21 @@
     return;
   }
 
-  if (options->exclusive) {
-    // StartWebXRPresentation is async as we may trigger a DON (Device ON) flow
-    // that pauses Chrome.
-    delegate_provider->StartWebXRPresentation(
-        GetVRDisplayInfo(), std::move(options),
-        base::BindOnce(&GvrDevice::OnRequestSessionResult,
-                       weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
-  } else {
-    // TODO(https://crbug.com/695937): This should be NOTREACHED() once
-    // orientation device handles non-exclusive VR sessions.
-    // TODO(https://crbug.com/842025): Handle this when RequestSession is called
-    // for non-exclusive sessions.
-    NOTREACHED();
+  if (options->immersive) {
+    if (options->immersive) {
+      // StartWebXRPresentation is async as we may trigger a DON (Device ON)
+      // flow that pauses Chrome.
+      delegate_provider->StartWebXRPresentation(
+          GetVRDisplayInfo(), std::move(options),
+          base::BindOnce(&GvrDevice::OnRequestSessionResult,
+                         weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
+    } else {
+      // TODO(https://crbug.com/695937): This should be NOTREACHED() once
+      // orientation device handles non-immersive VR sessions.
+      // TODO(https://crbug.com/842025): Handle this when RequestSession is
+      // called for non-immersive sessions.
+      NOTREACHED();
+    }
   }
 }
 
diff --git a/device/vr/oculus/oculus_render_loop.cc b/device/vr/oculus/oculus_render_loop.cc
index 241bf3f..80a37b6e 100644
--- a/device/vr/oculus/oculus_render_loop.cc
+++ b/device/vr/oculus/oculus_render_loop.cc
@@ -231,7 +231,7 @@
 void OculusRenderLoop::RequestSession(
     mojom::XRDeviceRuntimeSessionOptionsPtr options,
     RequestSessionCallback callback) {
-  DCHECK(options->exclusive);
+  DCHECK(options->immersive);
 
   StartOvrSession();
   if (!session_
diff --git a/device/vr/openvr/openvr_render_loop.cc b/device/vr/openvr/openvr_render_loop.cc
index e542bc1..fa37e4d 100644
--- a/device/vr/openvr/openvr_render_loop.cc
+++ b/device/vr/openvr/openvr_render_loop.cc
@@ -168,7 +168,7 @@
     base::OnceCallback<void()> on_presentation_ended,
     mojom::XRDeviceRuntimeSessionOptionsPtr options,
     RequestSessionCallback callback) {
-  DCHECK(options->exclusive);
+  DCHECK(options->immersive);
   binding_.Close();
 
   if (!openvr_) {
diff --git a/device/vr/orientation/orientation_device.cc b/device/vr/orientation/orientation_device.cc
index c0c0882..ee322dd 100644
--- a/device/vr/orientation/orientation_device.cc
+++ b/device/vr/orientation/orientation_device.cc
@@ -141,9 +141,9 @@
 void VROrientationDevice::RequestSession(
     mojom::XRDeviceRuntimeSessionOptionsPtr options,
     mojom::XRRuntime::RequestSessionCallback callback) {
-  DCHECK(!options->exclusive);
+  DCHECK(!options->immersive);
   // TODO(offenwanger): Perform a check to see if sensors are available when
-  // RequestSession is called for non-exclusive sessions.
+  // RequestSession is called for non-immersive sessions.
   std::move(callback).Run(nullptr, nullptr);
 }
 
diff --git a/device/vr/public/mojom/isolated_xr_service.mojom b/device/vr/public/mojom/isolated_xr_service.mojom
index eddbf817..5b33778 100644
--- a/device/vr/public/mojom/isolated_xr_service.mojom
+++ b/device/vr/public/mojom/isolated_xr_service.mojom
@@ -36,7 +36,7 @@
 };
 
 struct XRDeviceRuntimeSessionOptions {
-  bool exclusive;
+  bool immersive;
 
   // The following options are used for permission requests.
   // TODO(crbug.com/854655): remove these fields, and do permission checks in
diff --git a/device/vr/public/mojom/vr_service.mojom b/device/vr/public/mojom/vr_service.mojom
index 663276c3..a5b87a7 100644
--- a/device/vr/public/mojom/vr_service.mojom
+++ b/device/vr/public/mojom/vr_service.mojom
@@ -29,7 +29,7 @@
 };
 
 struct XRSessionOptions {
-  bool exclusive;
+  bool immersive;
 
   // A flag to indicate if there has been a user activation when the request
   // session is made.
@@ -297,7 +297,7 @@
 // utility process on Windows.  The render process communicates with it.
 // For AR displays (VRDisplayCapabilities.can_provide_pass_through_images
 // is true), clients can use GetFrameData to get images.
-// TODO(836478): rename VRMagicWindowProvider to NonExclusiveWindowProvider or
+// TODO(836478): rename VRMagicWindowProvider to NonImmersiveWindowProvider or
 // similar.
 interface VRMagicWindowProvider {
   // frame_data is optional and will not be set if and only if the call fails
diff --git a/device/vr/vr_display_impl_unittest.cc b/device/vr/vr_display_impl_unittest.cc
index e20d720..6735be75 100644
--- a/device/vr/vr_display_impl_unittest.cc
+++ b/device/vr/vr_display_impl_unittest.cc
@@ -23,10 +23,10 @@
   void onDisplaySynced() {}
   void onPresentComplete(
       device::mojom::XRPresentationConnectionPtr connection,
-      mojom::XRSessionControllerPtr exclusive_session_controller) {
+      mojom::XRSessionControllerPtr immersive_session_controller) {
     is_request_presenting_success_ = connection ? true : false;
 
-    exclusive_session_controller_ = std::move(exclusive_session_controller);
+    immersive_session_controller_ = std::move(immersive_session_controller);
   }
 
  protected:
@@ -56,7 +56,7 @@
 
   void ExitPresent() {
     device_->StopSession();
-    exclusive_session_controller_ = nullptr;
+    immersive_session_controller_ = nullptr;
   }
 
   bool presenting() { return device_->IsPresenting(); }
@@ -67,7 +67,7 @@
   bool is_request_presenting_success_ = false;
   std::unique_ptr<FakeVRDevice> device_;
   std::unique_ptr<FakeVRServiceClient> client_;
-  mojom::XRSessionControllerPtr exclusive_session_controller_;
+  mojom::XRSessionControllerPtr immersive_session_controller_;
 
   DISALLOW_COPY_AND_ASSIGN(VRDisplayImplTest);
 };
diff --git a/extensions/browser/BUILD.gn b/extensions/browser/BUILD.gn
index 26d6afa..bde7433 100644
--- a/extensions/browser/BUILD.gn
+++ b/extensions/browser/BUILD.gn
@@ -474,10 +474,6 @@
     "//ui/display:test_support",
   ]
 
-  if (is_mac) {
-    # Needed for App Shell.app's Helper.
-    deps += [ "//extensions/shell:app_shell" ]
-  }
   if (is_chromeos) {
     sources += [
       "api/cec_private/cec_private_apitest.cc",
diff --git a/extensions/shell/BUILD.gn b/extensions/shell/BUILD.gn
index b46aaa83..c14cff85 100644
--- a/extensions/shell/BUILD.gn
+++ b/extensions/shell/BUILD.gn
@@ -13,10 +13,6 @@
 
 if (is_linux) {
   import("//build/linux/extract_symbols.gni")
-} else if (is_mac) {
-  import("//build/config/mac/rules.gni")
-  import("//third_party/icu/config.gni")
-  import("//v8/gni/v8.gni")
 }
 
 assert(enable_extensions)
@@ -89,8 +85,6 @@
   }
 
   sources = [
-    "app/paths_mac.h",
-    "app/paths_mac.mm",
     "app/shell_main_delegate.cc",
     "app/shell_main_delegate.h",
     "browser/api/feedback_private/shell_feedback_private_delegate.cc",
@@ -260,44 +254,24 @@
   }
 }
 
-if (is_mac) {
-  mac_app_bundle("app_shell") {
-    testonly = true
-    output_name = "App Shell"
-    sources = [
-      "app/shell_main.cc",
-    ]
-    deps = [
-      ":app_shell_framework_bundle_data",
-      "//content/public/app:both",
-      "//extensions:shell_and_test_pak",
-    ]
-    ldflags = [
-      "-rpath",
-      "@executable_path/../",
-    ]
-    info_plist = "app/app-Info.plist"
-  }
-} else {
-  executable("app_shell") {
-    # testonly because :app_shell_lib is testonly. See :app_shell_lib comment.
-    testonly = true
-    sources = [
-      "app/shell_main.cc",
-    ]
+executable("app_shell") {
+  # testonly because :app_shell_lib is testonly. See :app_shell_lib comment.
+  testonly = true
+  sources = [
+    "app/shell_main.cc",
+  ]
 
-    deps = [
-      ":app_shell_lib",
-      "//build/win:default_exe_manifest",
-      "//content/public/app:both",
-      "//extensions:shell_and_test_pak",
-    ]
+  deps = [
+    ":app_shell_lib",
+    "//build/win:default_exe_manifest",
+    "//content/public/app:both",
+    "//extensions:shell_and_test_pak",
+  ]
 
-    if (is_win) {
-      configs += [ "//build/config/win:windowed" ]
-      configs -= [ "//build/config/win:console" ]
-      deps += [ "//sandbox/win:sandbox" ]
-    }
+  if (is_win) {
+    configs += [ "//build/config/win:windowed" ]
+    configs -= [ "//build/config/win:console" ]
+    deps += [ "//sandbox/win:sandbox" ]
   }
 }
 
@@ -392,103 +366,6 @@
   output = "$target_gen_dir/common/version.h"
 }
 
-if (is_mac) {
-  bundle_data("app_shell_framework_resources") {
-    sources = [
-      "$root_gen_dir/extensions/shell/app_shell_resources.pak",
-      "$root_out_dir/extensions_shell_and_test.pak",
-    ]
-    public_deps = [
-      ":resources_grit",
-      "//extensions:shell_and_test_pak",
-    ]
-    if (icu_use_data_file) {
-      sources += [ "$root_out_dir/icudtl.dat" ]
-      public_deps += [ "//third_party/icu:icudata" ]
-    }
-    if (v8_use_external_startup_data) {
-      sources += [ "$root_out_dir/natives_blob.bin" ]
-      public_deps += [ "//v8" ]
-      if (use_v8_context_snapshot) {
-        sources += [ "$root_out_dir/v8_context_snapshot.bin" ]
-        public_deps += [ "//tools/v8_context_snapshot" ]
-      } else {
-        sources += [ "$root_out_dir/snapshot_blob.bin" ]
-      }
-    }
-    outputs = [
-      "{{bundle_resources_dir}}/{{source_file_part}}",
-    ]
-  }
-
-  mac_framework_bundle("app_shell_framework") {
-    testonly = true
-    output_name = "App Shell Framework"
-    framework_version = "A"
-    framework_contents = [ "Resources" ]
-    sources = [
-      "app/shell_main_mac.cc",
-      "app/shell_main_mac.h",
-    ]
-    public_deps = [
-      ":app_shell_lib",
-    ]
-    deps = [
-      ":app_shell_framework_resources",
-      "//content/public/app:both",
-    ]
-    ldflags = [
-      "-Wl,-install_name,@rpath/Frameworks/$output_name.framework/$output_name",
-    ]
-    if (is_component_build) {
-      ldflags += [
-        "-rpath",
-        "@loader_path/../../../../../..",
-      ]
-    }
-    info_plist = "app/framework-Info.plist"
-  }
-
-  mac_app_bundle("app_shell_helper_app") {
-    testonly = true
-    output_name = "App Shell Helper"
-    sources = [
-      "app/shell_main.cc",
-    ]
-    deps = [
-      ":app_shell_framework+link",
-    ]
-
-    # deps must not include //content/public/app:both. shell_main.cc does
-    # include a #if !defined(OS_MACOSX) block. Rather than use nogncheck there,
-    # disable checking here so that checking still happens on non-mac targets.
-    check_includes = false
-
-    # The helper is in App Shell.app/Contents/Frameworks/App Shell Helper.app/Contents/MacOS/
-    # so set rpath up to Contents/ so that the loader can find Frameworks/.
-    ldflags = [
-      "-rpath",
-      "@executable_path/../../../..",
-    ]
-    info_plist = "app/helper-Info.plist"
-  }
-
-  bundle_data("app_shell_framework_bundle_data") {
-    testonly = true
-    sources = [
-      "$root_out_dir/App Shell Framework.framework",
-      "$root_out_dir/App Shell Helper.app",
-    ]
-    outputs = [
-      "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}",
-    ]
-    public_deps = [
-      ":app_shell_framework+link",
-      ":app_shell_helper_app",
-    ]
-  }
-}
-
 source_set("browser_tests") {
   testonly = true
   sources = [
diff --git a/extensions/shell/app/app-Info.plist b/extensions/shell/app/app-Info.plist
deleted file mode 100644
index a31859c..0000000
--- a/extensions/shell/app/app-Info.plist
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleDisplayName</key>
-	<string>${EXECUTABLE_NAME}</string>
-	<key>CFBundleExecutable</key>
-	<string>${EXECUTABLE_NAME}</string>
-	<key>CFBundleIconFile</key>
-	<string>app.icns</string>
-	<key>CFBundleIdentifier</key>
-	<string>org.chromium.AppShell</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>${PRODUCT_NAME}</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-	<key>CFBundleVersion</key>
-	<string>1.0</string>
-	<key>NSMainNibFile</key>
-	<string>MainMenu</string>
-	<key>NSPrincipalClass</key>
-	<string>NSApplication</string>
-	<key>LSMinimumSystemVersion</key>
-	<string>${CHROMIUM_MIN_SYSTEM_VERSION}</string>
-	<key>LSFileQuarantineEnabled</key>
-	<true/>
-	<key>NSSupportsAutomaticGraphicsSwitching</key>
-	<true/>
-</dict>
-</plist>
diff --git a/extensions/shell/app/framework-Info.plist b/extensions/shell/app/framework-Info.plist
deleted file mode 100644
index ec58d37..0000000
--- a/extensions/shell/app/framework-Info.plist
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleExecutable</key>
-	<string>${EXECUTABLE_NAME}</string>
-	<key>CFBundleIdentifier</key>
-	<string>org.chromium.AppShell.framework</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundlePackageType</key>
-	<string>FMWK</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-</dict>
-</plist>
diff --git a/extensions/shell/app/helper-Info.plist b/extensions/shell/app/helper-Info.plist
deleted file mode 100644
index 7ce23b2c..0000000
--- a/extensions/shell/app/helper-Info.plist
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>en</string>
-	<key>CFBundleDisplayName</key>
-	<string>${EXECUTABLE_NAME}</string>
-	<key>CFBundleExecutable</key>
-	<string>${EXECUTABLE_NAME}</string>
-	<key>CFBundleIdentifier</key>
-	<string>org.chromium.AppShell.helper</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>${PRODUCT_NAME}</string>
-	<key>CFBundlePackageType</key>
-	<string>APPL</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>LSFileQuarantineEnabled</key>
-	<true/>
-	<key>LSMinimumSystemVersion</key>
-	<string>${CHROMIUM_MIN_SYSTEM_VERSION}</string>
-	<key>LSUIElement</key>
-	<string>1</string>
-	<key>NSSupportsAutomaticGraphicsSwitching</key>
-	<true/>
-</dict>
-</plist>
diff --git a/extensions/shell/app/paths_mac.h b/extensions/shell/app/paths_mac.h
deleted file mode 100644
index ce847ef3..0000000
--- a/extensions/shell/app/paths_mac.h
+++ /dev/null
@@ -1,18 +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 EXTENSIONS_SHELL_APP_PATHS_MAC_H_
-#define EXTENSIONS_SHELL_APP_PATHS_MAC_H_
-
-namespace extensions {
-
-// Override the framework bundle path.
-void OverrideFrameworkBundlePath();
-
-// Override the helper (child process) path.
-void OverrideChildProcessFilePath();
-
-}  // namespace extensions
-
-#endif  // EXTENSIONS_SHELL_APP_PATHS_MAC_H_
diff --git a/extensions/shell/app/paths_mac.mm b/extensions/shell/app/paths_mac.mm
deleted file mode 100644
index 6540d64..0000000
--- a/extensions/shell/app/paths_mac.mm
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/shell/app/paths_mac.h"
-
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/mac/bundle_locations.h"
-#include "base/mac/foundation_util.h"
-#include "base/path_service.h"
-#include "content/public/common/content_paths.h"
-
-namespace extensions {
-
-namespace {
-
-base::FilePath GetFrameworksPath() {
-  base::FilePath path;
-  base::PathService::Get(base::FILE_EXE, &path);
-  // We now have a path .../App Shell.app/Contents/MacOS/App Shell, and want to
-  // transform it into
-  // .../App Shell.app/Contents/Frameworks/App Shell Framework.framework.
-  // But if it's App Shell Helper.app (inside Frameworks), we must go deeper.
-  if (base::mac::IsBackgroundOnlyProcess()) {
-    path = path.DirName().DirName().DirName().DirName().DirName();
-  } else {
-    path = path.DirName().DirName();
-  }
-  DCHECK_EQ("Contents", path.BaseName().value());
-  path = path.Append("Frameworks");
-  return path;
-}
-
-}  // namespace
-
-void OverrideFrameworkBundlePath() {
-  base::FilePath path =
-      GetFrameworksPath().Append("App Shell Framework.framework");
-  base::mac::SetOverrideFrameworkBundlePath(path);
-}
-
-void OverrideChildProcessFilePath() {
-  base::FilePath path = GetFrameworksPath()
-                            .Append("App Shell Helper.app")
-                            .Append("Contents")
-                            .Append("MacOS")
-                            .Append("App Shell Helper");
-  base::PathService::Override(content::CHILD_PROCESS_EXE, path);
-}
-
-}  // namespace extensions
diff --git a/extensions/shell/app/shell_main.cc b/extensions/shell/app/shell_main.cc
index 54ddc08e..05d57a8 100644
--- a/extensions/shell/app/shell_main.cc
+++ b/extensions/shell/app/shell_main.cc
@@ -3,26 +3,15 @@
 // found in the LICENSE file.
 
 #include "build/build_config.h"
+#include "content/public/app/content_main.h"
+#include "extensions/shell/app/shell_main_delegate.h"
 
 #if defined(OS_WIN)
 #include "content/public/app/sandbox_helper_win.h"
 #include "sandbox/win/src/sandbox_types.h"
 #endif
 
-#if defined(OS_MACOSX)
-#include "extensions/shell/app/shell_main_mac.h"
-#else
-#include "content/public/app/content_main.h"
-#include "extensions/shell/app/shell_main_delegate.h"
-#endif
-
-#if defined(OS_MACOSX)
-int main(int argc, const char** argv) {
-  // Do the delegate work in shell_main_mac to avoid having to export the
-  // delegate types.
-  return ::ContentMain(argc, argv);
-}
-#elif defined(OS_WIN)
+#if defined(OS_WIN)
 int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) {
   extensions::ShellMainDelegate delegate;
   content::ContentMainParams params(&delegate);
@@ -34,7 +23,7 @@
 
   return content::ContentMain(params);
 }
-#else  // non-Mac POSIX
+#else
 int main(int argc, const char** argv) {
   extensions::ShellMainDelegate delegate;
   content::ContentMainParams params(&delegate);
diff --git a/extensions/shell/app/shell_main_delegate.cc b/extensions/shell/app/shell_main_delegate.cc
index 7fc3d17..85dcdbd 100644
--- a/extensions/shell/app/shell_main_delegate.cc
+++ b/extensions/shell/app/shell_main_delegate.cc
@@ -27,11 +27,6 @@
 #include "chromeos/chromeos_paths.h"
 #endif
 
-#if defined(OS_MACOSX)
-#include "base/mac/foundation_util.h"
-#include "extensions/shell/app/paths_mac.h"
-#endif
-
 #if BUILDFLAG(ENABLE_NACL)
 #include "components/nacl/common/nacl_switches.h"  // nogncheck
 #if defined(OS_LINUX)
@@ -120,17 +115,12 @@
 
 // Returns the path to the extensions_shell_and_test.pak file.
 base::FilePath GetResourcesPakFilePath() {
-#if defined(OS_MACOSX)
-  return base::mac::PathForFrameworkBundleResource(
-      CFSTR("extensions_shell_and_test.pak"));
-#else
   base::FilePath extensions_shell_and_test_pak_path;
   base::PathService::Get(base::DIR_MODULE, &extensions_shell_and_test_pak_path);
   extensions_shell_and_test_pak_path =
       extensions_shell_and_test_pak_path.AppendASCII(
           "extensions_shell_and_test.pak");
   return extensions_shell_and_test_pak_path;
-#endif  // OS_MACOSX
 }
 
 }  // namespace
@@ -148,12 +138,6 @@
   content_client_.reset(CreateContentClient());
   SetContentClient(content_client_.get());
 
-#if defined(OS_MACOSX)
-  OverrideChildProcessFilePath();
-  // This must happen before InitializeResourceBundle.
-  OverrideFrameworkBundlePath();
-#endif
-
 #if defined(OS_CHROMEOS)
   chromeos::RegisterPathProvider();
 #endif
diff --git a/extensions/shell/app/shell_main_mac.cc b/extensions/shell/app/shell_main_mac.cc
deleted file mode 100644
index 85195c5..0000000
--- a/extensions/shell/app/shell_main_mac.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "extensions/shell/app/shell_main_mac.h"
-
-#include "content/public/app/content_main.h"
-#include "extensions/shell/app/shell_main_delegate.h"
-
-int ContentMain(int argc, const char** argv) {
-  extensions::ShellMainDelegate delegate;
-  content::ContentMainParams params(&delegate);
-  params.argc = argc;
-  params.argv = argv;
-  return content::ContentMain(params);
-}
diff --git a/extensions/shell/app/shell_main_mac.h b/extensions/shell/app/shell_main_mac.h
deleted file mode 100644
index 457806f..0000000
--- a/extensions/shell/app/shell_main_mac.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef EXTENSIONS_SHELL_APP_SHELL_MAIN_MAC_H_
-#define EXTENSIONS_SHELL_APP_SHELL_MAIN_MAC_H_
-
-#include "build/build_config.h"
-
-extern "C" {
-__attribute__((visibility("default"))) int ContentMain(int argc,
-                                                       const char** argv);
-}  // extern "C"
-
-#endif  // EXTENSIONS_SHELL_APP_SHELL_MAIN_MAC_H_
-
diff --git a/extensions/shell/browser/api/identity/identity_api_unittest.cc b/extensions/shell/browser/api/identity/identity_api_unittest.cc
index f33295773..d9e7e45c 100644
--- a/extensions/shell/browser/api/identity/identity_api_unittest.cc
+++ b/extensions/shell/browser/api/identity/identity_api_unittest.cc
@@ -22,7 +22,7 @@
 class MockShellOAuth2TokenService : public ShellOAuth2TokenService {
  public:
   // The service starts with no account id or refresh token.
-  MockShellOAuth2TokenService() : ShellOAuth2TokenService(nullptr, "", "") {}
+  MockShellOAuth2TokenService() : ShellOAuth2TokenService("", "") {}
   ~MockShellOAuth2TokenService() override {}
 
   // OAuth2TokenService:
diff --git a/extensions/shell/browser/shell_browser_main_parts.cc b/extensions/shell/browser/shell_browser_main_parts.cc
index ff8268f..0f2d390 100644
--- a/extensions/shell/browser/shell_browser_main_parts.cc
+++ b/extensions/shell/browser/shell_browser_main_parts.cc
@@ -233,7 +233,6 @@
   // Initialize OAuth2 support from command line.
   base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
   oauth2_token_service_.reset(new ShellOAuth2TokenService(
-      browser_context_.get(),
       cmd->GetSwitchValueASCII(switches::kAppShellUser),
       cmd->GetSwitchValueASCII(switches::kAppShellRefreshToken)));
 
diff --git a/extensions/shell/browser/shell_oauth2_token_service.cc b/extensions/shell/browser/shell_oauth2_token_service.cc
index 7419cd2..0e7b8f08 100644
--- a/extensions/shell/browser/shell_oauth2_token_service.cc
+++ b/extensions/shell/browser/shell_oauth2_token_service.cc
@@ -5,7 +5,6 @@
 #include "extensions/shell/browser/shell_oauth2_token_service.h"
 
 #include "base/logging.h"
-#include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/shell/browser/shell_oauth2_token_service_delegate.h"
 
@@ -16,13 +15,10 @@
 
 }  // namespace
 
-ShellOAuth2TokenService::ShellOAuth2TokenService(
-    content::BrowserContext* browser_context,
-    std::string account_id,
-    std::string refresh_token)
+ShellOAuth2TokenService::ShellOAuth2TokenService(std::string account_id,
+                                                 std::string refresh_token)
     : OAuth2TokenService(
-          std::make_unique<ShellOAuth2TokenServiceDelegate>(browser_context,
-                                                            account_id,
+          std::make_unique<ShellOAuth2TokenServiceDelegate>(account_id,
                                                             refresh_token)) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(!g_instance);
diff --git a/extensions/shell/browser/shell_oauth2_token_service.h b/extensions/shell/browser/shell_oauth2_token_service.h
index c93c9f20..a7d649b1 100644
--- a/extensions/shell/browser/shell_oauth2_token_service.h
+++ b/extensions/shell/browser/shell_oauth2_token_service.h
@@ -10,10 +10,6 @@
 #include "base/macros.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 
-namespace content {
-class BrowserContext;
-}
-
 namespace extensions {
 
 // Requests OAuth2 access tokens for app_shell. Requires the OAuth2 refresh
@@ -22,9 +18,7 @@
 // allowed.
 class ShellOAuth2TokenService : public OAuth2TokenService {
  public:
-  ShellOAuth2TokenService(content::BrowserContext* browser_context,
-                          std::string account_id,
-                          std::string refresh_token);
+  ShellOAuth2TokenService(std::string account_id, std::string refresh_token);
   ~ShellOAuth2TokenService() override;
 
   // Returns the single instance for app_shell.
diff --git a/extensions/shell/browser/shell_oauth2_token_service_delegate.cc b/extensions/shell/browser/shell_oauth2_token_service_delegate.cc
index c7f4a51..d6e60ad 100644
--- a/extensions/shell/browser/shell_oauth2_token_service_delegate.cc
+++ b/extensions/shell/browser/shell_oauth2_token_service_delegate.cc
@@ -11,13 +11,9 @@
 namespace extensions {
 
 ShellOAuth2TokenServiceDelegate::ShellOAuth2TokenServiceDelegate(
-    content::BrowserContext* browser_context,
     std::string account_id,
     std::string refresh_token)
-    : browser_context_(browser_context),
-      account_id_(account_id),
-      refresh_token_(refresh_token) {
-}
+    : account_id_(account_id), refresh_token_(refresh_token) {}
 
 ShellOAuth2TokenServiceDelegate::~ShellOAuth2TokenServiceDelegate() {
 }
@@ -33,7 +29,6 @@
 OAuth2AccessTokenFetcher*
 ShellOAuth2TokenServiceDelegate::CreateAccessTokenFetcher(
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     OAuth2AccessTokenConsumer* consumer) {
   DCHECK_EQ(account_id, account_id_);
@@ -42,12 +37,6 @@
                                           refresh_token_);
 }
 
-net::URLRequestContextGetter*
-ShellOAuth2TokenServiceDelegate::GetRequestContext() const {
-  return content::BrowserContext::GetDefaultStoragePartition(browser_context_)->
-      GetURLRequestContext();
-}
-
 std::vector<std::string> ShellOAuth2TokenServiceDelegate::GetAccounts() {
   std::vector<std::string> accounts;
   accounts.push_back(account_id_);
diff --git a/extensions/shell/browser/shell_oauth2_token_service_delegate.h b/extensions/shell/browser/shell_oauth2_token_service_delegate.h
index de8167c..3fb64e39 100644
--- a/extensions/shell/browser/shell_oauth2_token_service_delegate.h
+++ b/extensions/shell/browser/shell_oauth2_token_service_delegate.h
@@ -8,20 +8,14 @@
 #include <string>
 
 #include "base/macros.h"
-#include "content/public/browser/browser_context.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
 #include "google_apis/gaia/oauth2_token_service_delegate.h"
 
-namespace content {
-class BrowserContext;
-}
-
 namespace extensions {
 
 class ShellOAuth2TokenServiceDelegate : public OAuth2TokenServiceDelegate {
  public:
-  ShellOAuth2TokenServiceDelegate(content::BrowserContext* browser_context,
-                                  std::string account_id,
+  ShellOAuth2TokenServiceDelegate(std::string account_id,
                                   std::string refresh_token);
   ~ShellOAuth2TokenServiceDelegate() override;
 
@@ -29,10 +23,8 @@
 
   OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       OAuth2AccessTokenConsumer* consumer) override;
-  net::URLRequestContextGetter* GetRequestContext() const override;
 
   std::vector<std::string> GetAccounts() override;
 
@@ -40,9 +32,6 @@
                          const std::string& refresh_token) override;
 
  private:
-  // Not owned.
-  content::BrowserContext* browser_context_;
-
   // User account id, such as "foo@gmail.com".
   std::string account_id_;
 
diff --git a/extensions/shell/browser/shell_oauth2_token_service_unittest.cc b/extensions/shell/browser/shell_oauth2_token_service_unittest.cc
index 3396804..43bf44d 100644
--- a/extensions/shell/browser/shell_oauth2_token_service_unittest.cc
+++ b/extensions/shell/browser/shell_oauth2_token_service_unittest.cc
@@ -16,7 +16,7 @@
 
 // Verifies setting the refresh token makes it available.
 TEST_F(ShellOAuth2TokenServiceTest, SetRefreshToken) {
-  ShellOAuth2TokenService service(nullptr, "larry@google.com", "token123");
+  ShellOAuth2TokenService service("larry@google.com", "token123");
 
   // Only has a token for the account in the constructor.
   EXPECT_EQ("larry@google.com", service.AccountId());
diff --git a/extensions/shell/test/shell_test.cc b/extensions/shell/test/shell_test.cc
index 7684148..2b38101 100644
--- a/extensions/shell/test/shell_test.cc
+++ b/extensions/shell/test/shell_test.cc
@@ -4,14 +4,10 @@
 
 #include "extensions/shell/test/shell_test.h"
 
-#include "base/base_paths.h"
 #include "base/command_line.h"
-#include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
-#include "base/path_service.h"
 #include "base/run_loop.h"
-#include "build/build_config.h"
 #include "content/public/common/content_switches.h"
 #include "extensions/browser/extension_system.h"
 #include "extensions/shell/browser/desktop_controller.h"
@@ -23,18 +19,6 @@
 AppShellTest::AppShellTest()
     : browser_context_(nullptr),
       extension_system_(nullptr) {
-#if defined(OS_MACOSX)
-  // TODO(phajdan.jr): Make browser tests self-contained on Mac; remove this.
-  // Set up the application path as though we we are inside the App Shell.app
-  // bundle, rather than the top-level extensions_browsertests, because we
-  // make many assumptions about where the executable is located.
-  base::FilePath app_shell_path;
-  CHECK(base::PathService::Get(base::FILE_EXE, &app_shell_path));
-  app_shell_path = app_shell_path.DirName();
-  app_shell_path = app_shell_path.Append(
-      FILE_PATH_LITERAL("App Shell.app/Contents/MacOS/App Shell"));
-  CHECK(base::PathService::Override(base::FILE_EXE, app_shell_path));
-#endif
 }
 
 AppShellTest::~AppShellTest() {
diff --git a/google_apis/BUILD.gn b/google_apis/BUILD.gn
index d0d54b6b0..4567d96 100644
--- a/google_apis/BUILD.gn
+++ b/google_apis/BUILD.gn
@@ -137,6 +137,7 @@
       "//base/third_party/dynamic_annotations",
       "//crypto",
       "//mojo/public/cpp/bindings:struct_traits",
+      "//services/network/public/cpp",
     ]
 
     if (defined(invoker.deps)) {
diff --git a/google_apis/DEPS b/google_apis/DEPS
index 926008a..81c8611 100644
--- a/google_apis/DEPS
+++ b/google_apis/DEPS
@@ -2,7 +2,9 @@
   "-chrome",
   "-content",
   "+crypto",
+  "+mojo/edk",
   "+net",
+  "+services/network/public",
+  "+services/network/test",
   "+third_party/ocmock",
-  "+services/network/public/cpp",
 ]
diff --git a/google_apis/drive/auth_service.cc b/google_apis/drive/auth_service.cc
index 983c7d3..97ef25a 100644
--- a/google_apis/drive/auth_service.cc
+++ b/google_apis/drive/auth_service.cc
@@ -15,7 +15,6 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "google_apis/drive/auth_service_observer.h"
 #include "google_apis/gaia/google_service_auth_error.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace google_apis {
@@ -41,7 +40,6 @@
  public:
   AuthRequest(OAuth2TokenService* oauth2_token_service,
               const std::string& account_id,
-              net::URLRequestContextGetter* url_request_context_getter,
               scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
               const AuthStatusCallback& callback,
               const std::vector<std::string>& scopes);
@@ -65,14 +63,13 @@
 AuthRequest::AuthRequest(
     OAuth2TokenService* oauth2_token_service,
     const std::string& account_id,
-    net::URLRequestContextGetter* url_request_context_getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const AuthStatusCallback& callback,
     const std::vector<std::string>& scopes)
     : OAuth2TokenService::Consumer("auth_service"), callback_(callback) {
   DCHECK(!callback_.is_null());
   request_ = oauth2_token_service->StartRequestWithContext(
-      account_id, url_request_context_getter, url_loader_factory,
+      account_id, url_loader_factory,
       OAuth2TokenService::ScopeSet(scopes.begin(), scopes.end()), this);
 }
 
@@ -120,12 +117,10 @@
 AuthService::AuthService(
     OAuth2TokenService* oauth2_token_service,
     const std::string& account_id,
-    net::URLRequestContextGetter* url_request_context_getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::vector<std::string>& scopes)
     : oauth2_token_service_(oauth2_token_service),
       account_id_(account_id),
-      url_request_context_getter_(url_request_context_getter),
       url_loader_factory_(url_loader_factory),
       scopes_(scopes),
       weak_ptr_factory_(this) {
@@ -150,8 +145,7 @@
         FROM_HERE, base::Bind(callback, HTTP_SUCCESS, access_token_));
   } else if (HasRefreshToken()) {
     // We have refresh token, let's get an access token.
-    new AuthRequest(oauth2_token_service_, account_id_,
-                    url_request_context_getter_.get(), url_loader_factory_,
+    new AuthRequest(oauth2_token_service_, account_id_, url_loader_factory_,
                     base::Bind(&AuthService::OnAuthCompleted,
                                weak_ptr_factory_.GetWeakPtr(), callback),
                     scopes_);
diff --git a/google_apis/drive/auth_service.h b/google_apis/drive/auth_service.h
index cb36713..0b630b2 100644
--- a/google_apis/drive/auth_service.h
+++ b/google_apis/drive/auth_service.h
@@ -9,15 +9,13 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "base/threading/thread_checker.h"
 #include "google_apis/drive/auth_service_interface.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 
-namespace net {
-class URLRequestContextGetter;
-}
 namespace network {
 class SharedURLLoaderFactory;
 }
@@ -33,13 +31,12 @@
 class AuthService : public AuthServiceInterface,
                     public OAuth2TokenService::Observer {
  public:
-  // |url_request_context_getter| is used to perform authentication with
-  // URLFetcher.
+  // |url_loader_factory| is used to perform authentication with
+  // SimpleURLLoader.
   //
   // |scopes| specifies OAuth2 scopes.
   AuthService(OAuth2TokenService* oauth2_token_service,
               const std::string& account_id,
-              net::URLRequestContextGetter* url_request_context_getter,
               scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
               const std::vector<std::string>& scopes);
   ~AuthService() override;
@@ -70,7 +67,6 @@
 
   OAuth2TokenService* oauth2_token_service_;
   std::string account_id_;
-  scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   bool has_refresh_token_;
   std::string access_token_;
diff --git a/google_apis/gaia/DEPS b/google_apis/gaia/DEPS
index 7221ba14..35ee2420 100644
--- a/google_apis/gaia/DEPS
+++ b/google_apis/gaia/DEPS
@@ -6,8 +6,10 @@
 
 specific_include_rules = {
   r"(fake_oauth2_token_service_delegate\.h"
+  r"|gaia_auth_fetcher_unittest\.cc"
   r"|oauth2_access_token_fetcher_impl_unittest\.cc"
   r"|oauth2_token_service_unittest\.cc"
+  r"|ubertoken_fetcher_unittest\.cc"
   r")": [
     "+services/network/test",
     "+mojo/core/embedder",
diff --git a/google_apis/gaia/fake_oauth2_token_service.cc b/google_apis/gaia/fake_oauth2_token_service.cc
index 1d57b221..e17fdf4 100644
--- a/google_apis/gaia/fake_oauth2_token_service.cc
+++ b/google_apis/gaia/fake_oauth2_token_service.cc
@@ -16,8 +16,7 @@
 }
 
 FakeOAuth2TokenService::FakeOAuth2TokenService()
-    : OAuth2TokenService(
-          std::make_unique<FakeOAuth2TokenServiceDelegate>(nullptr)) {}
+    : OAuth2TokenService(std::make_unique<FakeOAuth2TokenServiceDelegate>()) {}
 
 FakeOAuth2TokenService::~FakeOAuth2TokenService() {
 }
@@ -25,8 +24,7 @@
 void FakeOAuth2TokenService::FetchOAuth2Token(
     RequestImpl* request,
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
-    scoped_refptr<network::SharedURLLoaderFactory> url_factory,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::string& client_id,
     const std::string& client_secret,
     const ScopeSet& scopes) {
diff --git a/google_apis/gaia/fake_oauth2_token_service.h b/google_apis/gaia/fake_oauth2_token_service.h
index 70a8a96..0e05171 100644
--- a/google_apis/gaia/fake_oauth2_token_service.h
+++ b/google_apis/gaia/fake_oauth2_token_service.h
@@ -10,9 +10,6 @@
 #include "google_apis/gaia/fake_oauth2_token_service_delegate.h"
 #include "google_apis/gaia/oauth2_token_service.h"
 
-namespace net {
-class URLRequestContextGetter;
-}
 namespace network {
 class SharedURLLoaderFactory;
 }
@@ -42,7 +39,6 @@
   void FetchOAuth2Token(
       RequestImpl* request,
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const std::string& client_id,
       const std::string& client_secret,
diff --git a/google_apis/gaia/fake_oauth2_token_service_delegate.cc b/google_apis/gaia/fake_oauth2_token_service_delegate.cc
index 4090022..9ee0ce4 100644
--- a/google_apis/gaia/fake_oauth2_token_service_delegate.cc
+++ b/google_apis/gaia/fake_oauth2_token_service_delegate.cc
@@ -10,10 +10,8 @@
     : refresh_token(refresh_token),
       error(GoogleServiceAuthError::NONE) {}
 
-FakeOAuth2TokenServiceDelegate::FakeOAuth2TokenServiceDelegate(
-    net::URLRequestContextGetter* request_context)
-    : request_context_(request_context),
-      shared_factory_(
+FakeOAuth2TokenServiceDelegate::FakeOAuth2TokenServiceDelegate()
+    : shared_factory_(
           base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
               &test_url_loader_factory_)) {}
 
@@ -23,12 +21,11 @@
 OAuth2AccessTokenFetcher*
 FakeOAuth2TokenServiceDelegate::CreateAccessTokenFetcher(
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
-    scoped_refptr<network::SharedURLLoaderFactory> url_factory,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     OAuth2AccessTokenConsumer* consumer) {
   AccountInfoMap::const_iterator it = refresh_tokens_.find(account_id);
   DCHECK(it != refresh_tokens_.end());
-  return new OAuth2AccessTokenFetcherImpl(consumer, url_factory,
+  return new OAuth2AccessTokenFetcherImpl(consumer, url_loader_factory,
                                           it->second->refresh_token);
 }
 
@@ -108,11 +105,6 @@
   IssueRefreshTokenForUser(account_id, std::string());
 }
 
-net::URLRequestContextGetter*
-FakeOAuth2TokenServiceDelegate::GetRequestContext() const {
-  return request_context_.get();
-}
-
 scoped_refptr<network::SharedURLLoaderFactory>
 FakeOAuth2TokenServiceDelegate::GetURLLoaderFactory() const {
   return shared_factory_;
diff --git a/google_apis/gaia/fake_oauth2_token_service_delegate.h b/google_apis/gaia/fake_oauth2_token_service_delegate.h
index 6c4cd77..e90d63c 100644
--- a/google_apis/gaia/fake_oauth2_token_service_delegate.h
+++ b/google_apis/gaia/fake_oauth2_token_service_delegate.h
@@ -10,7 +10,6 @@
 #include "base/memory/ref_counted.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_token_service_delegate.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
 
@@ -20,13 +19,12 @@
 
 class FakeOAuth2TokenServiceDelegate : public OAuth2TokenServiceDelegate {
  public:
-  FakeOAuth2TokenServiceDelegate(net::URLRequestContextGetter* request_context);
+  FakeOAuth2TokenServiceDelegate();
   ~FakeOAuth2TokenServiceDelegate() override;
 
   OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
-      scoped_refptr<network::SharedURLLoaderFactory> url_factory,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       OAuth2AccessTokenConsumer* consumer) override;
 
   // Overriden to make sure it works on Android.
@@ -45,14 +43,9 @@
                          const std::string& refresh_token) override;
   void RevokeCredentials(const std::string& account_id) override;
 
-  net::URLRequestContextGetter* GetRequestContext() const override;
   scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory()
       const override;
 
-  void set_request_context(net::URLRequestContextGetter* request_context) {
-    request_context_ = request_context;
-  }
-
   std::string GetRefreshToken(const std::string& account_id) const;
 
   network::TestURLLoaderFactory* test_url_loader_factory() {
@@ -74,8 +67,6 @@
   typedef std::map<std::string, linked_ptr<AccountInfo>> AccountInfoMap;
   AccountInfoMap refresh_tokens_;
 
-  scoped_refptr<net::URLRequestContextGetter> request_context_;
-
   network::TestURLLoaderFactory test_url_loader_factory_;
   scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
 
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index 73cbb495..e1f9910 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -28,15 +28,19 @@
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/http/http_util.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_status.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 
 namespace {
 
 const int kLoadFlagsIgnoreCookies = net::LOAD_DO_NOT_SEND_COOKIES |
                                     net::LOAD_DO_NOT_SAVE_COOKIES;
 
+const size_t kMaxMessageSize = 1024 * 1024;  // 1MB
+
 static bool CookiePartsContains(const std::vector<std::string>& parts,
                                 const char* part) {
   for (std::vector<std::string>::const_iterator it = parts.begin();
@@ -77,16 +81,13 @@
       refresh_token, access_token, expires_in_secs, is_child_account);
 }
 
-void GetCookiesFromResponse(const net::HttpResponseHeaders* headers,
-                            net::ResponseCookies* cookies) {
-  if (!headers)
-    return;
-
-  std::string value;
-  size_t iter = 0;
-  while (headers->EnumerateHeader(&iter, "Set-Cookie", &value)) {
-    if (!value.empty())
-      cookies->push_back(value);
+void GetCookiesFromResponse(
+    const network::HttpRawRequestResponseInfo::HeadersVector& headers,
+    net::ResponseCookies* cookies) {
+  for (const auto& header : headers) {
+    if (header.first == "Set-Cookie" && !header.second.empty()) {
+      cookies->push_back(header.second);
+    }
   }
 }
 
@@ -204,11 +205,12 @@
 const int GaiaAuthFetcher::kClientLoginToOAuth2CookiePartCodePrefixLength =
     arraysize(GaiaAuthFetcher::kClientLoginToOAuth2CookiePartCodePrefix) - 1;
 
-GaiaAuthFetcher::GaiaAuthFetcher(GaiaAuthConsumer* consumer,
-                                 const std::string& source,
-                                 net::URLRequestContextGetter* getter)
-    : consumer_(consumer),
-      getter_(getter),
+GaiaAuthFetcher::GaiaAuthFetcher(
+    GaiaAuthConsumer* consumer,
+    const std::string& source,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+    : url_loader_factory_(url_loader_factory),
+      consumer_(consumer),
       source_(source),
       oauth2_token_gurl_(GaiaUrls::GetInstance()->oauth2_token_url()),
       oauth2_revoke_gurl_(GaiaUrls::GetInstance()->oauth2_revoke_url()),
@@ -236,7 +238,8 @@
 }
 
 void GaiaAuthFetcher::CancelRequest() {
-  fetcher_.reset();
+  url_loader_.reset();
+  original_url_ = GURL();
   fetch_pending_ = false;
 }
 
@@ -247,35 +250,55 @@
     int load_flags,
     const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
-  fetcher_ = net::URLFetcher::Create(
-      0, gaia_gurl, body.empty() ? net::URLFetcher::GET : net::URLFetcher::POST,
-      this, traffic_annotation);
-  fetcher_->SetRequestContext(getter_);
-  fetcher_->SetUploadData("application/x-www-form-urlencoded", body);
-  gaia::MarkURLFetcherAsGaia(fetcher_.get());
 
-  VLOG(2) << "Gaia fetcher URL: " << gaia_gurl.spec();
-  VLOG(2) << "Gaia fetcher headers: " << headers;
-  VLOG(2) << "Gaia fetcher body: " << body;
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = gaia_gurl;
+  original_url_ = gaia_gurl;
+
+  if (!body.empty())
+    resource_request->method = "POST";
+
+  if (!headers.empty())
+    resource_request->headers.AddHeadersFromString(headers);
 
   // The Gaia token exchange requests do not require any cookie-based
   // identification as part of requests.  We suppress sending any cookies to
   // maintain a separation between the user's browsing and Chrome's internal
   // services.  Where such mixing is desired (MergeSession or OAuthLogin), it
   // will be done explicitly.
-  fetcher_->SetLoadFlags(load_flags);
+  resource_request->load_flags = load_flags;
+
+  // Use raw headers as the cookies are filtered-out of the response when
+  // serialized at the IPC layer.
+  resource_request->report_raw_headers = true;
+
+  url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
+                                                 traffic_annotation);
+  if (!body.empty())
+    url_loader_->AttachStringForUpload(body,
+                                       "application/x-www-form-urlencoded");
+
+  url_loader_->SetAllowHttpErrorResults(true);
+
+  VLOG(2) << "Gaia fetcher URL: " << gaia_gurl.spec();
+  VLOG(2) << "Gaia fetcher headers: " << headers;
+  VLOG(2) << "Gaia fetcher body: " << body;
 
   // Fetchers are sometimes cancelled because a network change was detected,
   // especially at startup and after sign-in on ChromeOS. Retrying once should
   // be enough in those cases; let the fetcher retry up to 3 times just in case.
   // http://crbug.com/163710
-  fetcher_->SetAutomaticallyRetryOnNetworkChanges(3);
-
-  if (!headers.empty())
-    fetcher_->SetExtraRequestHeaders(headers);
+  url_loader_->SetRetryOptions(
+      3, network::SimpleURLLoader::RETRY_ON_NETWORK_CHANGE);
 
   fetch_pending_ = true;
-  fetcher_->Start();
+
+  // Unretained is OK below as |url_loader_| is owned by this.
+  url_loader_->DownloadToString(
+      url_loader_factory_.get(),
+      base::BindOnce(&GaiaAuthFetcher::OnURLLoadComplete,
+                     base::Unretained(this)),
+      kMaxMessageSize);
 }
 
 // static
@@ -893,14 +916,14 @@
 // static
 GoogleServiceAuthError GaiaAuthFetcher::GenerateAuthError(
     const std::string& data,
-    const net::URLRequestStatus& status) {
-  if (!status.is_success()) {
-    if (status.status() == net::URLRequestStatus::CANCELED) {
+    net::Error net_error) {
+  if (net_error != net::OK) {
+    if (net_error == net::ERR_ABORTED) {
       return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
     }
     DLOG(WARNING) << "Could not reach Google Accounts servers: errno "
-                  << status.error();
-    return GoogleServiceAuthError::FromConnectionError(status.error());
+                  << net_error;
+    return GoogleServiceAuthError::FromConnectionError(net_error);
   }
 
   if (IsSecondFactorSuccess(data))
@@ -944,9 +967,9 @@
 void GaiaAuthFetcher::OnClientLoginToOAuth2Fetched(
     const std::string& data,
     const net::ResponseCookies& cookies,
-    const net::URLRequestStatus& status,
+    net::Error net_error,
     int response_code) {
-  if (status.is_success() && response_code == net::HTTP_OK) {
+  if (net_error == net::OK && response_code == net::HTTP_OK) {
     std::string auth_code;
     if (ParseClientLoginToOAuth2Response(cookies, &auth_code)) {
       if (fetch_token_from_auth_code_)
@@ -960,82 +983,79 @@
       consumer_->OnClientOAuthFailure(auth_error);
     }
   } else {
-    GoogleServiceAuthError auth_error(GenerateAuthError(data, status));
+    GoogleServiceAuthError auth_error(GenerateAuthError(data, net_error));
     consumer_->OnClientOAuthFailure(auth_error);
   }
 }
 
-void GaiaAuthFetcher::OnOAuth2TokenPairFetched(
-    const std::string& data,
-    const net::URLRequestStatus& status,
-    int response_code) {
+void GaiaAuthFetcher::OnOAuth2TokenPairFetched(const std::string& data,
+                                               net::Error net_error,
+                                               int response_code) {
   std::unique_ptr<const GaiaAuthConsumer::ClientOAuthResult> result;
-  if (status.is_success() && response_code == net::HTTP_OK) {
+  if (net_error == net::OK && response_code == net::HTTP_OK) {
     result = ExtractOAuth2TokenPairResponse(data);
   }
 
   if (result) {
     consumer_->OnClientOAuthSuccess(*result);
   } else {
-    consumer_->OnClientOAuthFailure(GenerateAuthError(data, status));
+    consumer_->OnClientOAuthFailure(GenerateAuthError(data, net_error));
   }
 }
 
-void GaiaAuthFetcher::OnOAuth2RevokeTokenFetched(
-    const std::string& data,
-    const net::URLRequestStatus& status,
-    int response_code) {
+void GaiaAuthFetcher::OnOAuth2RevokeTokenFetched(const std::string& data,
+                                                 net::Error net_error,
+                                                 int response_code) {
   GaiaAuthConsumer::TokenRevocationStatus revocation_status =
       GaiaAuthConsumer::TokenRevocationStatus::kUnknownError;
 
-  switch (status.status()) {
-    case net::URLRequestStatus::SUCCESS:
+  switch (net_error) {
+    case net::OK:
       revocation_status =
           GetTokenRevocationStatusFromResponseData(data, response_code);
       break;
-    case net::URLRequestStatus::IO_PENDING:
+    case net::ERR_IO_PENDING:
       NOTREACHED();
       break;
-    case net::URLRequestStatus::FAILED:
-      revocation_status =
-          (status.ToNetError() == net::ERR_TIMED_OUT)
-              ? GaiaAuthConsumer::TokenRevocationStatus::kConnectionTimeout
-              : GaiaAuthConsumer::TokenRevocationStatus::kConnectionFailed;
-      break;
-    case net::URLRequestStatus::CANCELED:
+    case net::ERR_ABORTED:
       revocation_status =
           GaiaAuthConsumer::TokenRevocationStatus::kConnectionCanceled;
       break;
+    default:
+      revocation_status =
+          (net_error == net::ERR_TIMED_OUT)
+              ? GaiaAuthConsumer::TokenRevocationStatus::kConnectionTimeout
+              : GaiaAuthConsumer::TokenRevocationStatus::kConnectionFailed;
+      break;
   }
 
   consumer_->OnOAuth2RevokeTokenCompleted(revocation_status);
 }
 
 void GaiaAuthFetcher::OnListAccountsFetched(const std::string& data,
-                                            const net::URLRequestStatus& status,
+                                            net::Error net_error,
                                             int response_code) {
-  if (status.is_success() && response_code == net::HTTP_OK) {
+  if (net_error == net::OK && response_code == net::HTTP_OK) {
     consumer_->OnListAccountsSuccess(data);
   } else {
-    consumer_->OnListAccountsFailure(GenerateAuthError(data, status));
+    consumer_->OnListAccountsFailure(GenerateAuthError(data, net_error));
   }
 }
 
 void GaiaAuthFetcher::OnLogOutFetched(const std::string& data,
-                                      const net::URLRequestStatus& status,
+                                      net::Error net_error,
                                       int response_code) {
-  if (status.is_success() && response_code == net::HTTP_OK) {
+  if (net_error == net::OK && response_code == net::HTTP_OK) {
     consumer_->OnLogOutSuccess();
   } else {
-    consumer_->OnLogOutFailure(GenerateAuthError(data, status));
+    consumer_->OnLogOutFailure(GenerateAuthError(data, net_error));
   }
 }
 
-void GaiaAuthFetcher::OnGetUserInfoFetched(
-    const std::string& data,
-    const net::URLRequestStatus& status,
-    int response_code) {
-  if (status.is_success() && response_code == net::HTTP_OK) {
+void GaiaAuthFetcher::OnGetUserInfoFetched(const std::string& data,
+                                           net::Error net_error,
+                                           int response_code) {
+  if (net_error == net::OK && response_code == net::HTTP_OK) {
     base::StringPairs tokens;
     UserInfoMap matches;
     base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens);
@@ -1045,34 +1065,34 @@
     }
     consumer_->OnGetUserInfoSuccess(matches);
   } else {
-    consumer_->OnGetUserInfoFailure(GenerateAuthError(data, status));
+    consumer_->OnGetUserInfoFailure(GenerateAuthError(data, net_error));
   }
 }
 
 void GaiaAuthFetcher::OnMergeSessionFetched(const std::string& data,
-                                            const net::URLRequestStatus& status,
+                                            net::Error net_error,
                                             int response_code) {
-  if (status.is_success() && response_code == net::HTTP_OK) {
+  if (net_error == net::OK && response_code == net::HTTP_OK) {
     consumer_->OnMergeSessionSuccess(data);
   } else {
-    consumer_->OnMergeSessionFailure(GenerateAuthError(data, status));
+    consumer_->OnMergeSessionFailure(GenerateAuthError(data, net_error));
   }
 }
 
 void GaiaAuthFetcher::OnUberAuthTokenFetch(const std::string& data,
-                                           const net::URLRequestStatus& status,
+                                           net::Error net_error,
                                            int response_code) {
-  if (status.is_success() && response_code == net::HTTP_OK) {
+  if (net_error == net::OK && response_code == net::HTTP_OK) {
     consumer_->OnUberAuthTokenSuccess(data);
   } else {
-    consumer_->OnUberAuthTokenFailure(GenerateAuthError(data, status));
+    consumer_->OnUberAuthTokenFailure(GenerateAuthError(data, net_error));
   }
 }
 
 void GaiaAuthFetcher::OnOAuthLoginFetched(const std::string& data,
-                                          const net::URLRequestStatus& status,
+                                          net::Error net_error,
                                           int response_code) {
-  if (status.is_success() && response_code == net::HTTP_OK) {
+  if (net_error == net::OK && response_code == net::HTTP_OK) {
     VLOG(1) << "ClientLogin successful!";
     std::string sid;
     std::string lsid;
@@ -1081,78 +1101,85 @@
     consumer_->OnClientLoginSuccess(
         GaiaAuthConsumer::ClientLoginResult(sid, lsid, token, data));
   } else {
-    consumer_->OnClientLoginFailure(GenerateAuthError(data, status));
+    consumer_->OnClientLoginFailure(GenerateAuthError(data, net_error));
   }
 }
 
-void GaiaAuthFetcher::OnGetCheckConnectionInfoFetched(
-    const std::string& data,
-    const net::URLRequestStatus& status,
-    int response_code) {
-  if (status.is_success() && response_code == net::HTTP_OK) {
+void GaiaAuthFetcher::OnGetCheckConnectionInfoFetched(const std::string& data,
+                                                      net::Error net_error,
+                                                      int response_code) {
+  if (net_error == net::Error::OK && response_code == net::HTTP_OK) {
     consumer_->OnGetCheckConnectionInfoSuccess(data);
   } else {
-    consumer_->OnGetCheckConnectionInfoError(GenerateAuthError(data, status));
+    consumer_->OnGetCheckConnectionInfoError(
+        GenerateAuthError(data, net_error));
   }
 }
 
-void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) {
+void GaiaAuthFetcher::OnURLLoadComplete(
+    std::unique_ptr<std::string> response_body) {
+  net::Error net_error = static_cast<net::Error>(url_loader_->NetError());
+  std::string data = response_body ? std::move(*response_body) : "";
+
+  int response_code = 0;
+  network::HttpRawRequestResponseInfo::HeadersVector headers;
+  if (url_loader_->ResponseInfo()) {
+    if (url_loader_->ResponseInfo()->headers)
+      response_code = url_loader_->ResponseInfo()->headers->response_code();
+    if (url_loader_->ResponseInfo()->raw_request_response_info) {
+      headers = url_loader_->ResponseInfo()
+                    ->raw_request_response_info->response_headers;
+    }
+  }
+  OnURLLoadCompleteInternal(net_error, response_code, headers, data);
+}
+
+void GaiaAuthFetcher::OnURLLoadCompleteInternal(
+    net::Error net_error,
+    int response_code,
+    const network::HttpRawRequestResponseInfo::HeadersVector& headers,
+    std::string data) {
   fetch_pending_ = false;
-  // Some of the GAIA requests perform redirects, which results in the final
-  // URL of the fetcher not being the original URL requested.  Therefore use
-  // the original URL when determining which OnXXX function to call.
-  const GURL& url = source->GetOriginalURL();
-  const net::URLRequestStatus& status = source->GetStatus();
-  int response_code = source->GetResponseCode();
-  std::string data;
-  source->GetResponseAsString(&data);
-
-// Retrieve the response headers from the request.  Must only be called after
-// the OnURLFetchComplete callback has run.
-#ifndef NDEBUG
-  std::string headers;
-  if (source->GetResponseHeaders())
-    headers = net::HttpUtil::ConvertHeadersBackToHTTPResponse(
-        source->GetResponseHeaders()->raw_headers());
-  DVLOG(2) << "Response " << url.spec() << ", code = " << response_code << "\n"
-           << headers << "\n";
-  DVLOG(2) << "data: " << data << "\n";
-#endif
-
   net::ResponseCookies cookies;
-  GetCookiesFromResponse(source->GetResponseHeaders(), &cookies);
-  DispatchFetchedRequest(url, data, cookies, status, response_code);
+  GetCookiesFromResponse(headers, &cookies);
+
+  // Some of the GAIA requests perform redirects, which results in the final URL
+  // of the fetcher not being the original URL requested.  Therefore use the
+  // original URL when determining which OnXXX function to call.
+  GURL url = original_url_;
+  original_url_ = GURL();
+  DispatchFetchedRequest(url, data, cookies, net_error, response_code);
 }
 
 void GaiaAuthFetcher::DispatchFetchedRequest(
     const GURL& url,
     const std::string& data,
     const net::ResponseCookies& cookies,
-    const net::URLRequestStatus& status,
+    net::Error net_error,
     int response_code) {
   if (base::StartsWith(url.spec(),
                        deprecated_client_login_to_oauth2_gurl_.spec(),
                        base::CompareCase::SENSITIVE)) {
-    OnClientLoginToOAuth2Fetched(data, cookies, status, response_code);
+    OnClientLoginToOAuth2Fetched(data, cookies, net_error, response_code);
   } else if (url == oauth2_token_gurl_) {
-    OnOAuth2TokenPairFetched(data, status, response_code);
+    OnOAuth2TokenPairFetched(data, net_error, response_code);
   } else if (url == get_user_info_gurl_) {
-    OnGetUserInfoFetched(data, status, response_code);
+    OnGetUserInfoFetched(data, net_error, response_code);
   } else if (base::StartsWith(url.spec(), merge_session_gurl_.spec(),
                               base::CompareCase::SENSITIVE)) {
-    OnMergeSessionFetched(data, status, response_code);
+    OnMergeSessionFetched(data, net_error, response_code);
   } else if (url == uberauth_token_gurl_) {
-    OnUberAuthTokenFetch(data, status, response_code);
+    OnUberAuthTokenFetch(data, net_error, response_code);
   } else if (url == oauth_login_gurl_) {
-    OnOAuthLoginFetched(data, status, response_code);
+    OnOAuthLoginFetched(data, net_error, response_code);
   } else if (url == oauth2_revoke_gurl_) {
-    OnOAuth2RevokeTokenFetched(data, status, response_code);
+    OnOAuth2RevokeTokenFetched(data, net_error, response_code);
   } else if (url == list_accounts_gurl_) {
-    OnListAccountsFetched(data, status, response_code);
+    OnListAccountsFetched(data, net_error, response_code);
   } else if (url == logout_gurl_) {
-    OnLogOutFetched(data, status, response_code);
+    OnLogOutFetched(data, net_error, response_code);
   } else if (url == get_check_connection_info_url_) {
-    OnGetCheckConnectionInfoFetched(data, status, response_code);
+    OnGetCheckConnectionInfoFetched(data, net_error, response_code);
   } else {
     NOTREACHED();
   }
diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h
index bf63d19..0d7fe2b2 100644
--- a/google_apis/gaia/gaia_auth_fetcher.h
+++ b/google_apis/gaia/gaia_auth_fetcher.h
@@ -11,10 +11,13 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
 #include "google_apis/gaia/google_service_auth_error.h"
+#include "net/base/net_errors.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher_delegate.h"
+#include "services/network/public/cpp/http_raw_request_response_info.h"
 #include "url/gurl.h"
 
 // Authenticate a user against the Google Accounts ClientLogin API
@@ -29,13 +32,12 @@
 
 class GaiaAuthFetcherTest;
 
-namespace net {
-class URLFetcher;
-class URLRequestContextGetter;
-class URLRequestStatus;
-}
+namespace network {
+class SimpleURLLoader;
+class SharedURLLoaderFactory;
+}  // namespace network
 
-class GaiaAuthFetcher : public net::URLFetcherDelegate {
+class GaiaAuthFetcher {
  public:
   // Magic string indicating that, while a second factor is still
   // needed to complete authentication, the user provided the right password.
@@ -45,12 +47,12 @@
   // Apps enabled, the user provided the right password.
   static const char kWebLoginRequired[];
 
-  // This will later be hidden behind an auth service which caches
-  // tokens.
-  GaiaAuthFetcher(GaiaAuthConsumer* consumer,
-                  const std::string& source,
-                  net::URLRequestContextGetter* getter);
-  ~GaiaAuthFetcher() override;
+  // This will later be hidden behind an auth service which caches tokens.
+  GaiaAuthFetcher(
+      GaiaAuthConsumer* consumer,
+      const std::string& source,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+  virtual ~GaiaAuthFetcher();
 
   // Start a request to revoke |auth_token|.
   //
@@ -175,29 +177,25 @@
   // /MergeSession requests.
   void StartGetCheckConnectionInfo();
 
-  // Implementation of net::URLFetcherDelegate
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
-
   // StartClientLogin been called && results not back yet?
   bool HasPendingFetch();
 
   // Stop any URL fetches in progress.
   virtual void CancelRequest();
 
-  // From a URLFetcher result, generate an appropriate error.
-  // From the API documentation, both IssueAuthToken and ClientLogin have
+  // From the data loaded from a SimpleURLLoader, generates an appropriate
+  // error. From the API documentation, both IssueAuthToken and ClientLogin have
   // the same error returns.
-  static GoogleServiceAuthError GenerateOAuthLoginError(
-      const std::string& data,
-      const net::URLRequestStatus& status);
+  static GoogleServiceAuthError GenerateOAuthLoginError(const std::string& data,
+                                                        net::Error net_error);
 
  protected:
-  // Create and start |fetcher_|, used to make all Gaia request.  |body| is
+  // Creates and starts |url_loader_|, used to make all Gaia request.  |body| is
   // used as the body of the POST request sent to GAIA.  Any strings listed in
   // |headers| are added as extra HTTP headers in the request.
   //
-  // |load_flags| are passed to directly to net::URLFetcher::Create() when
-  // creating the URL fetcher.
+  // |load_flags| are passed to directly to network::SimpleURLLoader::Create()
+  // when creating the SimpleURLLoader.
   //
   // HasPendingFetch() should return false before calling this method, and will
   // return true afterwards.
@@ -208,11 +206,18 @@
       int load_flags,
       const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
+  // Called by OnURLLoadComplete, exposed for ease of testing.
+  virtual void OnURLLoadCompleteInternal(
+      net::Error net_error,
+      int response_code,
+      const network::HttpRawRequestResponseInfo::HeadersVector& headers,
+      std::string response_body);
+
   // Dispatch the results of a request.
   void DispatchFetchedRequest(const GURL& url,
                               const std::string& data,
                               const net::ResponseCookies& cookies,
-                              const net::URLRequestStatus& status,
+                              net::Error net_error,
                               int response_code);
 
   void SetPendingFetch(bool pending_fetch);
@@ -268,45 +273,47 @@
   static const char kClientLoginToOAuth2CookiePartCodePrefix[];
   static const int kClientLoginToOAuth2CookiePartCodePrefixLength;
 
+  void OnURLLoadComplete(std::unique_ptr<std::string> response_body);
+
   void OnClientLoginToOAuth2Fetched(const std::string& data,
                                     const net::ResponseCookies& cookies,
-                                    const net::URLRequestStatus& status,
+                                    net::Error net_error,
                                     int response_code);
 
   void OnOAuth2TokenPairFetched(const std::string& data,
-                                const net::URLRequestStatus& status,
+                                net::Error net_error,
                                 int response_code);
 
   void OnOAuth2RevokeTokenFetched(const std::string& data,
-                                  const net::URLRequestStatus& status,
+                                  net::Error net_error,
                                   int response_code);
 
   void OnListAccountsFetched(const std::string& data,
-                             const net::URLRequestStatus& status,
+                             net::Error net_error,
                              int response_code);
 
   void OnLogOutFetched(const std::string& data,
-                       const net::URLRequestStatus& status,
+                       net::Error net_error,
                        int response_code);
 
   void OnGetUserInfoFetched(const std::string& data,
-                            const net::URLRequestStatus& status,
+                            net::Error net_error,
                             int response_code);
 
   void OnMergeSessionFetched(const std::string& data,
-                             const net::URLRequestStatus& status,
+                             net::Error net_error,
                              int response_code);
 
   void OnUberAuthTokenFetch(const std::string& data,
-                            const net::URLRequestStatus& status,
+                            net::Error net_error,
                             int response_code);
 
   void OnOAuthLoginFetched(const std::string& data,
-                           const net::URLRequestStatus& status,
+                           net::Error net_error,
                            int response_code);
 
   void OnGetCheckConnectionInfoFetched(const std::string& data,
-                                       const net::URLRequestStatus& status,
+                                       net::Error net_error,
                                        int response_code);
 
   // Tokenize the results of a ClientLogin fetch.
@@ -362,16 +369,15 @@
   static std::string MakeOAuthLoginBody(const std::string& service,
                                         const std::string& source);
 
-  // From a URLFetcher result, generate an appropriate error.
+  // From a SimpleURLLoader result, generates an appropriate error.
   // From the API documentation, both IssueAuthToken and ClientLogin have
   // the same error returns.
-  static GoogleServiceAuthError GenerateAuthError(
-      const std::string& data,
-      const net::URLRequestStatus& status);
+  static GoogleServiceAuthError GenerateAuthError(const std::string& data,
+                                                  net::Error net_error);
 
   // These fields are common to GaiaAuthFetcher, same every request.
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   GaiaAuthConsumer* const consumer_;
-  net::URLRequestContextGetter* const getter_;
   std::string source_;
   const GURL oauth2_token_gurl_;
   const GURL oauth2_revoke_gurl_;
@@ -384,7 +390,8 @@
   const GURL get_check_connection_info_url_;
 
   // While a fetch is going on:
-  std::unique_ptr<net::URLFetcher> fetcher_;
+  std::unique_ptr<network::SimpleURLLoader> url_loader_;
+  GURL original_url_;
   GURL deprecated_client_login_to_oauth2_gurl_;
   std::string request_body_;
 
diff --git a/google_apis/gaia/gaia_auth_fetcher_unittest.cc b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
index 766018da..bb0fe97 100644
--- a/google_apis/gaia/gaia_auth_fetcher_unittest.cc
+++ b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
@@ -6,11 +6,15 @@
 // Originally ported from GoogleAuthenticator tests.
 
 #include <string>
+#include <vector>
 
 #include "base/json/json_reader.h"
 #include "base/memory/ref_counted.h"
 #include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "base/test/bind_test_util.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
@@ -19,14 +23,13 @@
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/mock_url_fetcher_factory.h"
 #include "google_apis/google_api_keys.h"
+#include "mojo/core/embedder/embedder.h"
 #include "net/base/load_flags.h"
 #include "net/base/net_errors.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_fetcher_delegate.h"
-#include "net/url_request/url_request_status.h"
-#include "net/url_request/url_request_test_util.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -42,58 +45,18 @@
     "oauth_code=test-code; Path=/test; HttpOnly";
 const char kGetAuthCodeCookieNoHttpOnly[] =
     "oauth_code=test-code; Path=/test; Secure";
-const char kGetAuthCodeCookieNoOAuthCode[] =
-    "Path=/test; Secure; HttpOnly";
+const char kGetAuthCodeCookieNoOAuthCode[] = "Path=/test; Secure; HttpOnly";
 const char kGetTokenPairValidResponse[] =
-    "{"
-    "  \"refresh_token\": \"rt1\","
-    "  \"access_token\": \"at1\","
-    "  \"expires_in\": 3600,"
-    "  \"token_type\": \"Bearer\","
-    "  \"id_token\": \"it1\""
-    "}";
+    R"({
+        "refresh_token": "rt1",
+        "access_token": "at1",
+        "expires_in": 3600,
+        "token_type": "Bearer",
+        "id_token": "it1"
+     })";
 
 }  // namespace
 
-MockFetcher::MockFetcher(bool success,
-                         const GURL& url,
-                         const std::string& results,
-                         net::URLFetcher::RequestType request_type,
-                         net::URLFetcherDelegate* d)
-    : TestURLFetcher(0, url, d) {
-  set_url(url);
-  net::Error error;
-
-  if (success) {
-    error = net::OK;
-    set_response_code(net::HTTP_OK);
-  } else {
-    error = net::ERR_FAILED;
-  }
-
-  set_status(net::URLRequestStatus::FromError(error));
-  SetResponseString(results);
-}
-
-MockFetcher::MockFetcher(const GURL& url,
-                         const net::URLRequestStatus& status,
-                         int response_code,
-                         const std::string& results,
-                         net::URLFetcher::RequestType request_type,
-                         net::URLFetcherDelegate* d)
-    : TestURLFetcher(0, url, d) {
-  set_url(url);
-  set_status(status);
-  set_response_code(response_code);
-  SetResponseString(results);
-}
-
-MockFetcher::~MockFetcher() {}
-
-void MockFetcher::Start() {
-  delegate()->OnURLFetchComplete(this);
-}
-
 class GaiaAuthFetcherTest : public testing::Test {
  protected:
   GaiaAuthFetcherTest()
@@ -105,7 +68,17 @@
         uberauth_token_source_(
             GaiaUrls::GetInstance()->oauth1_login_url().Resolve(
                 "?source=&issueuberauth=1")),
-        oauth_login_gurl_(GaiaUrls::GetInstance()->oauth1_login_url()) {}
+        oauth_login_gurl_(GaiaUrls::GetInstance()->oauth1_login_url()),
+        deprecated_client_login_to_oauth2_url_(
+            GaiaUrls::GetInstance()->deprecated_client_login_to_oauth2_url()),
+        scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::UI),
+        test_shared_loader_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_)) {
+    test_url_loader_factory_.SetInterceptor(base::BindRepeating(
+        &GaiaAuthFetcherTest::OnResourceIntercepted, base::Unretained(this)));
+  }
 
   void RunParsingTest(const std::string& data,
                       const std::string& sid,
@@ -151,18 +124,29 @@
   GURL merge_session_source_;
   GURL uberauth_token_source_;
   GURL oauth_login_gurl_;
+  GURL deprecated_client_login_to_oauth2_url_;
 
  protected:
-  net::TestURLRequestContextGetter* GetRequestContext() {
-    if (!request_context_getter_.get()) {
-      request_context_getter_ = new net::TestURLRequestContextGetter(
-          message_loop_.task_runner());
-    }
-    return request_context_getter_.get();
+  void SetUp() override { mojo::core::Init(); }
+
+  void OnResourceIntercepted(const network::ResourceRequest& resource) {
+    received_requests_.push_back(resource);
   }
 
-  base::MessageLoop message_loop_;
-  scoped_refptr<net::TestURLRequestContextGetter> request_context_getter_;
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() {
+    return test_shared_loader_factory_;
+  }
+
+  bool WasLastURLServed(const GURL& url) {
+    if (received_requests_.empty())
+      return false;
+    return received_requests_.back().url == url;
+  }
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
+  std::vector<network::ResourceRequest> received_requests_;
 };
 
 class MockGaiaConsumer : public GaiaAuthConsumer {
@@ -220,6 +204,38 @@
   EXPECT_TRUE(expected_error == matching_error);
 }
 
+// A version of GaiaAuthFetcher that exposes some of the protected methods.
+class TestGaiaAuthFetcher : public GaiaAuthFetcher {
+ public:
+  TestGaiaAuthFetcher(
+      GaiaAuthConsumer* consumer,
+      const std::string& source,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+      : GaiaAuthFetcher(consumer, source, url_loader_factory) {}
+
+  void CreateAndStartGaiaFetcherForTesting(
+      const std::string& body,
+      const std::string& headers,
+      const GURL& gaia_gurl,
+      int load_flags,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) {
+    CreateAndStartGaiaFetcher(body, headers, gaia_gurl, load_flags,
+                              traffic_annotation);
+  }
+
+  void TestOnURLLoadCompleteInternal(
+      net::Error net_error,
+      int response_code = net::HTTP_OK,
+      const std::vector<std::string>& cookies = {},
+      std::string response_body = "") {
+    net::HttpRawRequestHeaders::HeaderVector headers;
+    for (auto& cookie : cookies) {
+      headers.push_back(std::make_pair("Set-Cookie", cookie));
+    }
+    OnURLLoadCompleteInternal(net_error, response_code, headers, response_body);
+  }
+};
+
 TEST_F(GaiaAuthFetcherTest, ParseRequest) {
   RunParsingTest("SID=sid\nLSID=lsid\nAuth=auth\n", "sid", "lsid", "auth");
   RunParsingTest("LSID=lsid\nSID=sid\nAuth=auth\n", "sid", "lsid", "auth");
@@ -258,13 +274,12 @@
 }
 
 TEST_F(GaiaAuthFetcherTest, CaptchaParse) {
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
   std::string data = "Url=http://www.google.com/login/captcha\n"
                      "Error=CaptchaRequired\n"
                      "CaptchaToken=CCTOKEN\n"
                      "CaptchaUrl=Captcha?ctoken=CCTOKEN\n";
   GoogleServiceAuthError error =
-      GaiaAuthFetcher::GenerateAuthError(data, status);
+      GaiaAuthFetcher::GenerateAuthError(data, net::OK);
 
   std::string token = "CCTOKEN";
   GURL image_url("http://accounts.google.com/Captcha?ctoken=CCTOKEN");
@@ -277,42 +292,37 @@
 }
 
 TEST_F(GaiaAuthFetcherTest, AccountDeletedError) {
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
   std::string data = "Error=AccountDeleted\n";
   GoogleServiceAuthError error =
-      GaiaAuthFetcher::GenerateAuthError(data, status);
+      GaiaAuthFetcher::GenerateAuthError(data, net::OK);
   EXPECT_EQ(error.state(), GoogleServiceAuthError::ACCOUNT_DELETED);
 }
 
 TEST_F(GaiaAuthFetcherTest, AccountDisabledError) {
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
   std::string data = "Error=AccountDisabled\n";
   GoogleServiceAuthError error =
-      GaiaAuthFetcher::GenerateAuthError(data, status);
+      GaiaAuthFetcher::GenerateAuthError(data, net::OK);
   EXPECT_EQ(error.state(), GoogleServiceAuthError::ACCOUNT_DISABLED);
 }
 
 TEST_F(GaiaAuthFetcherTest, BadAuthenticationError) {
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
   std::string data = "Error=BadAuthentication\n";
   GoogleServiceAuthError error =
-      GaiaAuthFetcher::GenerateAuthError(data, status);
+      GaiaAuthFetcher::GenerateAuthError(data, net::OK);
   EXPECT_EQ(error.state(), GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
 }
 
 TEST_F(GaiaAuthFetcherTest, IncomprehensibleError) {
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
   std::string data = "Error=Gobbledygook\n";
   GoogleServiceAuthError error =
-      GaiaAuthFetcher::GenerateAuthError(data, status);
+      GaiaAuthFetcher::GenerateAuthError(data, net::OK);
   EXPECT_EQ(error.state(), GoogleServiceAuthError::SERVICE_UNAVAILABLE);
 }
 
 TEST_F(GaiaAuthFetcherTest, ServiceUnavailableError) {
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
   std::string data = "Error=ServiceUnavailable\n";
   GoogleServiceAuthError error =
-      GaiaAuthFetcher::GenerateAuthError(data, status);
+      GaiaAuthFetcher::GenerateAuthError(data, net::OK);
   EXPECT_EQ(error.state(), GoogleServiceAuthError::SERVICE_UNAVAILABLE);
 }
 
@@ -324,34 +334,21 @@
                   "rt1", "at1", 3600, false /* is_child_account */)))
       .Times(1);
 
-  net::TestURLFetcherFactory factory;
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
   auth.DeprecatedStartCookieForOAuthLoginTokenExchange("0");
-  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
-  EXPECT_TRUE(NULL != fetcher);
-  EXPECT_EQ(net::LOAD_NORMAL, fetcher->GetLoadFlags());
+  ASSERT_EQ(received_requests_.size(), 1U);
+  EXPECT_EQ(net::LOAD_NORMAL, received_requests_.at(0).load_flags);
   EXPECT_EQ(std::string::npos,
-            fetcher->GetOriginalURL().query().find("device_type=chrome"));
+            received_requests_.at(0).url.query().find("device_type=chrome"));
+  EXPECT_TRUE(auth.HasPendingFetch());
 
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK,
+                                     {std::string(kGetAuthCodeValidCookie)},
+                                     /*body=*/"");
   EXPECT_TRUE(auth.HasPendingFetch());
-  scoped_refptr<net::HttpResponseHeaders> reponse_headers =
-      new net::HttpResponseHeaders("");
-  reponse_headers->AddCookie(kGetAuthCodeValidCookie);
-  MockFetcher mock_fetcher1(
-      client_login_to_oauth2_source_,
-      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0),
-      net::HTTP_OK,
-      std::string(),
-      net::URLFetcher::POST,
-      &auth);
-  mock_fetcher1.set_response_headers(reponse_headers);
-  auth.OnURLFetchComplete(&mock_fetcher1);
-  EXPECT_TRUE(auth.HasPendingFetch());
-  MockFetcher mock_fetcher2(
-      oauth2_token_source_,
-      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0), net::HTTP_OK,
-      kGetTokenPairValidResponse, net::URLFetcher::POST, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher2);
+
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, {},
+                                     kGetTokenPairValidResponse);
   EXPECT_FALSE(auth.HasPendingFetch());
 }
 
@@ -364,169 +361,96 @@
       .Times(0);
 
   net::TestURLFetcherFactory factory;
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
   auth.DeprecatedStartCookieForOAuthLoginTokenExchange(false, "0",
                                                        "ABCDE_12345", "");
-  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
-  EXPECT_TRUE(NULL != fetcher);
-  EXPECT_EQ(net::LOAD_NORMAL, fetcher->GetLoadFlags());
+  ASSERT_EQ(received_requests_.size(), 1U);
+  EXPECT_EQ(net::LOAD_NORMAL, received_requests_.at(0).load_flags);
   EXPECT_EQ(std::string::npos,
-            fetcher->GetOriginalURL().query().find("device_type=chrome"));
-
-  scoped_refptr<net::HttpResponseHeaders> reponse_headers =
-      new net::HttpResponseHeaders("");
-  reponse_headers->AddCookie(kGetAuthCodeValidCookie);
+            received_requests_.at(0).url.query().find("device_type=chrome"));
   EXPECT_TRUE(auth.HasPendingFetch());
-  MockFetcher mock_fetcher1(
-      client_login_to_oauth2_source_,
-      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0),
-      net::HTTP_OK,
-      std::string(),
-      net::URLFetcher::POST,
-      &auth);
-  mock_fetcher1.set_response_headers(reponse_headers);
-  auth.OnURLFetchComplete(&mock_fetcher1);
+
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK,
+                                     {kGetAuthCodeValidCookie});
   EXPECT_FALSE(auth.HasPendingFetch());
 }
 
 TEST_F(GaiaAuthFetcherTest, OAuthLoginTokenWithCookies_DeviceId) {
   MockGaiaConsumer consumer;
-  net::TestURLFetcherFactory factory;
   std::string expected_device_id("ABCDE-12345");
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
+  GaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
   auth.DeprecatedStartCookieForOAuthLoginTokenExchangeWithDeviceId(
       "0", expected_device_id);
-  net::TestURLFetcher* fetcher = factory.GetFetcherByID(0);
-  EXPECT_TRUE(NULL != fetcher);
-  EXPECT_EQ(net::LOAD_NORMAL, fetcher->GetLoadFlags());
+
+  ASSERT_EQ(received_requests_.size(), 1U);
+  EXPECT_EQ(net::LOAD_NORMAL, received_requests_.at(0).load_flags);
   EXPECT_NE(std::string::npos,
-            fetcher->GetOriginalURL().query().find("device_type=chrome"));
-  net::HttpRequestHeaders extra_request_headers;
-  fetcher->GetExtraRequestHeaders(&extra_request_headers);
+            received_requests_.at(0).url.query().find("device_type=chrome"));
+
   std::string device_id;
-  EXPECT_TRUE(extra_request_headers.GetHeader("X-Device-ID", &device_id));
+  EXPECT_TRUE(
+      received_requests_.at(0).headers.GetHeader("X-Device-ID", &device_id));
   EXPECT_EQ(device_id, expected_device_id);
 }
 
 TEST_F(GaiaAuthFetcherTest, OAuthLoginTokenClientLoginToOAuth2Failure) {
   MockGaiaConsumer consumer;
-  EXPECT_CALL(consumer, OnClientOAuthFailure(_))
-      .Times(1);
+  EXPECT_CALL(consumer, OnClientOAuthFailure(_)).Times(1);
 
-  net::TestURLFetcherFactory factory;
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
   auth.DeprecatedStartCookieForOAuthLoginTokenExchange(std::string());
 
   EXPECT_TRUE(auth.HasPendingFetch());
-  MockFetcher mock_fetcher(
-      client_login_to_oauth2_source_,
-      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0),
-      net::HTTP_FORBIDDEN,
-      std::string(),
-      net::URLFetcher::POST,
-      &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_FORBIDDEN);
+
   EXPECT_FALSE(auth.HasPendingFetch());
 }
 
 TEST_F(GaiaAuthFetcherTest, OAuthLoginTokenOAuth2TokenPairFailure) {
   MockGaiaConsumer consumer;
-  EXPECT_CALL(consumer, OnClientOAuthFailure(_))
-      .Times(1);
+  EXPECT_CALL(consumer, OnClientOAuthFailure(_)).Times(1);
 
   net::TestURLFetcherFactory factory;
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
   auth.DeprecatedStartCookieForOAuthLoginTokenExchange(std::string());
+  EXPECT_TRUE(auth.HasPendingFetch());
 
-  scoped_refptr<net::HttpResponseHeaders> reponse_headers =
-      new net::HttpResponseHeaders("");
-  reponse_headers->AddCookie(kGetAuthCodeValidCookie);
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK,
+                                     {kGetAuthCodeValidCookie});
+
   EXPECT_TRUE(auth.HasPendingFetch());
-  MockFetcher mock_fetcher1(
-      client_login_to_oauth2_source_,
-      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0),
-      net::HTTP_OK,
-      std::string(),
-      net::URLFetcher::POST,
-      &auth);
-  mock_fetcher1.set_response_headers(reponse_headers);
-  auth.OnURLFetchComplete(&mock_fetcher1);
-  EXPECT_TRUE(auth.HasPendingFetch());
-  MockFetcher mock_fetcher2(
-      oauth2_token_source_,
-      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0),
-      net::HTTP_FORBIDDEN,
-      std::string(),
-      net::URLFetcher::POST,
-      &auth);
-  auth.OnURLFetchComplete(&mock_fetcher2);
+
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_FORBIDDEN);
+
   EXPECT_FALSE(auth.HasPendingFetch());
 }
 
 TEST_F(GaiaAuthFetcherTest, MergeSessionSuccess) {
   MockGaiaConsumer consumer;
-  EXPECT_CALL(consumer, OnMergeSessionSuccess("<html></html>"))
-      .Times(1);
+  EXPECT_CALL(consumer, OnMergeSessionSuccess("<html></html>")).Times(1);
 
-  net::TestURLFetcherFactory factory;
-
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
   auth.StartMergeSession("myubertoken", std::string());
 
   EXPECT_TRUE(auth.HasPendingFetch());
-  MockFetcher mock_fetcher(
-      merge_session_source_,
-      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0), net::HTTP_OK,
-      "<html></html>", net::URLFetcher::GET, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
-  EXPECT_FALSE(auth.HasPendingFetch());
-}
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, {},
+                                     "<html></html>");
 
-TEST_F(GaiaAuthFetcherTest, MergeSessionSuccessRedirect) {
-  MockGaiaConsumer consumer;
-  EXPECT_CALL(consumer, OnMergeSessionSuccess("<html></html>"))
-      .Times(1);
-
-  net::TestURLFetcherFactory factory;
-
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  auth.StartMergeSession("myubertoken", std::string());
-
-  // Make sure the fetcher created has the expected flags.  Set its url()
-  // properties to reflect a redirect.
-  net::TestURLFetcher* test_fetcher = factory.GetFetcherByID(0);
-  EXPECT_TRUE(test_fetcher != NULL);
-  EXPECT_TRUE(test_fetcher->GetLoadFlags() == net::LOAD_NORMAL);
-  EXPECT_TRUE(auth.HasPendingFetch());
-
-  GURL final_url("http://www.google.com/CheckCookie");
-  test_fetcher->set_url(final_url);
-  test_fetcher->set_status(
-      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0));
-  test_fetcher->set_response_code(net::HTTP_OK);
-  test_fetcher->SetResponseString("<html></html>");
-
-  auth.OnURLFetchComplete(test_fetcher);
   EXPECT_FALSE(auth.HasPendingFetch());
 }
 
 TEST_F(GaiaAuthFetcherTest, UberAuthTokenSuccess) {
   MockGaiaConsumer consumer;
-  EXPECT_CALL(consumer, OnUberAuthTokenSuccess("uberToken"))
-      .Times(1);
+  EXPECT_CALL(consumer, OnUberAuthTokenSuccess("uberToken")).Times(1);
 
-  net::TestURLFetcherFactory factory;
-
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
   auth.StartTokenFetchForUberAuthExchange("myAccessToken",
                                           true /* is_bound_to_channel_id */);
 
   EXPECT_TRUE(auth.HasPendingFetch());
-  MockFetcher mock_fetcher(
-      uberauth_token_source_,
-      net::URLRequestStatus(net::URLRequestStatus::SUCCESS, 0), net::HTTP_OK,
-      "uberToken", net::URLFetcher::POST, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, {}, "uberToken");
+
   EXPECT_FALSE(auth.HasPendingFetch());
 }
 
@@ -581,45 +505,49 @@
   result.data = data;
 
   MockGaiaConsumer consumer;
-  EXPECT_CALL(consumer, OnClientLoginSuccess(result))
-      .Times(1);
+  EXPECT_CALL(consumer, OnClientLoginSuccess(result)).Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
-  MockFetcher mock_fetcher(oauth_login_gurl_, status, net::HTTP_OK, data,
-                           net::URLFetcher::GET, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+  auth.CreateAndStartGaiaFetcherForTesting(/*body=*/"", /*headers=*/"",
+                                           oauth_login_gurl_, /*load_flags=*/0,
+                                           NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, {}, data);
 }
 
 TEST_F(GaiaAuthFetcherTest, ListAccounts) {
-  std::string data("[\"gaia.l.a.r\", ["
-      "[\"gaia.l.a\", 1, \"First Last\", \"user@gmail.com\", "
-      "\"//googleusercontent.com/A/B/C/D/photo.jpg\", 1, 1, 0]]]");
+  std::string data(
+      R"(["gaia.l.a.r",
+           [
+             ["gaia.l.a", 1, "First Last", "user@gmail.com",
+              "//googleusercontent.com/A/B/C/D/photo.jpg", 1, 1, 0
+              ]
+           ]
+         ])");
   MockGaiaConsumer consumer;
   EXPECT_CALL(consumer, OnListAccountsSuccess(data)).Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
-  MockFetcher mock_fetcher(
-      GaiaUrls::GetInstance()->ListAccountsURLWithSource(std::string()), status,
-      net::HTTP_OK, data, net::URLFetcher::GET, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+  auth.CreateAndStartGaiaFetcherForTesting(
+      /*body=*/"", /*headers=*/"",
+      GaiaUrls::GetInstance()->ListAccountsURLWithSource(std::string()),
+      /*load_flags=*/0, NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, {}, data);
 }
 
 TEST_F(GaiaAuthFetcherTest, LogOutSuccess) {
   MockGaiaConsumer consumer;
   EXPECT_CALL(consumer, OnLogOutSuccess()).Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
-  MockFetcher mock_fetcher(
-      GaiaUrls::GetInstance()->LogOutURLWithSource(std::string()), status,
-      net::HTTP_OK, std::string(), net::URLFetcher::GET, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+  auth.CreateAndStartGaiaFetcherForTesting(
+      /*body=*/"", /*headers=*/"",
+      GaiaUrls::GetInstance()->LogOutURLWithSource(std::string()),
+      /*load_flags=*/0, NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(net::OK);
 }
 
 TEST_F(GaiaAuthFetcherTest, LogOutFailure) {
-  int error_no = net::ERR_CONNECTION_RESET;
+  net::Error error_no = net::ERR_CONNECTION_RESET;
   net::URLRequestStatus status(net::URLRequestStatus::FAILED, error_no);
 
   GoogleServiceAuthError expected_error =
@@ -627,27 +555,28 @@
   MockGaiaConsumer consumer;
   EXPECT_CALL(consumer, OnLogOutFailure(expected_error)).Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-
-  MockFetcher mock_fetcher(
-      GaiaUrls::GetInstance()->LogOutURLWithSource(std::string()), status, 0,
-      std::string(), net::URLFetcher::GET, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+  auth.CreateAndStartGaiaFetcherForTesting(
+      /*body=*/"", /*headers=*/"",
+      GaiaUrls::GetInstance()->LogOutURLWithSource(std::string()),
+      /*load_flags=*/0, NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(error_no);
 }
 
 TEST_F(GaiaAuthFetcherTest, GetCheckConnectionInfo) {
-  std::string data(
-      "[{\"carryBackToken\": \"token1\", \"url\": \"http://www.google.com\"}]");
+  std::string data(R"(
+      [{"carryBackToken": "token1", "url": "http://www.google.com"}])");
   MockGaiaConsumer consumer;
   EXPECT_CALL(consumer, OnGetCheckConnectionInfoSuccess(data)).Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
-  MockFetcher mock_fetcher(
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+
+  auth.CreateAndStartGaiaFetcherForTesting(
+      /*body=*/"", /*headers=*/"",
       GaiaUrls::GetInstance()->GetCheckConnectionInfoURLWithSource(
           std::string()),
-      status, net::HTTP_OK, data, net::URLFetcher::GET, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+      /*load_flags=*/0, NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, {}, data);
 }
 
 TEST_F(GaiaAuthFetcherTest, RevokeOAuth2TokenSuccess) {
@@ -657,11 +586,11 @@
                             GaiaAuthConsumer::TokenRevocationStatus::kSuccess))
       .Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
-  MockFetcher mock_fetcher(GaiaUrls::GetInstance()->oauth2_revoke_url(), status,
-                           net::HTTP_OK, data, net::URLFetcher::GET, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+  auth.CreateAndStartGaiaFetcherForTesting(
+      /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->oauth2_revoke_url(),
+      /*load_flags=*/0, NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_OK, {}, data);
 }
 
 TEST_F(GaiaAuthFetcherTest, RevokeOAuth2TokenCanceled) {
@@ -671,12 +600,11 @@
                   GaiaAuthConsumer::TokenRevocationStatus::kConnectionCanceled))
       .Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  net::URLRequestStatus status(net::URLRequestStatus::CANCELED,
-                               net::ERR_ABORTED);
-  MockFetcher mock_fetcher(GaiaUrls::GetInstance()->oauth2_revoke_url(), status,
-                           0, std::string(), net::URLFetcher::GET, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+  auth.CreateAndStartGaiaFetcherForTesting(
+      /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->oauth2_revoke_url(),
+      /*load_flags=*/0, NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(net::ERR_ABORTED);
 }
 
 TEST_F(GaiaAuthFetcherTest, RevokeOAuth2TokenFailed) {
@@ -686,12 +614,11 @@
                   GaiaAuthConsumer::TokenRevocationStatus::kConnectionFailed))
       .Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  int error_no = net::ERR_CERT_CONTAINS_ERRORS;
-  net::URLRequestStatus status(net::URLRequestStatus::FAILED, error_no);
-  MockFetcher mock_fetcher(GaiaUrls::GetInstance()->oauth2_revoke_url(), status,
-                           0, std::string(), net::URLFetcher::GET, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+  auth.CreateAndStartGaiaFetcherForTesting(
+      /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->oauth2_revoke_url(),
+      /*load_flags=*/0, NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(net::ERR_CERT_CONTAINS_ERRORS);
 }
 
 TEST_F(GaiaAuthFetcherTest, RevokeOAuth2TokenTimeout) {
@@ -701,12 +628,11 @@
                   GaiaAuthConsumer::TokenRevocationStatus::kConnectionTimeout))
       .Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  int error_no = net::ERR_TIMED_OUT;
-  net::URLRequestStatus status(net::URLRequestStatus::FAILED, error_no);
-  MockFetcher mock_fetcher(GaiaUrls::GetInstance()->oauth2_revoke_url(), status,
-                           0, std::string(), net::URLFetcher::GET, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+  auth.CreateAndStartGaiaFetcherForTesting(
+      /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->oauth2_revoke_url(),
+      /*load_flags=*/0, NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(net::ERR_TIMED_OUT);
 }
 
 TEST_F(GaiaAuthFetcherTest, RevokeOAuth2TokenInvalidToken) {
@@ -717,12 +643,11 @@
                   GaiaAuthConsumer::TokenRevocationStatus::kInvalidToken))
       .Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
-  MockFetcher mock_fetcher(GaiaUrls::GetInstance()->oauth2_revoke_url(), status,
-                           net::HTTP_BAD_REQUEST, data, net::URLFetcher::GET,
-                           &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+  auth.CreateAndStartGaiaFetcherForTesting(
+      /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->oauth2_revoke_url(),
+      /*load_flags=*/0, NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_BAD_REQUEST, {}, data);
 }
 
 TEST_F(GaiaAuthFetcherTest, RevokeOAuth2TokenInvalidRequest) {
@@ -733,12 +658,11 @@
                   GaiaAuthConsumer::TokenRevocationStatus::kInvalidRequest))
       .Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
-  MockFetcher mock_fetcher(GaiaUrls::GetInstance()->oauth2_revoke_url(), status,
-                           net::HTTP_BAD_REQUEST, data, net::URLFetcher::GET,
-                           &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+  auth.CreateAndStartGaiaFetcherForTesting(
+      /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->oauth2_revoke_url(),
+      /*load_flags=*/0, NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_BAD_REQUEST, {}, data);
 }
 
 TEST_F(GaiaAuthFetcherTest, RevokeOAuth2TokenServerError) {
@@ -749,10 +673,10 @@
                   GaiaAuthConsumer::TokenRevocationStatus::kServerError))
       .Times(1);
 
-  GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext());
-  net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0);
-  MockFetcher mock_fetcher(GaiaUrls::GetInstance()->oauth2_revoke_url(), status,
-                           net::HTTP_INTERNAL_SERVER_ERROR, data,
-                           net::URLFetcher::GET, &auth);
-  auth.OnURLFetchComplete(&mock_fetcher);
+  TestGaiaAuthFetcher auth(&consumer, std::string(), GetURLLoaderFactory());
+  auth.CreateAndStartGaiaFetcherForTesting(
+      /*body=*/"", /*headers=*/"", GaiaUrls::GetInstance()->oauth2_revoke_url(),
+      /*load_flags=*/0, NO_TRAFFIC_ANNOTATION_YET);
+  auth.TestOnURLLoadCompleteInternal(net::OK, net::HTTP_INTERNAL_SERVER_ERROR,
+                                     {}, data);
 }
diff --git a/google_apis/gaia/oauth2_token_service.cc b/google_apis/gaia/oauth2_token_service.cc
index 8b50814..de30c1a5 100644
--- a/google_apis/gaia/oauth2_token_service.cc
+++ b/google_apis/gaia/oauth2_token_service.cc
@@ -23,7 +23,6 @@
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
 #include "google_apis/gaia/oauth2_token_service_delegate.h"
-#include "net/url_request/url_request_context_getter.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 
 int OAuth2TokenService::max_fetch_retry_num_ = 5;
@@ -124,7 +123,6 @@
   static std::unique_ptr<OAuth2TokenService::Fetcher> CreateAndStart(
       OAuth2TokenService* oauth2_token_service,
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const std::string& client_id,
       const std::string& client_secret,
@@ -160,7 +158,6 @@
  private:
   Fetcher(OAuth2TokenService* oauth2_token_service,
           const std::string& account_id,
-          net::URLRequestContextGetter* getter,
           scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
           const std::string& client_id,
           const std::string& client_secret,
@@ -177,7 +174,6 @@
   // scheduled for deletion at the end of OnGetTokenFailure/OnGetTokenSuccess
   // (whichever comes first).
   OAuth2TokenService* const oauth2_token_service_;
-  scoped_refptr<net::URLRequestContextGetter> getter_;
   scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   const std::string account_id_;
   const ScopeSet scopes_;
@@ -206,14 +202,13 @@
 OAuth2TokenService::Fetcher::CreateAndStart(
     OAuth2TokenService* oauth2_token_service,
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::string& client_id,
     const std::string& client_secret,
     const OAuth2TokenService::ScopeSet& scopes,
     base::WeakPtr<RequestImpl> waiting_request) {
   std::unique_ptr<OAuth2TokenService::Fetcher> fetcher = base::WrapUnique(
-      new Fetcher(oauth2_token_service, account_id, getter, url_loader_factory,
+      new Fetcher(oauth2_token_service, account_id, url_loader_factory,
                   client_id, client_secret, scopes, waiting_request));
 
   fetcher->Start();
@@ -223,14 +218,12 @@
 OAuth2TokenService::Fetcher::Fetcher(
     OAuth2TokenService* oauth2_token_service,
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::string& client_id,
     const std::string& client_secret,
     const OAuth2TokenService::ScopeSet& scopes,
     base::WeakPtr<RequestImpl> waiting_request)
     : oauth2_token_service_(oauth2_token_service),
-      getter_(getter),
       url_loader_factory_(url_loader_factory),
       account_id_(account_id),
       scopes_(scopes),
@@ -250,7 +243,7 @@
 
 void OAuth2TokenService::Fetcher::Start() {
   fetcher_.reset(oauth2_token_service_->CreateAccessTokenFetcher(
-      account_id_, getter_.get(), url_loader_factory_, this));
+      account_id_, url_loader_factory_, this));
   DCHECK(fetcher_);
 
   // Stop the timer before starting the fetch, as defense in depth against the
@@ -427,7 +420,7 @@
     const OAuth2TokenService::ScopeSet& scopes,
     OAuth2TokenService::Consumer* consumer) {
   return StartRequestForClientWithContext(
-      account_id, GetRequestContext(), delegate_->GetURLLoaderFactory(),
+      account_id, delegate_->GetURLLoaderFactory(),
       GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
       GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), scopes, consumer);
 }
@@ -439,24 +432,24 @@
     const std::string& client_secret,
     const OAuth2TokenService::ScopeSet& scopes,
     OAuth2TokenService::Consumer* consumer) {
-  return StartRequestForClientWithContext(
-      account_id, GetRequestContext(), delegate_->GetURLLoaderFactory(),
-      client_id, client_secret, scopes, consumer);
+  return StartRequestForClientWithContext(account_id, GetURLLoaderFactory(),
+                                          client_id, client_secret, scopes,
+                                          consumer);
 }
 
-net::URLRequestContextGetter* OAuth2TokenService::GetRequestContext() const {
-  return delegate_->GetRequestContext();
+scoped_refptr<network::SharedURLLoaderFactory>
+OAuth2TokenService::GetURLLoaderFactory() const {
+  return delegate_->GetURLLoaderFactory();
 }
 
 std::unique_ptr<OAuth2TokenService::Request>
 OAuth2TokenService::StartRequestWithContext(
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const ScopeSet& scopes,
     Consumer* consumer) {
   return StartRequestForClientWithContext(
-      account_id, getter, url_loader_factory,
+      account_id, url_loader_factory,
       GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
       GaiaUrls::GetInstance()->oauth2_chrome_client_secret(), scopes, consumer);
 }
@@ -464,7 +457,6 @@
 std::unique_ptr<OAuth2TokenService::Request>
 OAuth2TokenService::StartRequestForClientWithContext(
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::string& client_id,
     const std::string& client_secret,
@@ -499,8 +491,8 @@
     InformConsumerWithCacheEntry(cache_entry, request.get(),
                                  request_parameters);
   } else {
-    FetchOAuth2Token(request.get(), account_id, getter, url_loader_factory,
-                     client_id, client_secret, scopes);
+    FetchOAuth2Token(request.get(), account_id, url_loader_factory, client_id,
+                     client_secret, scopes);
   }
   return std::move(request);
 }
@@ -508,7 +500,6 @@
 void OAuth2TokenService::FetchOAuth2Token(
     RequestImpl* request,
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::string& client_id,
     const std::string& client_secret,
@@ -525,18 +516,17 @@
     return;
   }
 
-  pending_fetchers_[request_parameters] = Fetcher::CreateAndStart(
-      this, account_id, getter, url_loader_factory, client_id, client_secret,
-      scopes, request->AsWeakPtr());
+  pending_fetchers_[request_parameters] =
+      Fetcher::CreateAndStart(this, account_id, url_loader_factory, client_id,
+                              client_secret, scopes, request->AsWeakPtr());
 }
 
 OAuth2AccessTokenFetcher* OAuth2TokenService::CreateAccessTokenFetcher(
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     OAuth2AccessTokenConsumer* consumer) {
-  return delegate_->CreateAccessTokenFetcher(account_id, getter,
-                                             url_loader_factory, consumer);
+  return delegate_->CreateAccessTokenFetcher(account_id, url_loader_factory,
+                                             consumer);
 }
 
 void OAuth2TokenService::InformConsumerWithCacheEntry(
diff --git a/google_apis/gaia/oauth2_token_service.h b/google_apis/gaia/oauth2_token_service.h
index 4b8bc853..c1c31929 100644
--- a/google_apis/gaia/oauth2_token_service.h
+++ b/google_apis/gaia/oauth2_token_service.h
@@ -23,9 +23,10 @@
 #include "google_apis/gaia/oauth2_access_token_consumer.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
 
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
 }
+
 namespace network {
 class SharedURLLoaderFactory;
 }
@@ -178,12 +179,11 @@
       const ScopeSet& scopes,
       Consumer* consumer);
 
-  // This method does the same as |StartRequest| except it uses the request
-  // context given by |getter| instead of using the one returned by
-  // |GetRequestContext| implemented by derived classes.
+  // This method does the same as |StartRequest| except it uses the
+  // URLLoaderfactory given by |url_loader_factory| instead of using the one
+  // returned by |GetURLLoaderFactory| implemented by derived classes.
   std::unique_ptr<Request> StartRequestWithContext(
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const ScopeSet& scopes,
       Consumer* consumer);
@@ -295,7 +295,6 @@
   virtual void FetchOAuth2Token(
       RequestImpl* request,
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const std::string& client_id,
       const std::string& client_secret,
@@ -304,7 +303,6 @@
   // Create an access token fetcher for the given account id.
   OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       OAuth2AccessTokenConsumer* consumer);
 
@@ -338,9 +336,9 @@
     ScopeSet scopes;
   };
 
-  // Provide a request context used for fetching access tokens with the
+  // Provide a URLLoaderFactory used for fetching access tokens with the
   // |StartRequest| method.
-  net::URLRequestContextGetter* GetRequestContext() const;
+  scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() const;
 
   // Struct that contains the information of an OAuth2 access token.
   struct CacheEntry {
@@ -353,7 +351,6 @@
   // client app instead of using Chrome's default values.
   std::unique_ptr<Request> StartRequestForClientWithContext(
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const std::string& client_id,
       const std::string& client_secret,
diff --git a/google_apis/gaia/oauth2_token_service_delegate.cc b/google_apis/gaia/oauth2_token_service_delegate.cc
index aa0bce3c..9949802 100644
--- a/google_apis/gaia/oauth2_token_service_delegate.cc
+++ b/google_apis/gaia/oauth2_token_service_delegate.cc
@@ -97,11 +97,6 @@
     observer.OnAuthErrorChanged(account_id, error);
 }
 
-net::URLRequestContextGetter* OAuth2TokenServiceDelegate::GetRequestContext()
-    const {
-  return nullptr;
-}
-
 scoped_refptr<network::SharedURLLoaderFactory>
 OAuth2TokenServiceDelegate::GetURLLoaderFactory() const {
   return nullptr;
diff --git a/google_apis/gaia/oauth2_token_service_delegate.h b/google_apis/gaia/oauth2_token_service_delegate.h
index d3f51328..8e7f87e 100644
--- a/google_apis/gaia/oauth2_token_service_delegate.h
+++ b/google_apis/gaia/oauth2_token_service_delegate.h
@@ -12,9 +12,6 @@
 #include "google_apis/gaia/oauth2_token_service.h"
 #include "net/base/backoff_entry.h"
 
-namespace net {
-class URLRequestContextGetter;
-}
 namespace network {
 class SharedURLLoaderFactory;
 }
@@ -44,8 +41,7 @@
 
   virtual OAuth2AccessTokenFetcher* CreateAccessTokenFetcher(
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
-      scoped_refptr<network::SharedURLLoaderFactory> url_factory,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       OAuth2AccessTokenConsumer* consumer) = 0;
 
   virtual bool RefreshTokenIsAvailable(const std::string& account_id) const = 0;
@@ -67,7 +63,6 @@
   virtual void UpdateCredentials(const std::string& account_id,
                                  const std::string& refresh_token) {}
   virtual void RevokeCredentials(const std::string& account_id) {}
-  virtual net::URLRequestContextGetter* GetRequestContext() const;
   virtual scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory()
       const;
 
diff --git a/google_apis/gaia/oauth2_token_service_request_unittest.cc b/google_apis/gaia/oauth2_token_service_request_unittest.cc
index c49d30f0..f5cab901 100644
--- a/google_apis/gaia/oauth2_token_service_request_unittest.cc
+++ b/google_apis/gaia/oauth2_token_service_request_unittest.cc
@@ -90,7 +90,6 @@
   void FetchOAuth2Token(
       RequestImpl* request,
       const std::string& account_id,
-      net::URLRequestContextGetter* getter,
       scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       const std::string& client_id,
       const std::string& client_secret,
@@ -130,7 +129,6 @@
 void MockOAuth2TokenService::FetchOAuth2Token(
     RequestImpl* request,
     const std::string& account_id,
-    net::URLRequestContextGetter* getter,
     scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     const std::string& client_id,
     const std::string& client_secret,
diff --git a/google_apis/gaia/oauth2_token_service_unittest.cc b/google_apis/gaia/oauth2_token_service_unittest.cc
index 3a1a66a31..12da58b9 100644
--- a/google_apis/gaia/oauth2_token_service_unittest.cc
+++ b/google_apis/gaia/oauth2_token_service_unittest.cc
@@ -73,8 +73,7 @@
  public:
   void SetUp() override {
     mojo::core::Init();
-    auto delegate = std::make_unique<FakeOAuth2TokenServiceDelegate>(
-        new net::TestURLRequestContextGetter(message_loop_.task_runner()));
+    auto delegate = std::make_unique<FakeOAuth2TokenServiceDelegate>();
     test_url_loader_factory_ = delegate->test_url_loader_factory();
     oauth2_service_ =
         std::make_unique<TestOAuth2TokenService>(std::move(delegate));
@@ -362,6 +361,7 @@
   std::unique_ptr<OAuth2TokenService::Request> request2(
       oauth2_service_->StartRequest(account_id_, scopes1, &consumer2));
   base::RunLoop().RunUntilIdle();
+  ASSERT_EQ(2, test_url_loader_factory_->NumPending());
 
   network::URLLoaderCompletionStatus ok_status(net::OK);
   network::ResourceResponseHead response_head =
diff --git a/google_apis/gaia/ubertoken_fetcher.cc b/google_apis/gaia/ubertoken_fetcher.cc
index f9351ae..93c85c0 100644
--- a/google_apis/gaia/ubertoken_fetcher.cc
+++ b/google_apis/gaia/ubertoken_fetcher.cc
@@ -14,13 +14,15 @@
 #include "google_apis/gaia/gaia_constants.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_token_service.h"
+#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
 
 namespace {
 std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
     GaiaAuthConsumer* consumer,
     const std::string& source,
-    net::URLRequestContextGetter* request_context) {
-  return std::make_unique<GaiaAuthFetcher>(consumer, source, request_context);
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+  return std::make_unique<GaiaAuthFetcher>(consumer, source,
+                                           url_loader_factory);
 }
 }
 
@@ -30,32 +32,31 @@
     OAuth2TokenService* token_service,
     UbertokenConsumer* consumer,
     const std::string& source,
-    net::URLRequestContextGetter* request_context)
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
     : UbertokenFetcher(token_service,
                        consumer,
                        source,
-                       request_context,
-                       base::Bind(CreateGaiaAuthFetcher)) {
-}
+                       url_loader_factory,
+                       base::BindRepeating(CreateGaiaAuthFetcher)) {}
 
 UbertokenFetcher::UbertokenFetcher(
     OAuth2TokenService* token_service,
     UbertokenConsumer* consumer,
     const std::string& source,
-    net::URLRequestContextGetter* request_context,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     GaiaAuthFetcherFactory factory)
     : OAuth2TokenService::Consumer("uber_token_fetcher"),
       token_service_(token_service),
       consumer_(consumer),
       source_(source),
-      request_context_(request_context),
+      url_loader_factory_(url_loader_factory),
       is_bound_to_channel_id_(true),
       gaia_auth_fetcher_factory_(factory),
       retry_number_(0),
       second_access_token_request_(false) {
   DCHECK(token_service);
   DCHECK(consumer);
-  DCHECK(request_context);
+  DCHECK(url_loader_factory);
 }
 
 UbertokenFetcher::~UbertokenFetcher() {
@@ -151,7 +152,7 @@
 
 void UbertokenFetcher::ExchangeTokens() {
   gaia_auth_fetcher_ =
-      gaia_auth_fetcher_factory_.Run(this, source_, request_context_);
+      gaia_auth_fetcher_factory_.Run(this, source_, url_loader_factory_);
   gaia_auth_fetcher_->StartTokenFetchForUberAuthExchange(
       access_token_, is_bound_to_channel_id_);
 }
diff --git a/google_apis/gaia/ubertoken_fetcher.h b/google_apis/gaia/ubertoken_fetcher.h
index 70079af..1848ef8 100644
--- a/google_apis/gaia/ubertoken_fetcher.h
+++ b/google_apis/gaia/ubertoken_fetcher.h
@@ -24,14 +24,14 @@
 class GaiaAuthFetcher;
 class GoogleServiceAuthError;
 
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
 }
 
 using GaiaAuthFetcherFactory = base::Callback<std::unique_ptr<GaiaAuthFetcher>(
     GaiaAuthConsumer*,
     const std::string&,
-    net::URLRequestContextGetter*)>;
+    scoped_refptr<network::SharedURLLoaderFactory>)>;
 
 // Callback for the |UbertokenFetcher| class.
 class UbertokenConsumer {
@@ -49,15 +49,17 @@
   // Maximum number of retries to get the uber-auth token before giving up.
   static const int kMaxRetries;
 
-  UbertokenFetcher(OAuth2TokenService* token_service,
-                   UbertokenConsumer* consumer,
-                   const std::string& source,
-                   net::URLRequestContextGetter* request_context);
-  UbertokenFetcher(OAuth2TokenService* token_service,
-                   UbertokenConsumer* consumer,
-                   const std::string& source,
-                   net::URLRequestContextGetter* request_context,
-                   GaiaAuthFetcherFactory factory);
+  UbertokenFetcher(
+      OAuth2TokenService* token_service,
+      UbertokenConsumer* consumer,
+      const std::string& source,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
+  UbertokenFetcher(
+      OAuth2TokenService* token_service,
+      UbertokenConsumer* consumer,
+      const std::string& source,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      GaiaAuthFetcherFactory factory);
   ~UbertokenFetcher() override;
 
   void set_is_bound_to_channel_id(bool is_bound_to_channel_id) {
@@ -90,7 +92,7 @@
   OAuth2TokenService* token_service_;
   UbertokenConsumer* consumer_;
   std::string source_;
-  net::URLRequestContextGetter* request_context_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   bool is_bound_to_channel_id_;  // defaults to true
   GaiaAuthFetcherFactory gaia_auth_fetcher_factory_;
   std::unique_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
diff --git a/google_apis/gaia/ubertoken_fetcher_unittest.cc b/google_apis/gaia/ubertoken_fetcher_unittest.cc
index 137ddeff..867c108 100644
--- a/google_apis/gaia/ubertoken_fetcher_unittest.cc
+++ b/google_apis/gaia/ubertoken_fetcher_unittest.cc
@@ -7,12 +7,13 @@
 #include <memory>
 
 #include "base/memory/ref_counted.h"
-#include "base/message_loop/message_loop.h"
+#include "base/test/scoped_task_environment.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "google_apis/gaia/fake_oauth2_token_service.h"
 #include "google_apis/gaia/gaia_constants.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_test_util.h"
+#include "mojo/core/embedder/embedder.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -48,22 +49,28 @@
 
 class UbertokenFetcherTest : public testing::Test {
  public:
+  UbertokenFetcherTest()
+      : scoped_task_environment_(
+            base::test::ScopedTaskEnvironment::MainThreadType::UI),
+        test_shared_loader_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &url_loader_factory_)) {}
+
   void SetUp() override {
-    request_context_getter_ = new net::TestURLRequestContextGetter(
-        base::ThreadTaskRunnerHandle::Get());
-    fetcher_.reset(new UbertokenFetcher(&token_service_,
-                                        &consumer_,
-                                        GaiaConstants::kChromeSource,
-                                        request_context_getter_.get()));
+    mojo::core::Init();
+
+    fetcher_ = std::make_unique<UbertokenFetcher>(&token_service_, &consumer_,
+                                                  GaiaConstants::kChromeSource,
+                                                  test_shared_loader_factory_);
   }
 
   void TearDown() override { fetcher_.reset(); }
 
  protected:
-  base::MessageLoop message_loop_;
-  net::TestURLFetcherFactory factory_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
   FakeOAuth2TokenService token_service_;
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
+  network::TestURLLoaderFactory url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_;
   MockUbertokenConsumer consumer_;
   std::unique_ptr<UbertokenFetcher> fetcher_;
 };
diff --git a/google_apis/gcm/BUILD.gn b/google_apis/gcm/BUILD.gn
index 2b4edb15..97642da9 100644
--- a/google_apis/gcm/BUILD.gn
+++ b/google_apis/gcm/BUILD.gn
@@ -126,8 +126,12 @@
       ":test_support",
       "//base",
       "//build/win:default_exe_manifest",
+      "//mojo/core/embedder",
       "//net",
       "//net:test_support",
+      "//services/network:network_service",
+      "//services/network/public/cpp",
+      "//services/network/public/mojom",
       "//third_party/protobuf:protobuf_lite",
     ]
   }
diff --git a/google_apis/gcm/engine/checkin_request.cc b/google_apis/gcm/engine/checkin_request.cc
index cec5e84..17cc0dd 100644
--- a/google_apis/gcm/engine/checkin_request.cc
+++ b/google_apis/gcm/engine/checkin_request.cc
@@ -12,8 +12,9 @@
 #include "google_apis/gcm/protocol/checkin.pb.h"
 #include "net/base/load_flags.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_status.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 
 namespace gcm {
 
@@ -101,21 +102,20 @@
     const RequestInfo& request_info,
     const net::BackoffEntry::Policy& backoff_policy,
     const CheckinRequestCallback& callback,
-    net::URLRequestContextGetter* request_context_getter,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     GCMStatsRecorder* recorder)
-    : request_context_getter_(request_context_getter),
+    : url_loader_factory_(url_loader_factory),
       callback_(callback),
       backoff_entry_(&backoff_policy),
       checkin_url_(checkin_url),
       request_info_(request_info),
       recorder_(recorder),
-      weak_ptr_factory_(this) {
-}
+      weak_ptr_factory_(this) {}
 
 CheckinRequest::~CheckinRequest() {}
 
 void CheckinRequest::Start() {
-  DCHECK(!url_fetcher_.get());
+  DCHECK(!url_loader_.get());
 
   checkin_proto::AndroidCheckinRequest request;
   request.set_id(request_info_.android_id);
@@ -177,20 +177,27 @@
           policy_exception_justification:
             "Not implemented, considered not useful."
         })");
-  url_fetcher_ = net::URLFetcher::Create(checkin_url_, net::URLFetcher::POST,
-                                         this, traffic_annotation);
-  url_fetcher_->SetRequestContext(request_context_getter_);
-  url_fetcher_->SetUploadData(kRequestContentType, upload_data);
-  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
-                             net::LOAD_DO_NOT_SAVE_COOKIES);
+  auto resource_request = std::make_unique<network::ResourceRequest>();
+  resource_request->url = checkin_url_;
+  resource_request->method = "POST";
+  resource_request->load_flags =
+      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  url_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
+                                                 traffic_annotation);
+  url_loader_->AttachStringForUpload(upload_data, kRequestContentType);
+  url_loader_->SetAllowHttpErrorResults(true);
   recorder_->RecordCheckinInitiated(request_info_.android_id);
   request_start_time_ = base::TimeTicks::Now();
-  url_fetcher_->Start();
+
+  url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      url_loader_factory_.get(),
+      base::BindOnce(&CheckinRequest::OnURLLoadComplete, base::Unretained(this),
+                     url_loader_.get()));
 }
 
 void CheckinRequest::RetryWithBackoff() {
   backoff_entry_.InformOfRequest(false);
-  url_fetcher_.reset();
+  url_loader_.reset();
 
   DVLOG(1) << "Delay GCM checkin for: "
            << backoff_entry_.GetTimeUntilRelease().InMilliseconds()
@@ -204,10 +211,11 @@
       backoff_entry_.GetTimeUntilRelease());
 }
 
-void CheckinRequest::OnURLFetchComplete(const net::URLFetcher* source) {
-  std::string response_string;
+void CheckinRequest::OnURLLoadComplete(const network::SimpleURLLoader* source,
+                                       std::unique_ptr<std::string> body) {
   checkin_proto::AndroidCheckinResponse response_proto;
-  if (!source->GetStatus().is_success()) {
+  if (source->NetError() != net::OK || !source->ResponseInfo() ||
+      !source->ResponseInfo()->headers) {
     LOG(ERROR) << "Failed to get checkin response. Fetcher failed. Retrying.";
     RecordCheckinStatusAndReportUMA(URL_FETCHING_FAILED, recorder_, true);
     RetryWithBackoff();
@@ -215,7 +223,7 @@
   }
 
   net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>(
-      source->GetResponseCode());
+      source->ResponseInfo()->headers->response_code());
   if (response_status == net::HTTP_BAD_REQUEST ||
       response_status == net::HTTP_UNAUTHORIZED) {
     // BAD_REQUEST indicates that the request was malformed.
@@ -229,9 +237,8 @@
     return;
   }
 
-  if (response_status != net::HTTP_OK ||
-      !source->GetResponseAsString(&response_string) ||
-      !response_proto.ParseFromString(response_string)) {
+  if (response_status != net::HTTP_OK || !body ||
+      !response_proto.ParseFromString(*body)) {
     LOG(ERROR) << "Failed to get checkin response. HTTP Status: "
                << response_status << ". Retrying.";
     CheckinRequestStatus status = response_status != net::HTTP_OK ?
diff --git a/google_apis/gcm/engine/checkin_request.h b/google_apis/gcm/engine/checkin_request.h
index 96e861c..0a9e5d6 100644
--- a/google_apis/gcm/engine/checkin_request.h
+++ b/google_apis/gcm/engine/checkin_request.h
@@ -18,11 +18,11 @@
 #include "google_apis/gcm/protocol/checkin.pb.h"
 #include "net/base/backoff_entry.h"
 #include "net/http/http_status_code.h"
-#include "net/url_request/url_fetcher_delegate.h"
 #include "url/gurl.h"
 
-namespace net {
-class URLRequestContextGetter;
+namespace network {
+class SharedURLLoaderFactory;
+class SimpleURLLoader;
 }
 
 namespace gcm {
@@ -33,7 +33,7 @@
 // with android_id and security_token both set to 0 it is an initial check-in
 // used to obtain credentials. These should be persisted and used for subsequent
 // check-ins.
-class GCM_EXPORT CheckinRequest : public net::URLFetcherDelegate {
+class GCM_EXPORT CheckinRequest {
  public:
   // A callback function for the checkin request, accepting |checkin_response|
   // protobuf.
@@ -64,29 +64,31 @@
     checkin_proto::ChromeBuildProto chrome_build_proto;
   };
 
-  CheckinRequest(const GURL& checkin_url,
-                 const RequestInfo& request_info,
-                 const net::BackoffEntry::Policy& backoff_policy,
-                 const CheckinRequestCallback& callback,
-                 net::URLRequestContextGetter* request_context_getter,
-                 GCMStatsRecorder* recorder);
-  ~CheckinRequest() override;
+  CheckinRequest(
+      const GURL& checkin_url,
+      const RequestInfo& request_info,
+      const net::BackoffEntry::Policy& backoff_policy,
+      const CheckinRequestCallback& callback,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      GCMStatsRecorder* recorder);
+  ~CheckinRequest();
 
   void Start();
 
-  // URLFetcherDelegate implementation.
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
+  // Invoked from SimpleURLLoader.
+  void OnURLLoadComplete(const network::SimpleURLLoader* source,
+                         std::unique_ptr<std::string> body);
 
  private:
   // Schedules a retry attempt with a backoff.
   void RetryWithBackoff();
 
-  net::URLRequestContextGetter* request_context_getter_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
   CheckinRequestCallback callback_;
 
   net::BackoffEntry backoff_entry_;
   GURL checkin_url_;
-  std::unique_ptr<net::URLFetcher> url_fetcher_;
+  std::unique_ptr<network::SimpleURLLoader> url_loader_;
   const RequestInfo request_info_;
   base::TimeTicks request_start_time_;
 
diff --git a/google_apis/gcm/engine/checkin_request_unittest.cc b/google_apis/gcm/engine/checkin_request_unittest.cc
index 1d562b4..8eafbfab 100644
--- a/google_apis/gcm/engine/checkin_request_unittest.cc
+++ b/google_apis/gcm/engine/checkin_request_unittest.cc
@@ -10,6 +10,7 @@
 #include "google_apis/gcm/engine/gcm_request_test_base.h"
 #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
 #include "google_apis/gcm/protocol/checkin.pb.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace gcm {
 
@@ -41,7 +42,7 @@
 
   void CreateRequest(uint64_t android_id, uint64_t security_token);
 
-  void SetResponseScenario(ResponseScenario response_scenario);
+  void SetResponseScenarioAndComplete(ResponseScenario response_scenario);
 
  protected:
   bool callback_called_;
@@ -95,12 +96,9 @@
   // Then create a request with that protobuf and specified android_id,
   // security_token.
   request_.reset(new CheckinRequest(
-      GURL(kCheckinURL),
-      request_info,
-      GetBackoffPolicy(),
+      GURL(kCheckinURL), request_info, GetBackoffPolicy(),
       base::Bind(&CheckinRequestTest::FetcherCallback, base::Unretained(this)),
-      url_request_context_getter(),
-      &recorder_));
+      url_loader_factory(), &recorder_));
 
   // Setting android_id_ and security_token_ to blank value, not used elsewhere
   // in the tests.
@@ -109,7 +107,7 @@
   security_token_ = kBlankSecurityToken;
 }
 
-void CheckinRequestTest::SetResponseScenario(
+void CheckinRequestTest::SetResponseScenarioAndComplete(
     ResponseScenario response_scenario) {
   checkin_proto::AndroidCheckinResponse response;
   response.set_stats_ok(true);
@@ -127,7 +125,7 @@
 
   std::string response_string;
   response.SerializeToString(&response_string);
-  SetResponse(net::HTTP_OK, response_string);
+  SetResponseForURLAndComplete(kCheckinURL, net::HTTP_OK, response_string);
 }
 
 TEST_F(CheckinRequestTest, FetcherDataAndURL) {
@@ -135,12 +133,11 @@
   request_->Start();
 
   // Get data sent by request.
-  net::TestURLFetcher* fetcher = GetFetcher();
-  ASSERT_TRUE(fetcher);
-  EXPECT_EQ(GURL(kCheckinURL), fetcher->GetOriginalURL());
+  std::string upload_data;
+  ASSERT_TRUE(GetUploadDataForURL(kCheckinURL, &upload_data));
 
   checkin_proto::AndroidCheckinRequest request_proto;
-  request_proto.ParseFromString(fetcher->upload_data());
+  request_proto.ParseFromString(upload_data);
   EXPECT_EQ(kAndroidId, static_cast<uint64_t>(request_proto.id()));
   EXPECT_EQ(kSecurityToken, request_proto.security_token());
   EXPECT_EQ(chrome_build_proto_.platform(),
@@ -167,14 +164,10 @@
   CreateRequest(0u, 0u);
   request_->Start();
 
-  SetResponse(net::HTTP_OK, std::string());
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kCheckinURL, net::HTTP_OK, std::string());
   EXPECT_FALSE(callback_called_);
 
-  SetResponseScenario(VALID_RESPONSE);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(VALID_RESPONSE);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(net::HTTP_OK, response_code_);
   EXPECT_EQ(kAndroidId, android_id_);
@@ -185,14 +178,11 @@
   CreateRequest(0u, 0u);
   request_->Start();
 
-  SetResponse(net::HTTP_OK, "Corrupted response body");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kCheckinURL, net::HTTP_OK,
+                               "Corrupted response body");
   EXPECT_FALSE(callback_called_);
 
-  SetResponseScenario(VALID_RESPONSE);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(VALID_RESPONSE);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(net::HTTP_OK, response_code_);
   EXPECT_EQ(kAndroidId, android_id_);
@@ -203,9 +193,8 @@
   CreateRequest(0u, 0u);
   request_->Start();
 
-  SetResponse(net::HTTP_UNAUTHORIZED, std::string());
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kCheckinURL, net::HTTP_UNAUTHORIZED,
+                               std::string());
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(net::HTTP_UNAUTHORIZED, response_code_);
   EXPECT_EQ(kBlankAndroidId, android_id_);
@@ -216,9 +205,8 @@
   CreateRequest(0u, 0u);
   request_->Start();
 
-  SetResponse(net::HTTP_BAD_REQUEST, std::string());
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kCheckinURL, net::HTTP_BAD_REQUEST,
+                               std::string());
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(net::HTTP_BAD_REQUEST, response_code_);
   EXPECT_EQ(kBlankAndroidId, android_id_);
@@ -229,14 +217,11 @@
   CreateRequest(0u, 0u);
   request_->Start();
 
-  SetResponse(net::HTTP_INTERNAL_SERVER_ERROR, std::string());
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kCheckinURL, net::HTTP_INTERNAL_SERVER_ERROR,
+                               std::string());
   EXPECT_FALSE(callback_called_);
 
-  SetResponseScenario(VALID_RESPONSE);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(VALID_RESPONSE);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(net::HTTP_OK, response_code_);
   EXPECT_EQ(kAndroidId, android_id_);
@@ -247,14 +232,10 @@
   CreateRequest(0u, 0u);
   request_->Start();
 
-  SetResponseScenario(MISSING_ANDROID_ID);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(MISSING_ANDROID_ID);
   EXPECT_FALSE(callback_called_);
 
-  SetResponseScenario(VALID_RESPONSE);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(VALID_RESPONSE);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(kAndroidId, android_id_);
   EXPECT_EQ(kSecurityToken, security_token_);
@@ -264,14 +245,10 @@
   CreateRequest(0u, 0u);
   request_->Start();
 
-  SetResponseScenario(MISSING_SECURITY_TOKEN);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(MISSING_SECURITY_TOKEN);
   EXPECT_FALSE(callback_called_);
 
-  SetResponseScenario(VALID_RESPONSE);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(VALID_RESPONSE);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(kAndroidId, android_id_);
   EXPECT_EQ(kSecurityToken, security_token_);
@@ -281,14 +258,10 @@
   CreateRequest(0u, 0u);
   request_->Start();
 
-  SetResponseScenario(ANDROID_ID_IS_ZER0);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(ANDROID_ID_IS_ZER0);
   EXPECT_FALSE(callback_called_);
 
-  SetResponseScenario(VALID_RESPONSE);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(VALID_RESPONSE);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(kAndroidId, android_id_);
   EXPECT_EQ(kSecurityToken, security_token_);
@@ -298,14 +271,10 @@
   CreateRequest(0u, 0u);
   request_->Start();
 
-  SetResponseScenario(SECURITY_TOKEN_IS_ZERO);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(SECURITY_TOKEN_IS_ZERO);
   EXPECT_FALSE(callback_called_);
 
-  SetResponseScenario(VALID_RESPONSE);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(VALID_RESPONSE);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(kAndroidId, android_id_);
   EXPECT_EQ(kSecurityToken, security_token_);
@@ -315,9 +284,7 @@
   CreateRequest(0u, 0u);
   request_->Start();
 
-  SetResponseScenario(VALID_RESPONSE);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(VALID_RESPONSE);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(kAndroidId, android_id_);
   EXPECT_EQ(kSecurityToken, security_token_);
@@ -327,9 +294,7 @@
   CreateRequest(kAndroidId, kSecurityToken);
   request_->Start();
 
-  SetResponseScenario(VALID_RESPONSE);
-  CompleteFetch();
-
+  SetResponseScenarioAndComplete(VALID_RESPONSE);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(kAndroidId, android_id_);
   EXPECT_EQ(kSecurityToken, security_token_);
diff --git a/google_apis/gcm/engine/gcm_request_test_base.cc b/google_apis/gcm/engine/gcm_request_test_base.cc
index ccaf7edbc..7fdea06f 100644
--- a/google_apis/gcm/engine/gcm_request_test_base.cc
+++ b/google_apis/gcm/engine/gcm_request_test_base.cc
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "google_apis/gcm/engine/gcm_request_test_base.h"
+
 #include <cmath>
 
-#include "google_apis/gcm/engine/gcm_request_test_base.h"
-#include "net/url_request/url_fetcher_delegate.h"
+#include "base/strings/string_tokenizer.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "services/network/test/test_utils.h"
@@ -59,8 +60,6 @@
 GCMRequestTestBase::GCMRequestTestBase()
     : task_runner_(new base::TestMockTimeTaskRunner(
           base::TestMockTimeTaskRunner::Type::kBoundToThread)),
-      url_request_context_getter_(
-          new net::TestURLRequestContextGetter(task_runner_)),
       shared_factory_(
           base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
               &test_url_loader_factory_)),
@@ -73,46 +72,7 @@
   return kDefaultBackoffPolicy;
 }
 
-net::TestURLFetcher* GCMRequestTestBase::GetFetcher() const {
-  return url_fetcher_factory_.GetFetcherByID(0);
-}
-
-void GCMRequestTestBase::SetResponse(net::HttpStatusCode status_code,
-                                     const std::string& response_body) {
-  if (retry_count_++)
-    FastForwardToTriggerNextRetry();
-
-  net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher);
-  fetcher->set_response_code(status_code);
-  fetcher->SetResponseString(response_body);
-}
-
-void GCMRequestTestBase::CompleteFetch() {
-  net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher);
-  fetcher->delegate()->OnURLFetchComplete(fetcher);
-}
-
-void GCMRequestTestBase::VerifyFetcherUploadData(
-    std::map<std::string, std::string>* expected_pairs) {
-  net::TestURLFetcher* fetcher = url_fetcher_factory_.GetFetcherByID(0);
-  ASSERT_TRUE(fetcher);
-
-  // Verify data was formatted properly.
-  std::string upload_data = fetcher->upload_data();
-  base::StringTokenizer data_tokenizer(upload_data, "&=");
-  while (data_tokenizer.GetNext()) {
-    auto iter = expected_pairs->find(data_tokenizer.token());
-    ASSERT_TRUE(iter != expected_pairs->end()) << data_tokenizer.token();
-    ASSERT_TRUE(data_tokenizer.GetNext()) << data_tokenizer.token();
-    ASSERT_EQ(iter->second, data_tokenizer.token());
-    // Ensure that none of the keys appears twice.
-    expected_pairs->erase(iter);
-  }
-
-  ASSERT_EQ(0UL, expected_pairs->size());
-}
+void GCMRequestTestBase::OnAboutToCompleteFetch() {}
 
 void GCMRequestTestBase::SetResponseForURLAndComplete(
     const std::string& url,
@@ -122,6 +82,7 @@
   if (retry_count_++)
     FastForwardToTriggerNextRetry();
 
+  OnAboutToCompleteFetch();
   EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest(
       GURL(url), network::URLLoaderCompletionStatus(net_error_code),
       network::CreateResourceResponseHead(status_code), response_body));
diff --git a/google_apis/gcm/engine/gcm_request_test_base.h b/google_apis/gcm/engine/gcm_request_test_base.h
index 93f23f2b..bbfa99ff 100644
--- a/google_apis/gcm/engine/gcm_request_test_base.h
+++ b/google_apis/gcm/engine/gcm_request_test_base.h
@@ -10,8 +10,6 @@
 #include "base/test/test_mock_time_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "net/base/backoff_entry.h"
-#include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_request_test_util.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -29,30 +27,11 @@
   ~GCMRequestTestBase() override;
 
   const net::BackoffEntry::Policy& GetBackoffPolicy() const;
-  net::TestURLFetcher* GetFetcher() const;
 
-  // Set the response status and body that will be returned by the URL fetch.
-  void SetResponse(net::HttpStatusCode status_code,
-                   const std::string& response_body);
+  // Called before fetch about to be completed. Can be overridden by the test
+  // class to add additional logic.
+  virtual void OnAboutToCompleteFetch();
 
-  // Completes the URL fetch.
-  // It can be overridden by the test class to add additional logic.
-  virtual void CompleteFetch();
-
-  // Verifies that the Fetcher's upload_data exactly matches the given
-  // properties. The map will be cleared as a side-effect. Wrap calls to this
-  // with ASSERT_NO_FATAL_FAILURE.
-  void VerifyFetcherUploadData(
-      std::map<std::string, std::string>* expected_pairs);
-
-  net::URLRequestContextGetter* url_request_context_getter() const {
-    return url_request_context_getter_.get();
-  }
-
-  // The code is in transition away from URLRequestContextGetter +
-  // URLFetcherFactory to SharedURLLoaderFactory. For now, both are needed.
-  // Things that use url_loader_factory() will be matched with test APIs with
-  // "ForURL" in their names below.
   network::SharedURLLoaderFactory* url_loader_factory() const {
     return shared_factory_.get();
   }
@@ -84,9 +63,6 @@
 
   scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
 
-  scoped_refptr<net::TestURLRequestContextGetter> url_request_context_getter_;
-  net::TestURLFetcherFactory url_fetcher_factory_;
-
   network::TestURLLoaderFactory test_url_loader_factory_;
   scoped_refptr<network::SharedURLLoaderFactory> shared_factory_;
 
diff --git a/google_apis/gcm/engine/registration_request_unittest.cc b/google_apis/gcm/engine/registration_request_unittest.cc
index e85864a..e181bec 100644
--- a/google_apis/gcm/engine/registration_request_unittest.cc
+++ b/google_apis/gcm/engine/registration_request_unittest.cc
@@ -44,7 +44,7 @@
   void RegistrationCallback(RegistrationRequest::Status status,
                             const std::string& registration_id);
 
-  void CompleteFetch() override;
+  void OnAboutToCompleteFetch() override;
 
   void set_max_retry_count(int max_retry_count) {
     max_retry_count_ = max_retry_count;
@@ -75,12 +75,10 @@
   callback_called_ = true;
 }
 
-void RegistrationRequestTest::CompleteFetch() {
+void RegistrationRequestTest::OnAboutToCompleteFetch() {
   registration_id_.clear();
   status_ = RegistrationRequest::SUCCESS;
   callback_called_ = false;
-
-  GCMRequestTestBase::CompleteFetch();
 }
 
 class GCMRegistrationRequestTest : public RegistrationRequestTest {
diff --git a/google_apis/gcm/engine/unregistration_request.cc b/google_apis/gcm/engine/unregistration_request.cc
index 6522c00b..21a6dd7 100644
--- a/google_apis/gcm/engine/unregistration_request.cc
+++ b/google_apis/gcm/engine/unregistration_request.cc
@@ -19,9 +19,9 @@
 #include "net/http/http_request_headers.h"
 #include "net/http/http_status_code.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_fetcher.h"
-#include "net/url_request/url_request_context_getter.h"
-#include "net/url_request/url_request_status.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/simple_url_loader.h"
 
 namespace gcm {
 
@@ -107,7 +107,7 @@
     const net::BackoffEntry::Policy& backoff_policy,
     const UnregistrationCallback& callback,
     int max_retry_count,
-    scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
     GCMStatsRecorder* recorder,
     const std::string& source_to_record)
     : callback_(callback),
@@ -115,7 +115,7 @@
       custom_request_handler_(std::move(custom_request_handler)),
       registration_url_(registration_url),
       backoff_entry_(&backoff_policy),
-      request_context_getter_(request_context_getter),
+      url_loader_factory_(std::move(url_loader_factory)),
       retries_left_(max_retry_count),
       recorder_(recorder),
       source_to_record_(source_to_record),
@@ -127,7 +127,7 @@
 
 void UnregistrationRequest::Start() {
   DCHECK(!callback_.is_null());
-  DCHECK(!url_fetcher_.get());
+  DCHECK(!url_loader_.get());
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("gcm_unregistration", R"(
         semantics {
@@ -156,36 +156,38 @@
           policy_exception_justification:
             "Not implemented, considered not useful."
         })");
-  url_fetcher_ = net::URLFetcher::Create(
-      registration_url_, net::URLFetcher::POST, this, traffic_annotation);
-  url_fetcher_->SetRequestContext(request_context_getter_.get());
-  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
-                             net::LOAD_DO_NOT_SAVE_COOKIES);
 
-  std::string extra_headers;
-  BuildRequestHeaders(&extra_headers);
-  url_fetcher_->SetExtraRequestHeaders(extra_headers);
+  auto request = std::make_unique<network::ResourceRequest>();
+  request->url = registration_url_;
+  request->method = "POST";
+  request->load_flags =
+      net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES;
+  BuildRequestHeaders(&request->headers);
 
   std::string body;
   BuildRequestBody(&body);
 
   DVLOG(1) << "Unregistration request: " << body;
-  url_fetcher_->SetUploadData(kRequestContentType, body);
-
+  url_loader_ =
+      network::SimpleURLLoader::Create(std::move(request), traffic_annotation);
+  url_loader_->AttachStringForUpload(body, kRequestContentType);
   DVLOG(1) << "Performing unregistration for: " << request_info_.app_id();
   recorder_->RecordUnregistrationSent(request_info_.app_id(),
                                       source_to_record_);
   request_start_time_ = base::TimeTicks::Now();
-  url_fetcher_->Start();
+  url_loader_->SetAllowHttpErrorResults(true);
+  url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+      url_loader_factory_.get(),
+      base::BindOnce(&UnregistrationRequest::OnURLLoadComplete,
+                     base::Unretained(this), url_loader_.get()));
 }
 
-void UnregistrationRequest::BuildRequestHeaders(std::string* extra_headers) {
-  net::HttpRequestHeaders headers;
-  headers.SetHeader(net::HttpRequestHeaders::kAuthorization,
-                    std::string(kLoginHeader) + " " +
-                        base::NumberToString(request_info_.android_id) + ":" +
-                        base::NumberToString(request_info_.security_token));
-  *extra_headers = headers.ToString();
+void UnregistrationRequest::BuildRequestHeaders(
+    net::HttpRequestHeaders* headers) {
+  headers->SetHeader(net::HttpRequestHeaders::kAuthorization,
+                     std::string(kLoginHeader) + " " +
+                         base::NumberToString(request_info_.android_id) + ":" +
+                         base::NumberToString(request_info_.security_token));
 }
 
 void UnregistrationRequest::BuildRequestBody(std::string* body) {
@@ -202,17 +204,14 @@
 }
 
 UnregistrationRequest::Status UnregistrationRequest::ParseResponse(
-    const net::URLFetcher* source) {
-  if (!source->GetStatus().is_success()) {
+    const network::SimpleURLLoader* source,
+    std::unique_ptr<std::string> body) {
+  if (!body) {
     DVLOG(1) << "Unregistration URL fetching failed.";
     return URL_FETCHING_FAILED;
   }
 
-  std::string response;
-  if (!source->GetResponseAsString(&response)) {
-    DVLOG(1) << "Failed to get unregistration response body.";
-    return NO_RESPONSE_BODY;
-  }
+  std::string response = std::move(*body);
 
   // If we are able to parse a meaningful known error, let's do so. Note that
   // some errors will have HTTP_OK response code!
@@ -223,8 +222,14 @@
     return GetStatusFromError(error);
   }
 
+  // Can't even get any header info.
+  if (!source->ResponseInfo() || !source->ResponseInfo()->headers) {
+    DVLOG(1) << "Unregistration HTTP response info or header missing";
+    return HTTP_NOT_OK;
+  }
+
   net::HttpStatusCode response_status = static_cast<net::HttpStatusCode>(
-      source->GetResponseCode());
+      source->ResponseInfo()->headers->response_code());
   if (response_status != net::HTTP_OK) {
     DVLOG(1) << "Unregistration HTTP response code not OK: " << response_status;
     if (response_status == net::HTTP_SERVICE_UNAVAILABLE)
@@ -241,7 +246,7 @@
 void UnregistrationRequest::RetryWithBackoff() {
   DCHECK_GT(retries_left_, 0);
   --retries_left_;
-  url_fetcher_.reset();
+  url_loader_.reset();
   backoff_entry_.InformOfRequest(false);
 
   DVLOG(1) << "Delaying GCM unregistration of app: " << request_info_.app_id()
@@ -257,8 +262,10 @@
       backoff_entry_.GetTimeUntilRelease());
 }
 
-void UnregistrationRequest::OnURLFetchComplete(const net::URLFetcher* source) {
-  UnregistrationRequest::Status status = ParseResponse(source);
+void UnregistrationRequest::OnURLLoadComplete(
+    const network::SimpleURLLoader* source,
+    std::unique_ptr<std::string> body) {
+  UnregistrationRequest::Status status = ParseResponse(source, std::move(body));
 
   DVLOG(1) << "UnregistrationRequestStatus: " << status;
 
diff --git a/google_apis/gcm/engine/unregistration_request.h b/google_apis/gcm/engine/unregistration_request.h
index 1f1d47a2a..bc74ef76 100644
--- a/google_apis/gcm/engine/unregistration_request.h
+++ b/google_apis/gcm/engine/unregistration_request.h
@@ -16,11 +16,15 @@
 #include "base/time/time.h"
 #include "google_apis/gcm/base/gcm_export.h"
 #include "net/base/backoff_entry.h"
-#include "net/url_request/url_fetcher_delegate.h"
 #include "url/gurl.h"
 
 namespace net {
-class URLRequestContextGetter;
+class HttpRequestHeaders;
+}
+
+namespace network {
+class SharedURLLoaderFactory;
+class SimpleURLLoader;
 }
 
 namespace gcm {
@@ -31,7 +35,7 @@
 // and InstanceID delete-token requests. In case an attempt fails, it will retry
 // using the backoff policy.
 // TODO(fgorski): Consider sharing code with RegistrationRequest if possible.
-class GCM_EXPORT UnregistrationRequest : public net::URLFetcherDelegate {
+class GCM_EXPORT UnregistrationRequest {
  public:
   // Outcome of the response parsing. Note that these enums are consumed by a
   // histogram, so ordering should not be modified.
@@ -114,21 +118,23 @@
       const net::BackoffEntry::Policy& backoff_policy,
       const UnregistrationCallback& callback,
       int max_retry_count,
-      scoped_refptr<net::URLRequestContextGetter> request_context_getter,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
       GCMStatsRecorder* recorder,
       const std::string& source_to_record);
-  ~UnregistrationRequest() override;
+  ~UnregistrationRequest();
 
   // Starts an unregistration request.
   void Start();
 
  private:
-  // URLFetcherDelegate implementation.
-  void OnURLFetchComplete(const net::URLFetcher* source) override;
+  // Invoked from SimpleURLLoader.
+  void OnURLLoadComplete(const network::SimpleURLLoader* source,
+                         std::unique_ptr<std::string> body);
 
-  void BuildRequestHeaders(std::string* extra_headers);
+  void BuildRequestHeaders(net::HttpRequestHeaders* headers);
   void BuildRequestBody(std::string* body);
-  Status ParseResponse(const net::URLFetcher* source);
+  Status ParseResponse(const network::SimpleURLLoader* source,
+                       std::unique_ptr<std::string> body);
 
   // Schedules a retry attempt with a backoff.
   void RetryWithBackoff();
@@ -139,8 +145,8 @@
   GURL registration_url_;
 
   net::BackoffEntry backoff_entry_;
-  scoped_refptr<net::URLRequestContextGetter> request_context_getter_;
-  std::unique_ptr<net::URLFetcher> url_fetcher_;
+  scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
+  std::unique_ptr<network::SimpleURLLoader> url_loader_;
   base::TimeTicks request_start_time_;
   int retries_left_;
 
diff --git a/google_apis/gcm/engine/unregistration_request_unittest.cc b/google_apis/gcm/engine/unregistration_request_unittest.cc
index a8c18e7..e32b47c 100644
--- a/google_apis/gcm/engine/unregistration_request_unittest.cc
+++ b/google_apis/gcm/engine/unregistration_request_unittest.cc
@@ -15,6 +15,7 @@
 #include "google_apis/gcm/engine/instance_id_delete_token_request_handler.h"
 #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
 #include "net/base/load_flags.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 namespace gcm {
 
@@ -42,7 +43,7 @@
 
   void UnregistrationCallback(UnregistrationRequest::Status status);
 
-  void CompleteFetch() override;
+  void OnAboutToCompleteFetch() override;
 
   int max_retry_count() const { return max_retry_count_; }
   void set_max_retry_count(int max_retry_count) {
@@ -70,11 +71,9 @@
   status_ = status;
 }
 
-void UnregistrationRequestTest::CompleteFetch() {
+void UnregistrationRequestTest::OnAboutToCompleteFetch() {
   status_ = UnregistrationRequest::UNREGISTRATION_STATUS_COUNT;
   callback_called_ = false;
-
-  GCMRequestTestBase::CompleteFetch();
 }
 
 class GCMUnregistrationRequestTest : public UnregistrationRequestTest {
@@ -102,29 +101,25 @@
       GetBackoffPolicy(),
       base::Bind(&UnregistrationRequestTest::UnregistrationCallback,
                  base::Unretained(this)),
-      max_retry_count_, url_request_context_getter(), &recorder_,
-      std::string()));
+      max_retry_count_, url_loader_factory(), &recorder_, std::string()));
 }
 
 TEST_F(GCMUnregistrationRequestTest, RequestDataPassedToFetcher) {
   CreateRequest();
   request_->Start();
 
-  // Get data sent by request.
-  net::TestURLFetcher* fetcher = GetFetcher();
-  ASSERT_TRUE(fetcher);
-
-  EXPECT_EQ(GURL(kRegistrationURL), fetcher->GetOriginalURL());
-
-  int flags = fetcher->GetLoadFlags();
+  // Verify that the no-cookie flag is set.
+  int flags = 0;
+  ASSERT_TRUE(test_url_loader_factory()->IsPending(kRegistrationURL, &flags));
   EXPECT_TRUE(flags & net::LOAD_DO_NOT_SEND_COOKIES);
   EXPECT_TRUE(flags & net::LOAD_DO_NOT_SAVE_COOKIES);
 
   // Verify that authorization header was put together properly.
-  net::HttpRequestHeaders headers;
-  fetcher->GetExtraRequestHeaders(&headers);
+  const net::HttpRequestHeaders* headers =
+      GetExtraHeadersForURL(kRegistrationURL);
+  ASSERT_TRUE(headers);
   std::string auth_header;
-  headers.GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header);
+  headers->GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header);
   base::StringTokenizer auth_tokenizer(auth_header, " :");
   ASSERT_TRUE(auth_tokenizer.GetNext());
   EXPECT_EQ(kLoginHeader, auth_tokenizer.token());
@@ -139,7 +134,8 @@
   expected_pairs["delete"] = "true";
   expected_pairs["gcm_unreg_caller"] = "false";
 
-  ASSERT_NO_FATAL_FAILURE(VerifyFetcherUploadData(&expected_pairs));
+  ASSERT_NO_FATAL_FAILURE(
+      VerifyFetcherUploadDataForURL(kRegistrationURL, &expected_pairs));
 }
 
 TEST_F(GCMUnregistrationRequestTest, SuccessfulUnregistration) {
@@ -147,9 +143,7 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_OK, kDeletedAppId);
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
 }
@@ -158,14 +152,10 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_UNAUTHORIZED, "");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_UNAUTHORIZED, "");
   EXPECT_FALSE(callback_called_);
 
-  SetResponse(net::HTTP_OK, kDeletedAppId);
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
 }
@@ -174,14 +164,10 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_OK, "");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "");
   EXPECT_FALSE(callback_called_);
 
-  SetResponse(net::HTTP_OK, kDeletedAppId);
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
 }
@@ -190,9 +176,8 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_OK, "Error=INVALID_PARAMETERS");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK,
+                               "Error=INVALID_PARAMETERS");
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::INVALID_PARAMETERS, status_);
 }
@@ -201,9 +186,8 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_OK, "Error=PHONE_REGISTRATION_ERROR");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK,
+                               "Error=PHONE_REGISTRATION_ERROR");
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::DEVICE_REGISTRATION_ERROR, status_);
 }
@@ -212,9 +196,7 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_OK, "Error=XXX");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "Error=XXX");
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::UNKNOWN_ERROR, status_);
 }
@@ -223,14 +205,11 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_SERVICE_UNAVAILABLE, "");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_SERVICE_UNAVAILABLE,
+                               "");
   EXPECT_FALSE(callback_called_);
 
-  SetResponse(net::HTTP_OK, kDeletedAppId);
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
 }
@@ -239,14 +218,11 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_INTERNAL_SERVER_ERROR, "");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL,
+                               net::HTTP_INTERNAL_SERVER_ERROR, "");
   EXPECT_FALSE(callback_called_);
 
-  SetResponse(net::HTTP_OK, kDeletedAppId);
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
 }
@@ -255,14 +231,11 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_OK, "deleted=OtherTestAppId");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK,
+                               "deleted=OtherTestAppId");
   EXPECT_FALSE(callback_called_);
 
-  SetResponse(net::HTTP_OK, kDeletedAppId);
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
 }
@@ -271,14 +244,11 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_OK, "some malformed response");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK,
+                               "some malformed response");
   EXPECT_FALSE(callback_called_);
 
-  SetResponse(net::HTTP_OK, kDeletedAppId);
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedAppId);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
 }
@@ -288,9 +258,8 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_GATEWAY_TIMEOUT, "bad response");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT,
+                               "bad response");
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::REACHED_MAX_RETRIES, status_);
 }
@@ -299,19 +268,16 @@
   CreateRequest();
   request_->Start();
 
-  SetResponse(net::HTTP_GATEWAY_TIMEOUT, "bad response");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT,
+                               "bad response");
   EXPECT_FALSE(callback_called_);
 
-  SetResponse(net::HTTP_GATEWAY_TIMEOUT, "bad response");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT,
+                               "bad response");
   EXPECT_FALSE(callback_called_);
 
-  SetResponse(net::HTTP_GATEWAY_TIMEOUT, "bad response");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_GATEWAY_TIMEOUT,
+                               "bad response");
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::REACHED_MAX_RETRIES, status_);
 }
@@ -350,25 +316,19 @@
       GetBackoffPolicy(),
       base::Bind(&UnregistrationRequestTest::UnregistrationCallback,
                  base::Unretained(this)),
-      max_retry_count(), url_request_context_getter(), &recorder_,
-      std::string()));
+      max_retry_count(), url_loader_factory(), &recorder_, std::string()));
 }
 
 TEST_F(InstaceIDDeleteTokenRequestTest, RequestDataPassedToFetcher) {
   CreateRequest(false /* use_subtype */, kInstanceId, kDeveloperId, kScope);
   request_->Start();
 
-  // Get data sent by request.
-  net::TestURLFetcher* fetcher = GetFetcher();
-  ASSERT_TRUE(fetcher);
-
-  EXPECT_EQ(GURL(kRegistrationURL), fetcher->GetOriginalURL());
-
   // Verify that authorization header was put together properly.
-  net::HttpRequestHeaders headers;
-  fetcher->GetExtraRequestHeaders(&headers);
+  const net::HttpRequestHeaders* headers =
+      GetExtraHeadersForURL(kRegistrationURL);
+  ASSERT_TRUE(headers);
   std::string auth_header;
-  headers.GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header);
+  headers->GetHeader(net::HttpRequestHeaders::kAuthorization, &auth_header);
   base::StringTokenizer auth_tokenizer(auth_header, " :");
   ASSERT_TRUE(auth_tokenizer.GetNext());
   EXPECT_EQ(kLoginHeader, auth_tokenizer.token());
@@ -387,17 +347,14 @@
   expected_pairs["scope"] = kScope;
   expected_pairs["X-scope"] = kScope;
 
-  ASSERT_NO_FATAL_FAILURE(VerifyFetcherUploadData(&expected_pairs));
+  ASSERT_NO_FATAL_FAILURE(
+      VerifyFetcherUploadDataForURL(kRegistrationURL, &expected_pairs));
 }
 
 TEST_F(InstaceIDDeleteTokenRequestTest, RequestDataWithSubtype) {
   CreateRequest(true /* use_subtype */, kInstanceId, kDeveloperId, kScope);
   request_->Start();
 
-  // Get data sent by request.
-  net::TestURLFetcher* fetcher = GetFetcher();
-  ASSERT_TRUE(fetcher);
-
   // Same as RequestDataPassedToFetcher except "app" and "X-subtype".
   std::map<std::string, std::string> expected_pairs;
   expected_pairs["gmsv"] = base::IntToString(kGCMVersion);
@@ -410,16 +367,15 @@
   expected_pairs["scope"] = kScope;
   expected_pairs["X-scope"] = kScope;
 
-  ASSERT_NO_FATAL_FAILURE(VerifyFetcherUploadData(&expected_pairs));
+  ASSERT_NO_FATAL_FAILURE(
+      VerifyFetcherUploadDataForURL(kRegistrationURL, &expected_pairs));
 }
 
 TEST_F(InstaceIDDeleteTokenRequestTest, SuccessfulUnregistration) {
   CreateRequest(false /* use_subtype */, kInstanceId, kDeveloperId, kScope);
   request_->Start();
 
-  SetResponse(net::HTTP_OK, kDeletedToken);
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedToken);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
 }
@@ -428,14 +384,10 @@
   CreateRequest(false /* use_subtype */, kInstanceId, kDeveloperId, kScope);
   request_->Start();
 
-  SetResponse(net::HTTP_UNAUTHORIZED, "");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_UNAUTHORIZED, "");
   EXPECT_FALSE(callback_called_);
 
-  SetResponse(net::HTTP_OK, kDeletedToken);
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, kDeletedToken);
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::SUCCESS, status_);
 }
@@ -444,9 +396,8 @@
   CreateRequest(false /* use_subtype */, kInstanceId, kDeveloperId, kScope);
   request_->Start();
 
-  SetResponse(net::HTTP_OK, "Error=INVALID_PARAMETERS");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK,
+                               "Error=INVALID_PARAMETERS");
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::INVALID_PARAMETERS, status_);
 }
@@ -455,9 +406,7 @@
   CreateRequest(false /* use_subtype */, kInstanceId, kDeveloperId, kScope);
   request_->Start();
 
-  SetResponse(net::HTTP_OK, "Error=XXX");
-  CompleteFetch();
-
+  SetResponseForURLAndComplete(kRegistrationURL, net::HTTP_OK, "Error=XXX");
   EXPECT_TRUE(callback_called_);
   EXPECT_EQ(UnregistrationRequest::UNKNOWN_ERROR, status_);
 }
diff --git a/google_apis/gcm/tools/DEPS b/google_apis/gcm/tools/DEPS
new file mode 100644
index 0000000..9243dcd6
--- /dev/null
+++ b/google_apis/gcm/tools/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+  "+mojo/core/embedder",
+]
diff --git a/google_apis/gcm/tools/mcs_probe.cc b/google_apis/gcm/tools/mcs_probe.cc
index dedbe02..61f9e0ae 100644
--- a/google_apis/gcm/tools/mcs_probe.cc
+++ b/google_apis/gcm/tools/mcs_probe.cc
@@ -39,6 +39,7 @@
 #include "google_apis/gcm/engine/gservices_settings.h"
 #include "google_apis/gcm/engine/mcs_client.h"
 #include "google_apis/gcm/monitoring/fake_gcm_stats_recorder.h"
+#include "mojo/core/embedder/embedder.h"
 #include "net/cert/cert_verifier.h"
 #include "net/cert/ct_policy_enforcer.h"
 #include "net/cert/multi_log_ct_verifier.h"
@@ -55,6 +56,11 @@
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/default_channel_id_store.h"
 #include "net/url_request/url_request_test_util.h"
+#include "services/network/network_context.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
 
 #if defined(OS_MACOSX)
 #include "base/mac/scoped_nsautorelease_pool.h"
@@ -260,6 +266,11 @@
 
   base::Thread file_thread_;
 
+  std::unique_ptr<network::NetworkContext> network_context_;
+  network::mojom::NetworkContextPtr network_context_pipe_;
+  network::mojom::URLLoaderFactoryPtr url_loader_factory_;
+  scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
+
   std::unique_ptr<base::RunLoop> run_loop_;
 };
 
@@ -385,6 +396,21 @@
   http_server_properties_ = std::make_unique<net::HttpServerPropertiesImpl>();
   proxy_resolution_service_ =
       net::ProxyResolutionService::CreateDirectWithNetLog(&net_log_);
+
+  // Wrap it up with network service APIs.
+  network_context_ = std::make_unique<network::NetworkContext>(
+      nullptr /* network_service */, mojo::MakeRequest(&network_context_pipe_),
+      url_request_context_getter_->GetURLRequestContext());
+  auto url_loader_factory_params =
+      network::mojom::URLLoaderFactoryParams::New();
+  url_loader_factory_params->process_id = network::mojom::kBrowserProcessId;
+  url_loader_factory_params->is_corb_enabled = false;
+  network_context_->CreateURLLoaderFactory(
+      mojo::MakeRequest(&url_loader_factory_),
+      std::move(url_loader_factory_params));
+  shared_url_loader_factory_ =
+      base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+          url_loader_factory_.get());
 }
 
 void MCSProbe::ErrorCallback() {
@@ -407,7 +433,7 @@
   checkin_request_ = std::make_unique<CheckinRequest>(
       GServicesSettings().GetCheckinURL(), request_info, kDefaultBackoffPolicy,
       base::Bind(&MCSProbe::OnCheckInCompleted, base::Unretained(this)),
-      url_request_context_getter_.get(), &recorder_);
+      shared_url_loader_factory_, &recorder_);
   checkin_request_->Start();
 }
 
@@ -450,6 +476,8 @@
   settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
   logging::InitLogging(settings);
 
+  mojo::core::Init();
+
   base::MessageLoopForIO message_loop;
   base::TaskScheduler::CreateAndStartWithDefaultParams("MCSProbe");
 
diff --git a/headless/lib/browser/headless_browser_context_impl.cc b/headless/lib/browser/headless_browser_context_impl.cc
index 55d6af0..9862f0f 100644
--- a/headless/lib/browser/headless_browser_context_impl.cc
+++ b/headless/lib/browser/headless_browser_context_impl.cc
@@ -75,7 +75,8 @@
     : browser_(browser),
       context_options_(std::move(context_options)),
       resource_context_(std::make_unique<HeadlessResourceContext>()),
-      permission_manager_(std::make_unique<HeadlessPermissionManager>(this)),
+      permission_controller_delegate_(
+          std::make_unique<HeadlessPermissionManager>(this)),
       net_log_(new net::NetLog()) {
   InitWhileIOAllowed();
 }
@@ -246,8 +247,9 @@
   return nullptr;
 }
 
-content::PermissionManager* HeadlessBrowserContextImpl::GetPermissionManager() {
-  return permission_manager_.get();
+content::PermissionControllerDelegate*
+HeadlessBrowserContextImpl::GetPermissionControllerDelegate() {
+  return permission_controller_delegate_.get();
 }
 
 content::BackgroundFetchDelegate*
diff --git a/headless/lib/browser/headless_browser_context_impl.h b/headless/lib/browser/headless_browser_context_impl.h
index b0d7f9c..3eb7684 100644
--- a/headless/lib/browser/headless_browser_context_impl.h
+++ b/headless/lib/browser/headless_browser_context_impl.h
@@ -72,7 +72,8 @@
   storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
   content::PushMessagingService* GetPushMessagingService() override;
   content::SSLHostStateDelegate* GetSSLHostStateDelegate() override;
-  content::PermissionManager* GetPermissionManager() override;
+  content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+      override;
   content::BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
   content::BackgroundSyncController* GetBackgroundSyncController() override;
   content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
@@ -142,7 +143,8 @@
   base::flat_map<int, base::UnguessableToken>
       frame_tree_node_id_to_devtools_frame_token_map_;
 
-  std::unique_ptr<content::PermissionManager> permission_manager_;
+  std::unique_ptr<content::PermissionControllerDelegate>
+      permission_controller_delegate_;
   std::unique_ptr<net::NetLog> net_log_;
 
   HeadlessNetworkConditions network_conditions_;
diff --git a/headless/lib/browser/headless_permission_manager.h b/headless/lib/browser/headless_permission_manager.h
index c53615dd..86488a0a 100644
--- a/headless/lib/browser/headless_permission_manager.h
+++ b/headless/lib/browser/headless_permission_manager.h
@@ -7,7 +7,7 @@
 
 #include "base/callback_forward.h"
 #include "base/macros.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 
 namespace content {
 class BrowserContext;
@@ -15,7 +15,7 @@
 
 namespace headless {
 
-class HeadlessPermissionManager : public content::PermissionManager {
+class HeadlessPermissionManager : public content::PermissionControllerDelegate {
  public:
   explicit HeadlessPermissionManager(content::BrowserContext* browser_context);
   ~HeadlessPermissionManager() override;
diff --git a/headless/lib/headless_browser_browsertest.cc b/headless/lib/headless_browser_browsertest.cc
index 6ab0f72..b808fd28 100644
--- a/headless/lib/headless_browser_browsertest.cc
+++ b/headless/lib/headless_browser_browsertest.cc
@@ -11,7 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
-#include "content/public/browser/permission_manager.h"
+#include "content/public/browser/permission_controller_delegate.h"
 #include "content/public/browser/permission_type.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_switches.h"
@@ -517,13 +517,13 @@
   HeadlessWebContentsImpl* web_contents =
       HeadlessWebContentsImpl::From(headless_web_contents);
 
-  content::PermissionManager* permission_manager =
-      web_contents->browser_context()->GetPermissionManager();
-  EXPECT_NE(nullptr, permission_manager);
+  content::PermissionControllerDelegate* permission_controller_delegate =
+      web_contents->browser_context()->GetPermissionControllerDelegate();
+  EXPECT_NE(nullptr, permission_controller_delegate);
 
   // Check that the permission manager returns ASK for a given permission type.
   EXPECT_EQ(blink::mojom::PermissionStatus::ASK,
-            permission_manager->GetPermissionStatus(
+            permission_controller_delegate->GetPermissionStatus(
                 content::PermissionType::NOTIFICATIONS, url, url));
 }
 
diff --git a/infra/config/global/cr-buildbucket-dev.cfg b/infra/config/global/cr-buildbucket-dev.cfg
index 115e4c7..44843552 100644
--- a/infra/config/global/cr-buildbucket-dev.cfg
+++ b/infra/config/global/cr-buildbucket-dev.cfg
@@ -159,7 +159,6 @@
     builders { mixins: "linux" name: "LUCI linux_nacl_sdk" }
     builders { mixins: "linux" name: "LUCI linux_nacl_sdk_build" }
     builders { mixins: "linux" name: "LUCI linux_optional_gpu_tests_rel" }
-    builders { mixins: "linux" name: "LUCI linux_site_isolation" }
     builders { mixins: "linux" name: "LUCI linux_upload_clang" }
 
     builders { mixins: "mac" name: "LUCI ios-device" }
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 235c4be..18e46b6 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -1592,11 +1592,6 @@
       mixins: "libfuzzer"
     }
     builders {
-      name: "Site Isolation Win"
-      dimensions: "os:Windows-10"
-      mixins: "fyi-ci"
-    }
-    builders {
       name: "Mac ASan 64 Builder"
       dimensions: "os:Mac-10.13"
       dimensions: "cores:"  # Swapping between 8 and 24
@@ -1761,11 +1756,6 @@
       mixins: "swarm-ci"
     }
     builders {
-      name: "Site Isolation Linux"
-      dimensions: "os:Ubuntu-14.04"
-      mixins: "fyi-ci"
-    }
-    builders {
       name: "Win ASan Release"
       dimensions: "os:Windows-10"
       mixins: "lkgr-ci"
@@ -2549,7 +2539,6 @@
       name: "linux_nacl_sdk_build"
     }
     builders { mixins: "linux-optional-gpu-try" name: "linux_optional_gpu_tests_rel" }
-    builders { mixins: "linux-try" name: "linux_site_isolation" }
     builders {
       mixins: "linux-try"
       mixins: "upload_clang"
diff --git a/infra/config/global/luci-milo-dev.cfg b/infra/config/global/luci-milo-dev.cfg
index c0b61ac..01ee6af 100644
--- a/infra/config/global/luci-milo-dev.cfg
+++ b/infra/config/global/luci-milo-dev.cfg
@@ -2106,14 +2106,6 @@
     category: "site_isolation"
   }
   builders: {
-    name: "buildbot/chromium.fyi/Site Isolation Linux"
-    category: "site_isolation"
-  }
-  builders: {
-    name: "buildbot/chromium.fyi/Site Isolation Win"
-    category: "site_isolation"
-  }
-  builders: {
     name: "buildbot/chromium.fyi/Linux Viz"
     category: "viz"
   }
@@ -3575,9 +3567,6 @@
     name: "buildbot/tryserver.chromium.linux/linux_optional_gpu_tests_rel"
   }
   builders: {
-    name: "buildbot/tryserver.chromium.linux/linux_site_isolation"
-  }
-  builders: {
     name: "buildbot/tryserver.chromium.linux/linux_upload_clang"
   }
   builders: {
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index e57a28e..9a0a13c 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -2332,14 +2332,6 @@
     category: "site_isolation"
   }
   builders {
-    name: "buildbucket/luci.chromium.ci/Site Isolation Linux"
-    category: "site_isolation"
-  }
-  builders {
-    name: "buildbucket/luci.chromium.ci/Site Isolation Win"
-    category: "site_isolation"
-  }
-  builders {
     name: "buildbucket/luci.chromium.ci/linux-annotator-rel"
     category: "network|traffic|annotations"
     short_name: "lnx"
@@ -2702,16 +2694,6 @@
     category: "site_isolation"
   }
   builders {
-    name: "buildbot/chromium.fyi/Site Isolation Linux"
-    name: "buildbucket/luci.chromium.ci/Site Isolation Linux"
-    category: "site_isolation"
-  }
-  builders {
-    name: "buildbot/chromium.fyi/Site Isolation Win"
-    name: "buildbucket/luci.chromium.ci/Site Isolation Win"
-    category: "site_isolation"
-  }
-  builders {
     name: "buildbot/chromium.fyi/linux-annotator-rel"
     name: "buildbucket/luci.chromium.ci/linux-annotator-rel"
     category: "network|traffic|annotations"
@@ -4094,9 +4076,6 @@
     name: "buildbucket/luci.chromium.try/linux_optional_gpu_tests_rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux_site_isolation"
-  }
-  builders {
     name: "buildbot/tryserver.chromium.linux/linux_upload_clang"
     name: "buildbucket/luci.chromium.try/linux_upload_clang"
   }
@@ -4758,9 +4737,6 @@
     name: "buildbucket/luci.chromium.try/linux_optional_gpu_tests_rel"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/linux_site_isolation"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux_upload_clang"
   }
   builders {
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index bbbc1881da..7adec62 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -181,8 +181,6 @@
   triggers: "Mojo Windows"
   triggers: "Optional Android Release (Nexus 5X)"
   triggers: "Site Isolation Android"
-  triggers: "Site Isolation Linux"
-  triggers: "Site Isolation Win"
   triggers: "TSAN Debug"
   triggers: "TSAN Release"
   triggers: "UBSan Release"
@@ -3158,26 +3156,6 @@
 }
 
 job {
-  id: "Site Isolation Linux"
-  acl_sets: "default"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "Site Isolation Linux"
-  }
-}
-
-job {
-  id: "Site Isolation Win"
-  acl_sets: "default"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "Site Isolation Win"
-  }
-}
-
-job {
   id: "TSAN Debug"
   acl_sets: "default"
   buildbucket: {
diff --git a/ios/build/bots/tests/uirefresh_unittests.json b/ios/build/bots/tests/uirefresh_unittests.json
index 5d10b2a..55f6d96a 100644
--- a/ios/build/bots/tests/uirefresh_unittests.json
+++ b/ios/build/bots/tests/uirefresh_unittests.json
@@ -6,9 +6,6 @@
   ],
   "tests": [
     {
-      "app": "ios_chrome_unittests"
-    },
-    {
       "app": "ios_net_unittests"
     },
     {
diff --git a/ios/chrome/app/strings/ios_strings.grd b/ios/chrome/app/strings/ios_strings.grd
index 2093899..db300b6c 100644
--- a/ios/chrome/app/strings/ios_strings.grd
+++ b/ios/chrome/app/strings/ios_strings.grd
@@ -534,7 +534,7 @@
       <message name="IDS_IOS_CONTENT_CONTEXT_COPYIMAGE" desc="The name of the Copy Image command in the content area context menu.">
         Copy Image
       </message>
-      <message name="IDS_IOS_CONTENT_CONTEXT_COPYING" desc="The title of the alert while the image to be copied is being downloaded.">
+      <message name="IDS_IOS_CONTENT_COPYIMAGE_ALERT_COPYING" desc="The title of the alert while the image to be copied is being downloaded.">
         Copying...
       </message>
       <message name="IDS_IOS_CONTENT_CONTEXT_OPEN" desc="The iOS menu item for opening a link. Shorter than the desktop version [Length: 25em] [iOS only]">
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios.h b/ios/chrome/browser/signin/gaia_auth_fetcher_ios.h
index 9afa58c..3716caad 100644
--- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios.h
+++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios.h
@@ -6,12 +6,22 @@
 #define IOS_CHROME_BROWSER_SIGNIN_GAIA_AUTH_FETCHER_IOS_H_
 
 #include <memory>
+#include <string>
 
 #include "base/macros.h"
 #include "google_apis/gaia/gaia_auth_fetcher.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 
 class GaiaAuthFetcherIOSBridge;
+class GURL;
+
+namespace net {
+class URLRequestStatus;
+}
+
+namespace network {
+class SharedURLLoaderFactory;
+}
 
 namespace web {
 class BrowserState;
@@ -37,10 +47,11 @@
   // used.
   static bool ShouldUseGaiaAuthFetcherIOS();
 
-  GaiaAuthFetcherIOS(GaiaAuthConsumer* consumer,
-                     const std::string& source,
-                     net::URLRequestContextGetter* getter,
-                     web::BrowserState* browser_state);
+  GaiaAuthFetcherIOS(
+      GaiaAuthConsumer* consumer,
+      const std::string& source,
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+      web::BrowserState* browser_state);
   ~GaiaAuthFetcherIOS() override;
 
   void CancelRequest() override;
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm b/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm
index d78181f3..d701444 100644
--- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm
+++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios.mm
@@ -20,6 +20,7 @@
 #include "net/base/net_errors.h"
 #include "net/http/http_request_headers.h"
 #include "net/url_request/url_request_status.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -150,7 +151,6 @@
 @implementation GaiaAuthFetcherNavigationDelegate {
   GaiaAuthFetcherIOSBridge* bridge_;  // weak
 }
-
 - (instancetype)initWithBridge:(GaiaAuthFetcherIOSBridge*)bridge {
   self = [super init];
   if (self) {
@@ -319,11 +319,12 @@
 
 #pragma mark - GaiaAuthFetcherIOS definition
 
-GaiaAuthFetcherIOS::GaiaAuthFetcherIOS(GaiaAuthConsumer* consumer,
-                                       const std::string& source,
-                                       net::URLRequestContextGetter* getter,
-                                       web::BrowserState* browser_state)
-    : GaiaAuthFetcher(consumer, source, getter),
+GaiaAuthFetcherIOS::GaiaAuthFetcherIOS(
+    GaiaAuthConsumer* consumer,
+    const std::string& source,
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
+    web::BrowserState* browser_state)
+    : GaiaAuthFetcher(consumer, source, url_loader_factory),
       bridge_(new GaiaAuthFetcherIOSBridge(this, browser_state)),
       browser_state_(browser_state) {}
 
@@ -373,7 +374,9 @@
   DVLOG(2) << "Response " << url.spec() << ", code = " << response_code << "\n";
   DVLOG(2) << "data: " << data << "\n";
   SetPendingFetch(false);
-  DispatchFetchedRequest(url, data, cookies, status, response_code);
+  DispatchFetchedRequest(url, data, cookies,
+                         static_cast<net::Error>(status.error()),
+                         response_code);
 }
 
 void GaiaAuthFetcherIOS::SetShouldUseGaiaAuthFetcherIOSForTesting(
diff --git a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_unittest.mm b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_unittest.mm
index d64643e..5f3d687 100644
--- a/ios/chrome/browser/signin/gaia_auth_fetcher_ios_unittest.mm
+++ b/ios/chrome/browser/signin/gaia_auth_fetcher_ios_unittest.mm
@@ -7,12 +7,16 @@
 #include <memory>
 
 #include "base/ios/ios_util.h"
+#include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/signin/gaia_auth_fetcher_ios_private.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
 #include "net/url_request/test_url_fetcher_factory.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/test/test_url_loader_factory.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -57,17 +61,22 @@
 // Tests fixture for GaiaAuthFetcherIOS
 class GaiaAuthFetcherIOSTest : public PlatformTest {
  protected:
-  GaiaAuthFetcherIOSTest() {
+  GaiaAuthFetcherIOSTest()
+      : test_shared_loader_factory_(
+            base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
+                &test_url_loader_factory_)) {
     browser_state_ = TestChromeBrowserState::Builder().Build();
 
     ActiveStateManager::FromBrowserState(browser_state())->SetActive(true);
     gaia_auth_fetcher_.reset(new GaiaAuthFetcherIOS(&consumer_, std::string(),
-                                                    nullptr, browser_state()));
+                                                    test_shared_loader_factory_,
+                                                    browser_state()));
     gaia_auth_fetcher_->bridge_.reset(new FakeGaiaAuthFetcherIOSBridge(
         gaia_auth_fetcher_.get(), browser_state()));
   }
 
   ~GaiaAuthFetcherIOSTest() override {
+    test_shared_loader_factory_->Detach();
     gaia_auth_fetcher_.reset();
     ActiveStateManager::FromBrowserState(browser_state())->SetActive(false);
   }
@@ -84,6 +93,9 @@
   // BrowserState, required for WKWebView creation.
   std::unique_ptr<ios::ChromeBrowserState> browser_state_;
   MockGaiaConsumer consumer_;
+  network::TestURLLoaderFactory test_url_loader_factory_;
+  scoped_refptr<network::WeakWrapperSharedURLLoaderFactory>
+      test_shared_loader_factory_;
   std::unique_ptr<GaiaAuthFetcherIOS> gaia_auth_fetcher_;
 };
 
@@ -146,13 +158,12 @@
       "[{\"carryBackToken\": \"token1\", \"url\": \"http://www.google.com\"}]");
   EXPECT_CALL(consumer_, OnGetCheckConnectionInfoSuccess(data)).Times(1);
 
-  // Set up the fake URL Fetcher.
-  std::unique_ptr<net::FakeURLFetcherFactory> fake_url_fetcher_factory(
-      new net::FakeURLFetcherFactory(new net::URLFetcherImplFactory()));
-  fake_url_fetcher_factory->SetFakeResponse(
-      GaiaUrls::GetInstance()->GetCheckConnectionInfoURLWithSource(
-          std::string()),
-      data, net::HTTP_OK, net::URLRequestStatus::SUCCESS);
+  // Set up the fake response.
+  test_url_loader_factory_.AddResponse(
+      GaiaUrls::GetInstance()
+          ->GetCheckConnectionInfoURLWithSource(std::string())
+          .spec(),
+      data);
 
   gaia_auth_fetcher_->StartGetCheckConnectionInfo();
   base::RunLoop().RunUntilIdle();
diff --git a/ios/chrome/browser/signin/ios_chrome_signin_client.h b/ios/chrome/browser/signin/ios_chrome_signin_client.h
index 7f2126c..e2a54c9cb 100644
--- a/ios/chrome/browser/signin/ios_chrome_signin_client.h
+++ b/ios/chrome/browser/signin/ios_chrome_signin_client.h
@@ -45,7 +45,8 @@
   std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
       GaiaAuthConsumer* consumer,
       const std::string& source,
-      net::URLRequestContextGetter* getter) override;
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+      override;
   void PreGaiaLogout(base::OnceClosure callback) override;
   scoped_refptr<TokenWebData> GetDatabase() override;
   PrefService* GetPrefs() override;
diff --git a/ios/chrome/browser/signin/ios_chrome_signin_client.mm b/ios/chrome/browser/signin/ios_chrome_signin_client.mm
index 45b0f41..e28c3a2 100644
--- a/ios/chrome/browser/signin/ios_chrome_signin_client.mm
+++ b/ios/chrome/browser/signin/ios_chrome_signin_client.mm
@@ -155,9 +155,9 @@
 std::unique_ptr<GaiaAuthFetcher> IOSChromeSigninClient::CreateGaiaAuthFetcher(
     GaiaAuthConsumer* consumer,
     const std::string& source,
-    net::URLRequestContextGetter* getter) {
-  return std::make_unique<GaiaAuthFetcherIOS>(consumer, source, getter,
-                                              browser_state_);
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+  return std::make_unique<GaiaAuthFetcherIOS>(
+      consumer, source, url_loader_factory, browser_state_);
 }
 
 void IOSChromeSigninClient::PreGaiaLogout(base::OnceClosure callback) {
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index ce28346..b8419b3 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -3795,11 +3795,11 @@
               referrer:(const web::Referrer&)referrer {
   DCHECK(url.is_valid());
 
-  ImageCopierSessionId context_id = [self.imageCopier beginSession];
+  ImageCopierSessionID sessionID = [self.imageCopier beginSession];
 
   image_fetcher::ImageDataFetcherBlock callback =
       ^(NSData* data, const image_fetcher::RequestMetadata& metadata) {
-        [self.imageCopier endSession:context_id withImageData:data];
+        [self.imageCopier endSession:sessionID withImageData:data];
       };
   _imageFetcher->FetchImageDataWebpDecoded(
       url, callback, web::ReferrerHeaderValueForNavigation(url, referrer),
diff --git a/ios/chrome/browser/ui/image_util/BUILD.gn b/ios/chrome/browser/ui/image_util/BUILD.gn
index 6a74bba..2bb523e 100644
--- a/ios/chrome/browser/ui/image_util/BUILD.gn
+++ b/ios/chrome/browser/ui/image_util/BUILD.gn
@@ -18,7 +18,7 @@
     "//components/strings",
     "//ios/chrome/app/strings",
     "//ios/chrome/browser/ui/alert_coordinator",
-    "//ios/chrome/browser/ui/alert_coordinator:alert_coordinator_internal",
+    "//ios/web",
     "//net",
     "//ui/base",
   ]
diff --git a/ios/chrome/browser/ui/image_util/image_copier.h b/ios/chrome/browser/ui/image_util/image_copier.h
index 03274e6f..e0117b65 100644
--- a/ios/chrome/browser/ui/image_util/image_copier.h
+++ b/ios/chrome/browser/ui/image_util/image_copier.h
@@ -9,7 +9,7 @@
 
 #include "components/image_fetcher/core/request_metadata.h"
 
-typedef int64_t ImageCopierSessionId;
+typedef int64_t ImageCopierSessionID;
 
 // Object copying images to the system's pasteboard.
 // TODO(crbug.com/163201): Current implementation won't terminate the
@@ -23,13 +23,19 @@
 - (instancetype)initWithBaseViewController:
     (UIViewController*)baseViewController;
 
-// Begins a session of downloading image, and returns an identifier for this
-// session.
-- (ImageCopierSessionId)beginSession;
+// When user taps "Copy Image", downloader should call |beginSession| and get
+// an ID for the session. That ID will also be recorded by ImageCopier, and may
+// get erased if user cancels the copy, or overridden if user starts another
+// copy. When download is finished, downloader should call
+// |endSession:withImageData:| with that ID, and ImageCopier will compare this
+// ID with its internal ID to decide whether to paste or discard the image data.
 
-// Ends the downloading session. The image data won't be copied if the user has
+// Begin the download session, and return an ID for this session.
+- (ImageCopierSessionID)beginSession;
+
+// End the download session. The image data won't be copied if the user has
 // canceled copying.
-- (void)endSession:(ImageCopierSessionId)image_id withImageData:(NSData*)data;
+- (void)endSession:(ImageCopierSessionID)sessionID withImageData:(NSData*)data;
 
 @end
 
diff --git a/ios/chrome/browser/ui/image_util/image_copier.mm b/ios/chrome/browser/ui/image_util/image_copier.mm
index b3a67cb..a3ae0ab 100644
--- a/ios/chrome/browser/ui/image_util/image_copier.mm
+++ b/ios/chrome/browser/ui/image_util/image_copier.mm
@@ -5,87 +5,100 @@
 #import "image_copier.h"
 
 #include "base/task_scheduler/post_task.h"
-#import "ios/chrome/browser/ui/alert_coordinator/loading_alert_coordinator.h"
+#include "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
 #include "ios/chrome/grit/ios_strings.h"
+#include "ios/web/public/web_thread.h"
 #include "ui/base/l10n/l10n_util.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
+namespace {
+
 // Time Period between "Copy Image" is clicked and "Copying..." alert is
 // launched.
-static const int IMAGE_COPIER_ALERT_DELAY_MS = 300;
+const int kAlertDelayInMs = 300;
 // A unique id indicates that last session is finished or canceled and next
 // session has not started.
-static const ImageCopierSessionId ImageCopierNoSession = -1;
+const ImageCopierSessionID ImageCopierNoSession = -1;
+}
 
 @interface ImageCopier ()
 // Base view controller for the alerts.
 @property(nonatomic, weak) UIViewController* baseViewController;
 // Alert coordinator to give feedback to the user.
-@property(nonatomic, strong) LoadingAlertCoordinator* alertCoordinator;
+@property(nonatomic, strong) AlertCoordinator* alertCoordinator;
+// ID of current copying session.
+@property(nonatomic) ImageCopierSessionID currentSessionID;
 @end
 
-@implementation ImageCopier {
-  ImageCopierSessionId current_session_id_;
-}
+@implementation ImageCopier
 
-@synthesize alertCoordinator = _loadingAlertCoordinator;
+@synthesize alertCoordinator = _alertCoordinator;
 @synthesize baseViewController = _baseViewController;
+@synthesize currentSessionID = _currentSessionID;
 
 - (instancetype)initWithBaseViewController:
     (UIViewController*)baseViewController {
   self = [super init];
   if (self) {
-    _baseViewController = baseViewController;
+    self.baseViewController = baseViewController;
   }
   return self;
 }
 
 // Use current timestamp as identifier for the session. The "Copying..." alert
-// will be launched after |IMAGE_COPIER_ALERT_DELAY_MS| so that user won't
-// notice a fast download.
-- (ImageCopierSessionId)beginSession {
+// will be launched after |kAlertDelayInMs| so that user won't notice a fast
+// download.
+- (ImageCopierSessionID)beginSession {
   // Dismiss current alert.
-  [_loadingAlertCoordinator stop];
+  [self.alertCoordinator stop];
 
-  self.alertCoordinator = [[LoadingAlertCoordinator alloc]
+  __weak ImageCopier* weakSelf = self;
+
+  self.alertCoordinator = [[AlertCoordinator alloc]
       initWithBaseViewController:self.baseViewController
                            title:l10n_util::GetNSStringWithFixup(
-                                     IDS_IOS_CONTENT_CONTEXT_COPYING)
-                   cancelHandler:^() {
-                     // Cancel current session and close the alert.
-                     current_session_id_ = ImageCopierNoSession;
-                     [_loadingAlertCoordinator stop];
-                   }];
+                                     IDS_IOS_CONTENT_COPYIMAGE_ALERT_COPYING)
+                         message:nil];
+  [self.alertCoordinator
+      addItemWithTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)
+                action:^() {
+                  // Cancel current session and close the alert.
+                  weakSelf.currentSessionID = ImageCopierNoSession;
+                  [weakSelf.alertCoordinator stop];
+                }
+                 style:UIAlertActionStyleCancel];
 
   double time = [NSDate timeIntervalSinceReferenceDate];
-  ImageCopierSessionId image_id = *(int64_t*)(&time);
-  current_session_id_ = image_id;
+  ImageCopierSessionID sessionID = *(int64_t*)(&time);
+  self.currentSessionID = sessionID;
 
   // Delay launching alert by |IMAGE_COPIER_ALERT_DELAY_MS|.
-  base::PostDelayedTask(
-      FROM_HERE, base::BindOnce(^{
+  web::WebThread::PostDelayedTask(
+      web::WebThread::UI, FROM_HERE, base::BindOnce(^{
         // Check that the session has not finished yet.
-        if (image_id == current_session_id_) {
-          [_loadingAlertCoordinator start];
+        if (sessionID == weakSelf.currentSessionID) {
+          [weakSelf.alertCoordinator start];
         }
       }),
-      base::TimeDelta::FromMilliseconds(IMAGE_COPIER_ALERT_DELAY_MS));
+      base::TimeDelta::FromMilliseconds(kAlertDelayInMs));
 
-  return image_id;
+  return sessionID;
 }
 
 // End the session. If the session is not canceled, paste the image data to
 // system's pasteboard.
-- (void)endSession:(ImageCopierSessionId)image_id withImageData:(NSData*)data {
+- (void)endSession:(ImageCopierSessionID)sessionID withImageData:(NSData*)data {
   // Check that the downloading session is not canceled.
-  if (image_id == current_session_id_ && data && data.length > 0) {
-    UIPasteboard* pasteBoard = [UIPasteboard generalPasteboard];
-    [pasteBoard setImage:[UIImage imageWithData:data]];
-    [_loadingAlertCoordinator stop];
-    current_session_id_ = ImageCopierNoSession;
+  if (sessionID == self.currentSessionID) {
+    if (data && data.length > 0) {
+      [UIPasteboard.generalPasteboard setImage:[UIImage imageWithData:data]];
+    }
+    self.currentSessionID = ImageCopierNoSession;
+    [self.alertCoordinator stop];
   }
 }
 
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
index 365b30c..529d7c5 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_view_ios.mm
@@ -934,9 +934,8 @@
     return GetIconForSecurityState(
         controller()->GetToolbarModel()->GetSecurityLevel(false));
   }
-
   return GetIconForAutocompleteMatchType(
-      model() ? model()->CurrentTextType()
+      model() ? model()->CurrentMatch(nullptr).type
               : AutocompleteMatchType::URL_WHAT_YOU_TYPED,
       /* is_starred */ false, /* is_incognito */ false);
 }
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
index 7e00b3b..147d8466 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
@@ -184,6 +184,11 @@
   self.tableView.estimatedSectionHeaderHeight = 56;
   self.tableView.allowsMultipleSelectionDuringEditing = YES;
   self.tableView.allowsMultipleSelection = YES;
+  // Add a tableFooterView in order to disable separators at the bottom of the
+  // tableView.
+  // TODO(crbug.com/863606): Remove this workaround when iOS10 is no longer
+  // supported, as it is not necessary in iOS 11.
+  self.tableView.tableFooterView = [[UIView alloc] init];
 
   // Add gesture recognizer for the context menu.
   UILongPressGestureRecognizer* longPressRecognizer =
diff --git a/ios/chrome/browser/ui/settings/autofill_profile_edit_collection_view_controller.mm b/ios/chrome/browser/ui/settings/autofill_profile_edit_collection_view_controller.mm
index 6d0ce88..73dbf7e 100644
--- a/ios/chrome/browser/ui/settings/autofill_profile_edit_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/autofill_profile_edit_collection_view_controller.mm
@@ -184,6 +184,7 @@
     const AutofillFieldDisplayInfo& field = kFieldsToDisplay[i];
     AutofillEditItem* item =
         [[AutofillEditItem alloc] initWithType:ItemTypeField];
+    item.cellStyle = CollectionViewCellStyle::kUIKit;
     item.textFieldName = l10n_util::GetNSString(field.displayStringID);
     item.textFieldValue = base::SysUTF16ToNSString(_autofillProfile.GetInfo(
         autofill::AutofillType(field.autofillType), locale));
diff --git a/ios/chrome/browser/ui/settings/cells/settings_detail_item.mm b/ios/chrome/browser/ui/settings/cells/settings_detail_item.mm
index b871cce1..8e4f013 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_detail_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_detail_item.mm
@@ -24,6 +24,9 @@
 // two labels.
 const CGFloat kHorizontalPadding = 16;
 
+// Padding used between the icon and the text labels.
+const CGFloat kIconTrailingPadding = 12;
+
 // Padding used on the top and bottom edges of the cell.
 const CGFloat kVerticalPadding = 16;
 
@@ -134,7 +137,7 @@
                        constant:kHorizontalPadding];
     _iconVisibleConstraint = [_labelContainerGuide.leadingAnchor
         constraintEqualToAnchor:_iconImageView.trailingAnchor
-                       constant:kHorizontalPadding];
+                       constant:kIconTrailingPadding];
 
     [NSLayoutConstraint activateConstraints:@[
       [_iconImageView.leadingAnchor
diff --git a/ios/chrome/browser/ui/settings/cells/settings_switch_item.mm b/ios/chrome/browser/ui/settings/cells/settings_switch_item.mm
index 12a1d53b..f133fe8 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_switch_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_switch_item.mm
@@ -22,6 +22,9 @@
 // Padding used on the leading and trailing edges of the cell.
 const CGFloat kHorizontalPadding = 16;
 
+// Padding used between the icon and the text labels.
+const CGFloat kIconTrailingPadding = 12;
+
 // Padding used on the top and bottom edges of the cell.
 const CGFloat kVerticalPadding = 16;
 
@@ -122,7 +125,7 @@
     // Set up the constraints assuming that the icon image is hidden..
     _iconVisibleConstraint = [_textLabel.leadingAnchor
         constraintEqualToAnchor:_iconImageView.trailingAnchor
-                       constant:kHorizontalPadding];
+                       constant:kIconTrailingPadding];
     _iconHiddenConstraint = [_textLabel.leadingAnchor
         constraintEqualToAnchor:self.contentView.leadingAnchor
                        constant:kHorizontalPadding];
diff --git a/ios/chrome/browser/ui/settings/cells/settings_text_item.mm b/ios/chrome/browser/ui/settings/cells/settings_text_item.mm
index dab8a0c3..a18b378e 100644
--- a/ios/chrome/browser/ui/settings/cells/settings_text_item.mm
+++ b/ios/chrome/browser/ui/settings/cells/settings_text_item.mm
@@ -90,7 +90,7 @@
 - (UIFont*)detailTextFont {
   if (!_detailTextFont) {
     if (experimental_flags::IsSettingsUIRebootEnabled()) {
-      _detailTextFont = [UIFont systemFontOfSize:kUIKitDetailFontSize];
+      _detailTextFont = [UIFont systemFontOfSize:kUIKitMultilineDetailFontSize];
     } else {
       _detailTextFont = [[MDCTypography fontLoader] regularFontOfSize:14];
     }
@@ -101,7 +101,7 @@
 - (UIColor*)detailTextColor {
   if (!_detailTextColor) {
     if (experimental_flags::IsSettingsUIRebootEnabled()) {
-      _detailTextColor = UIColorFromRGB(kUIKitDetailTextColor);
+      _detailTextColor = UIColorFromRGB(kUIKitMultilineDetailTextColor);
     } else {
       _detailTextColor = [[MDCPalette greyPalette] tint500];
     }
diff --git a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
index b24e5e7..2c8fb7ee 100644
--- a/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_collection_view_controller.mm
@@ -324,6 +324,16 @@
 
 #pragma mark View lifecycle
 
+- (void)viewDidLoad {
+  [super viewDidLoad];
+
+  // Change the separator inset from the settings default because this
+  // collectionview shows leading icons.
+  const CGFloat kSettingsSeparatorLeadingInset = 56;
+  self.styler.separatorInset =
+      UIEdgeInsetsMake(0, kSettingsSeparatorLeadingInset, 0, 0);
+}
+
 // TODO(crbug.com/661915): Refactor TemplateURLObserver and re-implement this so
 // it observes the default search engine name instead of reloading on
 // ViewWillAppear.
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
index ffa0a5a..3d0ebca9 100644
--- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -538,6 +538,13 @@
     appBarContainer.view.backgroundColor = [UIColor whiteColor];
     ConfigureAppBarWithCardStyle(appBarContainer.appBar);
 
+    // Override the header view's background color if the UIRefresh experiment
+    // is enabled.
+    if (experimental_flags::IsSettingsUIRebootEnabled()) {
+      appBarContainer.appBar.headerViewController.headerView.backgroundColor =
+          [UIColor groupTableViewBackgroundColor];
+    }
+
     // Register the app bar container and return it.
     [self registerAppBarContainer:appBarContainer];
     return appBarContainer;
diff --git a/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm b/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm
index d2a5427..aa30ee1 100644
--- a/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_root_collection_view_controller.mm
@@ -9,6 +9,7 @@
 
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #import "ios/chrome/browser/experimental_flags.h"
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/settings/bar_button_activity_indicator.h"
@@ -17,6 +18,7 @@
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
+#import "ios/third_party/material_components_ios/src/components/AppBar/src/MaterialAppBar.h"
 #import "ios/third_party/material_components_ios/src/components/Collections/src/MaterialCollections.h"
 #include "ui/base/l10n/l10n_util.h"
 
@@ -58,11 +60,13 @@
     self.collectionView.backgroundColor =
         [UIColor groupTableViewBackgroundColor];
     self.styler.cellStyle = MDCCollectionViewCellStyleGrouped;
-    self.styler.separatorInset = UIEdgeInsetsMake(0, 48, 0, 0);
+    self.styler.separatorColor = UIColorFromRGB(kUIKitSeparatorColor);
+    self.appBar.headerViewController.headerView.backgroundColor =
+        [UIColor groupTableViewBackgroundColor];
   } else {
     self.styler.cellStyle = MDCCollectionViewCellStyleCard;
-    self.styler.separatorInset = UIEdgeInsetsMake(0, 16, 0, 16);
   }
+  self.styler.separatorInset = UIEdgeInsetsMake(0, 16, 0, 16);
 }
 
 - (void)viewWillAppear:(BOOL)animated {
diff --git a/ios/chrome/browser/ui/settings/sync_create_passphrase_collection_view_controller.mm b/ios/chrome/browser/ui/settings/sync_create_passphrase_collection_view_controller.mm
index 2c9b083..6f729c6 100644
--- a/ios/chrome/browser/ui/settings/sync_create_passphrase_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/sync_create_passphrase_collection_view_controller.mm
@@ -10,6 +10,7 @@
 #import "base/mac/foundation_util.h"
 #include "base/strings/sys_string_conversions.h"
 #include "components/strings/grit/components_strings.h"
+#import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
 #import "ios/chrome/browser/ui/settings/cells/byo_textfield_item.h"
@@ -86,7 +87,9 @@
 - (CollectionViewItem*)confirmPassphraseItem {
   if (!confirmPassphrase_) {
     confirmPassphrase_ = [[UITextField alloc] init];
-    [confirmPassphrase_ setFont:[MDCTypography body1Font]];
+    if (!experimental_flags::IsSettingsUIRebootEnabled()) {
+      [confirmPassphrase_ setFont:[MDCTypography body1Font]];
+    }
     [confirmPassphrase_ setSecureTextEntry:YES];
     [confirmPassphrase_ setBackgroundColor:[UIColor clearColor]];
     [confirmPassphrase_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
diff --git a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm
index 6df3d50..5e1d5218 100644
--- a/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/sync_encryption_passphrase_collection_view_controller.mm
@@ -18,6 +18,7 @@
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
+#import "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #include "ios/chrome/browser/signin/profile_oauth2_token_service_factory.h"
@@ -25,6 +26,7 @@
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
+#import "ios/chrome/browser/ui/collection_view/cells/collection_view_cell_constants.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_footer_item.h"
 #import "ios/chrome/browser/ui/collection_view/cells/collection_view_item.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
@@ -237,7 +239,9 @@
     [self unregisterTextField:passphrase_];
   }
   passphrase_ = [[UITextField alloc] init];
-  [passphrase_ setFont:[MDCTypography body1Font]];
+  if (!experimental_flags::IsSettingsUIRebootEnabled()) {
+    [passphrase_ setFont:[MDCTypography body1Font]];
+  }
   [passphrase_ setSecureTextEntry:YES];
   [passphrase_ setBackgroundColor:[UIColor clearColor]];
   [passphrase_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
@@ -324,8 +328,13 @@
   if (item.type == ItemTypeMessage) {
     CardMultilineCell* messageCell =
         base::mac::ObjCCastStrict<CardMultilineCell>(cell);
-    messageCell.textLabel.font =
-        [[MDCTypography fontLoader] mediumFontOfSize:14];
+    if (experimental_flags::IsSettingsUIRebootEnabled()) {
+      messageCell.textLabel.font =
+          [UIFont boldSystemFontOfSize:kUIKitMainFontSize];
+    } else {
+      messageCell.textLabel.font =
+          [[MDCTypography fontLoader] mediumFontOfSize:14];
+    }
   }
   return cell;
 }
diff --git a/ios/chrome/browser/ui/settings/translate_collection_view_controller.mm b/ios/chrome/browser/ui/settings/translate_collection_view_controller.mm
index 14d1d81..1b12ae2f 100644
--- a/ios/chrome/browser/ui/settings/translate_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/translate_collection_view_controller.mm
@@ -112,7 +112,6 @@
       [[SettingsTextItem alloc] initWithType:ItemTypeResetTranslate];
   resetTranslate.text = l10n_util::GetNSString(IDS_IOS_TRANSLATE_SETTING_RESET);
   resetTranslate.accessibilityTraits |= UIAccessibilityTraitButton;
-  resetTranslate.textFont = [MDCTypography body2Font];
   [model addItem:resetTranslate
       toSectionWithIdentifier:SectionIdentifierTranslate];
 
diff --git a/ios/web_view/internal/signin/ios_web_view_signin_client.h b/ios/web_view/internal/signin/ios_web_view_signin_client.h
index 31d43582..de45064 100644
--- a/ios/web_view/internal/signin/ios_web_view_signin_client.h
+++ b/ios/web_view/internal/signin/ios_web_view_signin_client.h
@@ -59,7 +59,8 @@
   std::unique_ptr<GaiaAuthFetcher> CreateGaiaAuthFetcher(
       GaiaAuthConsumer* consumer,
       const std::string& source,
-      net::URLRequestContextGetter* getter) override;
+      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
+      override;
 
   // SigninErrorController::Observer implementation.
   void OnErrorChanged() override;
diff --git a/ios/web_view/internal/signin/ios_web_view_signin_client.mm b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
index f2861221..58b86cd 100644
--- a/ios/web_view/internal/signin/ios_web_view_signin_client.mm
+++ b/ios/web_view/internal/signin/ios_web_view_signin_client.mm
@@ -117,8 +117,9 @@
 std::unique_ptr<GaiaAuthFetcher> IOSWebViewSigninClient::CreateGaiaAuthFetcher(
     GaiaAuthConsumer* consumer,
     const std::string& source,
-    net::URLRequestContextGetter* getter) {
-  return std::make_unique<GaiaAuthFetcher>(consumer, source, getter);
+    scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+  return std::make_unique<GaiaAuthFetcher>(consumer, source,
+                                           url_loader_factory);
 }
 
 void IOSWebViewSigninClient::OnErrorChanged() {}
diff --git a/media/base/decrypt_config.cc b/media/base/decrypt_config.cc
index 7d073bca..eda225a1 100644
--- a/media/base/decrypt_config.cc
+++ b/media/base/decrypt_config.cc
@@ -72,7 +72,7 @@
 
 DecryptConfig::~DecryptConfig() = default;
 
-std::unique_ptr<DecryptConfig> DecryptConfig::Clone() {
+std::unique_ptr<DecryptConfig> DecryptConfig::Clone() const {
   return base::WrapUnique(new DecryptConfig(*this));
 }
 
diff --git a/media/base/decrypt_config.h b/media/base/decrypt_config.h
index 29f3249e..25265a2 100644
--- a/media/base/decrypt_config.h
+++ b/media/base/decrypt_config.h
@@ -72,7 +72,7 @@
     return encryption_pattern_;
   };
 
-  std::unique_ptr<DecryptConfig> Clone();
+  std::unique_ptr<DecryptConfig> Clone() const;
 
   // Returns whether this config has EncryptionPattern set or not.
   bool HasPattern() const;
diff --git a/media/blink/watch_time_reporter.cc b/media/blink/watch_time_reporter.cc
index 72b259c5..67a22d9 100644
--- a/media/blink/watch_time_reporter.cc
+++ b/media/blink/watch_time_reporter.cc
@@ -509,7 +509,7 @@
                                              FOREGROUND_KEY(NativeControlsOff)};
 
   return std::make_unique<WatchTimeComponent<bool>>(
-      IsOnBatteryPower(), std::move(keys_to_finalize),
+      false, std::move(keys_to_finalize),
       base::BindRepeating(&WatchTimeReporter::GetControlsKey,
                           base::Unretained(this)),
       get_media_time_cb_, recorder_.get());
diff --git a/media/gpu/h264_decoder.cc b/media/gpu/h264_decoder.cc
index 83ced10..ae9b190 100644
--- a/media/gpu/h264_decoder.cc
+++ b/media/gpu/h264_decoder.cc
@@ -93,8 +93,6 @@
 
 bool H264Decoder::DecodePicture() {
   DCHECK(curr_pic_.get());
-
-  DVLOG(4) << "Decoding POC " << curr_pic_->pic_order_cnt;
   return accelerator_->SubmitDecode(curr_pic_) == H264Accelerator::Status::kOk;
 }
 
@@ -1233,16 +1231,17 @@
                             const DecryptConfig* decrypt_config) {
   DCHECK(ptr);
   DCHECK(size);
-  if (decrypt_config) {
-    NOTIMPLEMENTED();
-    state_ = kError;
-    return;
-  }
 
   DVLOG(4) << "New input stream id: " << id << " at: " << (void*)ptr
            << " size: " << size;
   stream_id_ = id;
-  parser_.SetStream(ptr, size);
+  if (decrypt_config) {
+    parser_.SetEncryptedStream(ptr, size, decrypt_config->subsamples());
+    current_decrypt_config_ = decrypt_config->Clone();
+  } else {
+    parser_.SetStream(ptr, size);
+    current_decrypt_config_ = nullptr;
+  }
 }
 
 H264Decoder::DecodeResult H264Decoder::Decode() {
@@ -1301,6 +1300,8 @@
           curr_pic_ = accelerator_->CreateH264Picture();
           if (!curr_pic_)
             return kRanOutOfSurfaces;
+          if (current_decrypt_config_)
+            curr_pic_->set_decrypt_config(current_decrypt_config_->Clone());
 
           if (!StartNewFrame(curr_slice_hdr_.get()))
             SET_ERROR_AND_RETURN();
diff --git a/media/gpu/h264_decoder.h b/media/gpu/h264_decoder.h
index 38326b0..c153e3ae 100644
--- a/media/gpu/h264_decoder.h
+++ b/media/gpu/h264_decoder.h
@@ -261,6 +261,9 @@
   // Parser in use.
   H264Parser parser_;
 
+  // Decrypting config for the most recent data passed to SetStream().
+  std::unique_ptr<DecryptConfig> current_decrypt_config_;
+
   // DPB in use.
   H264DPB dpb_;
 
diff --git a/media/gpu/h264_decoder_unittest.cc b/media/gpu/h264_decoder_unittest.cc
index 3c6f912..2d5ae0fd 100644
--- a/media/gpu/h264_decoder_unittest.cc
+++ b/media/gpu/h264_decoder_unittest.cc
@@ -40,24 +40,29 @@
 const std::string kHighFrame2 = "bear-320x192-high-frame-2.h264";
 const std::string kHighFrame3 = "bear-320x192-high-frame-3.h264";
 
+// Checks whether the decrypt config in the picture matches the decrypt config
+// passed to this matcher.
+MATCHER_P(DecryptConfigMatches, decrypt_config, "") {
+  const scoped_refptr<H264Picture>& pic = arg;
+  return pic->decrypt_config()->Matches(*decrypt_config);
+}
+
 class MockH264Accelerator : public H264Decoder::H264Accelerator {
  public:
   MockH264Accelerator() = default;
 
   MOCK_METHOD0(CreateH264Picture, scoped_refptr<H264Picture>());
   MOCK_METHOD1(SubmitDecode, Status(const scoped_refptr<H264Picture>& pic));
+  MOCK_METHOD7(SubmitFrameMetadata,
+               Status(const H264SPS* sps,
+                      const H264PPS* pps,
+                      const H264DPB& dpb,
+                      const H264Picture::Vector& ref_pic_listp0,
+                      const H264Picture::Vector& ref_pic_listb0,
+                      const H264Picture::Vector& ref_pic_listb1,
+                      const scoped_refptr<H264Picture>& pic));
   MOCK_METHOD1(OutputPicture, bool(const scoped_refptr<H264Picture>& pic));
 
-  Status SubmitFrameMetadata(const H264SPS* sps,
-                             const H264PPS* pps,
-                             const H264DPB& dpb,
-                             const H264Picture::Vector& ref_pic_listp0,
-                             const H264Picture::Vector& ref_pic_listb0,
-                             const H264Picture::Vector& ref_pic_listb1,
-                             const scoped_refptr<H264Picture>& pic) override {
-    return Status::kOk;
-  }
-
   Status SubmitSlice(const H264PPS* pps,
                      const H264SliceHeader* slice_hdr,
                      const H264Picture::Vector& ref_pic_list0,
@@ -113,6 +118,8 @@
   ON_CALL(*accelerator_, CreateH264Picture()).WillByDefault(Invoke([]() {
     return new H264Picture();
   }));
+  ON_CALL(*accelerator_, SubmitFrameMetadata(_, _, _, _, _, _, _))
+      .WillByDefault(Return(H264Decoder::H264Accelerator::Status::kOk));
   ON_CALL(*accelerator_, SubmitDecode(_))
       .WillByDefault(Return(H264Decoder::H264Accelerator::Status::kOk));
   ON_CALL(*accelerator_, OutputPicture(_)).WillByDefault(Return(true));
@@ -340,5 +347,36 @@
   ASSERT_TRUE(decoder_->Flush());
 }
 
+// Verify that the decryption config is passed to the accelerator.
+TEST_F(H264DecoderTest, SetEncryptedStream) {
+  std::string bitstream;
+  auto input_file = GetTestDataFilePath(kBaselineFrame0);
+  CHECK(base::ReadFileToString(input_file, &bitstream));
+
+  const char kAnyKeyId[] = "any_16byte_keyid";
+  const char kAnyIv[] = "any_16byte_iv___";
+  const std::vector<SubsampleEntry> subsamples = {
+      // No encrypted bytes. This test only checks whether the data is passed
+      // thru to the acclerator so making this completely clear.
+      {bitstream.size(), 0},
+  };
+
+  std::unique_ptr<DecryptConfig> decrypt_config =
+      DecryptConfig::CreateCencConfig(kAnyKeyId, kAnyIv, subsamples);
+  EXPECT_CALL(*accelerator_,
+              SubmitFrameMetadata(_, _, _, _, _, _,
+                                  DecryptConfigMatches(decrypt_config.get())))
+      .WillOnce(Return(H264Decoder::H264Accelerator::Status::kOk));
+  EXPECT_CALL(*accelerator_,
+              SubmitDecode(DecryptConfigMatches(decrypt_config.get())))
+      .WillOnce(Return(H264Decoder::H264Accelerator::Status::kOk));
+
+  decoder_->SetStream(0, reinterpret_cast<const uint8_t*>(bitstream.data()),
+                      bitstream.size(), decrypt_config.get());
+  EXPECT_EQ(AcceleratedVideoDecoder::kAllocateNewSurfaces, decoder_->Decode());
+  EXPECT_EQ(AcceleratedVideoDecoder::kRanOutOfStreamData, decoder_->Decode());
+  EXPECT_TRUE(decoder_->Flush());
+}
+
 }  // namespace
 }  // namespace media
diff --git a/media/gpu/vaapi/vaapi_h264_accelerator.cc b/media/gpu/vaapi/vaapi_h264_accelerator.cc
index a46c0fa7..3bcf0f34 100644
--- a/media/gpu/vaapi/vaapi_h264_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_h264_accelerator.cc
@@ -15,7 +15,6 @@
                   #from " and " #to " arrays must be of same size"); \
     memcpy(to, from, sizeof(to));                                    \
   } while (0)
-#define VLOGF(level) VLOG(level) << __func__ << "(): "
 
 namespace media {
 
@@ -295,7 +294,6 @@
 
 Status VaapiH264Accelerator::SubmitDecode(
     const scoped_refptr<H264Picture>& pic) {
-  VLOGF(4) << "Decoding POC " << pic->pic_order_cnt;
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
   return vaapi_dec_->DecodeVASurface(pic->AsVaapiH264Picture()->va_surface())
diff --git a/media/gpu/vaapi/vaapi_video_decode_accelerator.cc b/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
index 6f5a5b40..2b8cb4d 100644
--- a/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
@@ -90,7 +90,7 @@
               base::OnceCallback<void(int32_t id)> release_cb)
       : id_(id), shm_(std::move(shm)), release_cb_(std::move(release_cb)) {}
   ~InputBuffer() {
-    VLOGF(4) << "id = " << id_;
+    DVLOGF(4) << "id = " << id_;
     if (release_cb_)
       std::move(release_cb_).Run(id_);
   }
@@ -132,7 +132,7 @@
     int32_t picture_buffer_id) {
   Pictures::iterator it = pictures_.find(picture_buffer_id);
   if (it == pictures_.end()) {
-    VLOGF(4) << "Picture id " << picture_buffer_id << " does not exist";
+    DVLOGF(4) << "Picture id " << picture_buffer_id << " does not exist";
     return NULL;
   }
 
@@ -226,8 +226,8 @@
 
   int32_t output_id = picture->picture_buffer_id();
 
-  VLOGF(4) << "Outputting VASurface " << va_surface->id()
-           << " into pixmap bound to picture buffer id " << output_id;
+  DVLOGF(4) << "Outputting VASurface " << va_surface->id()
+            << " into pixmap bound to picture buffer id " << output_id;
   {
     TRACE_EVENT2("media,gpu", "VAVDA::DownloadFromSurface", "input_id",
                  input_id, "output_id", output_id);
@@ -238,9 +238,9 @@
   // Notify the client a picture is ready to be displayed.
   ++num_frames_at_client_;
   TRACE_COUNTER1("media,gpu", "Vaapi frames at client", num_frames_at_client_);
-  VLOGF(4) << "Notifying output picture id " << output_id << " for input "
-           << input_id
-           << " is ready. visible rect: " << visible_rect.ToString();
+  DVLOGF(4) << "Notifying output picture id " << output_id << " for input "
+            << input_id
+            << " is ready. visible rect: " << visible_rect.ToString();
   if (client_) {
     // TODO(hubbe): Use the correct color space.  http://crbug.com/647725
     client_->PictureReady(Picture(output_id, input_id, visible_rect,
@@ -273,8 +273,8 @@
 
 void VaapiVideoDecodeAccelerator::QueueInputBuffer(
     const BitstreamBuffer& bitstream_buffer) {
-  VLOGF(4) << "Queueing new input buffer id: " << bitstream_buffer.id()
-           << " size: " << (int)bitstream_buffer.size();
+  DVLOGF(4) << "Queueing new input buffer id: " << bitstream_buffer.id()
+            << " size: " << (int)bitstream_buffer.size();
   DCHECK(task_runner_->BelongsToCurrentThread());
   TRACE_EVENT1("media,gpu", "QueueInputBuffer", "input_id",
                bitstream_buffer.id());
@@ -352,12 +352,12 @@
   TRACE_COUNTER1("media,gpu", "Input buffers", input_buffers_.size());
 
   if (curr_input_buffer_->IsFlushRequest()) {
-    VLOGF(4) << "New flush buffer";
+    DVLOGF(4) << "New flush buffer";
     return true;
   }
 
-  VLOGF(4) << "New |curr_input_buffer_|, id: " << curr_input_buffer_->id()
-           << " size: " << curr_input_buffer_->shm()->size() << "B";
+  DVLOGF(4) << "New |curr_input_buffer_|, id: " << curr_input_buffer_->id()
+            << " size: " << curr_input_buffer_->shm()->size() << "B";
   decoder_->SetStream(
       curr_input_buffer_->id(),
       static_cast<uint8_t*>(curr_input_buffer_->shm()->memory()),
@@ -393,7 +393,7 @@
 
   if (state_ != kDecoding)
     return;
-  VLOGF(4) << "Decode task";
+  DVLOGF(4) << "Decode task";
 
   // Try to decode what stream data is (still) in the decoder until we run out
   // of it.
@@ -641,8 +641,8 @@
     // picture, but it has not yet executed when this ImportBufferForPicture
     // was posted to us by the client. In that case just ignore this (we've
     // already dismissed it and accounted for that).
-    VLOGF(3) << "got picture id=" << picture_buffer_id
-             << " not in use (anymore?).";
+    DVLOGF(3) << "got picture id=" << picture_buffer_id
+              << " not in use (anymore?).";
     return;
   }
 
@@ -662,7 +662,7 @@
 
 void VaapiVideoDecodeAccelerator::ReusePictureBuffer(
     int32_t picture_buffer_id) {
-  VLOGF(4) << "picture id=" << picture_buffer_id;
+  DVLOGF(4) << "picture id=" << picture_buffer_id;
   DCHECK(task_runner_->BelongsToCurrentThread());
   TRACE_EVENT1("media,gpu", "VAVDA::ReusePictureBuffer", "Picture id",
                picture_buffer_id);
@@ -672,8 +672,8 @@
     // picture, but it has not yet executed when this ReusePictureBuffer
     // was posted to us by the client. In that case just ignore this (we've
     // already dismissed it and accounted for that).
-    VLOGF(3) << "got picture id=" << picture_buffer_id
-             << " not in use (anymore?).";
+    DVLOGF(3) << "got picture id=" << picture_buffer_id
+              << " not in use (anymore?).";
     return;
   }
 
diff --git a/media/test/pipeline_integration_test.cc b/media/test/pipeline_integration_test.cc
index e232086..16a6779 100644
--- a/media/test/pipeline_integration_test.cc
+++ b/media/test/pipeline_integration_test.cc
@@ -1072,7 +1072,9 @@
   Stop();
 }
 
-TEST_F(PipelineIntegrationTest, PipelineStoppedWhileVideoRestartPending) {
+// Flaky crashes on multiple platforms. crbug.com/864018
+TEST_F(PipelineIntegrationTest,
+       DISABLED_PipelineStoppedWhileVideoRestartPending) {
   ASSERT_EQ(PIPELINE_OK, Start("bear-320x240.webm"));
   Play();
 
diff --git a/mojo/public/tools/bindings/blink_bindings_configuration.gni b/mojo/public/tools/bindings/blink_bindings_configuration.gni
index 1783945..990d133 100644
--- a/mojo/public/tools/bindings/blink_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/blink_bindings_configuration.gni
@@ -7,6 +7,7 @@
 for_blink = true
 
 _typemap_imports = [
+  "//device/gamepad/public/cpp/typemaps.gni",
   "//mojo/public/cpp/bindings/tests/blink_typemaps.gni",
   "//third_party/blink/renderer/platform/mojo/blink_typemaps.gni",
   "//third_party/blink/public/blink_typemaps.gni",
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index 07122cb..526e9e7d 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -1297,6 +1297,11 @@
       return ERR_METHOD_NOT_SUPPORTED;
   }
 
+  if (can_send_early_data_ && response_.headers.get() &&
+      response_.headers->response_code() == HTTP_TOO_EARLY) {
+    return HandleIOError(ERR_EARLY_DATA_REJECTED);
+  }
+
   // Check for an intermediate 100 Continue response.  An origin server is
   // allowed to send this response even if we didn't ask for it, so we just
   // need to skip over it.
@@ -1589,6 +1594,15 @@
         error = OK;
       }
       break;
+    case ERR_EARLY_DATA_REJECTED:
+    case ERR_WRONG_VERSION_ON_EARLY_DATA:
+      net_log_.AddEventWithNetErrorCode(
+          NetLogEventType::HTTP_TRANSACTION_RESTART_AFTER_ERROR, error);
+      // Disable early data on the SSLConfig on a reset.
+      can_send_early_data_ = false;
+      ResetConnectionAndRequestForResend();
+      error = OK;
+      break;
     case ERR_SPDY_PING_FAILED:
     case ERR_SPDY_SERVER_REFUSED_STREAM:
     case ERR_SPDY_PUSHED_STREAM_NOT_AVAILABLE:
diff --git a/net/http/http_status_code_list.h b/net/http/http_status_code_list.h
index 53f633c..bb69708 100644
--- a/net/http/http_status_code_list.h
+++ b/net/http/http_status_code_list.h
@@ -59,6 +59,7 @@
 HTTP_STATUS(REQUESTED_RANGE_NOT_SATISFIABLE, 416,
             "Requested Range Not Satisfiable")
 HTTP_STATUS(EXPECTATION_FAILED, 417, "Expectation Failed")
+HTTP_STATUS(TOO_EARLY, 425, "Too Early")
 
 // Server error 5xx
 HTTP_STATUS(INTERNAL_SERVER_ERROR, 500, "Internal Server Error")
diff --git a/net/quic/chromium/quic_network_transaction_unittest.cc b/net/quic/chromium/quic_network_transaction_unittest.cc
index 88ea330..f16c7720 100644
--- a/net/quic/chromium/quic_network_transaction_unittest.cc
+++ b/net/quic/chromium/quic_network_transaction_unittest.cc
@@ -4461,6 +4461,191 @@
   CheckResponseData(&trans, "hello!");
 }
 
+TEST_P(QuicNetworkTransactionTest, ZeroRTTWithTooEarlyResponse) {
+  MockQuicData mock_quic_data;
+  quic::QuicStreamOffset client_header_stream_offset = 0;
+  quic::QuicStreamOffset server_header_stream_offset = 0;
+  client_maker_.SetEncryptionLevel(quic::ENCRYPTION_INITIAL);
+  client_maker_.SetLongHeaderType(quic::ZERO_RTT_PROTECTED);
+  mock_quic_data.AddWrite(SYNCHRONOUS,
+                          ConstructClientRequestHeadersPacket(
+                              1, GetNthClientInitiatedStreamId(0), true, true,
+                              GetRequestHeaders("GET", "https", "/"),
+                              &client_header_stream_offset));
+  mock_quic_data.AddRead(ASYNC, ConstructServerResponseHeadersPacket(
+                                    1, GetNthClientInitiatedStreamId(0), false,
+                                    false, GetResponseHeaders("425 TOO_EARLY"),
+                                    &server_header_stream_offset));
+  mock_quic_data.AddWrite(
+      SYNCHRONOUS,
+      ConstructClientAckAndRstPacket(2, GetNthClientInitiatedStreamId(0),
+                                     quic::QUIC_STREAM_CANCELLED, 1, 1, 1));
+
+  client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
+
+  spdy::SpdySettingsIR settings_frame;
+  settings_frame.AddSetting(spdy::SETTINGS_MAX_HEADER_LIST_SIZE,
+                            quic::kDefaultMaxUncompressedHeaderSize);
+  spdy::SpdySerializedFrame spdy_frame(
+      client_maker_.spdy_request_framer()->SerializeFrame(settings_frame));
+  mock_quic_data.AddWrite(
+      SYNCHRONOUS,
+      client_maker_.MakeDataPacket(
+          3, 3, false, false, client_header_stream_offset,
+          quic::QuicStringPiece(spdy_frame.data(), spdy_frame.size())));
+  client_header_stream_offset += spdy_frame.size();
+
+  mock_quic_data.AddWrite(
+      SYNCHRONOUS,
+      ConstructClientRequestHeadersPacket(
+          4, GetNthClientInitiatedStreamId(1), false, true,
+          GetRequestHeaders("GET", "https", "/"),
+          GetNthClientInitiatedStreamId(0), &client_header_stream_offset));
+  mock_quic_data.AddRead(
+      ASYNC, ConstructServerResponseHeadersPacket(
+                 2, GetNthClientInitiatedStreamId(1), false, false,
+                 GetResponseHeaders("200 OK"), &server_header_stream_offset));
+  mock_quic_data.AddRead(
+      ASYNC, ConstructServerDataPacket(3, GetNthClientInitiatedStreamId(1),
+                                       false, true, 0, "hello!"));
+  mock_quic_data.AddWrite(
+      SYNCHRONOUS, ConstructClientAckAndConnectionClosePacket(5, 3, 1, 1));
+  mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING);  // No more data to read
+  mock_quic_data.AddRead(ASYNC, 0);               // EOF
+
+  mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+  // In order for a new QUIC session to be established via alternate-protocol
+  // without racing an HTTP connection, we need the host resolution to happen
+  // synchronously.
+  host_resolver_.set_synchronous_mode(true);
+  host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
+                                           "");
+  HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
+  AddressList address;
+  std::unique_ptr<HostResolver::Request> request;
+  host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address,
+                         CompletionOnceCallback(), &request, net_log_.bound());
+
+  AddHangingNonAlternateProtocolSocketData();
+  CreateSession();
+  AddQuicAlternateProtocolMapping(quic::MockCryptoClientStream::ZERO_RTT);
+
+  HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+  TestCompletionCallback callback;
+  int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  // Confirm the handshake after the 425 Too Early.
+  base::RunLoop().RunUntilIdle();
+
+  // The handshake hasn't been confirmed yet, so the retry should not have
+  // succeeded.
+  EXPECT_FALSE(callback.have_result());
+
+  crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+      quic::QuicSession::HANDSHAKE_CONFIRMED);
+
+  EXPECT_THAT(callback.WaitForResult(), IsOk());
+  CheckWasQuicResponse(&trans);
+  CheckResponseData(&trans, "hello!");
+}
+
+TEST_P(QuicNetworkTransactionTest, ZeroRTTWithMultipleTooEarlyResponse) {
+  MockQuicData mock_quic_data;
+  quic::QuicStreamOffset client_header_stream_offset = 0;
+  quic::QuicStreamOffset server_header_stream_offset = 0;
+  client_maker_.SetEncryptionLevel(quic::ENCRYPTION_INITIAL);
+  client_maker_.SetLongHeaderType(quic::ZERO_RTT_PROTECTED);
+  mock_quic_data.AddWrite(SYNCHRONOUS,
+                          ConstructClientRequestHeadersPacket(
+                              1, GetNthClientInitiatedStreamId(0), true, true,
+                              GetRequestHeaders("GET", "https", "/"),
+                              &client_header_stream_offset));
+  mock_quic_data.AddRead(ASYNC, ConstructServerResponseHeadersPacket(
+                                    1, GetNthClientInitiatedStreamId(0), false,
+                                    false, GetResponseHeaders("425 TOO_EARLY"),
+                                    &server_header_stream_offset));
+  mock_quic_data.AddWrite(
+      SYNCHRONOUS,
+      ConstructClientAckAndRstPacket(2, GetNthClientInitiatedStreamId(0),
+                                     quic::QUIC_STREAM_CANCELLED, 1, 1, 1));
+
+  client_maker_.SetEncryptionLevel(quic::ENCRYPTION_FORWARD_SECURE);
+
+  spdy::SpdySettingsIR settings_frame;
+  settings_frame.AddSetting(spdy::SETTINGS_MAX_HEADER_LIST_SIZE,
+                            quic::kDefaultMaxUncompressedHeaderSize);
+  spdy::SpdySerializedFrame spdy_frame(
+      client_maker_.spdy_request_framer()->SerializeFrame(settings_frame));
+  mock_quic_data.AddWrite(
+      SYNCHRONOUS,
+      client_maker_.MakeDataPacket(
+          3, 3, false, false, client_header_stream_offset,
+          quic::QuicStringPiece(spdy_frame.data(), spdy_frame.size())));
+  client_header_stream_offset += spdy_frame.size();
+
+  mock_quic_data.AddWrite(
+      SYNCHRONOUS,
+      ConstructClientRequestHeadersPacket(
+          4, GetNthClientInitiatedStreamId(1), false, true,
+          GetRequestHeaders("GET", "https", "/"),
+          GetNthClientInitiatedStreamId(0), &client_header_stream_offset));
+  mock_quic_data.AddRead(ASYNC, ConstructServerResponseHeadersPacket(
+                                    2, GetNthClientInitiatedStreamId(1), false,
+                                    false, GetResponseHeaders("425 TOO_EARLY"),
+                                    &server_header_stream_offset));
+  mock_quic_data.AddWrite(
+      SYNCHRONOUS,
+      ConstructClientAckAndRstPacket(5, GetNthClientInitiatedStreamId(1),
+                                     quic::QUIC_STREAM_CANCELLED, 2, 1, 1));
+  mock_quic_data.AddRead(ASYNC, ERR_IO_PENDING);  // No more data to read
+  mock_quic_data.AddRead(ASYNC, 0);               // EOF
+
+  mock_quic_data.AddSocketDataToFactory(&socket_factory_);
+
+  // In order for a new QUIC session to be established via alternate-protocol
+  // without racing an HTTP connection, we need the host resolution to happen
+  // synchronously.
+  host_resolver_.set_synchronous_mode(true);
+  host_resolver_.rules()->AddIPLiteralRule("mail.example.org", "192.168.0.1",
+                                           "");
+  HostResolver::RequestInfo info(HostPortPair("mail.example.org", 443));
+  AddressList address;
+  std::unique_ptr<HostResolver::Request> request;
+  host_resolver_.Resolve(info, DEFAULT_PRIORITY, &address,
+                         CompletionOnceCallback(), &request, net_log_.bound());
+
+  AddHangingNonAlternateProtocolSocketData();
+  CreateSession();
+  AddQuicAlternateProtocolMapping(quic::MockCryptoClientStream::ZERO_RTT);
+
+  HttpNetworkTransaction trans(DEFAULT_PRIORITY, session_.get());
+  TestCompletionCallback callback;
+  int rv = trans.Start(&request_, callback.callback(), net_log_.bound());
+  EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
+
+  // Confirm the handshake after the 425 Too Early.
+  base::RunLoop().RunUntilIdle();
+
+  // The handshake hasn't been confirmed yet, so the retry should not have
+  // succeeded.
+  EXPECT_FALSE(callback.have_result());
+
+  crypto_client_stream_factory_.last_stream()->SendOnCryptoHandshakeEvent(
+      quic::QuicSession::HANDSHAKE_CONFIRMED);
+
+  EXPECT_THAT(callback.WaitForResult(), IsOk());
+  const HttpResponseInfo* response = trans.GetResponseInfo();
+  ASSERT_TRUE(response != nullptr);
+  ASSERT_TRUE(response->headers.get() != nullptr);
+  EXPECT_EQ("HTTP/1.1 425 TOO_EARLY", response->headers->GetStatusLine());
+  EXPECT_TRUE(response->was_fetched_via_spdy);
+  EXPECT_TRUE(response->was_alpn_negotiated);
+  EXPECT_EQ(QuicHttpStream::ConnectionInfoFromQuicVersion(version_),
+            response->connection_info);
+}
+
 TEST_P(QuicNetworkTransactionTest,
        LogGranularQuicErrorCodeOnQuicProtocolErrorLocal) {
   session_params_.retry_without_alt_svc_on_quic_errors = false;
diff --git a/net/quic/chromium/quic_test_packet_maker.h b/net/quic/chromium/quic_test_packet_maker.h
index 55cbb62..47747089 100644
--- a/net/quic/chromium/quic_test_packet_maker.h
+++ b/net/quic/chromium/quic_test_packet_maker.h
@@ -347,6 +347,9 @@
   spdy::SpdyHeaderBlock GetResponseHeaders(const std::string& status,
                                            const std::string& alt_svc);
 
+  spdy::SpdyFramer* spdy_request_framer() { return &spdy_request_framer_; }
+  spdy::SpdyFramer* spdy_response_framer() { return &spdy_response_framer_; }
+
  private:
   std::unique_ptr<quic::QuicReceivedPacket> MakePacket(
       const quic::QuicPacketHeader& header,
diff --git a/net/test/embedded_test_server/controllable_http_response.cc b/net/test/embedded_test_server/controllable_http_response.cc
index 226b126..9398b31 100644
--- a/net/test/embedded_test_server/controllable_http_response.cc
+++ b/net/test/embedded_test_server/controllable_http_response.cc
@@ -5,6 +5,7 @@
 #include "net/test/embedded_test_server/controllable_http_response.h"
 
 #include "base/logging.h"
+#include "base/strings/stringprintf.h"
 #include "base/threading/thread_task_runner_handle.h"
 
 namespace net {
@@ -65,6 +66,20 @@
   state_ = State::READY_TO_SEND_DATA;
 }
 
+void ControllableHttpResponse::Send(net::HttpStatusCode http_status,
+                                    const std::string& content_type,
+                                    const std::string& content,
+                                    const std::vector<std::string>& cookies) {
+  std::string content_data(base::StringPrintf(
+      "HTTP/1.1 %d %s\nContent-type: %s\n", static_cast<int>(http_status),
+      net::GetHttpReasonPhrase(http_status), content_type.c_str()));
+  for (auto& cookie : cookies)
+    content_data += "Set-Cookie: " + cookie + "\n";
+  content_data += "\n";
+  content_data += content;
+  Send(content_data);
+}
+
 void ControllableHttpResponse::Send(const std::string& bytes) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK_EQ(State::READY_TO_SEND_DATA, state_) << "Send() called without any "
diff --git a/net/test/embedded_test_server/controllable_http_response.h b/net/test/embedded_test_server/controllable_http_response.h
index ffc7271..efb23fd 100644
--- a/net/test/embedded_test_server/controllable_http_response.h
+++ b/net/test/embedded_test_server/controllable_http_response.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -14,6 +15,7 @@
 #include "base/run_loop.h"
 #include "base/sequence_checker.h"
 #include "base/single_thread_task_runner.h"
+#include "net/http/http_status_code.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/test/embedded_test_server/http_request.h"
 #include "net/test/embedded_test_server/http_response.h"
@@ -46,6 +48,12 @@
   //    May be called several time.
   void Send(const std::string& bytes);
 
+  // Same as 2) but with more specific parameters.
+  void Send(net::HttpStatusCode http_status,
+            const std::string& content_type = std::string("text/html"),
+            const std::string& content = std::string(),
+            const std::vector<std::string>& cookies = {});
+
   // 3) Notify there are no more data to be sent and close the socket.
   void Done();
 
diff --git a/pdf/BUILD.gn b/pdf/BUILD.gn
index 5841d56..ee973f4 100644
--- a/pdf/BUILD.gn
+++ b/pdf/BUILD.gn
@@ -8,6 +8,7 @@
 import("//pdf/features.gni")
 import("//testing/test.gni")
 import("//third_party/pdfium/pdfium.gni")
+import("//v8/gni/v8.gni")
 
 # Generate a buildflag header for compile-time checking of PDF support.
 buildflag_header("buildflags") {
@@ -134,8 +135,19 @@
     ]
 
     if (pdf_engine == 0) {
-      sources += [ "pdfium/findtext_unittest.cc" ]
+      configs += [ "//v8:external_startup_data" ]
+      sources += [
+        "pdfium/findtext_unittest.cc",
+        "pdfium/pdfium_engine_exports_unittest.cc",
+      ]
       include_dirs = [ "//third_party/pdfium" ]
+
+      if (v8_use_external_startup_data) {
+        data += [
+          "$root_out_dir/natives_blob.bin",
+          "$root_out_dir/snapshot_blob.bin",
+        ]
+      }
     }
   }
 } else {
diff --git a/pdf/pdfium/DEPS b/pdf/pdfium/DEPS
index 5e8aa4c..f157a81 100644
--- a/pdf/pdfium/DEPS
+++ b/pdf/pdfium/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+gin/array_buffer.h",
   "+gin/public",
+  "+gin/v8_initializer.h",
   "+printing/nup_parameters.h",
   "+third_party/pdfium/public",
   "+ui/gfx/codec/jpeg_codec.h",
diff --git a/pdf/pdfium/pdfium_engine_exports_unittest.cc b/pdf/pdfium/pdfium_engine_exports_unittest.cc
new file mode 100644
index 0000000..fe83add7
--- /dev/null
+++ b/pdf/pdfium/pdfium_engine_exports_unittest.cc
@@ -0,0 +1,101 @@
+// 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.
+
+#include "base/files/file_util.h"
+#include "base/path_service.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "gin/v8_initializer.h"
+#include "pdf/pdf.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_pdf {
+
+namespace {
+
+void LoadV8SnapshotData() {
+#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
+  static bool loaded = false;
+  if (!loaded) {
+    loaded = true;
+    gin::V8Initializer::LoadV8Snapshot();
+    gin::V8Initializer::LoadV8Natives();
+  }
+#endif
+}
+
+class PDFiumEngineExportsTest : public testing::Test {
+ public:
+  PDFiumEngineExportsTest() = default;
+  ~PDFiumEngineExportsTest() override = default;
+
+ protected:
+  void SetUp() override {
+    LoadV8SnapshotData();
+
+    handle_ = std::make_unique<base::ThreadTaskRunnerHandle>(
+        base::MakeRefCounted<base::TestSimpleTaskRunner>());
+
+    CHECK(base::PathService::Get(base::DIR_SOURCE_ROOT, &pdf_data_dir_));
+    pdf_data_dir_ = pdf_data_dir_.Append(FILE_PATH_LITERAL("pdf"))
+                        .Append(FILE_PATH_LITERAL("test"))
+                        .Append(FILE_PATH_LITERAL("data"));
+  }
+
+  const base::FilePath& pdf_data_dir() const { return pdf_data_dir_; }
+
+ private:
+  std::unique_ptr<base::ThreadTaskRunnerHandle> handle_;
+  base::FilePath pdf_data_dir_;
+
+  DISALLOW_COPY_AND_ASSIGN(PDFiumEngineExportsTest);
+};
+
+}  // namespace
+
+TEST_F(PDFiumEngineExportsTest, GetPDFDocInfo) {
+  base::FilePath pdf_path =
+      pdf_data_dir().Append(FILE_PATH_LITERAL("hello_world2.pdf"));
+  std::string pdf_data;
+  ASSERT_TRUE(base::ReadFileToString(pdf_path, &pdf_data));
+
+  EXPECT_FALSE(GetPDFDocInfo(nullptr, 0, nullptr, nullptr));
+
+  ASSERT_TRUE(
+      GetPDFDocInfo(pdf_data.data(), pdf_data.size(), nullptr, nullptr));
+
+  int page_count;
+  double max_page_width;
+  ASSERT_TRUE(GetPDFDocInfo(pdf_data.data(), pdf_data.size(), &page_count,
+                            &max_page_width));
+  EXPECT_EQ(2, page_count);
+  EXPECT_DOUBLE_EQ(200.0, max_page_width);
+}
+
+TEST_F(PDFiumEngineExportsTest, GetPDFPageSizeByIndex) {
+  // TODO(thestig): Use a better PDF for this test, as hello_world2.pdf's page
+  // dimensions are uninteresting.
+  base::FilePath pdf_path =
+      pdf_data_dir().Append(FILE_PATH_LITERAL("hello_world2.pdf"));
+  std::string pdf_data;
+  ASSERT_TRUE(base::ReadFileToString(pdf_path, &pdf_data));
+
+  EXPECT_FALSE(GetPDFPageSizeByIndex(nullptr, 0, 0, nullptr, nullptr));
+
+  int page_count;
+  ASSERT_TRUE(
+      GetPDFDocInfo(pdf_data.data(), pdf_data.size(), &page_count, nullptr));
+  ASSERT_EQ(2, page_count);
+  for (int page_number = 0; page_number < page_count; ++page_number) {
+    double width;
+    double height;
+    ASSERT_TRUE(GetPDFPageSizeByIndex(pdf_data.data(), pdf_data.size(),
+                                      page_number, &width, &height));
+    EXPECT_DOUBLE_EQ(200.0, width);
+    EXPECT_DOUBLE_EQ(200.0, height);
+  }
+}
+
+}  // namespace chrome_pdf
diff --git a/services/network/test/test_url_loader_factory.cc b/services/network/test/test_url_loader_factory.cc
index 6877a1c..4cdd1df 100644
--- a/services/network/test/test_url_loader_factory.cc
+++ b/services/network/test/test_url_loader_factory.cc
@@ -141,11 +141,18 @@
   const bool url_match_prefix = flags & kUrlMatchPrefix;
   const bool reverse = flags & kMostRecentMatch;
 
+  // Give any cancellations a chance to happen...
+  base::RunLoop().RunUntilIdle();
+
   bool found_request = false;
   network::TestURLLoaderFactory::PendingRequest request;
   for (int i = (reverse ? static_cast<int>(pending_requests_.size()) - 1 : 0);
        reverse ? i >= 0 : i < static_cast<int>(pending_requests_.size());
        reverse ? --i : ++i) {
+    // Skip already cancelled.
+    if (pending_requests_[i].client.encountered_error())
+      continue;
+
     if (pending_requests_[i].request.url == url ||
         (url_match_prefix &&
          base::StartsWith(pending_requests_[i].request.url.spec(), url.spec(),
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index e737a28..95e5e47f6 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -789,6 +789,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -1403,6 +1409,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.clang.json b/testing/buildbot/chromium.clang.json
index 7506ca7..6a26d4cf 100644
--- a/testing/buildbot/chromium.clang.json
+++ b/testing/buildbot/chromium.clang.json
@@ -2455,6 +2455,17 @@
             }
           ]
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Windows-10-15063"
+            }
+          ]
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -3606,6 +3617,17 @@
             }
           ]
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Windows-10-15063"
+            }
+          ]
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -4745,6 +4767,17 @@
             }
           ]
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Windows-10-15063"
+            }
+          ]
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -5463,6 +5496,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -6126,6 +6165,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -6789,6 +6834,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -7452,6 +7503,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -16665,6 +16722,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -17234,6 +17297,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -17873,6 +17942,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -18536,6 +18611,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -19199,6 +19280,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -19862,6 +19949,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -20525,6 +20618,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -21188,6 +21287,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -21851,6 +21956,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -22514,6 +22625,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -23177,6 +23294,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -23840,6 +23963,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -25610,6 +25739,17 @@
             }
           ]
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "os": "Windows-10"
+            }
+          ]
+        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index d9ba275..b1616ba 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -755,6 +755,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -1826,139 +1832,6 @@
       }
     ]
   },
-  "Site Isolation Linux": {
-    "additional_compile_targets": [
-      "base_unittests"
-    ]
-  },
-  "Site Isolation Win": {
-    "gtest_tests": [
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "app_shell_unittests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "shards": 10
-        },
-        "test": "browser_tests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "components_browsertests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "components_unittests"
-      },
-      {
-        "args": [
-          "--site-per-process",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "extensions_browsertests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "extensions_unittests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "integrity": "high"
-            }
-          ]
-        },
-        "test": "installer_util_unittests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "interactive_ui_tests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "nacl_loader_unittests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "sync_integration_tests"
-      },
-      {
-        "args": [
-          "--site-per-process"
-        ],
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
-        "test": "unit_tests"
-      }
-    ]
-  },
   "VR Linux": {
     "additional_compile_targets": [
       "vr_common_perftests",
@@ -2639,6 +2512,12 @@
         "swarming": {
           "can_use_on_swarming_builders": false
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": false
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -3606,12 +3485,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "url_unittests"
       },
       {
@@ -3878,12 +3751,6 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
-        "test": "unit_tests"
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        },
         "test": "url_unittests"
       },
       {
@@ -5411,6 +5278,15 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "args": [
+          "--enable-features=ViewsBrowserWindows"
+        ],
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 7e0e6b04..fe9ec4f 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -1162,6 +1162,25 @@
     "isolated_scripts": [
       {
         "args": [
+          "-v",
+          "--one-frame-only"
+        ],
+        "isolate_name": "angle_perftests",
+        "name": "angle_perftests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "device_os": "L",
+              "device_type": "hammerhead",
+              "os": "Android",
+              "pool": "Chrome-GPU"
+            }
+          ]
+        }
+      },
+      {
+        "args": [
           "context_lost",
           "--show-stdout",
           "--browser=android-chromium",
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 70ec90ef..de130c6 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -123,10 +123,10 @@
       },
       {
         "args": [
-          "--test-launcher-filter-file=src/testing/buildbot/filters/cast-linux.content_browsertests.filter"
+          "--test-launcher-filter-file=../../testing/buildbot/filters/cast-linux.content_browsertests.filter"
         ],
         "swarming": {
-          "can_use_on_swarming_builders": false
+          "can_use_on_swarming_builders": true
         },
         "test": "content_browsertests"
       },
@@ -428,10 +428,10 @@
       },
       {
         "args": [
-          "--test-launcher-filter-file=src/testing/buildbot/filters/cast-linux.content_browsertests.filter"
+          "--test-launcher-filter-file=../../testing/buildbot/filters/cast-linux.content_browsertests.filter"
         ],
         "swarming": {
-          "can_use_on_swarming_builders": false
+          "can_use_on_swarming_builders": true
         },
         "test": "content_browsertests"
       },
@@ -1441,7 +1441,7 @@
       },
       {
         "swarming": {
-          "can_use_on_swarming_builders": false
+          "can_use_on_swarming_builders": true
         },
         "test": "traffic_annotation_auditor_unittests"
       },
@@ -2288,6 +2288,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -2980,6 +2986,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index 0efd5c4..c3b058f 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -438,6 +438,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -1032,6 +1038,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -2047,6 +2059,18 @@
             }
           ]
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "gpu": "8086:0a2e",
+              "os": "Mac-10.12.6"
+            }
+          ]
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -2739,6 +2763,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -3328,6 +3358,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index ceb651c..b91b408 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -4746,6 +4746,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -5351,6 +5357,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -7067,6 +7079,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index 67f867b..6400d98 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -582,6 +582,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -1312,6 +1318,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -1905,6 +1917,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -1917,6 +1935,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "unit_tests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "url_unittests"
       },
       {
@@ -2013,6 +2037,17 @@
         }
       },
       {
+        "args": [
+          "--jobs=1"
+        ],
+        "isolate_name": "telemetry_unittests",
+        "name": "telemetry_unittests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "shards": 4
+        }
+      },
+      {
         "isolate_name": "views_perftests",
         "name": "views_perftests",
         "swarming": {
@@ -2600,6 +2635,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
@@ -3355,6 +3396,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "traffic_annotation_auditor_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "ui_base_unittests"
       },
       {
diff --git a/testing/buildbot/client.v8.chromium.json b/testing/buildbot/client.v8.chromium.json
index 01eff36..34e9c2eb 100644
--- a/testing/buildbot/client.v8.chromium.json
+++ b/testing/buildbot/client.v8.chromium.json
@@ -392,6 +392,12 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         },
+        "test": "gin_unittests"
+      },
+      {
+        "swarming": {
+          "can_use_on_swarming_builders": true
+        },
         "test": "google_apis_unittests"
       },
       {
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index fd8926df..dcdc2c20 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -39,7 +39,6 @@
   },
   'angle_perftests': {
     'remove_from': [
-      'Android FYI Release (Nexus 5)',  # crbug.com/860800
       'Android FYI Release (Nexus 6)',  # anglebug.com/2433
     ],
   },
@@ -380,19 +379,13 @@
       # chromium.linux
       'Cast Audio Linux': {
         'args': [
-          '--test-launcher-filter-file=src/testing/buildbot/filters/cast-linux.content_browsertests.filter',
+          '--test-launcher-filter-file=../../testing/buildbot/filters/cast-linux.content_browsertests.filter',
         ],
-        'swarming': {
-          'can_use_on_swarming_builders': False,  # https://crbug.com/861843
-        },
       },
       'Cast Linux': {
         'args': [
-          '--test-launcher-filter-file=src/testing/buildbot/filters/cast-linux.content_browsertests.filter',
+          '--test-launcher-filter-file=../../testing/buildbot/filters/cast-linux.content_browsertests.filter',
         ],
-        'swarming': {
-          'can_use_on_swarming_builders': False,  # https://crbug.com/861843
-        },
       },
       # chromium.memory
       'Linux ASan LSan Tests (1)': {
@@ -476,8 +469,6 @@
       # chromium.memory
       'Linux ASan LSan Tests (1)',  # https://crbug.com/831667
       'Linux Chromium OS ASan LSan Tests (1)',  # https://crbug.com/831667
-      # client.v8.chromium
-      'Linux - Future (dbg)',
     ],
   },
   'gl_tests': {
@@ -1196,35 +1187,7 @@
       'Win10 Tests x64 (dbg)',
     ],
   },
-  'telemetry_unittests': {
-    'remove_from': [
-      # chromium.win
-      'Win10 Tests x64 (dbg)',
-    ],
-  },
-  'traffic_annotation_auditor_unittests': {
-    'modifications': {
-      'Linux Tests': {
-        # Unclear why this isn't swarmed.
-        'swarming': {
-          'can_use_on_swarming_builders': False,
-        },
-      },
-    },
-    'remove_from': [
-      # On chromium.linux, unclear why these only run on "Linux Tests".
-      'Linux Tests (dbg)(1)',
-      'Linux Tests (dbg)(1)(32)',
-    ],
-  },
   'unit_tests': {
-    'remove_from': [
-      # On chromium.linux, unclear why these aren't run on Cast.
-      'Cast Audio Linux',
-      'Cast Linux',
-      # chromium.win
-      'Win10 Tests x64 (dbg)',
-    ],
     'modifications': {
       # chromium.clang
       'ToTLinuxASan': {
diff --git a/testing/buildbot/test_suites.pyl b/testing/buildbot/test_suites.pyl
index f149b74..cde53db2 100644
--- a/testing/buildbot/test_suites.pyl
+++ b/testing/buildbot/test_suites.pyl
@@ -547,12 +547,6 @@
     'storage_unittests': {},
     'ui_base_unittests': {},
     'ui_touch_selection_unittests': {},
-    'unit_tests': {
-      'android_swarming': {
-        'hard_timeout': 900,
-        'shards': 5,
-      },
-    },
     'url_unittests': {},
     'webkit_unit_tests': {},
     'wtf_unittests': {},
@@ -571,6 +565,12 @@
         'hard_timeout': 900,
       },
     },
+    'unit_tests': {
+      'android_swarming': {
+        'hard_timeout': 900,
+        'shards': 5,
+      },
+    },
     'viz_unittests': {},
   },
 
@@ -1821,12 +1821,6 @@
     'sandbox_linux_unittests': {},
   },
 
-  'linux_specific_chromium_gtests': {
-    # Linux only.
-    # TODO(kbr): unclear why some of these aren't run more broadly.
-    'traffic_annotation_auditor_unittests': {},
-  },
-
   'linux_specific_chromium_isolated_scripts': {
     'devtools_closure_compile': {},
     'devtools_eslint': {},
@@ -1871,7 +1865,7 @@
     'accessibility_unittests': {},
     'app_shell_unittests': {},
     'blink_fuzzer_unittests': {},
-    'browser_tests': {
+    'browser_tests': {  # https://crbug.com/611756
       'swarming': {
         'shards': 10,
       },
@@ -1894,9 +1888,10 @@
     'ppapi_unittests': {},
     'printing_unittests': {},
     'remoting_unittests': {},
-    'service_manager_unittests': {}, # crbug.com/843134
+    'service_manager_unittests': {}, # https://crbug.com/843134
     'snapshot_unittests': {},
     'sync_integration_tests': {},
+    'traffic_annotation_auditor_unittests': {},
     'views_unittests': {},
     # TODO(thakis): When they work on Android, move viz_ tests to
     # chromium_gtests_for_devices_with_graphical_output.
@@ -2051,89 +2046,6 @@
     },
   },
 
-  'site_isolation_win_fyi_gtests': {
-    # TODO(kbr): most of the tests on this bot have different names
-    # than the other site isolation bots, so we can't simply reuse the
-    # site_isolation_chromium_gtests test suite. These should be
-    # unified.
-    'app_shell_unittests': {
-      'args': [
-        '--site-per-process',
-      ],
-    },
-    'browser_tests': {
-      'args': [
-        '--site-per-process'
-      ],
-      'swarming': {
-        'shards': 10,
-      },
-    },
-    'components_browsertests': {
-      'args': [
-        '--site-per-process',
-      ],
-    },
-    'components_unittests': {
-      'args': [
-        '--site-per-process',
-      ],
-    },
-    'content_browsertests': {
-      'args': [
-        '--site-per-process',
-        '--test-launcher-filter-file=../../testing/buildbot/filters/site-per-process.content_browsertests.filter',
-      ],
-    },
-    'content_unittests': {
-      'args': [
-        '--site-per-process',
-      ],
-    },
-    'extensions_browsertests': {
-      'args': [
-        '--site-per-process',
-      ],
-    },
-    'extensions_unittests': {
-      'args': [
-        '--site-per-process',
-      ],
-    },
-    'interactive_ui_tests': {
-      'args': [
-        '--site-per-process',
-      ],
-    },
-    'installer_util_unittests': {
-      'args': [
-        '--site-per-process',
-      ],
-      'swarming': {
-        'dimension_sets': [
-          {
-            'integrity': 'high',
-          }
-        ],
-      },
-    },
-    'nacl_loader_unittests': {
-      'args': [
-        '--site-per-process',
-      ],
-    },
-    'sync_integration_tests': {
-      'args': [
-        '--site-per-process',
-      ],
-    },
-    'unit_tests': {
-      'args': [
-        '--site-per-process',
-      ],
-    },
-  },
-
   'system_webview_shell_instrumentation_tests': {
     'system_webview_shell_layout_test_apk': {},
   },
@@ -2379,7 +2291,6 @@
     'chromium_gtests_for_devices_with_graphical_output',
     'chromium_gtests_for_linux_and_chromeos_only',
     'linux_flavor_specific_chromium_gtests',
-    'linux_specific_chromium_gtests',
     'network_service_gtests',
     'non_android_chromium_gtests',
     'non_android_and_cast_and_chromeos_chromium_gtests',
@@ -2395,7 +2306,6 @@
     'chromium_gtests_for_devices_with_graphical_output',
     'chromium_gtests_for_linux_and_chromeos_only',
     'linux_flavor_specific_chromium_gtests',
-    'linux_specific_chromium_gtests',
     'network_service_gtests',
     'non_android_chromium_gtests',
     'non_android_and_cast_and_chromeos_chromium_gtests',
@@ -2407,7 +2317,6 @@
   'linux_chromeos_gtests': [
     # This is:
     #   linux_chromium_gtests
-    #   - linux_specific_chromium_gtests
     #   - non_android_and_cast_and_chromeos_chromium_gtests
     #   + linux_chromeos_specific_gtests
     #   + mash_chromium_gtests
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 6052771..4863adb 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -2490,24 +2490,6 @@
           'gtest_tests': 'site_isolation_android_fyi_gtests',
         },
       },
-      'Site Isolation Linux': {
-        # TODO(lukasza, dpranke): Remove this bot once site-per-process has
-        # been turned on by default for a while (e.g. once
-        # https://crrev.com/c/981019 "sticks").
-        # base_unittests is a placeholder
-        # to keep the builder from building "all".
-        'additional_compile_targets': [
-          'base_unittests',
-        ],
-      },
-      'Site Isolation Win': {
-        # TODO(lukasza, dpranke): Remove this bot once site-per-process has
-        # been turned on by default for a while (e.g. once
-        # https://crrev.com/c/981019 "sticks").
-        'test_suites': {
-          'gtest_tests': 'site_isolation_win_fyi_gtests',
-        },
-      },
       'VR Linux': {
         'additional_compile_targets': [
           'vr_common_perftests',
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index ca8c5dd..979f0cea 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -104,6 +104,7 @@
 crbug.com/591099 external/wpt/WebCryptoAPI/generateKey/successes.worker.html [ Timeout ]
 crbug.com/591099 external/wpt/WebCryptoAPI/import_export/rsa_importKey.worker.html [ Timeout ]
 crbug.com/709227 external/wpt/WebCryptoAPI/import_export/symmetric_importKey.worker.html [ Failure ]
+crbug.com/591099 external/wpt/css/CSS2/floats/floats-line-wrap-shifted-001.html [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-empty-001.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-empty-004.xht [ Pass ]
 crbug.com/591099 external/wpt/css/CSS2/normal-flow/block-in-inline-insert-001e.xht [ Pass ]
@@ -531,7 +532,6 @@
 crbug.com/714962 fast/css/focus-ring-recursive-continuations.html [ Failure ]
 crbug.com/714962 fast/css/focus-ring-recursive-inlines.html [ Failure ]
 crbug.com/591099 fast/css/getComputedStyle/computed-style-percentage-top-with-position-inline.html [ Failure ]
-crbug.com/591099 fast/css/negative-text-indent-in-inline-block.html [ Failure ]
 crbug.com/591099 fast/css/outline-narrowLine.html [ Failure ]
 crbug.com/591099 fast/css/transform-inline-style-remove.html [ Failure ]
 crbug.com/591099 fast/css3-text/css3-text-decoration/text-underline-position/text-underline-position-auto.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 74e385d..3db4991 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -172,6 +172,7 @@
 
 # ====== Layout team owned tests from here ======
 
+crbug.com/591099 external/wpt/css/CSS2/floats/floats-line-wrap-shifted-001.html [ Failure ]
 crbug.com/711704 external/wpt/css/CSS2/floats/floats-rule3-outside-left-002.xht [ Failure ]
 crbug.com/711704 external/wpt/css/CSS2/floats/floats-rule3-outside-right-002.xht [ Failure ]
 crbug.com/711704 external/wpt/css/CSS2/floats/floats-rule7-outside-left-001.xht [ Failure ]
@@ -2561,9 +2562,7 @@
 crbug.com/704259 external/wpt/content-security-policy/reporting/reporting-api-report-to-overrides-report-uri-2.https.sub.html [ Skip ]
 crbug.com/704259 external/wpt/content-security-policy/reporting/reporting-api-sends-reports-on-violation.https.sub.html [ Skip ]
 
-# These HTTP tests that started failing after a web-platform-tests import.
-crbug.com/711529 http/tests/permissions/test-api-surface.html [ Timeout ]
-crbug.com/711529 http/tests/permissions/test-query.html [ Timeout ]
+crbug.com/863896 http/tests/permissions/test-query.html [ Timeout ]
 
 # This test requires enabling the flag CustomUserTiming in a virtual test.
 crbug.com/758385 http/tests/performance-timing/custom-user-timing/po-customusertiming-mark.html [ Skip ]
@@ -3456,9 +3455,6 @@
 crbug.com/636055 external/wpt/css/css-multicol/multicol-span-all-margin-nested-002.xht [ Failure ]
 crbug.com/792446 external/wpt/css/css-multicol/multicol-span-float-001.xht [ Failure ]
 
-crbug.com/796668 external/wpt/longtask-timing/longtask-in-sibling-iframe.html [ Pass Timeout ]
-crbug.com/796668 external/wpt/longtask-timing/longtask-in-sibling-iframe-crossorigin.html [ Pass Timeout ]
-
 # This test times out on debug builds, see https://crbug.com/755810
 crbug.com/626703 [ Debug ] external/wpt/html/semantics/tabular-data/processing-model-1/span-limits.html [ Skip ]
 
@@ -3687,7 +3683,7 @@
 crbug.com/709227 external/wpt/user-timing/invoke_with_timing_attributes.worker.html [ Failure ]
 
 # Crashes
-crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.pattern.basic.nocontext.worker.html [ Crash ]
+crbug.com/709227 external/wpt/offscreen-canvas/fill-and-stroke-styles/2d.pattern.basic.nocontext.worker.html [ Crash Pass ]
 
 # ====== Tests from enabling .any.js/.worker.js tests end here ========
 
@@ -3712,8 +3708,6 @@
 crbug.com/810254 [ Win7 ] storage/indexeddb/observer-workers.html [ Pass Timeout ]
 
 crbug.com/678346 [ Win7 Debug ] storage/indexeddb/mozilla/test_objectStore_openKeyCursor.html [ Pass Timeout ]
-# Temporarily disabled due to conflicting NeedsManualRebaseline below
-# crbug.com/678346 [ Win7 Debug ] storage/indexeddb/structured-clone.html [ Pass Timeout ]
 
 crbug.com/678493 http/tests/permissions/chromium/test-request-window.html [ Timeout Pass ]
 crbug.com/678499 http/tests/security/contentSecurityPolicy/require-sri-for/require-sri-for-script-preload-allowed.php [ Failure Pass ]
@@ -4397,8 +4391,6 @@
 crbug.com/826936 external/wpt/webauthn/getcredential-passing.https.html [ Pass Timeout ]
 crbug.com/826936 external/wpt/webauthn/getcredential-timeout.https.html [ Pass Timeout ]
 crbug.com/826936 external/wpt/webauthn/createcredential-pubkeycredparams.https.html [ Pass Timeout ]
-crbug.com/826936 http/tests/credentialmanager/credentialscontainer-get-from-nested-frame.html [ Pass Timeout ]
-crbug.com/826936 http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html [ Pass Timeout ]
 
 # WebRTC with Unified Plan
 crbug.com/828866 virtual/webrtc-wpt-unified-plan/external/wpt/webrtc/RTCPeerConnection-setRemoteDescription-tracks.https.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
index 78158f78e..b960978 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST.json
@@ -158410,6 +158410,11 @@
      {}
     ]
    ],
+   "interfaces/geolocation-API.idl": [
+    [
+     {}
+    ]
+   ],
    "interfaces/geolocation-sensor.idl": [
     [
      {}
@@ -212481,9 +212486,9 @@
      {}
     ]
    ],
-   "geolocation-API/interfaces.html": [
+   "geolocation-API/idlharness.window.js": [
     [
-     "/geolocation-API/interfaces.html",
+     "/geolocation-API/idlharness.window.html",
      {}
     ]
    ],
@@ -356678,8 +356683,8 @@
    "aabbc7b2d392e2bbc26c08262bae4d57348da7a2",
    "testharness"
   ],
-  "geolocation-API/interfaces.html": [
-   "c5e300b504b6bf75818fbe79728c87b086ccce3d",
+  "geolocation-API/idlharness.window.js": [
+   "9ac60d18abcfe72209d493d4046d86b7605f1760",
    "testharness"
   ],
   "geolocation-API/support.js": [
@@ -377570,6 +377575,10 @@
    "b926fccfdfec89604ca6c582b0826c20c4b815d3",
    "support"
   ],
+  "interfaces/geolocation-API.idl": [
+   "87be830712d8d40ec01b200935a41422e72ab7c4",
+   "support"
+  ],
   "interfaces/geolocation-sensor.idl": [
    "28bc4d15ea571290fe9e48e7c136bc3684e08660",
    "support"
@@ -377667,7 +377676,7 @@
    "support"
   ],
   "interfaces/payment-request.idl": [
-   "cd78318a2e40a56c9b3233b950ec666f3ca89828",
+   "1523f682dd32680417a5e45d9201743685549fe6",
    "support"
   ],
   "interfaces/performance-timeline.idl": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats/floats-line-wrap-shifted-001-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats/floats-line-wrap-shifted-001-ref.html
new file mode 100644
index 0000000..ab06bba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats/floats-line-wrap-shifted-001-ref.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<style>
+div {
+  font-size: 10px;
+  width: 12ch;
+  line-height: 1;
+  background: yellow;
+}
+.float {
+  width: 12ch;
+  height: 1em;
+  background: orange;
+}
+</style>
+
+<body>
+<div>
+  1111<br>
+  2222 3333
+  <div class="float"></div>
+</div>
+
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats/floats-line-wrap-shifted-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats/floats-line-wrap-shifted-001.html
new file mode 100644
index 0000000..c3f8a63
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/CSS2/floats/floats-line-wrap-shifted-001.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<link rel="author" title="Koji Ishii" href="kojii@chromium.org">
+<link rel="help" href="https://drafts.csswg.org/css2/visuren.html#float-position">
+<link rel="match" href="floats-line-wrap-shifted-001-ref.html">
+<meta name="flags" content="" />
+<meta name="assert" content="Float may not be higher than line-box containing a box generated by an element earlier in the source document." />
+
+<style>
+div {
+  font-size: 10px;
+  width: 12ch;
+  line-height: 1;
+  background: yellow;
+}
+.float {
+  float: left;
+  width: 12ch;
+  height: 1em;
+  background: orange;
+}
+</style>
+
+<body>
+<div>
+  1111
+  <nobr>
+    2222
+<!--
+  This float does not fit in the 1st line and thus shifted downward.
+-->
+    <div class="float"></div>
+<!--
+  The next word causes the 1st line to wrap.
+  The last break opportunity was before the float, and thus the float is also
+  wrapped to the next line.
+
+  According to the rule 6, the float should be below <nobr> box.
+  6. The outer top of an element's floating box may not be higher than the top
+     of any line-box containing a box generated by an element earlier in the
+     source document.
+-->
+    3333
+  </nobr>
+</div>
+</body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/geolocation-API/idlharness.window.js b/third_party/WebKit/LayoutTests/external/wpt/geolocation-API/idlharness.window.js
new file mode 100644
index 0000000..f8c92c1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/geolocation-API/idlharness.window.js
@@ -0,0 +1,18 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+// https://www.w3.org/TR/geolocation-API/
+
+promise_test(async () => {
+  const idl = await fetch('/interfaces/geolocation-API.idl').then(r => r.text());
+  const html = await fetch('/interfaces/html.idl').then(r => r.text());
+
+  const idl_array = new IdlArray();
+  idl_array.add_idls(idl);
+  idl_array.add_dependency_idls(html);
+  idl_array.add_objects({
+    Navigator: ["navigator"],
+    Geolocation: ["navigator.geolocation"]
+  });
+  idl_array.test();
+}, 'geolocation-API interfaces');
diff --git a/third_party/WebKit/LayoutTests/external/wpt/geolocation-API/interfaces.html b/third_party/WebKit/LayoutTests/external/wpt/geolocation-API/interfaces.html
deleted file mode 100644
index 0db42046..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/geolocation-API/interfaces.html
+++ /dev/null
@@ -1,95 +0,0 @@
-<!DOCTYPE html>
-<meta charset="utf-8">
-<title>Geolocation API IDL tests</title>
-<link rel="author" title="Intel" href="http://www.intel.com">
-<link rel="help" href="http://www.w3.org/TR/geolocation-API/">
-<script src="/resources/testharness.js"></script>
-<script src="/resources/testharnessreport.js"></script>
-<script src="/resources/WebIDLParser.js"></script>
-<script src="/resources/idlharness.js"></script>
-
-<h1>Geolocation API IDL tests</h1>
-<div id="log"></div>
-
-<script type=text/plain class=untested>
-interface Navigator {
-};
-
-typedef unsigned long long DOMTimeStamp;
-</script>
-
-<script type=text/plain>
-partial interface Navigator {
-  readonly attribute Geolocation geolocation;
-};
-
-[NoInterfaceObject]
-interface Geolocation {
-  void getCurrentPosition(PositionCallback successCallback,
-                          optional PositionErrorCallback errorCallback,
-                          optional PositionOptions options);
-
-  long watchPosition(PositionCallback successCallback,
-                     optional PositionErrorCallback errorCallback,
-                     optional PositionOptions options);
-
-  void clearWatch(long watchId);
-};
-
-callback PositionCallback = void (Position position);
-
-callback PositionErrorCallback = void (PositionError positionError);
-
-dictionary PositionOptions {
-  boolean enableHighAccuracy = false;
-  [Clamp] unsigned long timeout = 0xFFFFFFFF;
-  [Clamp] unsigned long maximumAge = 0;
-};
-
-[NoInterfaceObject]
-interface Position {
-  readonly attribute Coordinates coords;
-  readonly attribute DOMTimeStamp timestamp;
-};
-
-[NoInterfaceObject]
-interface Coordinates {
-  readonly attribute double latitude;
-  readonly attribute double longitude;
-  readonly attribute double? altitude;
-  readonly attribute double accuracy;
-  readonly attribute double? altitudeAccuracy;
-  readonly attribute double? heading;
-  readonly attribute double? speed;
-};
-
-[NoInterfaceObject]
-interface PositionError {
-  const unsigned short PERMISSION_DENIED = 1;
-  const unsigned short POSITION_UNAVAILABLE = 2;
-  const unsigned short TIMEOUT = 3;
-  readonly attribute unsigned short code;
-  readonly attribute DOMString message;
-};
-</script>
-
-<script>
-"use strict";
-var idlArray;
-setup(function() {
-  idlArray = new IdlArray();
-  [].forEach.call(document.querySelectorAll("script[type=text\\/plain]"), function(node) {
-    if (node.className == "untested") {
-      idlArray.add_untested_idls(node.textContent);
-    } else {
-      idlArray.add_idls(node.textContent);
-    }
-  });
-  idlArray.add_objects({
-    Navigator: ["navigator"],
-    Geolocation: ["navigator.geolocation"]
-  });
-});
-idlArray.test();
-</script>
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/geolocation-API.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/geolocation-API.idl
new file mode 100644
index 0000000..2972539e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/geolocation-API.idl
@@ -0,0 +1,59 @@
+// GENERATED CONTENT - DO NOT EDIT
+// Content of this file was automatically extracted from the
+// "Geolocation API Specification 2nd Edition" spec.
+// See: https://www.w3.org/TR/geolocation-API/
+
+partial interface Navigator {
+   readonly attribute Geolocation geolocation;
+ };
+
+
+ [NoInterfaceObject]
+ interface Geolocation {
+   void getCurrentPosition(PositionCallback successCallback,
+                           optional PositionErrorCallback errorCallback,
+                           optional PositionOptions options);
+
+   long watchPosition(PositionCallback successCallback,
+                      optional PositionErrorCallback errorCallback,
+                      optional PositionOptions options);
+
+   void clearWatch(long watchId);
+ };
+
+ callback PositionCallback = void (Position position);
+
+ callback PositionErrorCallback = void (PositionError positionError);
+
+  dictionary PositionOptions {
+    boolean enableHighAccuracy = false;
+    [Clamp] unsigned long timeout = 0xFFFFFFFF;
+    [Clamp] unsigned long maximumAge = 0;
+  };
+
+
+  [NoInterfaceObject]
+  interface Position {
+    readonly attribute Coordinates coords;
+    readonly attribute DOMTimeStamp timestamp;
+  };
+
+  [NoInterfaceObject]
+  interface Coordinates {
+    readonly attribute double latitude;
+    readonly attribute double longitude;
+    readonly attribute double? altitude;
+    readonly attribute double accuracy;
+    readonly attribute double? altitudeAccuracy;
+    readonly attribute double? heading;
+    readonly attribute double? speed;
+  };
+
+  [NoInterfaceObject]
+  interface PositionError {
+    const unsigned short PERMISSION_DENIED = 1;
+    const unsigned short POSITION_UNAVAILABLE = 2;
+    const unsigned short TIMEOUT = 3;
+    readonly attribute unsigned short code;
+    readonly attribute DOMString message;
+  };
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl
index 13a0672..6e42524 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/payment-request.idl
@@ -47,7 +47,7 @@
 dictionary PaymentDetailsUpdate : PaymentDetailsBase {
   DOMString error;
   PaymentItem total;
-  AddressErrorFields shippingAddressErrors;
+  AddressErrors shippingAddressErrors;
 };
 
 dictionary PaymentDetailsModifier {
@@ -115,7 +115,7 @@
   DOMString phone;
 };
 
-dictionary AddressErrorFields {
+dictionary AddressErrors {
   DOMString addressLine;
   DOMString city;
   DOMString country;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/webxr.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/webxr.idl
index 62f2622..ca6d3fc 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/interfaces/webxr.idl
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/webxr.idl
@@ -18,14 +18,14 @@
 };
 
 dictionary XRSessionCreationOptions {
-  boolean exclusive = false;
+  boolean immersive = false;
   XRPresentationContext outputContext;
 };
 
 [SecureContext, Exposed=Window] interface XRSession : EventTarget {
   // Attributes
   readonly attribute XRDevice device;
-  readonly attribute boolean exclusive;
+  readonly attribute boolean immersive;
   readonly attribute XRPresentationContext outputContext;
 
   attribute double depthNear;
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-attributes.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-attributes.html
index bd7e478a..6af90cd 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-attributes.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-attributes.html
@@ -44,10 +44,11 @@
     );
     observer.observe({entryTypes: ['longtask']});
 
-    /* Generate a slow task */
-    const begin = window.performance.now();
-    while (window.performance.now() < begin + 51);
-
+    window.onload = () => {
+        /* Generate a slow task */
+        const begin = window.performance.now();
+        while (window.performance.now() < begin + 60);
+    };
 }, 'Performance longtask entries are observable.');
 </script>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-childiframe-crossorigin.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-childiframe-crossorigin.html
index 58fa519..17b0fd2 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-childiframe-crossorigin.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-childiframe-crossorigin.html
@@ -45,13 +45,15 @@
         })
     );
     observer.observe({entryTypes: ['longtask']});
-    const iframe = document.createElement('iframe');
-    iframe.id = 'child-iframe-id';
-    iframe.name = 'child-iframe-name';
-    // Simulate cross-origin by using sandbox.
-    iframe.sandbox = "allow-scripts";
-    document.body.appendChild(iframe);
-    iframe.src = 'resources/subframe-with-longtask.html';
+    window.onload = () => {
+        const iframe = document.createElement('iframe');
+        iframe.id = 'child-iframe-id';
+        iframe.name = 'child-iframe-name';
+        // Simulate cross-origin by using sandbox.
+        iframe.sandbox = "allow-scripts";
+        document.body.appendChild(iframe);
+        iframe.src = 'resources/subframe-with-longtask.html';
+    };
 }, 'Performance longtask entries in cross-origin child iframe are observable in parent.');
 </script>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-childiframe.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-childiframe.html
index 536bd6e..b7137043 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-childiframe.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-childiframe.html
@@ -49,11 +49,13 @@
         })
     );
     observer.observe({entryTypes: ['longtask']});
-    const iframe = document.createElement('iframe');
-    iframe.id = 'child-iframe-id';
-    iframe.name = 'child-iframe-name';
-    document.body.appendChild(iframe);
-    iframe.src = 'resources/subframe-with-longtask.html';
+    window.onload = () => {
+        const iframe = document.createElement('iframe');
+        iframe.id = 'child-iframe-id';
+        iframe.name = 'child-iframe-name';
+        document.body.appendChild(iframe);
+        iframe.src = 'resources/subframe-with-longtask.html';
+    };
 }, 'Performance longtask entries in child iframe are observable in parent.');
 </script>
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-externalscript.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-externalscript.html
index a179198..51c58af 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-externalscript.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-externalscript.html
@@ -5,7 +5,6 @@
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="resources/makelongtask.js"></script>
 
 <h1>Long Task: External Script</h1>
 <div id="log"></div>
@@ -41,7 +40,11 @@
         })
     );
     observer.observe({entryTypes: ['longtask']});
+    window.onload = () => {
+        const script = document.createElement('script');
+        script.src = 'resources/makelongtask.js';
+        document.body.appendChild(script);
+    }
 }, 'Performance longtask entries are observable.');
 </script>
-
 </body>
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-parentiframe.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-parentiframe.html
index 379d051..2e7a9990 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-parentiframe.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-parentiframe.html
@@ -24,16 +24,16 @@
   }, 'Performance longtask entries in parent are observable in child iframe.');
 
   const iframe = document.createElement('iframe');
-  iframe.onload = function() {
-    t.step_timeout(function(){
-      const begin = window.performance.now();
-      while (window.performance.now() < begin + 51);
-    }, 50);
-  }
   iframe.id = 'child-iframe-id';
   iframe.name = 'child-iframe-name';
   document.body.appendChild(iframe);
   iframe.src = 'resources/subframe-observing-longtask.html';
+  iframe.onload = () => {
+    t.step_timeout( () => {
+      const begin = window.performance.now();
+      while (window.performance.now() < begin + 60);
+    }, 50);
+  };
 </script>
 
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-raf.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-raf.html
index 43885ab7..8a5a729 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-raf.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-raf.html
@@ -5,7 +5,6 @@
 
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
-<script src="resources/raflongtask.js"></script>
 
 <h1>Long Task: requestAnimationFrame</h1>
 <div id="log"></div>
@@ -41,7 +40,11 @@
         })
     );
     observer.observe({entryTypes: ['longtask']});
+    window.onload = () => {
+        const script = document.createElement('script');
+        script.src = 'resources/raflongtask.js';
+        document.body.appendChild(script);
+    };
 }, 'Performance longtask entries are observable.');
 </script>
-
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-sibling-iframe-crossorigin.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-sibling-iframe-crossorigin.html
index ec5d934..cfcc189 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-sibling-iframe-crossorigin.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-sibling-iframe-crossorigin.html
@@ -27,14 +27,16 @@
     document.body.appendChild(observingFrame);
     observingFrame.src = 'resources/subframe-observing-longtask.html'
 
-    /* Create a cross-origin iframe that generates a long task. */
-    const longtaskFrame = document.createElement('iframe');
-    longtaskFrame.id = 'longtask-iframe-id';
-    longtaskFrame.name = 'longtask-iframe-name';
-    // Simulate cross-origin by using sandbox.
-    longtaskFrame.sandbox = "allow-scripts";
-    document.body.appendChild(longtaskFrame);
-    longtaskFrame.src = 'resources/subframe-with-longtask.html'
+    observingFrame.onload = () => {
+      /* Create a cross-origin iframe that generates a long task. */
+      const longtaskFrame = document.createElement('iframe');
+      longtaskFrame.id = 'longtask-iframe-id';
+      longtaskFrame.name = 'longtask-iframe-name';
+      // Simulate cross-origin by using sandbox.
+      longtaskFrame.sandbox = "allow-scripts";
+      document.body.appendChild(longtaskFrame);
+      longtaskFrame.src = 'resources/subframe-with-longtask.html'
+    };
 }, 'Performance longtask entries from cross-origin iframe are observable in its sibling.');
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-sibling-iframe.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-sibling-iframe.html
index 9f584c7..e6041e4 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-sibling-iframe.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-in-sibling-iframe.html
@@ -27,11 +27,13 @@
     document.body.appendChild(observingFrame);
     observingFrame.src = 'resources/subframe-observing-longtask.html'
 
-    const longtaskFrame = document.createElement('iframe');
-    longtaskFrame.id = 'longtask-iframe-id';
-    longtaskFrame.name = 'longtask-iframe-name';
-    document.body.appendChild(longtaskFrame);
-    longtaskFrame.src = 'resources/subframe-with-longtask.html'
+    observingFrame.onload = () => {
+      const longtaskFrame = document.createElement('iframe');
+      longtaskFrame.id = 'longtask-iframe-id';
+      longtaskFrame.name = 'longtask-iframe-name';
+      document.body.appendChild(longtaskFrame);
+      longtaskFrame.src = 'resources/subframe-with-longtask.html'
+    };
 }, 'Performance longtask entries are observable in sibling iframe.');
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-tojson.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-tojson.html
index 63aba31..20a97a1 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-tojson.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/longtask-tojson.html
@@ -66,9 +66,11 @@
     );
     observer.observe({entryTypes: ['longtask']});
 
-    // Trigger a long task.
-    const begin = window.performance.now();
-    while (window.performance.now() < begin + 51);
+    window.onload = () => {
+        // Trigger a long task.
+        const begin = window.performance.now();
+        while (window.performance.now() < begin + 60);
+    };
   }, 'Test toJSON() in PerformanceLongTaskTiming and TaskAttributionTiming');
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/makelongtask.js b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/makelongtask.js
index d58b4f9..75de545 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/makelongtask.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/makelongtask.js
@@ -1,3 +1,3 @@
 /* Generate a slow task. */
 const begin = window.performance.now();
-while (window.performance.now() < begin + 51);
+while (window.performance.now() < begin + 60);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/raflongtask.js b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/raflongtask.js
index 95bfce1..ec39cb8 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/raflongtask.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/raflongtask.js
@@ -1,5 +1,5 @@
 window.requestAnimationFrame(function() {
   /* Generate a slow task. */
   const begin = window.performance.now();
-  while (window.performance.now() < begin + 51);
+  while (window.performance.now() < begin + 60);
 });
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/subframe-with-longtask.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/subframe-with-longtask.html
index 957d114..298b252d 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/subframe-with-longtask.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/resources/subframe-with-longtask.html
@@ -7,5 +7,5 @@
 
 <script>
     const begin = window.performance.now();
-    while (window.performance.now() < begin + 51);
+    while (window.performance.now() < begin + 60);
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/shared-renderer/longtask-in-new-window.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/shared-renderer/longtask-in-new-window.html
index 95d4cdf4..3a68d14 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/shared-renderer/longtask-in-new-window.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/shared-renderer/longtask-in-new-window.html
@@ -38,12 +38,14 @@
   );
   observer.observe({entryTypes: ['mark', 'longtask']});
 
-  // Open a window with a longtask.
-  const other_window = window.open('resources/frame-with-longtask.html');
-  window.addEventListener('message', t.step_func(e => {
-    // Do a mark (after the other window's longtask) to fire the callback.
-    self.performance.mark('mark1');
-  }));
+  window.onload = () => {
+    // Open a window with a longtask.
+    const other_window = window.open('resources/frame-with-longtask.html');
+    window.addEventListener('message', t.step_func(e => {
+      // Do a mark (after the other window's longtask) to fire the callback.
+      self.performance.mark('mark1');
+    }));
+  };
 }, 'A longtask in a frame from window.open is not reported in original frame');
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/shared-renderer/resources/frame-with-longtask.html b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/shared-renderer/resources/frame-with-longtask.html
index 72e525f0..9d0273e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/shared-renderer/resources/frame-with-longtask.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/longtask-timing/shared-renderer/resources/frame-with-longtask.html
@@ -8,7 +8,7 @@
 
 <script>
   const begin = window.performance.now();
-  while (window.performance.now() < begin + 51);
+  while (window.performance.now() < begin + 60);
   window.opener.postMessage('Finished.', '*');
 </script>
 </body>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/webxr/interfaces.https-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/webxr/interfaces.https-expected.txt
index 36cfae2..44bae2a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/webxr/interfaces.https-expected.txt
+++ b/third_party/WebKit/LayoutTests/external/wpt/webxr/interfaces.https-expected.txt
@@ -33,8 +33,8 @@
 PASS XRSession interface: existence and properties of interface prototype object's @@unscopables property
 PASS XRSession interface: attribute device
 PASS Unscopable handled correctly for device property on XRSession
-PASS XRSession interface: attribute exclusive
-PASS Unscopable handled correctly for exclusive property on XRSession
+PASS XRSession interface: attribute immersive
+PASS Unscopable handled correctly for immersive property on XRSession
 PASS XRSession interface: attribute outputContext
 PASS Unscopable handled correctly for outputContext property on XRSession
 PASS XRSession interface: attribute depthNear
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame.html
index 8a51dd13..acde25f3 100644
--- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame.html
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-from-nested-frame.html
@@ -120,9 +120,9 @@
   someOtherCredential.id = new TextEncoder().encode("someOtherCredential");
   delete customGetAssertionOptions.allowCredentials;
 
-  return promise_rejects(t, "NotSupportedError",
+  return promise_rejects(t, "InvalidStateError",
     navigator.credentials.get({ publicKey : customGetAssertionOptions}));
-}, "navigator.credentials.get() with empty allowCredentials returns NotSupportedError");
+}, "navigator.credentials.get() with empty allowCredentials returns InvalidStateError if the user has provided user presence");
 
 promise_test(t => {
   return navigator.credentials.test.clearAuthenticators();
diff --git a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html
index 949f6a76..58cec0d1 100644
--- a/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html
+++ b/third_party/WebKit/LayoutTests/http/tests/credentialmanager/credentialscontainer-get-with-virtual-authenticator.html
@@ -43,9 +43,9 @@
   someOtherCredential.id = new TextEncoder().encode("someOtherCredential");
   delete customGetAssertionOptions.allowCredentials;
 
-  return promise_rejects(t, "NotSupportedError",
+  return promise_rejects(t, "InvalidStateError",
     navigator.credentials.get({ publicKey : customGetAssertionOptions}));
-}, "navigator.credentials.get() with empty allowCredentials returns NotSupportedError");
+}, "navigator.credentials.get() with empty allowCredentials returns InvalidStateError if the user has provided user presence");
 
 promise_test(t => {
   return navigator.credentials.test.clearAuthenticators();
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index ff7e92f..4a3113cc 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -10019,7 +10019,7 @@
     getter depthNear
     getter device
     getter environmentBlendMode
-    getter exclusive
+    getter immersive
     getter onblur
     getter onend
     getter onfocus
diff --git a/third_party/WebKit/LayoutTests/xr/ar_hittest-expected.txt b/third_party/WebKit/LayoutTests/xr/ar_hittest-expected.txt
index 4a6c0c54..f585c1c7 100644
--- a/third_party/WebKit/LayoutTests/xr/ar_hittest-expected.txt
+++ b/third_party/WebKit/LayoutTests/xr/ar_hittest-expected.txt
@@ -1,4 +1,4 @@
 This is a testharness.js-based test.
-FAIL Ensures hit-test returns expected mock results promise_test: Unhandled rejection with value: "Test failed while running with the following options:\n                            { exclusive: false, outputContext: [object XRPresentationContext] } NotSupportedError: The specified session configuration is not supported."
+FAIL Ensures hit-test returns expected mock results promise_test: Unhandled rejection with value: "Test failed while running with the following options:\n                            { immersive: false, outputContext: [object XRPresentationContext] } NotSupportedError: The specified session configuration is not supported."
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/xr/ar_hittest.html b/third_party/WebKit/LayoutTests/xr/ar_hittest.html
index 2cdb073c..a0734aa 100644
--- a/third_party/WebKit/LayoutTests/xr/ar_hittest.html
+++ b/third_party/WebKit/LayoutTests/xr/ar_hittest.html
@@ -12,7 +12,7 @@
 let fakeDevices = fakeXRDevices();
 
 xr_session_promise_test((session, t) => {
-  assert_false(session.exclusive);
+  assert_false(session.immersive);
   return session.requestFrameOfReference("eye-level").then((frameOfReference) => {
     let direction = new Float32Array([1.0, 0.0, 0.0]);
     let origin = new Float32Array([0.0, 0.0, 0.0]);
@@ -40,7 +40,7 @@
           }
         });
     });
-  }, fakeDevices["FakeARPhone"], [ { exclusive: false, outputContext: getOutputContext() } ],
+  }, fakeDevices["FakeARPhone"], [ { immersive: false, outputContext: getOutputContext() } ],
 "Ensures hit-test returns expected mock results");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/events_session_end.html b/third_party/WebKit/LayoutTests/xr/events_session_end.html
index acf93636..853196a8 100644
--- a/third_party/WebKit/LayoutTests/xr/events_session_end.html
+++ b/third_party/WebKit/LayoutTests/xr/events_session_end.html
@@ -27,7 +27,7 @@
 
   return eventPromise;
 }, fakeDevices["FakeGooglePixelPhone"], [
-      { exclusive: true },
+      { immersive: true },
       { outputContext: getOutputContext() }
   ],
 "Test end fires when session ends");
diff --git a/third_party/WebKit/LayoutTests/xr/events_session_resetpose.html b/third_party/WebKit/LayoutTests/xr/events_session_resetpose.html
index 1c016e4..bb62e6e3 100644
--- a/third_party/WebKit/LayoutTests/xr/events_session_resetpose.html
+++ b/third_party/WebKit/LayoutTests/xr/events_session_resetpose.html
@@ -39,7 +39,7 @@
     return eventPromise;
   }, fakeDevices["FakeGooglePixelPhone"], [
     { outputContext: getOutputContext() },
-    { exclusive: true },
+    { immersive: true },
   ],
 "XRSession resetpose from a device properly fires off the right events");
 
diff --git a/third_party/WebKit/LayoutTests/xr/events_session_select.html b/third_party/WebKit/LayoutTests/xr/events_session_select.html
index 5874cc6e..b6fe9c70 100644
--- a/third_party/WebKit/LayoutTests/xr/events_session_select.html
+++ b/third_party/WebKit/LayoutTests/xr/events_session_select.html
@@ -68,7 +68,7 @@
     });
 
     return eventPromise;
-  }, fakeDevices["FakeGooglePixelPhone"], [ { exclusive: true } ],
+  }, fakeDevices["FakeGooglePixelPhone"], [ { immersive: true } ],
 "XRInputSources primary input presses properly fires off the right events");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/events_session_select_subframe.html b/third_party/WebKit/LayoutTests/xr/events_session_select_subframe.html
index ae4093fab..1afa558 100644
--- a/third_party/WebKit/LayoutTests/xr/events_session_select_subframe.html
+++ b/third_party/WebKit/LayoutTests/xr/events_session_select_subframe.html
@@ -65,7 +65,7 @@
     });
 
     return eventPromise;
-  }, fakeDevices["FakeGooglePixelPhone"], [ { exclusive: true } ],
+  }, fakeDevices["FakeGooglePixelPhone"], [ { immersive: true } ],
 "Ensures that an XRInputSources primary input being pressed and released in the space of a single frame properly fires off the right events");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_called.html b/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_called.html
index 24bfd31..341a0318 100644
--- a/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_called.html
+++ b/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_called.html
@@ -22,7 +22,7 @@
 
     session.requestAnimationFrame(onFrame);
   }), fakeDevices["FakeGooglePixelPhone"], [
-      { exclusive: true },
+      { immersive: true },
       { outputContext: getOutputContext() }
   ],
 "XRSession requestAnimationFrame properly calls the provided callback");
diff --git a/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_invalidhandle.html b/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_invalidhandle.html
index edd902b..720e87f 100644
--- a/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_invalidhandle.html
+++ b/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_invalidhandle.html
@@ -37,7 +37,7 @@
   session.cancelAnimationFrame(0.5);
   session.cancelAnimationFrame(null);
 }), fakeDevices["FakeGooglePixelPhone"], [
-      { exclusive: true },
+      { immersive: true },
       { outputContext: getOutputContext() }
   ],
 "XRSession cancelAnimationFrame does not have unexpected behavior when given invalid handles");
diff --git a/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_nolayer.html b/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_nolayer.html
index dbe20a1..752985e 100644
--- a/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_nolayer.html
+++ b/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_nolayer.html
@@ -34,7 +34,7 @@
   assert_not_equals(goodHandle, 0);
 
 }), fakeDevices["FakeGooglePixelPhone"], [
-      { exclusive: true },
+      { immersive: true },
       { outputContext: getOutputContext() }
   ],
 "XRSession requestAnimationFrame must fail if the session has no baseLayer");
diff --git a/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_unregister.html b/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_unregister.html
index 130ca47..f46afb1 100644
--- a/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_unregister.html
+++ b/third_party/WebKit/LayoutTests/xr/exclusive_requestFrame_unregister.html
@@ -45,7 +45,7 @@
   session.requestAnimationFrame(onFrameGood);
   handle2 = session.requestAnimationFrame(onFrameBad);
 }), fakeDevices["FakeGooglePixelPhone"], [
-      { exclusive: true },
+      { immersive: true },
       { outputContext: getOutputContext() }
   ],
 "XRSession requestAnimationFrame callbacks can be unregistered with cancelAnimationFrame");
diff --git a/third_party/WebKit/LayoutTests/xr/getDevicePose_oneframeupdate.html b/third_party/WebKit/LayoutTests/xr/getDevicePose_oneframeupdate.html
index c5de3df..e394a76 100644
--- a/third_party/WebKit/LayoutTests/xr/getDevicePose_oneframeupdate.html
+++ b/third_party/WebKit/LayoutTests/xr/getDevicePose_oneframeupdate.html
@@ -55,7 +55,7 @@
       session.requestAnimationFrame(onFrame);
     }));
 }, fakeDevices["FakeGooglePixelPhone"], [
-      { exclusive: true },
+      { immersive: true },
       { outputContext: getOutputContext() }
   ],
 "XRFrame getDevicePose updates on the next frame");
diff --git a/third_party/WebKit/LayoutTests/xr/getInputPose_hand.html b/third_party/WebKit/LayoutTests/xr/getInputPose_hand.html
index 80f665e..c096ac7 100644
--- a/third_party/WebKit/LayoutTests/xr/getInputPose_hand.html
+++ b/third_party/WebKit/LayoutTests/xr/getInputPose_hand.html
@@ -82,7 +82,7 @@
       // Can only request input poses in an xr frame.
       session.requestAnimationFrame(CheckInvalidGrip);
     });
-  }), fakeDevices["FakeGooglePixelPhone"], [ { exclusive: true } ],
+  }), fakeDevices["FakeGooglePixelPhone"], [ { immersive: true } ],
 "XRInputSources with a pointer origin of 'hand' properly communicate their poses");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/resources/xr-device-mocking.js b/third_party/WebKit/LayoutTests/xr/resources/xr-device-mocking.js
index 476bffc4..2be7b2c 100644
--- a/third_party/WebKit/LayoutTests/xr/resources/xr-device-mocking.js
+++ b/third_party/WebKit/LayoutTests/xr/resources/xr-device-mocking.js
@@ -327,7 +327,7 @@
   supportsSession(options) {
     return Promise.resolve({
       supportsSession:
-          !options.exclusive || this.displayInfo_.capabilities.canPresent
+          !options.immersive || this.displayInfo_.capabilities.canPresent
     });
   };
 
diff --git a/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_no_gesture.html b/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_no_gesture.html
index a6f3bd5..7d717b11 100644
--- a/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_no_gesture.html
+++ b/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_no_gesture.html
@@ -13,6 +13,6 @@
 promise_test( (t) => {
   setFakeDevices([fakeDevices["FakeGooglePixelPhone"]]);
   return navigator.xr.requestDevice().then( (device) =>
-    promise_rejects(t, 'SecurityError', device.requestSession({ exclusive: true })));
-}, "requestSession with an exclusive session outside of a user gesture rejects");
+    promise_rejects(t, 'SecurityError', device.requestSession({ immersive: true })));
+}, "requestSession with an immersive session outside of a user gesture rejects");
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_supported.html b/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_supported.html
index f57ec3d6..4aeaeae3 100644
--- a/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_supported.html
+++ b/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_supported.html
@@ -13,6 +13,6 @@
 
 xr_session_promise_test( (session) => {
   assert_not_equals(session, null);
-}, fakeDevices["FakeGooglePixelPhone"], [{ exclusive: true }],
-"requestSession for an exclusive session with a user gesture resolves");
+}, fakeDevices["FakeGooglePixelPhone"], [{ immersive: true }],
+"requestSession for an immersive session with a user gesture resolves");
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_unsupported.html b/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_unsupported.html
index 79e1dc2..b1e98b7 100644
--- a/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_unsupported.html
+++ b/third_party/WebKit/LayoutTests/xr/xrDevice_requestSession_exclusive_unsupported.html
@@ -19,10 +19,10 @@
         resolve(promise_rejects(
           t,
           "NotAllowedError",
-          magicWindowOnlyDevice.requestSession({ exclusive: true })
+          magicWindowOnlyDevice.requestSession({ immersive: true })
         ))
       });
     }));
-}, "requesting an exclusive session on an unsupported device rejects");
+}, "requesting an immersive session on an unsupported device rejects");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_exclusive_rejects.html b/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_exclusive_rejects.html
index 25f762eb..9e9ef8d 100644
--- a/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_exclusive_rejects.html
+++ b/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_exclusive_rejects.html
@@ -15,9 +15,9 @@
     return promise_rejects(
       t,
       "NotSupportedError",
-      magicWindowOnlyDevice.supportsSession({ exclusive: true })
+      magicWindowOnlyDevice.supportsSession({ immersive: true })
     );
   });
-}, "supportsSession rejects when exclusive session is not supported on device");
+}, "supportsSession rejects when immersive session is not supported on device");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_exclusive_resolves.html b/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_exclusive_resolves.html
index 64923d7f..1f5b4587 100644
--- a/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_exclusive_resolves.html
+++ b/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_exclusive_resolves.html
@@ -12,7 +12,7 @@
 promise_test( () => {
   setFakeDevices([fakeDevices["FakeGooglePixelPhone"]]);
   return navigator.xr.requestDevice().then( (device) =>
-    device.supportsSession({ exclusive: true }));
-}, "supportsSession resolves when support exclusive session is supported on device");
+    device.supportsSession({ immersive: true }));
+}, "supportsSession resolves when support immersive session is supported on device");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_non_exclusive.html b/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_non_exclusive.html
index 035a521..a3e806b 100644
--- a/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_non_exclusive.html
+++ b/third_party/WebKit/LayoutTests/xr/xrDevice_supportsSession_non_exclusive.html
@@ -12,14 +12,14 @@
 promise_test( (t) => {
   setFakeDevices([fakeDevices["FakeGooglePixelPhone"]]);
   return navigator.xr.requestDevice().then( (device) => {
-    // Non-exclusive sessions without a outputContext should not be supported.
+    // Non-immersive sessions without a outputContext should not be supported.
     promise_rejects(t, 'NotSupportedError', device.supportsSession());
 
-    // Non-exclusive sessions with an outputContexted should be supported.
+    // Non-immersive sessions with an outputContexted should be supported.
     return device.supportsSession({
         outputContext: getOutputContext()
     });
   });
-}, "supportsSession properly identifies supported non-exclusive sessions");
+}, "supportsSession properly identifies supported non-immersive sessions");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrFrameOfReference_stage_updates.html b/third_party/WebKit/LayoutTests/xr/xrFrameOfReference_stage_updates.html
index 647f5e3..86de570 100644
--- a/third_party/WebKit/LayoutTests/xr/xrFrameOfReference_stage_updates.html
+++ b/third_party/WebKit/LayoutTests/xr/xrFrameOfReference_stage_updates.html
@@ -56,7 +56,7 @@
       session.requestAnimationFrame(onFirstFrame);
     }));
 }, fakeDevices["FakeGooglePixelPhone"], [
-      { exclusive: true },
+      { immersive: true },
       { outputContext: getOutputContext() }
   ],
 "'stage' XRFrameOfReference updates properly when the transform changes");
diff --git a/third_party/WebKit/LayoutTests/xr/xrInputSource_add_remove.html b/third_party/WebKit/LayoutTests/xr/xrInputSource_add_remove.html
index a496105b..2c74994e 100644
--- a/third_party/WebKit/LayoutTests/xr/xrInputSource_add_remove.html
+++ b/third_party/WebKit/LayoutTests/xr/xrInputSource_add_remove.html
@@ -68,7 +68,7 @@
         });
       });
     });
-  }), fakeDevices["FakeGooglePixelPhone"], [ { exclusive: true } ],
+  }), fakeDevices["FakeGooglePixelPhone"], [ { immersive: true } ],
 "XRInputSources can be properly added and removed from the session");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrSession_environmentBlendMode.html b/third_party/WebKit/LayoutTests/xr/xrSession_environmentBlendMode.html
index 6019e5b..217cfb9 100644
--- a/third_party/WebKit/LayoutTests/xr/xrSession_environmentBlendMode.html
+++ b/third_party/WebKit/LayoutTests/xr/xrSession_environmentBlendMode.html
@@ -16,7 +16,7 @@
     assert_equals(session.environmentBlendMode, 'opaque');
   });
 }, fakeDevices["FakeGooglePixelPhone"], [
-    { exclusive: true },
+    { immersive: true },
     { outputContext: getOutputContext() }
 ],
 "environmentBlendMode is correct for a VR device");
diff --git a/third_party/WebKit/LayoutTests/xr/xrSession_exclusive.html b/third_party/WebKit/LayoutTests/xr/xrSession_exclusive.html
index 858195b..bbd3ad00 100644
--- a/third_party/WebKit/LayoutTests/xr/xrSession_exclusive.html
+++ b/third_party/WebKit/LayoutTests/xr/xrSession_exclusive.html
@@ -15,14 +15,14 @@
   setFakeDevices([fakeDevices["FakeGooglePixelPhone"]]);
   return navigator.xr.requestDevice().then( (device) => new Promise((resolve) => {
     runWithUserGesture( () => {
-      resolve(device.requestSession({ exclusive: true }).then( (session) => {
-        assert_true(session.exclusive);
+      resolve(device.requestSession({ immersive: true }).then( (session) => {
+        assert_true(session.immersive);
         assert_equals(session.device, device);
         assert_approx_equals(session.depthNear, 0.1, FLOAT_EPSILON);
         assert_approx_equals(session.depthFar, 1000.0, FLOAT_EPSILON);
       }));
     });
   }));
-}, "supportsSession returns expected exclusive session");
+}, "supportsSession returns expected immersive session");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrSession_prevent_multiple_exclusive.html b/third_party/WebKit/LayoutTests/xr/xrSession_prevent_multiple_exclusive.html
index 7e45047..95ee719 100644
--- a/third_party/WebKit/LayoutTests/xr/xrSession_prevent_multiple_exclusive.html
+++ b/third_party/WebKit/LayoutTests/xr/xrSession_prevent_multiple_exclusive.html
@@ -15,22 +15,22 @@
   setFakeDevices([fakeDevices["FakeGooglePixelPhone"]]);
   return navigator.xr.requestDevice().then( (device) => new Promise((resolve) => {
     runWithUserGesture( () => {
-      resolve(device.requestSession({ exclusive: true })
+      resolve(device.requestSession({ immersive: true })
         .then( (session) => new Promise((resolve) => {
           runWithUserGesture( () => {
-            // Requesting a second exclusive session from a device that already
-            // has an active exclusive session should fail. Exclusive sessions
-            // are, well... exclusive!
+            // Requesting a second immersive session from a device that already
+            // has an active immersive session should fail. Immersive sessions
+            // are, well... immersive!
             resolve(promise_rejects(
               t,
               "InvalidStateError",
-              device.requestSession({ exclusive: true })
+              device.requestSession({ immersive: true })
             ).then( () => {
-                // End the exclusive session and try again. Now the exclusive
+                // End the immersive session and try again. Now the immersive
                 // session creation should succeed.
                 return session.end().then( () => new Promise((resolve) => {
                   runWithUserGesture( () => {
-                    resolve(device.requestSession({ exclusive: true }));
+                    resolve(device.requestSession({ immersive: true }));
                   });
                 }));
               }));
@@ -38,6 +38,6 @@
       })));
     });
   }));
-}, "requestSession prevents creation of multiple simultaneous exclusive sessions");
+}, "requestSession prevents creation of multiple simultaneous immersive sessions");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrSession_requestFrameOfReference.html b/third_party/WebKit/LayoutTests/xr/xrSession_requestFrameOfReference.html
index 438cf5b9..33627b4 100644
--- a/third_party/WebKit/LayoutTests/xr/xrSession_requestFrameOfReference.html
+++ b/third_party/WebKit/LayoutTests/xr/xrSession_requestFrameOfReference.html
@@ -34,7 +34,7 @@
       })
   ]));
 }, fakeDevices["FakeGooglePixelPhone"], [
-    { exclusive: true },
+    { immersive: true },
     { outputContext: getOutputContext() }
 ],
 "requestFrameOfReference returns the expected objects");
diff --git a/third_party/WebKit/LayoutTests/xr/xrView_match.html b/third_party/WebKit/LayoutTests/xr/xrView_match.html
index dbdca43..dd459fb 100644
--- a/third_party/WebKit/LayoutTests/xr/xrView_match.html
+++ b/third_party/WebKit/LayoutTests/xr/xrView_match.html
@@ -54,7 +54,7 @@
 
     session.requestAnimationFrame(onFrame);
   }));
-}, fakeDevices["FakeGooglePixelPhone"], [{ exclusive: true }],
+}, fakeDevices["FakeGooglePixelPhone"], [{ immersive: true }],
 "XRFrame contains the expected views");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrView_oneframeupdate.html b/third_party/WebKit/LayoutTests/xr/xrView_oneframeupdate.html
index 794ada6..130de587 100644
--- a/third_party/WebKit/LayoutTests/xr/xrView_oneframeupdate.html
+++ b/third_party/WebKit/LayoutTests/xr/xrView_oneframeupdate.html
@@ -62,7 +62,7 @@
 
       session.requestAnimationFrame(onFrame);
   }));
-}, fakeDevices["FakeGooglePixelPhone"], [{ exclusive: true }],
+}, fakeDevices["FakeGooglePixelPhone"], [{ immersive: true }],
 "XRView projection matrices update near and far depths on the next frame");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrViewport_valid.html b/third_party/WebKit/LayoutTests/xr/xrViewport_valid.html
index 55aabd0..d88f65f 100644
--- a/third_party/WebKit/LayoutTests/xr/xrViewport_valid.html
+++ b/third_party/WebKit/LayoutTests/xr/xrViewport_valid.html
@@ -65,7 +65,7 @@
       }
       session.requestAnimationFrame(onFrame);
   }));
-}, fakeDevices["FakeGooglePixelPhone"], [{ exclusive: true }],
+}, fakeDevices["FakeGooglePixelPhone"], [{ immersive: true }],
 "XRViewport attributes are valid");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_constructor.html b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_constructor.html
index 1de464b..907c8c4 100644
--- a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_constructor.html
+++ b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_constructor.html
@@ -45,7 +45,7 @@
 
   lose_context_ext.loseContext();
 
-}), fakeDevices["FakeGooglePixelPhone"], [{ exclusive: true }],
+}), fakeDevices["FakeGooglePixelPhone"], [{ immersive: true }],
 "Ensure a WebGL layer's framebuffer can only be drawn to inside a XR frame");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_dirty_framebuffer.html b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_dirty_framebuffer.html
index 018e9c3..843f0c5f 100644
--- a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_dirty_framebuffer.html
+++ b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_dirty_framebuffer.html
@@ -52,6 +52,6 @@
   }
 
   session.requestAnimationFrame(onSkipFrame);
-}), fakeDevices["FakeGooglePixelPhone"], [{ exclusive: true }],
+}), fakeDevices["FakeGooglePixelPhone"], [{ immersive: true }],
 "A frame should be submitted if the base layer was written to during requestAnimationFrame");
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_framebuffer_draw.html b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_framebuffer_draw.html
index 99ed8bfb..709e8dd 100644
--- a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_framebuffer_draw.html
+++ b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_framebuffer_draw.html
@@ -86,7 +86,7 @@
     resolve();
   });
 
-}), fakeDevices["FakeGooglePixelPhone"], [{ exclusive: true }],
+}), fakeDevices["FakeGooglePixelPhone"], [{ immersive: true }],
 "Ensure a WebGL layer's framebuffer can only be drawn to inside a XR frame");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_framebuffer_scale.html b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_framebuffer_scale.html
index e1bb9fe9..6800f9f7 100644
--- a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_framebuffer_scale.html
+++ b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_framebuffer_scale.html
@@ -50,6 +50,6 @@
   });
 
   resolve();
-}), fakeDevices["FakeGooglePixelPhone"], [{ exclusive: true }],
+}), fakeDevices["FakeGooglePixelPhone"], [{ immersive: true }],
 "Ensure framebuffer scaling works as expected.");
 </script>
diff --git a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_incompatible_device.html b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_incompatible_device.html
index f6e45bd8..e529071 100644
--- a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_incompatible_device.html
+++ b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_incompatible_device.html
@@ -16,7 +16,7 @@
   webglCanvasSetup();
   return navigator.xr.requestDevice().then( (device) => new Promise((resolve) => {
     runWithUserGesture( () => {
-      resolve(device.requestSession({ exclusive: true })
+      resolve(device.requestSession({ immersive: true })
         .then( (session) => new Promise((resolve) => {
           try {
             let webglLayer = new XRWebGLLayer(session, gl);
diff --git a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_opaque_framebuffer.html b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_opaque_framebuffer.html
index ae21e25..8f77b02 100644
--- a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_opaque_framebuffer.html
+++ b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_opaque_framebuffer.html
@@ -99,7 +99,7 @@
   });
 
 }), fakeDevices["FakeGooglePixelPhone"], [
-    { exclusive: true },
+    { immersive: true },
     { outputContext: getOutputContext() }
 ],
 "Ensure that the framebuffer given by the WebGL layer is opaque");
diff --git a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_viewport_scale.html b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_viewport_scale.html
index 57ddfc4..923690de 100644
--- a/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_viewport_scale.html
+++ b/third_party/WebKit/LayoutTests/xr/xrWebGLLayer_viewport_scale.html
@@ -69,6 +69,6 @@
   }
 
   session.requestAnimationFrame(onFirstFrame);
-}), fakeDevices["FakeGooglePixelPhone"], [{ exclusive: true }],
+}), fakeDevices["FakeGooglePixelPhone"], [{ immersive: true }],
 "Ensure viewport scale changes only take effect on the next frame and are properly clamped.");
 </script>
diff --git a/third_party/android_async_task/README.chromium b/third_party/android_async_task/README.chromium
index fe9823d3..eeadcefa 100644
--- a/third_party/android_async_task/README.chromium
+++ b/third_party/android_async_task/README.chromium
@@ -14,6 +14,8 @@
 - Switch to using android.support.annotations (from android.support.v13).
 - Added annotations to help it compile issue-free.
 - Changed THREAD_POOL_EXECUTOR to use our extension of Android's
-  ThreadPoolExecutor, shut down Android's ThreadPoolExecutor, and rerouted
-  runnables sent to Android's ThreadPoolExecutor to our extension.
+  ThreadPoolExecutor (which adds information about the work queue when it fills
+  up)
+- Added function which shuts down Android's ThreadPoolExecutor, and rerouted
+  runnables sent to Android's ThreadPoolExecutor to our Executor.
 - Changed SERIAL_EXECUTOR to reuse the executor from android.os.AsyncTask
diff --git a/third_party/android_async_task/java/src/org/chromium/base/AsyncTask.java b/third_party/android_async_task/java/src/org/chromium/base/AsyncTask.java
index 9a69d601..2d9c969 100644
--- a/third_party/android_async_task/java/src/org/chromium/base/AsyncTask.java
+++ b/third_party/android_async_task/java/src/org/chromium/base/AsyncTask.java
@@ -25,14 +25,18 @@
 import android.support.annotation.Nullable;
 import android.support.annotation.WorkerThread;
 
+import java.lang.reflect.Field;
 import java.util.ArrayDeque;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 import java.util.concurrent.FutureTask;
-import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.RejectedExecutionHandler;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
@@ -205,20 +209,12 @@
     };
 
     private static final BlockingQueue<Runnable> sPoolWorkQueue =
-            new LinkedBlockingQueue<Runnable>(128);
+            new ArrayBlockingQueue<Runnable>(128);
 
     /**
      * An {@link Executor} that can be used to execute tasks in parallel.
      */
-    public static final Executor THREAD_POOL_EXECUTOR;
-
-    static {
-        ThreadPoolExecutor threadPoolExecutor =
-                new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS,
-                        TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
-        threadPoolExecutor.allowCoreThreadTimeOut(true);
-        THREAD_POOL_EXECUTOR = threadPoolExecutor;
-    }
+    public static final Executor THREAD_POOL_EXECUTOR = new ChromeThreadPoolExecutor();
 
     /**
      * An {@link Executor} that executes tasks one at a time in serial
@@ -244,6 +240,87 @@
 
     private final Handler mHandler;
 
+    public static class ChromeThreadPoolExecutor extends ThreadPoolExecutor {
+        // May have to be lowered if we are not capturing any Runnable sources.
+        private static final int RUNNABLE_WARNING_COUNT = 32;
+
+        ChromeThreadPoolExecutor() {
+            this(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS,
+                    sPoolWorkQueue, sThreadFactory);
+        }
+
+        @VisibleForTesting
+        ChromeThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
+                TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
+            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
+            allowCoreThreadTimeOut(true);
+        }
+
+        private static String getClassName(Runnable runnable) {
+            Class blamedClass = runnable.getClass();
+            try {
+                if (blamedClass == AsyncTask.NamedFutureTask.class) {
+                    blamedClass = ((AsyncTask.NamedFutureTask) runnable).getBlamedClass();
+                } else if (blamedClass.getEnclosingClass() == android.os.AsyncTask.class) {
+                    // This gets the AsyncTask that produced the runnable.
+                    Field field = blamedClass.getDeclaredField("this$0");
+                    field.setAccessible(true);
+                    blamedClass = field.get(runnable).getClass();
+                }
+            } catch (NoSuchFieldException e) {
+                if (BuildConfig.DCHECK_IS_ON) {
+                    throw new RuntimeException(e);
+                }
+            } catch (IllegalAccessException e) {
+                if (BuildConfig.DCHECK_IS_ON) {
+                    throw new RuntimeException(e);
+                }
+            }
+            return blamedClass.getName();
+        }
+
+        private Map<String, Integer> getNumberOfClassNameOccurrencesInQueue() {
+            Map<String, Integer> counts = new HashMap<>();
+            Runnable[] copiedQueue = getQueue().toArray(new Runnable[0]);
+            for (Runnable runnable : copiedQueue) {
+                String className = getClassName(runnable);
+                int count = counts.containsKey(className) ? counts.get(className) : 0;
+                counts.put(className, count + 1);
+            }
+            return counts;
+        }
+
+        private String findClassNamesWithTooManyRunnables(Map<String, Integer> counts) {
+            // We only show the classes over RUNNABLE_WARNING_COUNT appearances so that these
+            // crashes group up together in the reporting dashboards. If we were to print all
+            // the Runnables or their counts, this would fragment the reporting, with one for
+            // each unique set of Runnables/counts.
+            StringBuilder classesWithTooManyRunnables = new StringBuilder();
+            for (Map.Entry<String, Integer> entry : counts.entrySet()) {
+                if (entry.getValue() > RUNNABLE_WARNING_COUNT) {
+                    classesWithTooManyRunnables.append(entry.getKey()).append(' ');
+                }
+            }
+            if (classesWithTooManyRunnables.length() == 0) {
+                return "NO CLASSES FOUND";
+            }
+            return classesWithTooManyRunnables.toString();
+        }
+
+        @Override
+        public void execute(Runnable command) {
+            try {
+                super.execute(command);
+            } catch (RejectedExecutionException e) {
+                Map<String, Integer> counts = getNumberOfClassNameOccurrencesInQueue();
+
+                throw new RejectedExecutionException("Prominent classes in AsyncTask: "
+                                + findClassNamesWithTooManyRunnables(counts),
+                        e);
+            }
+        }
+    }
+
     private static class SerialExecutor implements Executor {
         final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
         Runnable mActive;
@@ -368,21 +445,7 @@
             }
         };
 
-        mFuture = new FutureTask<Result>(mWorker) {
-            @Override
-            protected void done() {
-                try {
-                    postResultIfNotInvoked(get());
-                } catch (InterruptedException e) {
-                    android.util.Log.w(TAG, e);
-                } catch (ExecutionException e) {
-                    throw new RuntimeException(
-                            "An error occurred while executing doInBackground()", e.getCause());
-                } catch (CancellationException e) {
-                    postResultIfNotInvoked(null);
-                }
-            }
-        };
+        mFuture = new NamedFutureTask(mWorker);
     }
 
     private void postResultIfNotInvoked(Result result) {
@@ -750,6 +813,30 @@
         Params[] mParams;
     }
 
+    private class NamedFutureTask extends FutureTask<Result> {
+        NamedFutureTask(Callable<Result> c) {
+            super(c);
+        }
+
+        Class getBlamedClass() {
+            return AsyncTask.this.getClass();
+        }
+
+        @Override
+        protected void done() {
+            try {
+                postResultIfNotInvoked(get());
+            } catch (InterruptedException e) {
+                android.util.Log.w(TAG, e);
+            } catch (ExecutionException e) {
+                throw new RuntimeException(
+                        "An error occurred while executing doInBackground()", e.getCause());
+            } catch (CancellationException e) {
+                postResultIfNotInvoked(null);
+            }
+        }
+    }
+
     @SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
     private static class AsyncTaskResult<Data> {
         final AsyncTask mTask;
diff --git a/third_party/blink/renderer/core/dom/synchronous_mutation_notifier.cc b/third_party/blink/renderer/core/dom/synchronous_mutation_notifier.cc
index c2c71988..53e1eb05 100644
--- a/third_party/blink/renderer/core/dom/synchronous_mutation_notifier.cc
+++ b/third_party/blink/renderer/core/dom/synchronous_mutation_notifier.cc
@@ -46,7 +46,14 @@
     unsigned offset,
     unsigned old_length,
     unsigned new_length) {
-  ForEachObserver([&](SynchronousMutationObserver* observer) {
+  // Using ForEachObserverWithoutChecks() instead of ForEachObserver() is
+  // necessary because DocumentMarkerController::DidUpdateCharacterData ends up
+  // calling SynchronousMutationNotifier::RemoveObserver, which is unsafe and
+  // can result in memory corruption.
+  //
+  // TODO(crbug.com/862900): Fix DocumentMarkerController and switch to
+  //                         ForEachObsever() here.
+  ForEachObserverWithoutChecks([&](SynchronousMutationObserver* observer) {
     observer->DidUpdateCharacterData(character_data, offset, old_length,
                                      new_length);
   });
diff --git a/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc b/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
index 7299054f..1fb2fcf6 100644
--- a/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
+++ b/third_party/blink/renderer/core/editing/markers/document_marker_controller_test.cc
@@ -189,6 +189,30 @@
   EXPECT_EQ(0u, MarkerController().Markers().size());
 }
 
+// TODO(crbug.com/862900): Fix DocumentMarkerController::DidUpdateCharacterData
+//                         and enable this test.
+TEST_F(DocumentMarkerControllerTest,
+       DISABLED_SynchronousMutationNotificationAfterGC) {
+  SetBodyContent("<b><i>foo</i></b>");
+  Persistent<Text> sibling_text = CreateTextNode("bar");
+  {
+    Element* parent =
+        ToElement(GetDocument().body()->firstChild()->firstChild());
+    parent->parentNode()->AppendChild(sibling_text);
+    MarkNodeContents(parent);
+    EXPECT_EQ(1u, MarkerController().Markers().size());
+    parent->parentNode()->RemoveChild(parent);
+  }
+
+  // GC the marked node, so it disappears from WeakMember collections.
+  ThreadState::Current()->CollectAllGarbage();
+  EXPECT_EQ(0u, MarkerController().Markers().size());
+
+  // Trigger SynchronousMutationNotifier::NotifyUpdateCharacterData().
+  // This matches the conditions for the crashes in crbug.com/862960.
+  sibling_text->setData("baz");
+}
+
 TEST_F(DocumentMarkerControllerTest, UpdateRenderedRects) {
   SetBodyContent("<div style='margin: 100px'>foo</div>");
   Element* div = ToElement(GetDocument().body()->firstChild());
diff --git a/third_party/blink/renderer/core/events/pointer_event_factory.cc b/third_party/blink/renderer/core/events/pointer_event_factory.cc
index 64bfd19..f3e6855 100644
--- a/third_party/blink/renderer/core/events/pointer_event_factory.cc
+++ b/third_party/blink/renderer/core/events/pointer_event_factory.cc
@@ -192,14 +192,6 @@
   SetIdTypeButtons(pointer_event_init, web_pointer_event);
 
   AtomicString type = PointerEventNameForEventType(event_type);
-  // Make sure chorded buttons fire pointermove instead of pointerup/down.
-  if ((event_type == WebInputEvent::kPointerDown &&
-       (pointer_event_init.buttons() &
-        ~ButtonToButtonsBitfield(web_pointer_event.button)) != 0) ||
-      (event_type == WebInputEvent::kPointerUp &&
-       pointer_event_init.buttons() != 0))
-    type = EventTypeNames::pointermove;
-
   if (event_type == WebInputEvent::kPointerDown ||
       event_type == WebInputEvent::kPointerUp) {
     WebPointerProperties::Button button = web_pointer_event.button;
@@ -209,6 +201,14 @@
         button == WebPointerProperties::Button::kLeft)
       button = WebPointerProperties::Button::kEraser;
     pointer_event_init.setButton(static_cast<int>(button));
+
+    // Make sure chorded buttons fire pointermove instead of pointerup/down.
+    if ((event_type == WebInputEvent::kPointerDown &&
+         (pointer_event_init.buttons() & ~ButtonToButtonsBitfield(button)) !=
+             0) ||
+        (event_type == WebInputEvent::kPointerUp &&
+         pointer_event_init.buttons() != 0))
+      type = EventTypeNames::pointermove;
   } else {
     pointer_event_init.setButton(
         static_cast<int>(WebPointerProperties::Button::kNoButton));
diff --git a/third_party/blink/renderer/core/events/pointer_event_factory_test.cc b/third_party/blink/renderer/core/events/pointer_event_factory_test.cc
index 0fceeb9..0cea2c4 100644
--- a/third_party/blink/renderer/core/events/pointer_event_factory_test.cc
+++ b/third_party/blink/renderer/core/events/pointer_event_factory_test.cc
@@ -25,6 +25,7 @@
     case WebPointerProperties::PointerType::kTouch:
       return "touch";
     case WebPointerProperties::PointerType::kPen:
+    case WebPointerProperties::PointerType::kEraser:
       return "pen";
     case WebPointerProperties::PointerType::kMouse:
       return "mouse";
@@ -50,6 +51,8 @@
       bool hovering,
       WebInputEvent::Modifiers modifiers = WebInputEvent::kNoModifiers,
       WebInputEvent::Type type = WebInputEvent::kPointerDown,
+      WebPointerProperties::Button button =
+          WebPointerProperties::Button::kNoButton,
       size_t coalesced_event_count = 0) {
     WebPointerEvent web_pointer_event;
     web_pointer_event.pointer_type = pointer_type;
@@ -59,6 +62,7 @@
     web_pointer_event.SetModifiers(modifiers);
     web_pointer_event.force = 1.0;
     web_pointer_event.hovering = hovering;
+    web_pointer_event.button = button;
     Vector<WebPointerEvent> coalesced_events;
     for (size_t i = 0; i < coalesced_event_count; i++) {
       coalesced_events.push_back(web_pointer_event);
@@ -527,11 +531,47 @@
   CreateAndCheckWebPointerEvent(
       WebPointerProperties::PointerType::kMouse, 0, expected_mouse_id_,
       true /* isprimary */, true /* hovering */, WebInputEvent::kNoModifiers,
-      WebInputEvent::kPointerMove, 4);
+      WebInputEvent::kPointerMove, WebPointerProperties::Button::kNoButton, 4);
   CreateAndCheckWebPointerEvent(
       WebPointerProperties::PointerType::kTouch, 0, mapped_id_start_,
       true /* isprimary */, false /* hovering */, WebInputEvent::kNoModifiers,
-      WebInputEvent::kPointerMove, 3);
+      WebInputEvent::kPointerMove, WebPointerProperties::Button::kNoButton, 3);
+}
+
+TEST_F(PointerEventFactoryTest, PenEraserButton) {
+  // Send the pointerdown event when pressing the eraser button on the tablet.
+  PointerEvent* first_pointerdown_event = CreateAndCheckWebPointerEvent(
+      WebPointerProperties::PointerType::kEraser, 0, mapped_id_start_,
+      true /* isprimary */, false /* hovering */,
+      WebInputEvent::kLeftButtonDown, WebInputEvent::kPointerDown,
+      WebPointerProperties::Button::kLeft);
+  EXPECT_EQ(EventTypeNames::pointerdown, first_pointerdown_event->type());
+
+  // Send the pointermove event when pressing any other button while the eraser
+  // button is still pressed on the tablet.
+  WebInputEvent::Modifiers modifiers = static_cast<WebInputEvent::Modifiers>(
+      WebInputEvent::kLeftButtonDown | WebInputEvent::kRightButtonDown);
+  PointerEvent* second_pointerdown_event = CreateAndCheckWebPointerEvent(
+      WebPointerProperties::PointerType::kEraser, 1, mapped_id_start_ + 1,
+      false /* isprimary */, false /* hovering */, modifiers,
+      WebInputEvent::kPointerDown, WebPointerProperties::Button::kRight);
+  EXPECT_EQ(EventTypeNames::pointermove, second_pointerdown_event->type());
+
+  // Send the pointermove event when releasing any other button while the
+  // eraser button is still pressed on the tablet.
+  PointerEvent* first_pointerup_event = CreateAndCheckWebPointerEvent(
+      WebPointerProperties::PointerType::kEraser, 1, mapped_id_start_ + 1,
+      false /* isprimary */, true /* hovering */,
+      WebInputEvent::kLeftButtonDown, WebInputEvent::kPointerUp,
+      WebPointerProperties::Button::kRight);
+  EXPECT_EQ(EventTypeNames::pointermove, first_pointerup_event->type());
+
+  // Send the pointerup event when releasing the eraser button from the tablet.
+  PointerEvent* last_pointerup_event = CreateAndCheckWebPointerEvent(
+      WebPointerProperties::PointerType::kEraser, 0, mapped_id_start_,
+      true /* isprimary */, true /* hovering */, WebInputEvent::kNoModifiers,
+      WebInputEvent::kPointerUp, WebPointerProperties::Button::kLeft);
+  EXPECT_EQ(EventTypeNames::pointerup, last_pointerup_event->type());
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index 36dd07d3..f016403 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -673,6 +673,7 @@
   LayoutUnit result;
   LayoutUnit previous_floats_inline_size =
       input.float_left_inline_size + input.float_right_inline_size;
+  DCHECK_GE(previous_floats_inline_size, 0);
   while (!break_token || !break_token->IsFinished()) {
     unpositioned_floats.clear();
 
@@ -729,7 +730,10 @@
           floats_inline_size = LayoutUnit();
         }
 
-        floats_inline_size += child_sizes.max_size + child_inline_margins;
+        // When negative margins move the float outside the content area,
+        // such float should not affect the content size.
+        floats_inline_size +=
+            (child_sizes.max_size + child_inline_margins).ClampNegativeToZero();
         previous_float_type = float_style.Floating();
       }
     }
diff --git a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index ca837f4..05934ae6 100644
--- a/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -1077,25 +1077,46 @@
 }
 
 void NGLineBreaker::Rewind(NGLineInfo* line_info, unsigned new_end) {
-  NGInlineItemResults* item_results = &line_info->Results();
-  DCHECK_LT(new_end, item_results->size());
+  NGInlineItemResults& item_results = line_info->Results();
+  DCHECK_LT(new_end, item_results.size());
 
-  // TODO(ikilpatrick): Add DCHECK that we never rewind past any floats.
+  // Avoid rewinding floats if possible. They will be added back anyway while
+  // processing trailing items even when zero available width. Also this saves
+  // most cases where our support for rewinding positioned floats is not great
+  // yet (see below.)
+  while (item_results[new_end].item->Type() == NGInlineItem::kFloating) {
+    ++new_end;
+    if (new_end == item_results.size()) {
+      UpdatePosition(*line_info);
+      return;
+    }
+  }
 
   if (new_end) {
     // Use |results[new_end - 1].end_offset| because it may have been truncated
     // and may not be equal to |results[new_end].start_offset|.
-    MoveToNextOf((*item_results)[new_end - 1]);
+    MoveToNextOf(item_results[new_end - 1]);
   } else {
     // When rewinding all items, use |results[0].start_offset|.
-    const NGInlineItemResult& first_remove = (*item_results)[new_end];
+    const NGInlineItemResult& first_remove = item_results[new_end];
     item_index_ = first_remove.item_index;
     offset_ = first_remove.start_offset;
   }
 
-  // TODO(kojii): Should we keep results for the next line? We don't need to
-  // re-layout atomic inlines.
-  item_results->Shrink(new_end);
+  // Remove unpositioned floats that are to be rewound.
+  // Note, items before |handled_floats_end_item_index_| are inserted outside of
+  // the line breaker and that should not be removed when rewinding.
+  for (unsigned i = new_end; i < item_results.size(); i++) {
+    NGInlineItemResult& rewind = item_results[i];
+    if (rewind.item->Type() == NGInlineItem::kFloating) {
+      NGBlockNode float_node(ToLayoutBox(rewind.item->GetLayoutObject()));
+      RemoveUnpositionedFloat(unpositioned_floats_, float_node);
+      // TODO(kojii): Probably need to do something if this float was already
+      // positioned, but haven't got how to do this yet.
+    }
+  }
+
+  item_results.Shrink(new_end);
 
   SetLineEndFragment(nullptr, line_info);
   UpdatePosition(*line_info);
diff --git a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
index d4fb70ac..c6d40fe1 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
@@ -346,6 +346,10 @@
     Vector<scoped_refptr<NGUnpositionedFloat>>* unpositioned_floats,
     NGContainerFragmentBuilder* fragment_builder,
     scoped_refptr<NGUnpositionedFloat> unpositioned_float) {
+  // The same float node should not be added more than once.
+  DCHECK(
+      !RemoveUnpositionedFloat(unpositioned_floats, unpositioned_float->node));
+
   if (fragment_builder && !fragment_builder->BfcOffset()) {
     fragment_builder->AddAdjoiningFloatTypes(
         unpositioned_float->IsLeft() ? kFloatTypeLeft : kFloatTypeRight);
@@ -353,6 +357,19 @@
   unpositioned_floats->push_back(std::move(unpositioned_float));
 }
 
+bool RemoveUnpositionedFloat(
+    Vector<scoped_refptr<NGUnpositionedFloat>>* unpositioned_floats,
+    NGBlockNode float_node) {
+  for (scoped_refptr<NGUnpositionedFloat>& unpositioned_float :
+       *unpositioned_floats) {
+    if (unpositioned_float->node == float_node) {
+      unpositioned_floats->erase(&unpositioned_float);
+      return true;
+    }
+  }
+  return false;
+}
+
 NGFloatTypes ToFloatTypes(EClear clear) {
   switch (clear) {
     default:
diff --git a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
index 10973f66..ffd1b872 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
+++ b/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
@@ -13,6 +13,7 @@
 
 namespace blink {
 
+class NGBlockNode;
 class NGConstraintSpace;
 class NGContainerFragmentBuilder;
 class NGExclusionSpace;
@@ -59,6 +60,11 @@
     NGContainerFragmentBuilder* fragment_builder,
     scoped_refptr<NGUnpositionedFloat> unpositioned_float);
 
+// Remove a pending float from the list.
+bool RemoveUnpositionedFloat(
+    Vector<scoped_refptr<NGUnpositionedFloat>>* unpositioned_floats,
+    NGBlockNode float_node);
+
 NGFloatTypes ToFloatTypes(EClear clear);
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/gamepad/BUILD.gn b/third_party/blink/renderer/modules/gamepad/BUILD.gn
index a00b583..2545e1c 100644
--- a/third_party/blink/renderer/modules/gamepad/BUILD.gn
+++ b/third_party/blink/renderer/modules/gamepad/BUILD.gn
@@ -20,6 +20,8 @@
     "gamepad_list.h",
     "gamepad_pose.cc",
     "gamepad_pose.h",
+    "gamepad_shared_memory_reader.cc",
+    "gamepad_shared_memory_reader.h",
     "navigator_gamepad.cc",
     "navigator_gamepad.h",
   ]
diff --git a/third_party/blink/renderer/modules/gamepad/DEPS b/third_party/blink/renderer/modules/gamepad/DEPS
index d605f27..2fa9b457 100644
--- a/third_party/blink/renderer/modules/gamepad/DEPS
+++ b/third_party/blink/renderer/modules/gamepad/DEPS
@@ -1,15 +1,19 @@
 include_rules = [
+    "+device/base/synchronization/shared_memory_seqlock_buffer.h",
     # NOTE: These files are POD structs used to interpret shared memory across
     # the Device Gamepad implementation and the Blink client.
     "+device/gamepad/public/cpp/gamepad.h",
     "+device/gamepad/public/cpp/gamepads.h",
 
     "+device/gamepad/public/mojom/gamepad.mojom-blink.h",
-
+    "+device/gamepad/public/mojom/gamepad_hardware_buffer.h",
+    "+mojo/public/cpp/bindings/binding.h",
+    "+mojo/public/cpp/system/buffer.h",
     "-third_party/blink/renderer/modules",
     "+third_party/blink/renderer/modules/event_modules.h",
     "+third_party/blink/renderer/modules/gamepad",
     "+third_party/blink/renderer/modules/modules_export.h",
+    "+third_party/blink/renderer/platform/wtf/noncopyable.h",
 
     # For shared metrics.
     "+third_party/blink/renderer/modules/vr/navigator_vr.h",
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
index bbd5b451..76128a9 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/public/platform/interface_provider.h"
 #include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.h"
 #include "third_party/blink/renderer/modules/gamepad/navigator_gamepad.h"
 
 namespace blink {
@@ -19,7 +20,9 @@
 }
 
 void GamepadDispatcher::SampleGamepads(device::Gamepads& gamepads) {
-  Platform::Current()->SampleGamepads(gamepads);
+  if (reader_) {
+    reader_->SampleGamepads(gamepads);
+  }
 }
 
 void GamepadDispatcher::PlayVibrationEffectOnce(
@@ -76,11 +79,17 @@
 }
 
 void GamepadDispatcher::StartListening(LocalFrame* frame) {
-  Platform::Current()->StartListening(kWebPlatformEventTypeGamepad, this);
+  // TODO(crbug.com/850619): ensure a valid frame is passed
+  if (!frame)
+    return;
+  if (!reader_)
+    reader_ = std::make_unique<GamepadSharedMemoryReader>(*frame);
+  reader_->Start(this);
 }
 
 void GamepadDispatcher::StopListening() {
-  Platform::Current()->StopListening(kWebPlatformEventTypeGamepad);
+  if (reader_)
+    reader_->Stop();
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
index 5168cb9..381b073 100644
--- a/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_dispatcher.h
@@ -13,6 +13,8 @@
 
 namespace blink {
 
+class GamepadSharedMemoryReader;
+
 class GamepadDispatcher final
     : public GarbageCollectedFinalized<GamepadDispatcher>,
       public PlatformEventDispatcher,
@@ -53,6 +55,7 @@
                                              const device::Gamepad&,
                                              bool connected);
 
+  std::unique_ptr<GamepadSharedMemoryReader> reader_;
   device::mojom::blink::GamepadHapticsManagerPtr gamepad_haptics_manager_;
 };
 
diff --git a/content/renderer/gamepad_shared_memory_reader.cc b/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.cc
similarity index 86%
rename from content/renderer/gamepad_shared_memory_reader.cc
rename to third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.cc
index 38f3e542..f178ab8 100644
--- a/content/renderer/gamepad_shared_memory_reader.cc
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.cc
@@ -2,20 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/renderer/gamepad_shared_memory_reader.h"
-
+#include "third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/trace_event/trace_event.h"
-#include "content/renderer/renderer_blink_platform_impl.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/platform/interface_provider.h"
-#include "third_party/blink/public/platform/platform.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 
-namespace content {
+namespace blink {
 
-GamepadSharedMemoryReader::GamepadSharedMemoryReader() : binding_(this) {
-  blink::Platform::Current()->GetInterfaceProvider()->GetInterface(
+GamepadSharedMemoryReader::GamepadSharedMemoryReader(LocalFrame& frame)
+    : binding_(this) {
+  frame.GetInterfaceProvider().GetInterface(
       mojo::MakeRequest(&gamepad_monitor_));
-  device::mojom::GamepadObserverPtr observer;
+  device::mojom::blink::GamepadObserverPtr observer;
   binding_.Bind(mojo::MakeRequest(&observer));
   gamepad_monitor_->SetObserver(std::move(observer));
 }
@@ -40,9 +39,10 @@
 
   // If we don't get a valid handle from the browser, don't try to Map (we're
   // probably out of memory or file handles).
-  bool valid_handle = renderer_shared_buffer_handle_.is_valid();
-  UMA_HISTOGRAM_BOOLEAN("Gamepad.ValidSharedMemoryHandle", valid_handle);
-  if (!valid_handle)
+  bool is_valid = renderer_shared_buffer_handle_.is_valid();
+  UMA_HISTOGRAM_BOOLEAN("Gamepad.ValidSharedMemoryHandle", is_valid);
+
+  if (!is_valid)
     return;
 
   renderer_shared_buffer_mapping_ = renderer_shared_buffer_handle_->Map(
@@ -135,4 +135,4 @@
     listener_->DidDisconnectGamepad(index, gamepad);
 }
 
-} // namespace content
+}  // namespace blink
diff --git a/content/renderer/gamepad_shared_memory_reader.h b/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.h
similarity index 60%
rename from content/renderer/gamepad_shared_memory_reader.h
rename to third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.h
index 32e2b50..5f6b1e0 100644
--- a/content/renderer/gamepad_shared_memory_reader.h
+++ b/third_party/blink/renderer/modules/gamepad/gamepad_shared_memory_reader.h
@@ -2,25 +2,29 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_GAMEPAD_SHARED_MEMORY_READER_H_
-#define CONTENT_RENDERER_GAMEPAD_SHARED_MEMORY_READER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_GAMEPAD_GAMEPAD_SHARED_MEMORY_READER_H_
+#define THIRD_PARTY_BLINK_RENDERER_MODULES_GAMEPAD_GAMEPAD_SHARED_MEMORY_READER_H_
 
 #include <memory>
 
-#include "base/macros.h"
 #include "device/base/synchronization/shared_memory_seqlock_buffer.h"
 #include "device/gamepad/public/cpp/gamepads.h"
-#include "device/gamepad/public/mojom/gamepad.mojom.h"
+#include "device/gamepad/public/mojom/gamepad.mojom-blink.h"
 #include "device/gamepad/public/mojom/gamepad_hardware_buffer.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/system/buffer.h"
 #include "third_party/blink/public/platform/web_gamepad_listener.h"
+#include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
-namespace content {
+namespace blink {
 
-class GamepadSharedMemoryReader : public device::mojom::GamepadObserver {
+class LocalFrame;
+
+class GamepadSharedMemoryReader : public device::mojom::blink::GamepadObserver {
+  WTF_MAKE_NONCOPYABLE(GamepadSharedMemoryReader);
+
  public:
-  GamepadSharedMemoryReader();
+  explicit GamepadSharedMemoryReader(LocalFrame& frame);
   ~GamepadSharedMemoryReader() override;
 
   void SampleGamepads(device::Gamepads& gamepads);
@@ -32,7 +36,7 @@
   void SendStopMessage();
 
  private:
-  // device::mojom::GamepadObserver methods.
+  // device::mojom::blink::GamepadObserver methods.
   void GamepadConnected(int index, const device::Gamepad& gamepad) override;
   void GamepadDisconnected(int index, const device::Gamepad& gamepad) override;
 
@@ -42,13 +46,11 @@
 
   bool ever_interacted_with_ = false;
 
-  mojo::Binding<device::mojom::GamepadObserver> binding_;
-  device::mojom::GamepadMonitorPtr gamepad_monitor_;
+  mojo::Binding<device::mojom::blink::GamepadObserver> binding_;
+  device::mojom::blink::GamepadMonitorPtr gamepad_monitor_;
   blink::WebGamepadListener* listener_ = nullptr;
-
-  DISALLOW_COPY_AND_ASSIGN(GamepadSharedMemoryReader);
 };
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_RENDERER_GAMEPAD_SHARED_MEMORY_READER_H_
+#endif  // THIRD_PARTY_BLINK_RENDERER_MODULES_GAMEPAD_GAMEPAD_SHARED_MEMORY_READER_H_
diff --git a/third_party/blink/renderer/modules/vr/vr_display.cc b/third_party/blink/renderer/modules/vr/vr_display.cc
index 9116dcc4..73ea3f76 100644
--- a/third_party/blink/renderer/modules/vr/vr_display.cc
+++ b/third_party/blink/renderer/modules/vr/vr_display.cc
@@ -464,7 +464,7 @@
     // properties.
     device::mojom::blink::XRSessionOptionsPtr options =
         device::mojom::blink::XRSessionOptions::New();
-    options->exclusive = true;
+    options->immersive = true;
     options->use_legacy_webvr_render_path = true;
 
     display_->RequestSession(
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc
index 666c238..1b4aace 100644
--- a/third_party/blink/renderer/modules/xr/xr.cc
+++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -154,7 +154,7 @@
       pending_devices_resolver_->Reject(DOMException::Create(
           DOMExceptionCode::kNotFoundError, kNoDevicesMessage));
     } else {
-      if (!did_log_returned_device_ || !did_log_supports_exclusive_) {
+      if (!did_log_returned_device_ || !did_log_supports_immersive_) {
         Document* doc = GetFrame() ? GetFrame()->GetDocument() : nullptr;
         if (doc) {
           ukm::builders::XR_WebXR ukm_builder(ukm_source_id_);
@@ -163,9 +163,9 @@
 
           // We only expose a single device to WebXR, so report that device's
           // capabilities.
-          if (devices_[0]->SupportsExclusive()) {
+          if (devices_[0]->SupportsImmersive()) {
             ukm_builder.SetReturnedPresentationCapableDevice(1);
-            did_log_supports_exclusive_ = true;
+            did_log_supports_immersive_ = true;
           }
 
           ukm_builder.Record(doc->UkmRecorder());
diff --git a/third_party/blink/renderer/modules/xr/xr.h b/third_party/blink/renderer/modules/xr/xr.h
index c7127cac..19c80ba 100644
--- a/third_party/blink/renderer/modules/xr/xr.h
+++ b/third_party/blink/renderer/modules/xr/xr.h
@@ -68,7 +68,7 @@
   // Indicates whether use of requestDevice has already been logged.
   bool did_log_requestDevice_ = false;
   bool did_log_returned_device_ = false;
-  bool did_log_supports_exclusive_ = false;
+  bool did_log_supports_immersive_ = false;
   const int64_t ukm_source_id_;
 
   HeapVector<Member<XRDevice>> devices_;
diff --git a/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc b/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc
index d2e9884f..92794cc 100644
--- a/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc
+++ b/third_party/blink/renderer/modules/xr/xr_canvas_input_provider.cc
@@ -66,8 +66,8 @@
 }
 
 bool XRCanvasInputProvider::ShouldProcessEvents() {
-  // Don't process canvas gestures if there's an active exclusive session.
-  return !(session_->device()->frameProvider()->exclusive_session());
+  // Don't process canvas gestures if there's an active immersive session.
+  return !(session_->device()->frameProvider()->immersive_session());
 }
 
 void XRCanvasInputProvider::OnClick(MouseEvent* event) {
diff --git a/third_party/blink/renderer/modules/xr/xr_device.cc b/third_party/blink/renderer/modules/xr/xr_device.cc
index ac550d8..1a883f2 100644
--- a/third_party/blink/renderer/modules/xr/xr_device.cc
+++ b/third_party/blink/renderer/modules/xr/xr_device.cc
@@ -19,14 +19,14 @@
 
 namespace {
 
-const char kActiveExclusiveSession[] =
-    "XRDevice already has an active, exclusive session";
+const char kActiveImmersiveSession[] =
+    "XRDevice already has an active, immersive session";
 
-const char kExclusiveNotSupported[] =
-    "XRDevice does not support the creation of exclusive sessions.";
+const char kImmersiveNotSupported[] =
+    "XRDevice does not support the creation of immersive sessions.";
 
 const char kNoOutputContext[] =
-    "Non-exclusive sessions must be created with an outputContext.";
+    "Non-immersive sessions must be created with an outputContext.";
 
 const char kRequestRequiresUserActivation[] =
     "The requested session requires user activation.";
@@ -53,8 +53,8 @@
 
 const char* XRDevice::checkSessionSupport(
     const XRSessionCreationOptions& options) const {
-  if (!options.exclusive()) {
-    // Validation for non-exclusive sessions. Validation for exclusive sessions
+  if (!options.immersive()) {
+    // Validation for non-immersive sessions. Validation for immersive sessions
     // happens browser side.
     if (!options.hasOutputContext()) {
       return kNoOutputContext;
@@ -69,8 +69,8 @@
     }
     // TODO(https://crbug.com/828321): Expose information necessary to check
     // combinations.
-    // For now, exclusive AR is not supported.
-    if (options.exclusive()) {
+    // For now, immersive AR is not supported.
+    if (options.immersive()) {
       return kSessionNotSupported;
     }
   } else {
@@ -94,7 +94,7 @@
   // Check to see if the device is capable of supporting the requested session
   // options. Note that reporting support here does not guarantee that creating
   // a session with those options will succeed, as other external and
-  // time-sensitve factors (focus state, existance of another exclusive session,
+  // time-sensitve factors (focus state, existance of another immersive session,
   // etc.) may prevent the creation of a session as well.
   const char* reject_reason = checkSessionSupport(options);
   if (reject_reason) {
@@ -110,7 +110,7 @@
 
   device::mojom::blink::XRSessionOptionsPtr session_options =
       device::mojom::blink::XRSessionOptions::New();
-  session_options->exclusive = options.exclusive();
+  session_options->immersive = options.immersive();
 
   display_->SupportsSession(
       std::move(session_options),
@@ -122,13 +122,13 @@
 
 void XRDevice::OnSupportsSessionReturned(ScriptPromiseResolver* resolver,
                                          bool supports_session) {
-  // kExclusiveNotSupported is currently the only reason that SupportsSession
+  // kImmersiveNotSupported is currently the only reason that SupportsSession
   // rejects on the browser side. That or there are no devices, but that should
   // technically not be possible.
   supports_session
       ? resolver->Resolve()
       : resolver->Reject(DOMException::Create(
-            DOMExceptionCode::kNotSupportedError, kExclusiveNotSupported));
+            DOMExceptionCode::kNotSupportedError, kImmersiveNotSupported));
 }
 
 int64_t XRDevice::GetSourceId() const {
@@ -140,11 +140,11 @@
     const XRSessionCreationOptions& options) {
   Document* doc = ToDocumentOrNull(ExecutionContext::From(script_state));
 
-  if (options.exclusive() && !did_log_request_exclusive_session_ && doc) {
+  if (options.immersive() && !did_log_request_immersive_session_ && doc) {
     ukm::builders::XR_WebXR(GetSourceId())
         .SetDidRequestPresentation(1)
         .Record(doc->UkmRecorder());
-    did_log_request_exclusive_session_ = true;
+    did_log_request_immersive_session_ = true;
   }
 
   // Check first to see if the device is capable of supporting the requested
@@ -162,12 +162,12 @@
 
   // Check if the current page state prevents the requested session from being
   // created.
-  if (options.exclusive()) {
-    if (frameProvider()->exclusive_session()) {
+  if (options.immersive()) {
+    if (frameProvider()->immersive_session()) {
       return ScriptPromise::RejectWithDOMException(
           script_state,
           DOMException::Create(DOMExceptionCode::kInvalidStateError,
-                               kActiveExclusiveSession));
+                               kActiveImmersiveSession));
     }
 
     if (!has_user_activation) {
@@ -192,7 +192,7 @@
 
   device::mojom::blink::XRSessionOptionsPtr session_options =
       device::mojom::blink::XRSessionOptions::New();
-  session_options->exclusive = options.exclusive();
+  session_options->immersive = options.immersive();
   session_options->has_user_activation = has_user_activation;
 
   // TODO(offenwanger): Once device activation is sorted out for WebXR, either
@@ -228,11 +228,11 @@
   }
 
   XRSession* session =
-      new XRSession(this, options.exclusive(), output_context, blend_mode);
+      new XRSession(this, options.immersive(), output_context, blend_mode);
   sessions_.insert(session);
 
-  if (options.exclusive()) {
-    frameProvider()->BeginExclusiveSession(session, std::move(connection));
+  if (options.immersive()) {
+    frameProvider()->BeginImmersiveSession(session, std::move(connection));
   }
 
   resolver->Resolve(session);
@@ -264,7 +264,7 @@
 void XRDevice::OnBlur() {
   // The device is reporting to us that it is blurred.  This could happen for a
   // variety of reasons, such as browser UI, a different application using the
-  // headset, or another page entering an exclusive session.
+  // headset, or another page entering an immersive session.
   has_device_focus_ = false;
   OnFocusChanged();
 }
@@ -295,7 +295,7 @@
   display_info_id_++;
   display_info_ = std::move(display_info);
   is_external_ = display_info_->capabilities->hasExternalDisplay;
-  supports_exclusive_ = (display_info_->capabilities->canPresent);
+  supports_immersive_ = (display_info_->capabilities->canPresent);
   supports_ar_ = display_info_->capabilities->can_provide_pass_through_images;
 }
 
diff --git a/third_party/blink/renderer/modules/xr/xr_device.h b/third_party/blink/renderer/modules/xr/xr_device.h
index 6a294699..ac7df4f 100644
--- a/third_party/blink/renderer/modules/xr/xr_device.h
+++ b/third_party/blink/renderer/modules/xr/xr_device.h
@@ -73,7 +73,7 @@
   bool HasDeviceFocus() { return has_device_focus_; }
   bool HasDeviceAndFrameFocus() { return IsFrameFocused() && HasDeviceFocus(); }
 
-  bool SupportsExclusive() { return supports_exclusive_; }
+  bool SupportsImmersive() { return supports_immersive_; }
 
   int64_t GetSourceId() const;
 
@@ -102,12 +102,12 @@
   Member<XRFrameProvider> frame_provider_;
   HeapHashSet<WeakMember<XRSession>> sessions_;
   bool is_external_ = false;
-  bool supports_exclusive_ = false;
+  bool supports_immersive_ = false;
   bool supports_ar_ = false;
   bool has_device_focus_ = true;
 
-  // Indicates whether we've already logged a request for an exclusive session.
-  bool did_log_request_exclusive_session_ = false;
+  // Indicates whether we've already logged a request for an immersive session.
+  bool did_log_request_immersive_session_ = false;
 
   device::mojom::blink::VRMagicWindowProviderPtr magic_window_provider_;
   device::mojom::blink::VRDisplayHostPtr display_;
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
index 2e0796cb..ce5e8c46 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
+++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.cc
@@ -35,7 +35,7 @@
       : frame_provider_(frame_provider) {}
   ~XRFrameProviderRequestCallback() override = default;
   void Invoke(double high_res_time_ms) override {
-    frame_provider_->OnNonExclusiveVSync(high_res_time_ms / 1000.0);
+    frame_provider_->OnNonImmersiveVSync(high_res_time_ms / 1000.0);
   }
 
   void Trace(blink::Visitor* visitor) override {
@@ -90,17 +90,17 @@
   frame_transport_ = new XRFrameTransport();
 }
 
-void XRFrameProvider::BeginExclusiveSession(
+void XRFrameProvider::BeginImmersiveSession(
     XRSession* session,
     device::mojom::blink::XRPresentationConnectionPtr connection) {
-  // Make sure the session is indeed an exclusive one.
-  DCHECK(session && session->exclusive());
+  // Make sure the session is indeed an immersive one.
+  DCHECK(session && session->immersive());
 
-  // Ensure we can only have one exclusive session at a time.
-  DCHECK(!exclusive_session_);
+  // Ensure we can only have one immersive session at a time.
+  DCHECK(!immersive_session_);
   DCHECK(connection);
 
-  exclusive_session_ = session;
+  immersive_session_ = session;
 
   presentation_provider_.Bind(std::move(connection->provider));
   presentation_provider_.set_connection_error_handler(
@@ -119,12 +119,12 @@
 
   // If we are gaining focus, schedule a frame for magic window.  This accounts
   // for skipping RAFs in ProcessScheduledFrame.  Only do this when there are
-  // magic window sessions but no exclusive session. Note that exclusive
+  // magic window sessions but no immersive session. Note that immersive
   // sessions don't stop scheduling RAFs when focus is lost, so there is no need
-  // to schedule exclusive frames when focus is acquired.
+  // to schedule immersive frames when focus is acquired.
   if (focus && !last_has_focus_ && requesting_sessions_.size() > 0 &&
-      !exclusive_session_) {
-    ScheduleNonExclusiveFrame();
+      !immersive_session_) {
+    ScheduleNonImmersiveFrame();
   }
   last_has_focus_ = focus;
 }
@@ -133,19 +133,19 @@
   presentation_provider_.reset();
   if (vsync_connection_failed_)
     return;
-  exclusive_session_->ForceEnd();
+  immersive_session_->ForceEnd();
   vsync_connection_failed_ = true;
 }
 
-// Called by the exclusive session when it is ended.
-void XRFrameProvider::OnExclusiveSessionEnded() {
-  if (!exclusive_session_)
+// Called by the immersive session when it is ended.
+void XRFrameProvider::OnImmersiveSessionEnded() {
+  if (!immersive_session_)
     return;
 
   device_->xrDisplayHostPtr()->ExitPresent();
 
-  exclusive_session_ = nullptr;
-  pending_exclusive_vsync_ = false;
+  immersive_session_ = nullptr;
+  pending_immersive_vsync_ = false;
   frame_id_ = -1;
 
   if (presentation_provider_.is_bound()) {
@@ -154,11 +154,11 @@
 
   frame_transport_ = new XRFrameTransport();
 
-  // When we no longer have an active exclusive session schedule all the
-  // outstanding frames that were requested while the exclusive session was
+  // When we no longer have an active immersive session schedule all the
+  // outstanding frames that were requested while the immersive session was
   // active.
   if (requesting_sessions_.size() > 0)
-    ScheduleNonExclusiveFrame();
+    ScheduleNonImmersiveFrame();
 }
 
 // Schedule a session to be notified when the next XR frame is available.
@@ -166,44 +166,44 @@
   TRACE_EVENT0("gpu", __FUNCTION__);
   DCHECK(session);
 
-  // Exclusive frame logic.
-  if (session->exclusive()) {
-    ScheduleExclusiveFrame();
+  // Immersive frame logic.
+  if (session->immersive()) {
+    ScheduleImmersiveFrame();
     return;
   }
 
-  // Non-exclusive frame logic.
+  // Non-immersive frame logic.
 
   requesting_sessions_.push_back(session);
 
-  // If there's an active exclusive session save the request but suppress
-  // processing it until the exclusive session is no longer active.
-  if (exclusive_session_)
+  // If there's an active immersive session save the request but suppress
+  // processing it until the immersive session is no longer active.
+  if (immersive_session_)
     return;
 
-  ScheduleNonExclusiveFrame();
+  ScheduleNonImmersiveFrame();
 }
 
-void XRFrameProvider::ScheduleExclusiveFrame() {
+void XRFrameProvider::ScheduleImmersiveFrame() {
   TRACE_EVENT0("gpu", __FUNCTION__);
-  if (pending_exclusive_vsync_)
+  if (pending_immersive_vsync_)
     return;
 
-  pending_exclusive_vsync_ = true;
+  pending_immersive_vsync_ = true;
 
   presentation_provider_->GetFrameData(WTF::Bind(
-      &XRFrameProvider::OnExclusiveFrameData, WrapWeakPersistent(this)));
+      &XRFrameProvider::OnImmersiveFrameData, WrapWeakPersistent(this)));
 }
 
-// TODO(lincolnfrog): add a ScheduleNonExclusiveARFrame, if we want camera RAF
+// TODO(lincolnfrog): add a ScheduleNonImmersiveARFrame, if we want camera RAF
 // alignment instead of doc RAF alignment.
-void XRFrameProvider::ScheduleNonExclusiveFrame() {
+void XRFrameProvider::ScheduleNonImmersiveFrame() {
   TRACE_EVENT0("gpu", __FUNCTION__);
-  DCHECK(!exclusive_session_)
-      << "Scheduling should be done via the exclusive session if present.";
+  DCHECK(!immersive_session_)
+      << "Scheduling should be done via the immersive session if present.";
   DCHECK(device_->xrMagicWindowProviderPtr());
 
-  if (pending_non_exclusive_vsync_)
+  if (pending_non_immersive_vsync_)
     return;
 
   LocalFrame* frame = device_->xr()->GetFrame();
@@ -216,13 +216,13 @@
   if (!doc)
     return;
 
-  pending_non_exclusive_vsync_ = true;
+  pending_non_immersive_vsync_ = true;
 
   device_->xrMagicWindowProviderPtr()->GetFrameData(WTF::Bind(
-      &XRFrameProvider::OnNonExclusiveFrameData, WrapWeakPersistent(this)));
+      &XRFrameProvider::OnNonImmersiveFrameData, WrapWeakPersistent(this)));
 
   // TODO(https://crbug.com/839253): Generalize the pass-through images
-  // code path so that it also works for exclusive sessions on an AR device
+  // code path so that it also works for immersive sessions on an AR device
   // with pass-through technology.
 
   // TODO(http://crbug.com/856257) Remove the special casing for AR and non-AR.
@@ -232,7 +232,7 @@
   }
 }
 
-void XRFrameProvider::OnExclusiveFrameData(
+void XRFrameProvider::OnImmersiveFrameData(
     device::mojom::blink::XRFrameDataPtr data) {
   TRACE_EVENT0("gpu", __FUNCTION__);
   DVLOG(2) << __FUNCTION__;
@@ -241,10 +241,10 @@
     return;
   }
 
-  // We may have lost the exclusive session since the last VSync request.
-  if (!exclusive_session_) {
+  // We may have lost the immersive session since the last VSync request.
+  if (!immersive_session_) {
     // TODO(https://crbug.com/836496): do we need to include this in the
-    // image size calculation for AR? What about exclusive AR (full-screen?)
+    // image size calculation for AR? What about immersive AR (full-screen?)
     return;
   }
 
@@ -252,7 +252,7 @@
   frame_id_ = data->frame_id;
   buffer_mailbox_holder_ = data->buffer_holder;
 
-  pending_exclusive_vsync_ = false;
+  pending_immersive_vsync_ = false;
 
   // Post a task to handle scheduled animations after the current
   // execution context finishes, so that we yield to non-mojo tasks in
@@ -265,14 +265,14 @@
                            data->time_delta.InSecondsF()));
 }
 
-void XRFrameProvider::OnNonExclusiveVSync(double timestamp) {
+void XRFrameProvider::OnNonImmersiveVSync(double timestamp) {
   TRACE_EVENT0("gpu", __FUNCTION__);
   DVLOG(2) << __FUNCTION__;
 
-  pending_non_exclusive_vsync_ = false;
+  pending_non_immersive_vsync_ = false;
 
-  // Suppress non-exclusive vsyncs when there's an exclusive session active.
-  if (exclusive_session_)
+  // Suppress non-immersive vsyncs when there's an immersive session active.
+  if (immersive_session_)
     return;
 
   Platform::Current()->CurrentThread()->GetTaskRunner()->PostTask(
@@ -280,14 +280,14 @@
                            WrapWeakPersistent(this), nullptr, timestamp));
 }
 
-void XRFrameProvider::OnNonExclusiveFrameData(
+void XRFrameProvider::OnNonImmersiveFrameData(
     device::mojom::blink::XRFrameDataPtr frame_data) {
   TRACE_EVENT0("gpu", __FUNCTION__);
   DVLOG(2) << __FUNCTION__;
 
   // TODO(https://crbug.com/837834): add unit tests for this code path.
 
-  pending_non_exclusive_vsync_ = false;
+  pending_non_immersive_vsync_ = false;
   LocalFrame* frame = device_->xr()->GetFrame();
   if (!frame)
     return;
@@ -325,39 +325,39 @@
   TRACE_EVENT1("gpu", "XRFrameProvider::ProcessScheduledFrame", "frame",
                frame_id_);
 
-  if (!device_->HasDeviceAndFrameFocus() && !exclusive_session_) {
+  if (!device_->HasDeviceAndFrameFocus() && !immersive_session_) {
     return;  // Not currently focused, so we won't expose poses (except to
-             // exclusive sessions).
+             // immersive sessions).
   }
 
-  if (exclusive_session_) {
+  if (immersive_session_) {
     if (frame_pose_ && frame_pose_->input_state.has_value()) {
-      exclusive_session_->OnInputStateChange(frame_id_,
+      immersive_session_->OnInputStateChange(frame_id_,
                                              frame_pose_->input_state.value());
     }
 
-    // Check if exclusive session is still set as OnInputStateChange may have
+    // Check if immersive session is still set as OnInputStateChange may have
     // allowed a ForceEndSession to be triggered.
-    if (!exclusive_session_)
+    if (!immersive_session_)
       return;
 
     if (frame_pose_ && frame_pose_->pose_reset) {
-      exclusive_session_->OnPoseReset();
+      immersive_session_->OnPoseReset();
     }
 
-    // Check if exclusive session is still set as OnPoseReset may have allowed a
+    // Check if immersive session is still set as OnPoseReset may have allowed a
     // ForceEndSession to be triggered.
-    if (!exclusive_session_)
+    if (!immersive_session_)
       return;
 
-    // If there's an exclusive session active only process its frame.
+    // If there's an immersive session active only process its frame.
     std::unique_ptr<TransformationMatrix> pose_matrix =
         getPoseMatrix(frame_pose_);
     // Sanity check: if drawing into a shared buffer, the optional mailbox
     // holder must be present.
     DCHECK(!frame_transport_->DrawingIntoSharedBuffer() ||
            buffer_mailbox_holder_);
-    exclusive_session_->OnFrame(std::move(pose_matrix), buffer_mailbox_holder_,
+    immersive_session_->OnFrame(std::move(pose_matrix), buffer_mailbox_holder_,
                                 base::nullopt, base::nullopt);
   } else {
     // In the process of fulfilling the frame requests for each session they are
@@ -376,7 +376,7 @@
       }
 
       if (frame_data && frame_data->projection_matrix.has_value()) {
-        session->SetNonExclusiveProjectionMatrix(
+        session->SetNonImmersiveProjectionMatrix(
             frame_data->projection_matrix.value());
       }
 
@@ -401,8 +401,8 @@
 
 void XRFrameProvider::SubmitWebGLLayer(XRWebGLLayer* layer, bool was_changed) {
   DCHECK(layer);
-  DCHECK(exclusive_session_);
-  DCHECK(layer->session() == exclusive_session_);
+  DCHECK(immersive_session_);
+  DCHECK(layer->session() == immersive_session_);
   if (!presentation_provider_.is_bound())
     return;
 
@@ -413,8 +413,8 @@
   if (frame_id_ < 0) {
     // There is no valid frame_id_, and the browser side is not currently
     // expecting a frame to be submitted. That can happen for the first
-    // exclusive frame if the animation loop submits without a preceding
-    // exclusive GetFrameData response, in that case frame_id_ is -1 (see
+    // immersive frame if the animation loop submits without a preceding
+    // immersive GetFrameData response, in that case frame_id_ is -1 (see
     // https://crbug.com/855722).
     return;
   }
@@ -474,7 +474,7 @@
 // TODO(bajones): This only works because we're restricted to a single layer at
 // the moment. Will need an overhaul when we get more robust layering support.
 void XRFrameProvider::UpdateWebGLLayerViewports(XRWebGLLayer* layer) {
-  DCHECK(layer->session() == exclusive_session_);
+  DCHECK(layer->session() == immersive_session_);
   DCHECK(presentation_provider_);
 
   XRViewport* left = layer->GetViewportForEye(XRView::kEyeLeft);
@@ -505,7 +505,7 @@
 void XRFrameProvider::Trace(blink::Visitor* visitor) {
   visitor->Trace(device_);
   visitor->Trace(frame_transport_);
-  visitor->Trace(exclusive_session_);
+  visitor->Trace(immersive_session_);
   visitor->Trace(requesting_sessions_);
 }
 
diff --git a/third_party/blink/renderer/modules/xr/xr_frame_provider.h b/third_party/blink/renderer/modules/xr/xr_frame_provider.h
index 1f0fd82..f8524be3 100644
--- a/third_party/blink/renderer/modules/xr/xr_frame_provider.h
+++ b/third_party/blink/renderer/modules/xr/xr_frame_provider.h
@@ -26,17 +26,17 @@
  public:
   explicit XRFrameProvider(XRDevice*);
 
-  XRSession* exclusive_session() const { return exclusive_session_; }
+  XRSession* immersive_session() const { return immersive_session_; }
   device::mojom::blink::VRSubmitFrameClientPtr GetSubmitFrameClient();
 
-  void BeginExclusiveSession(
+  void BeginImmersiveSession(
       XRSession* session,
       device::mojom::blink::XRPresentationConnectionPtr connection);
-  void OnExclusiveSessionEnded();
+  void OnImmersiveSessionEnded();
 
   void RequestFrame(XRSession*);
 
-  void OnNonExclusiveVSync(double timestamp);
+  void OnNonImmersiveVSync(double timestamp);
 
   void SubmitWebGLLayer(XRWebGLLayer*, bool was_changed);
   void UpdateWebGLLayerViewports(XRWebGLLayer*);
@@ -47,21 +47,21 @@
   virtual void Trace(blink::Visitor*);
 
  private:
-  void OnExclusiveFrameData(device::mojom::blink::XRFrameDataPtr data);
-  void OnNonExclusiveFrameData(device::mojom::blink::XRFrameDataPtr data);
+  void OnImmersiveFrameData(device::mojom::blink::XRFrameDataPtr data);
+  void OnNonImmersiveFrameData(device::mojom::blink::XRFrameDataPtr data);
 
-  void ScheduleExclusiveFrame();
-  void ScheduleNonExclusiveFrame();
+  void ScheduleImmersiveFrame();
+  void ScheduleNonImmersiveFrame();
 
   void OnPresentationProviderConnectionError();
   void ProcessScheduledFrame(device::mojom::blink::XRFrameDataPtr frame_data,
                              double timestamp);
 
   const Member<XRDevice> device_;
-  Member<XRSession> exclusive_session_;
+  Member<XRSession> immersive_session_;
   Member<XRFrameTransport> frame_transport_;
 
-  // Non-exclusive Sessions which have requested a frame update.
+  // Non-immersive Sessions which have requested a frame update.
   HeapVector<Member<XRSession>> requesting_sessions_;
 
   device::mojom::blink::VRPresentationProviderPtr presentation_provider_;
@@ -72,8 +72,8 @@
   // XR compositor so that it knows which poses to use, when to apply bounds
   // updates, etc.
   int16_t frame_id_ = -1;
-  bool pending_exclusive_vsync_ = false;
-  bool pending_non_exclusive_vsync_ = false;
+  bool pending_immersive_vsync_ = false;
+  bool pending_non_immersive_vsync_ = false;
   bool vsync_connection_failed_ = false;
 
   base::Optional<gpu::MailboxHolder> buffer_mailbox_holder_;
diff --git a/third_party/blink/renderer/modules/xr/xr_session.cc b/third_party/blink/renderer/modules/xr/xr_session.cc
index 6ac38b0a..57306f0 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.cc
+++ b/third_party/blink/renderer/modules/xr/xr_session.cc
@@ -90,11 +90,11 @@
 };
 
 XRSession::XRSession(XRDevice* device,
-                     bool exclusive,
+                     bool immersive,
                      XRPresentationContext* output_context,
                      EnvironmentBlendMode environment_blend_mode)
     : device_(device),
-      exclusive_(exclusive),
+      immersive_(immersive),
       output_context_(output_context),
       callback_collection_(new XRFrameRequestCallbackCollection(
           device->xr()->GetExecutionContext())) {
@@ -109,7 +109,7 @@
       resize_observer_->observe(canvas);
 
       // Begin processing input events on the output context's canvas.
-      if (!exclusive_) {
+      if (!immersive_) {
         canvas_input_provider_ = new XRCanvasInputProvider(this, canvas);
       }
 
@@ -151,17 +151,17 @@
 void XRSession::setBaseLayer(XRLayer* value) {
   base_layer_ = value;
   // Make sure that the layer's drawing buffer is updated to the right size
-  // if this is a non-exclusive session.
-  if (!exclusive_ && base_layer_) {
+  // if this is a non-immersive session.
+  if (!immersive_ && base_layer_) {
     base_layer_->OnResize();
   }
 }
 
-void XRSession::SetNonExclusiveProjectionMatrix(
+void XRSession::SetNonImmersiveProjectionMatrix(
     const WTF::Vector<float>& projection_matrix) {
   DCHECK_EQ(projection_matrix.size(), 16lu);
 
-  non_exclusive_projection_matrix_ = projection_matrix;
+  non_immersive_projection_matrix_ = projection_matrix;
   // It is about as expensive to check equality as to just
   // update the views, so just update.
   update_views_next_frame_ = true;
@@ -372,17 +372,17 @@
     canvas_input_provider_ = nullptr;
   }
 
-  // If this session is the active exclusive session for the device, notify the
+  // If this session is the active immersive session for the device, notify the
   // frameProvider that it's ended.
-  if (device_->frameProvider()->exclusive_session() == this) {
-    device_->frameProvider()->OnExclusiveSessionEnded();
+  if (device_->frameProvider()->immersive_session() == this) {
+    device_->frameProvider()->OnImmersiveSessionEnded();
   }
 
   DispatchEvent(XRSessionEvent::Create(EventTypeNames::end, this));
 }
 
 double XRSession::NativeFramebufferScale() const {
-  if (exclusive_) {
+  if (immersive_) {
     double scale = device_->xrDisplayInfoPtr()->webxr_default_framebuffer_scale;
     DCHECK(scale);
 
@@ -394,7 +394,7 @@
 }
 
 DoubleSize XRSession::DefaultFramebufferSize() const {
-  if (!exclusive_) {
+  if (!immersive_) {
     return OutputCanvasSize();
   }
 
@@ -431,11 +431,11 @@
   DispatchEvent(XRSessionEvent::Create(EventTypeNames::blur, this));
 }
 
-// Exclusive sessions may still not be blurred in headset even if the page isn't
+// Immersive sessions may still not be blurred in headset even if the page isn't
 // focused.  This prevents the in-headset experience from freezing on an
 // external display headset when the user clicks on another tab.
 bool XRSession::HasAppropriateFocus() {
-  return exclusive_ ? device_->HasDeviceFocus()
+  return immersive_ ? device_->HasDeviceFocus()
                     : device_->HasDeviceAndFrameFocus();
 }
 
@@ -721,18 +721,18 @@
 }
 
 const HeapVector<Member<XRView>>& XRSession::views() {
-  // TODO(bajones): For now we assume that exclusive sessions render a stereo
-  // pair of views and non-exclusive sessions render a single view. That doesn't
+  // TODO(bajones): For now we assume that immersive sessions render a stereo
+  // pair of views and non-immersive sessions render a single view. That doesn't
   // always hold true, however, so the view configuration should ultimately come
   // from the backing service.
   if (views_dirty_) {
-    if (exclusive_) {
+    if (immersive_) {
       // If we don't already have the views allocated, do so now.
       if (views_.IsEmpty()) {
         views_.push_back(new XRView(this, XRView::kEyeLeft));
         views_.push_back(new XRView(this, XRView::kEyeRight));
       }
-      // In exclusive mode the projection and view matrices must be aligned with
+      // In immersive mode the projection and view matrices must be aligned with
       // the device's physical optics.
       UpdateViewFromEyeParameters(views_[XRView::kEyeLeft],
                                   device_->xrDisplayInfoPtr()->leftEye,
@@ -752,11 +752,11 @@
                  static_cast<float>(output_height_);
       }
 
-      if (non_exclusive_projection_matrix_.size() > 0) {
+      if (non_immersive_projection_matrix_.size() > 0) {
         views_[XRView::kEyeLeft]->UpdateProjectionMatrixFromRawValues(
-            non_exclusive_projection_matrix_, depth_near_, depth_far_);
+            non_immersive_projection_matrix_, depth_near_, depth_far_);
       } else {
-        // In non-exclusive mode, if there is no explicit projection matrix
+        // In non-immersive mode, if there is no explicit projection matrix
         // provided, the projection matrix must be aligned with the
         // output canvas dimensions.
         views_[XRView::kEyeLeft]->UpdateProjectionMatrixFromAspect(
@@ -770,9 +770,9 @@
     // AR mode, we're not picking up the change on the right frame. Remove this
     // fallback once that's sorted out.
     DVLOG(2) << __FUNCTION__ << ": FIXME, fallback proj matrix update";
-    if (non_exclusive_projection_matrix_.size() > 0) {
+    if (non_immersive_projection_matrix_.size() > 0) {
       views_[XRView::kEyeLeft]->UpdateProjectionMatrixFromRawValues(
-          non_exclusive_projection_matrix_, depth_near_, depth_far_);
+          non_immersive_projection_matrix_, depth_near_, depth_far_);
     }
   }
 
diff --git a/third_party/blink/renderer/modules/xr/xr_session.h b/third_party/blink/renderer/modules/xr/xr_session.h
index a6c3cc0..6677778 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.h
+++ b/third_party/blink/renderer/modules/xr/xr_session.h
@@ -45,13 +45,13 @@
   };
 
   XRSession(XRDevice*,
-            bool exclusive,
+            bool immersive,
             XRPresentationContext* output_context,
             EnvironmentBlendMode environment_blend_mode);
   ~XRSession() override = default;
 
   XRDevice* device() const { return device_; }
-  bool exclusive() const { return exclusive_; }
+  bool immersive() const { return immersive_; }
   XRPresentationContext* outputContext() const { return output_context_; }
   const String& environmentBlendMode() const { return blend_mode_string_; }
 
@@ -136,7 +136,7 @@
 
   void OnPoseReset();
 
-  void SetNonExclusiveProjectionMatrix(const WTF::Vector<float>&);
+  void SetNonImmersiveProjectionMatrix(const WTF::Vector<float>&);
 
   void Trace(blink::Visitor*) override;
 
@@ -162,7 +162,7 @@
           results);
 
   const Member<XRDevice> device_;
-  const bool exclusive_;
+  const bool immersive_;
   const Member<XRPresentationContext> output_context_;
   String blend_mode_string_;
   Member<XRLayer> base_layer_;
@@ -174,7 +174,7 @@
   TraceWrapperMember<XRFrameRequestCallbackCollection> callback_collection_;
   std::unique_ptr<TransformationMatrix> base_pose_matrix_;
 
-  WTF::Vector<float> non_exclusive_projection_matrix_;
+  WTF::Vector<float> non_immersive_projection_matrix_;
 
   double depth_near_ = 0.1;
   double depth_far_ = 1000.0;
diff --git a/third_party/blink/renderer/modules/xr/xr_session.idl b/third_party/blink/renderer/modules/xr/xr_session.idl
index 365f18e..a34084b75 100644
--- a/third_party/blink/renderer/modules/xr/xr_session.idl
+++ b/third_party/blink/renderer/modules/xr/xr_session.idl
@@ -14,7 +14,7 @@
     OriginTrialEnabled=WebXR
 ] interface XRSession : EventTarget {
   readonly attribute XRDevice device;
-  readonly attribute boolean exclusive;
+  readonly attribute boolean immersive;
   readonly attribute XRPresentationContext outputContext;
   readonly attribute XREnvironmentBlendMode environmentBlendMode;
 
diff --git a/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl b/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl
index 6a1bbf6e..f1ceaa8 100644
--- a/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl
+++ b/third_party/blink/renderer/modules/xr/xr_session_creation_options.idl
@@ -6,6 +6,6 @@
 [
     SecureContext
 ] dictionary XRSessionCreationOptions {
-  boolean exclusive = false;
+  boolean immersive = false;
   XRPresentationContext outputContext;
 };
diff --git a/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc b/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
index e243cee..69bde9c 100644
--- a/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
+++ b/third_party/blink/renderer/modules/xr/xr_webgl_layer.cc
@@ -126,7 +126,7 @@
       framebuffer_scale_(framebuffer_scale) {
   DCHECK(drawing_buffer_);
   // If the contents need mirroring, indicate that to the drawing buffer.
-  if (session->exclusive() && session->outputContext() &&
+  if (session->immersive() && session->outputContext() &&
       session->device()->external()) {
     mirroring_ = true;
     drawing_buffer_->SetMirrorClient(this);
@@ -169,9 +169,9 @@
 }
 
 void XRWebGLLayer::requestViewportScaling(double scale_factor) {
-  if (!session()->exclusive()) {
+  if (!session()->immersive()) {
     // TODO(bajones): For the moment we're just going to ignore viewport changes
-    // in non-exclusive mode. This is legal, but probably not what developers
+    // in non-immersive mode. This is legal, but probably not what developers
     // would like to see. Look into making viewport scale apply properly.
     scale_factor = 1.0;
   } else {
@@ -197,7 +197,7 @@
 
   viewports_dirty_ = false;
 
-  if (session()->exclusive()) {
+  if (session()->immersive()) {
     left_viewport_ =
         new XRViewport(0, 0, framebuffer_width * 0.5 * viewport_scale_,
                        framebuffer_height * viewport_scale_);
@@ -283,7 +283,7 @@
   }
 
   // Submit the frame to the XR compositor.
-  if (session()->exclusive()) {
+  if (session()->immersive()) {
     // Always call submit, but notify if the contents were changed or not.
     session()->device()->frameProvider()->SubmitWebGLLayer(
         this, framebuffer_->HaveContentsChanged());
@@ -298,8 +298,8 @@
 }
 
 void XRWebGLLayer::OnResize() {
-  if (!session()->exclusive()) {
-    // For non-exclusive sessions a resize indicates we should adjust the
+  if (!session()->immersive()) {
+    // For non-immersive sessions a resize indicates we should adjust the
     // drawing buffer size to match the canvas.
     DoubleSize framebuffers_size = session()->DefaultFramebufferSize();
 
@@ -308,7 +308,7 @@
     drawing_buffer_->Resize(desired_size);
   }
 
-  // With both exclusive and non-exclusive session the viewports should be
+  // With both immersive and non-immersive session the viewports should be
   // recomputed when the output canvas resizes.
   viewports_dirty_ = true;
 }
diff --git a/third_party/blink/renderer/platform/lifecycle_notifier.h b/third_party/blink/renderer/platform/lifecycle_notifier.h
index 47e9a283..668002ef 100644
--- a/third_party/blink/renderer/platform/lifecycle_notifier.h
+++ b/third_party/blink/renderer/platform/lifecycle_notifier.h
@@ -81,6 +81,20 @@
     }
   }
 
+  // ForEachObserver() variant that does not protect against memory corruption.
+  //
+  // Only used by SynchronousMutationNotifier::NotifyUpdateCharacterData. See
+  // implementation comment for why it is necessary.
+  //
+  // TODO(crbug.com/862900): Fix SynchronousMutationNotifier and remove this.
+  template <typename ForEachCallable>
+  void ForEachObserverWithoutChecks(const ForEachCallable& callable) const {
+    for (LifecycleObserverBase* observer_base : observers_) {
+      Observer* observer = static_cast<Observer*>(observer_base);
+      callable(observer);
+    }
+  }
+
  private:
   using ObserverSet = HeapHashSet<WeakMember<LifecycleObserverBase>>;
 
diff --git a/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.cc b/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.cc
index 041a370..ed9bf1541 100644
--- a/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.cc
+++ b/third_party/blink/renderer/platform/scroll/scrollbar_layer_delegate.cc
@@ -109,6 +109,12 @@
 }
 
 bool ScrollbarLayerDelegate::HasTickmarks() const {
+  // TODO(crbug.com/860499): Remove this condition, it should not occur.
+  // Layers may exist and be painted for a |scrollbar_| that has had its
+  // ScrollableArea detached. This seems weird because if the area is detached
+  // the layer should be destroyed but here we are. https://crbug.com/860499.
+  if (!scrollbar_->GetScrollableArea())
+    return false;
   // When the frame is throttled, the scrollbar will not be painted because
   // the frame has not had its lifecycle updated. Thus the actual value of
   // HasTickmarks can't be known and may change once the frame is unthrottled.
@@ -126,6 +132,14 @@
   PaintCanvasAutoRestore auto_restore(canvas, true);
   blink::Scrollbar& scrollbar = *scrollbar_;
 
+  // TODO(crbug.com/860499): Remove this condition, it should not occur.
+  // Layers may exist and be painted for a |scrollbar_| that has had its
+  // ScrollableArea detached. This seems weird because if the area is detached
+  // the layer should be destroyed but here we are.
+  if (!scrollbar_->GetScrollableArea())
+    return;
+  // When the frame is throttled, the scrollbar will not be painted because
+  // the frame has not had its lifecycle updated.
   if (scrollbar.GetScrollableArea()->IsThrottled())
     return;
 
diff --git a/third_party/blink/tools/audit_non_blink_usage.py b/third_party/blink/tools/audit_non_blink_usage.py
index e032348..0fdf3f1 100755
--- a/third_party/blink/tools/audit_non_blink_usage.py
+++ b/third_party/blink/tools/audit_non_blink_usage.py
@@ -302,7 +302,10 @@
             'third_party/blink/renderer/modules/gamepad/',
             'third_party/blink/renderer/modules/sensor/',
         ],
-        'allowed': ['device::.+'],
+        'allowed': [
+            'base::subtle::Atomic32',
+            'device::.+',
+        ],
     },
     {
         'paths': [
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index 62abc55..aed01e02 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: c0a0d70a2b7a5d973828e6079386cb2a852e5b1c
+Revision: fb0f7ca8d7eb55ca51b77eb89813a3283a461b0c
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/AUTHORS b/third_party/crashpad/crashpad/AUTHORS
index 7c40c4f..8dcac32 100644
--- a/third_party/crashpad/crashpad/AUTHORS
+++ b/third_party/crashpad/crashpad/AUTHORS
@@ -11,3 +11,4 @@
 Opera Software ASA
 Vewd Software AS
 LG Electronics, Inc.
+MIPS Technologies, Inc.
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS
index fbbd899..dbdc3a4 100644
--- a/third_party/crashpad/crashpad/DEPS
+++ b/third_party/crashpad/crashpad/DEPS
@@ -14,7 +14,8 @@
 
 vars = {
   'chromium_git': 'https://chromium.googlesource.com',
-  'pull_linux_clang': False
+  'pull_linux_clang': False,
+  'pull_win_toolchain': False
 }
 
 deps = {
@@ -29,7 +30,7 @@
       '5e2b3ddde7cda5eb6bc09a5546a76b00e49d888f',
   'crashpad/third_party/mini_chromium/mini_chromium':
       Var('chromium_git') + '/chromium/mini_chromium@' +
-      'd5523a7033c013dd2ae73fa29428f7b70dc0b3a0',
+      '793e94e2c652831af2d25bb5288b04e59048c62d',
   'crashpad/third_party/libfuzzer/src':
       Var('chromium_git') + '/chromium/llvm-project/compiler-rt/lib/fuzzer.git@' +
       'fda403cf93ecb8792cb1d061564d89a6553ca020',
@@ -232,6 +233,23 @@
     ],
   },
   {
+    'name': 'toolchain_win',
+    'pattern': '.',
+    # This package is only updated when the solution in .gclient includes an
+    # entry like:
+    #   "custom_vars": { "pull_win_toolchain": True }
+    # This is because the contained bits are not redistributable.
+    'condition': 'checkout_win and pull_win_toolchain',
+    'action': [
+      'cipd',
+      'install',
+      'chrome_internal/third_party/sdk/windows',
+      'uploaded:2018-06-13',
+      '-root', 'crashpad/third_party/win/toolchain',
+      '-log-level', 'info',
+    ],
+  },
+  {
     'name': 'gyp',
     'pattern': '\.gypi?$',
     'action': ['python', 'crashpad/build/gyp_crashpad.py'],
diff --git a/third_party/crashpad/crashpad/compat/BUILD.gn b/third_party/crashpad/crashpad/compat/BUILD.gn
index 8db7b4de..2bfe074f 100644
--- a/third_party/crashpad/crashpad/compat/BUILD.gn
+++ b/third_party/crashpad/crashpad/compat/BUILD.gn
@@ -69,6 +69,7 @@
     sources += [
       "linux/signal.h",
       "linux/sys/ptrace.h",
+      "linux/sys/user.h",
     ]
   }
 
diff --git a/third_party/crashpad/crashpad/compat/compat.gyp b/third_party/crashpad/crashpad/compat/compat.gyp
index c5fe350f..1229ee0 100644
--- a/third_party/crashpad/crashpad/compat/compat.gyp
+++ b/third_party/crashpad/crashpad/compat/compat.gyp
@@ -19,7 +19,6 @@
   'targets': [
     {
       'target_name': 'crashpad_compat',
-      'type': 'static_library',
       'sources': [
         'android/dlfcn_internal.cc',
         'android/dlfcn_internal.h',
@@ -36,6 +35,7 @@
         'android/sys/user.h',
         'linux/signal.h',
         'linux/sys/ptrace.h',
+        'linux/sys/user.h',
         'mac/AvailabilityMacros.h',
         'mac/kern/exc_resource.h',
         'mac/mach/i386/thread_state.h',
@@ -62,6 +62,7 @@
       ],
       'conditions': [
         ['OS=="mac"', {
+          'type': 'none',
           'include_dirs': [
             'mac',
           ],
@@ -70,8 +71,18 @@
               'mac',
             ],
           },
+        }, {
+          'include_dirs': [
+            'non_mac',
+          ],
+          'direct_dependent_settings': {
+            'include_dirs': [
+              'non_mac',
+            ],
+          },
         }],
         ['OS=="win"', {
+          'type': 'static_library',
           'include_dirs': [
             'win',
           ],
@@ -94,6 +105,7 @@
           },
         }],
         ['OS=="android"', {
+          'type': 'static_library',
           'include_dirs': [
             'android',
             'linux',
@@ -111,6 +123,7 @@
           },
         }],
         ['OS=="linux"', {
+          'type': 'none',
           'include_dirs': [
             'linux',
           ],
diff --git a/third_party/crashpad/crashpad/compat/linux/sys/ptrace.h b/third_party/crashpad/crashpad/compat/linux/sys/ptrace.h
index e5c95c7..fa89438 100644
--- a/third_party/crashpad/crashpad/compat/linux/sys/ptrace.h
+++ b/third_party/crashpad/crashpad/compat/linux/sys/ptrace.h
@@ -30,6 +30,13 @@
 static constexpr __ptrace_request PTRACE_GET_THREAD_AREA =
     static_cast<__ptrace_request>(22);
 #define PTRACE_GET_THREAD_AREA PTRACE_GET_THREAD_AREA
+#elif defined(__mips__)
+static constexpr __ptrace_request PTRACE_GET_THREAD_AREA =
+    static_cast<__ptrace_request>(25);
+#define PTRACE_GET_THREAD_AREA PTRACE_GET_THREAD_AREA
+static constexpr __ptrace_request PTRACE_GET_THREAD_AREA_3264 =
+    static_cast<__ptrace_request>(0xc4);
+#define PTRACE_GET_THREAD_AREA_3264 PTRACE_GET_THREAD_AREA_3264
 #endif
 #endif  // !PTRACE_GET_THREAD_AREA && !PT_GET_THREAD_AREA && defined(__GLIBC__)
 
diff --git a/third_party/crashpad/crashpad/compat/linux/sys/user.h b/third_party/crashpad/crashpad/compat/linux/sys/user.h
new file mode 100644
index 0000000..0ce5338b
--- /dev/null
+++ b/third_party/crashpad/crashpad/compat/linux/sys/user.h
@@ -0,0 +1,30 @@
+// Copyright 2018 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_COMPAT_LINUX_SYS_USER_H_
+#define CRASHPAD_COMPAT_LINUX_SYS_USER_H_
+
+#include_next <sys/user.h>
+
+#include <features.h>
+
+// glibc for 64-bit ARM uses different names for these structs prior to 2.20.
+#if defined(__arm64__) && defined(__GLIBC__)
+#if !__GLIBC_PREREQ(2, 20)
+using user_regs_struct = user_pt_regs;
+using user_fpsimd_struct = user_fpsimd_state;
+#endif
+#endif
+
+#endif  // CRASHPAD_COMPAT_LINUX_SYS_USER_H_
diff --git a/third_party/crashpad/crashpad/infra/config/cq.cfg b/third_party/crashpad/crashpad/infra/config/cq.cfg
index 64213fc3..b6bf0434 100644
--- a/third_party/crashpad/crashpad/infra/config/cq.cfg
+++ b/third_party/crashpad/crashpad/infra/config/cq.cfg
@@ -39,10 +39,10 @@
       builders { name: "crashpad_try_win_rel" }
       builders { name: "crashpad_try_linux_dbg" }
       builders { name: "crashpad_try_linux_rel" }
-      # https://bugs.chromium.org/p/crashpad/issues/detail?id=219 QEMU runs are
-      # flaking; remove from CQ while being investigated.
-      #builders { name: "crashpad_try_fuchsia_x64_dbg" }
-      #builders { name: "crashpad_try_fuchsia_x64_rel" }
+      builders { name: "crashpad_try_fuchsia_arm64_dbg" }
+      builders { name: "crashpad_try_fuchsia_arm64_rel" }
+      builders { name: "crashpad_try_fuchsia_x64_dbg" }
+      builders { name: "crashpad_try_fuchsia_x64_rel" }
       # https://crbug.com/743139 - disabled until we can move these to swarming,
       # at which point we can just remove them.
       #builders { name: "crashpad_try_win_x86_dbg" }
diff --git a/third_party/crashpad/crashpad/minidump/minidump_context.h b/third_party/crashpad/crashpad/minidump/minidump_context.h
index a7328ca..6f51b5a 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_context.h
+++ b/third_party/crashpad/crashpad/minidump/minidump_context.h
@@ -432,6 +432,138 @@
   uint128_struct fpsimd[32];
 };
 
+//! \brief 32bit MIPS-specifc flags for MinidumpContextMIPS::context_flags.
+//! Based on minidump_cpu_mips.h from breakpad
+enum MinidumpContextMIPSFlags : uint32_t {
+  //! \brief Identifies the context structure as MIPSEL.
+  kMinidumpContextMIPS = 0x00040000,
+
+  //! \brief Indicates the validity of integer registers.
+  //!
+  //! Registers `0`-`31`, `mdhi`, `mdlo`, `epc`, `badvaddr`, `status` and
+  //! `cause` are valid.
+  kMinidumpContextMIPSInteger = kMinidumpContextMIPS | 0x00000002,
+
+  //! \brief Indicates the validity of floating point registers.
+  //!
+  //! Floating point registers `0`-`31`, `fpcsr` and `fir` are valid
+  kMinidumpContextMIPSFloatingPoint = kMinidumpContextMIPS | 0x00000004,
+
+  //! \brief Indicates the validity of DSP registers.
+  //!
+  //! Registers `hi0`-`hi2`, `lo0`-`lo2` and `dsp_control` are valid
+  kMinidumpContextMIPSDSP = kMinidumpContextMIPS | 0x00000008,
+
+  //! \brief Indicates the validity of all registers.
+  kMinidumpContextMIPSAll = kMinidumpContextMIPSInteger |
+                            kMinidumpContextMIPSFloatingPoint |
+                            kMinidumpContextMIPSDSP,
+};
+
+//! \brief A 32bit MIPS CPU context (register state) carried in a minidump file.
+struct MinidumpContextMIPS {
+  uint32_t context_flags;
+
+  //! \brief This padding field is included for breakpad compatibility.
+  uint32_t _pad0;
+  //! \brief General purpose registers `0`-`31`.
+  uint64_t regs[32];
+
+  //! \brief Multiply/divide result.
+  uint64_t mdhi, mdlo;
+
+  //! \brief DSP registers.
+  uint32_t hi[3];
+  uint32_t lo[3];
+  uint32_t dsp_control;
+  //! \brief This padding field is included for breakpad compatibility.
+  uint32_t _pad1;
+
+  // \brief cp0 registers.
+  uint64_t epc;
+  uint64_t badvaddr;
+  uint32_t status;
+  uint32_t cause;
+
+  //! \brief FPU registers.
+  union {
+    struct {
+      float _fp_fregs;
+      uint32_t _fp_pad;
+    } fregs[32];
+    double dregs[32];
+  } fpregs;
+
+  //! \brief FPU status register.
+  uint32_t fpcsr;
+  //! \brief FPU implementation register.
+  uint32_t fir;
+};
+
+//! \brief 64bit MIPS-specifc flags for MinidumpContextMIPS64::context_flags.
+//! Based on minidump_cpu_mips.h from breakpad
+enum MinidumpContextMIPS64Flags : uint32_t {
+  //! \brief Identifies the context structure as MIPS64EL.
+  kMinidumpContextMIPS64 = 0x00080000,
+
+  //! \brief Indicates the validity of integer registers.
+  //!
+  //! Registers `0`-`31`, `mdhi`, `mdlo`, `epc`, `badvaddr`, `status` and
+  //! `cause` are valid.
+  kMinidumpContextMIPS64Integer = kMinidumpContextMIPS64 | 0x00000002,
+
+  //! \brief Indicates the validity of floating point registers.
+  //!
+  //! Floating point registers `0`-`31`, `fpcsr` and `fir` are valid
+  kMinidumpContextMIPS64FloatingPoint = kMinidumpContextMIPS64 | 0x00000004,
+
+  //! \brief Indicates the validity of DSP registers.
+  //!
+  //! Registers `hi0`-`hi2`, `lo0`-`lo2` and `dsp_control` are valid.
+  kMinidumpContextMIPS64DSP = kMinidumpContextMIPS64 | 0x00000008,
+
+  //! \brief Indicates the validity of all registers.
+  kMinidumpContextMIPS64All = kMinidumpContextMIPS64Integer |
+                              kMinidumpContextMIPS64FloatingPoint |
+                              kMinidumpContextMIPS64DSP,
+};
+
+//! \brief A 32bit MIPS CPU context (register state) carried in a minidump file.
+struct MinidumpContextMIPS64 {
+  uint64_t context_flags;
+
+  //! \brief General purpose registers.
+  uint64_t regs[32];
+
+  //! \brief Multiply/divide result.
+  uint64_t mdhi, mdlo;
+
+  //! \brief DSP registers.
+  uint64_t hi[3];
+  uint64_t lo[3];
+  uint64_t dsp_control;
+
+  //! \brief cp0 registers.
+  uint64_t epc;
+  uint64_t badvaddr;
+  uint64_t status;
+  uint64_t cause;
+
+  //! \brief FPU registers.
+  union {
+    struct {
+      float _fp_fregs;
+      uint32_t _fp_pad;
+    } fregs[32];
+    double dregs[32];
+  } fpregs;
+
+  //! \brief FPU status register.
+  uint64_t fpcsr;
+  //! \brief FPU implementation register.
+  uint64_t fir;
+};
+
 }  // namespace crashpad
 
 #endif  // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_H_
diff --git a/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
index 2fa2e53..20adbf3 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer.cc
@@ -87,6 +87,20 @@
       break;
     }
 
+    case kCPUArchitectureMIPSEL: {
+      context = std::make_unique<MinidumpContextMIPSWriter>();
+      reinterpret_cast<MinidumpContextMIPSWriter*>(context.get())
+          ->InitializeFromSnapshot(context_snapshot->mipsel);
+      break;
+    }
+
+    case kCPUArchitectureMIPS64EL: {
+      context = std::make_unique<MinidumpContextMIPS64Writer>();
+      reinterpret_cast<MinidumpContextMIPS64Writer*>(context.get())
+          ->InitializeFromSnapshot(context_snapshot->mips64);
+      break;
+    }
+
     default: {
       LOG(ERROR) << "unknown context architecture "
                  << context_snapshot->architecture;
@@ -339,4 +353,101 @@
   return sizeof(context_);
 }
 
+MinidumpContextMIPSWriter::MinidumpContextMIPSWriter()
+    : MinidumpContextWriter(), context_() {
+  context_.context_flags = kMinidumpContextMIPS;
+}
+
+MinidumpContextMIPSWriter::~MinidumpContextMIPSWriter() = default;
+
+void MinidumpContextMIPSWriter::InitializeFromSnapshot(
+    const CPUContextMIPS* context_snapshot) {
+  DCHECK_EQ(state(), kStateMutable);
+  DCHECK_EQ(context_.context_flags, kMinidumpContextMIPS);
+
+  context_.context_flags = kMinidumpContextMIPSAll;
+
+  static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs),
+                "GPRs size mismatch");
+  memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
+  context_.mdhi = context_snapshot->mdhi;
+  context_.mdlo = context_snapshot->mdlo;
+  context_.epc = context_snapshot->cp0_epc;
+  context_.badvaddr = context_snapshot->cp0_badvaddr;
+  context_.status = context_snapshot->cp0_status;
+  context_.cause = context_snapshot->cp0_cause;
+
+  static_assert(sizeof(context_.fpregs) == sizeof(context_snapshot->fpregs),
+                "FPRs size mismatch");
+  memcpy(&context_.fpregs, &context_snapshot->fpregs, sizeof(context_.fpregs));
+  context_.fpcsr = context_snapshot->fpcsr;
+  context_.fir = context_snapshot->fir;
+
+  for (size_t index = 0; index < 3; ++index) {
+    context_.hi[index] = context_snapshot->hi[index];
+    context_.lo[index] = context_snapshot->lo[index];
+  }
+  context_.dsp_control = context_snapshot->dsp_control;
+}
+
+bool MinidumpContextMIPSWriter::WriteObject(FileWriterInterface* file_writer) {
+  DCHECK_EQ(state(), kStateWritable);
+  return file_writer->Write(&context_, sizeof(context_));
+}
+
+size_t MinidumpContextMIPSWriter::ContextSize() const {
+  DCHECK_GE(state(), kStateFrozen);
+  return sizeof(context_);
+}
+
+MinidumpContextMIPS64Writer::MinidumpContextMIPS64Writer()
+    : MinidumpContextWriter(), context_() {
+  context_.context_flags = kMinidumpContextMIPS64;
+}
+
+MinidumpContextMIPS64Writer::~MinidumpContextMIPS64Writer() = default;
+
+void MinidumpContextMIPS64Writer::InitializeFromSnapshot(
+    const CPUContextMIPS64* context_snapshot) {
+  DCHECK_EQ(state(), kStateMutable);
+  DCHECK_EQ(context_.context_flags, kMinidumpContextMIPS64);
+
+  context_.context_flags = kMinidumpContextMIPS64All;
+
+  static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs),
+                "GPRs size mismatch");
+  memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
+  context_.mdhi = context_snapshot->mdhi;
+  context_.mdlo = context_snapshot->mdlo;
+  context_.epc = context_snapshot->cp0_epc;
+  context_.badvaddr = context_snapshot->cp0_badvaddr;
+  context_.status = context_snapshot->cp0_status;
+  context_.cause = context_snapshot->cp0_cause;
+
+  static_assert(sizeof(context_.fpregs) == sizeof(context_snapshot->fpregs),
+                "FPRs size mismatch");
+  memcpy(context_.fpregs.dregs,
+         context_snapshot->fpregs.dregs,
+         sizeof(context_.fpregs.dregs));
+  context_.fpcsr = context_snapshot->fpcsr;
+  context_.fir = context_snapshot->fir;
+
+  for (size_t index = 0; index < 3; ++index) {
+    context_.hi[index] = context_snapshot->hi[index];
+    context_.lo[index] = context_snapshot->lo[index];
+  }
+  context_.dsp_control = context_snapshot->dsp_control;
+}
+
+bool MinidumpContextMIPS64Writer::WriteObject(
+    FileWriterInterface* file_writer) {
+  DCHECK_EQ(state(), kStateWritable);
+  return file_writer->Write(&context_, sizeof(context_));
+}
+
+size_t MinidumpContextMIPS64Writer::ContextSize() const {
+  DCHECK_GE(state(), kStateFrozen);
+  return sizeof(context_);
+}
+
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/minidump/minidump_context_writer.h b/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
index fb3b151..d4ab936e 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
+++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer.h
@@ -235,6 +235,86 @@
   DISALLOW_COPY_AND_ASSIGN(MinidumpContextARM64Writer);
 };
 
+//! \brief The writer for a MinidumpContextMIPS structure in a minidump file.
+class MinidumpContextMIPSWriter final : public MinidumpContextWriter {
+ public:
+  MinidumpContextMIPSWriter();
+  ~MinidumpContextMIPSWriter() override;
+
+  //! \brief Initializes the MinidumpContextMIPS based on \a context_snapshot.
+  //!
+  //! \param[in] context_snapshot The context snapshot to use as source data.
+  //!
+  //! \note Valid in #kStateMutable. No mutation of context() may be done before
+  //!     calling this method, and it is not normally necessary to alter
+  //!     context() after calling this method.
+  void InitializeFromSnapshot(const CPUContextMIPS* context_snapshot);
+
+  //! \brief Returns a pointer to the context structure that this object will
+  //!     write.
+  //!
+  //! \attention This returns a non-`const` pointer to this object’s private
+  //!     data so that a caller can populate the context structure directly.
+  //!     This is done because providing setter interfaces to each field in the
+  //!     context structure would be unwieldy and cumbersome. Care must be taken
+  //!     to populate the context structure correctly. The context structure
+  //!     must only be modified while this object is in the #kStateMutable
+  //!     state.
+  MinidumpContextMIPS* context() { return &context_; }
+
+ protected:
+  // MinidumpWritable:
+  bool WriteObject(FileWriterInterface* file_writer) override;
+
+  // MinidumpContextWriter:
+  size_t ContextSize() const override;
+
+ private:
+  MinidumpContextMIPS context_;
+
+  DISALLOW_COPY_AND_ASSIGN(MinidumpContextMIPSWriter);
+};
+
+//! \brief The writer for a MinidumpContextMIPS64 structure in a minidump file.
+class MinidumpContextMIPS64Writer final : public MinidumpContextWriter {
+ public:
+  MinidumpContextMIPS64Writer();
+  ~MinidumpContextMIPS64Writer() override;
+
+  //! \brief Initializes the MinidumpContextMIPS based on \a context_snapshot.
+  //!
+  //! \param[in] context_snapshot The context snapshot to use as source data.
+  //!
+  //! \note Valid in #kStateMutable. No mutation of context() may be done before
+  //!     calling this method, and it is not normally necessary to alter
+  //!     context() after calling this method.
+  void InitializeFromSnapshot(const CPUContextMIPS64* context_snapshot);
+
+  //! \brief Returns a pointer to the context structure that this object will
+  //!     write.
+  //!
+  //! \attention This returns a non-`const` pointer to this object’s private
+  //!     data so that a caller can populate the context structure directly.
+  //!     This is done because providing setter interfaces to each field in the
+  //!     context structure would be unwieldy and cumbersome. Care must be taken
+  //!     to populate the context structure correctly. The context structure
+  //!     must only be modified while this object is in the #kStateMutable
+  //!     state.
+  MinidumpContextMIPS64* context() { return &context_; }
+
+ protected:
+  // MinidumpWritable:
+  bool WriteObject(FileWriterInterface* file_writer) override;
+
+  // MinidumpContextWriter:
+  size_t ContextSize() const override;
+
+ private:
+  MinidumpContextMIPS64 context_;
+
+  DISALLOW_COPY_AND_ASSIGN(MinidumpContextMIPS64Writer);
+};
+
 }  // namespace crashpad
 
 #endif  // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_WRITER_H_
diff --git a/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc
index 0122683..3216a906 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_context_writer_test.cc
@@ -183,6 +183,36 @@
       context, ExpectMinidumpContextARM64, kSeed);
 }
 
+TEST(MinidumpContextWriter, MIPS_Zeros) {
+  EmptyContextTest<MinidumpContextMIPSWriter, MinidumpContextMIPS>(
+      ExpectMinidumpContextMIPS);
+}
+
+TEST(MinidumpContextWriter, MIPS64_Zeros) {
+  EmptyContextTest<MinidumpContextMIPS64Writer, MinidumpContextMIPS64>(
+      ExpectMinidumpContextMIPS64);
+}
+
+TEST(MinidumpContextWriter, MIPS_FromSnapshot) {
+  constexpr uint32_t kSeed = 32;
+  CPUContextMIPS context_mips;
+  CPUContext context;
+  context.mipsel = &context_mips;
+  InitializeCPUContextMIPS(&context, kSeed);
+  FromSnapshotTest<MinidumpContextMIPSWriter, MinidumpContextMIPS>(
+      context, ExpectMinidumpContextMIPS, kSeed);
+}
+
+TEST(MinidumpContextWriter, MIPS64_FromSnapshot) {
+  constexpr uint32_t kSeed = 64;
+  CPUContextMIPS64 context_mips;
+  CPUContext context;
+  context.mips64 = &context_mips;
+  InitializeCPUContextMIPS64(&context, kSeed);
+  FromSnapshotTest<MinidumpContextMIPS64Writer, MinidumpContextMIPS64>(
+      context, ExpectMinidumpContextMIPS64, kSeed);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
index c1e24892..d83ed23 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
@@ -122,6 +122,10 @@
   static constexpr char kCPU[] = "arm";
 #elif defined(ARCH_CPU_ARM64)
   static constexpr char kCPU[] = "arm64";
+#elif defined(ARCH_CPU_MIPSEL)
+  static constexpr char kCPU[] = "mips";
+#elif defined(ARCH_CPU_MIPS64EL)
+  static constexpr char kCPU[] = "mips64";
 #else
 #error define kCPU for this CPU
 #endif
diff --git a/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc b/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc
index 0dc3a97..28f9410 100644
--- a/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc
+++ b/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.cc
@@ -195,6 +195,80 @@
   context->fpcr = value++;
 }
 
+void InitializeMinidumpContextMIPS(MinidumpContextMIPS* context,
+                                   uint32_t seed) {
+  if (seed == 0) {
+    memset(context, 0, sizeof(*context));
+    context->context_flags = kMinidumpContextMIPS;
+    return;
+  }
+
+  context->context_flags = kMinidumpContextMIPSAll;
+
+  uint32_t value = seed;
+
+  for (size_t index = 0; index < arraysize(context->regs); ++index) {
+    context->regs[index] = value++;
+  }
+
+  context->mdlo = value++;
+  context->mdhi = value++;
+  context->epc = value++;
+  context->badvaddr = value++;
+  context->status = value++;
+  context->cause = value++;
+
+  for (size_t index = 0; index < arraysize(context->fpregs.fregs); ++index) {
+    context->fpregs.fregs[index]._fp_fregs = static_cast<float>(value++);
+  }
+
+  context->fpcsr = value++;
+  context->fir = value++;
+
+  for (size_t index = 0; index < 3; ++index) {
+    context->hi[index] = value++;
+    context->lo[index] = value++;
+  }
+
+  context->dsp_control = value++;
+}
+
+void InitializeMinidumpContextMIPS64(MinidumpContextMIPS64* context,
+                                     uint32_t seed) {
+  if (seed == 0) {
+    memset(context, 0, sizeof(*context));
+    context->context_flags = kMinidumpContextMIPS64;
+    return;
+  }
+
+  context->context_flags = kMinidumpContextMIPS64All;
+
+  uint64_t value = seed;
+
+  for (size_t index = 0; index < arraysize(context->regs); ++index) {
+    context->regs[index] = value++;
+  }
+
+  context->mdlo = value++;
+  context->mdhi = value++;
+  context->epc = value++;
+  context->badvaddr = value++;
+  context->status = value++;
+  context->cause = value++;
+
+  for (size_t index = 0; index < arraysize(context->fpregs.dregs); ++index) {
+    context->fpregs.dregs[index] = static_cast<double>(value++);
+  }
+  context->fpcsr = value++;
+  context->fir = value++;
+
+  for (size_t index = 0; index < 3; ++index) {
+    context->hi[index] = value++;
+    context->lo[index] = value++;
+  }
+  context->dsp_control = value++;
+}
+
 namespace {
 
 // Using gtest assertions, compares |expected| to |observed|. This is
@@ -453,5 +527,70 @@
   }
 }
 
+void ExpectMinidumpContextMIPS(uint32_t expect_seed,
+                               const MinidumpContextMIPS* observed,
+                               bool snapshot) {
+  MinidumpContextMIPS expected;
+  InitializeMinidumpContextMIPS(&expected, expect_seed);
+
+  EXPECT_EQ(observed->context_flags, expected.context_flags);
+
+  for (size_t index = 0; index < arraysize(expected.regs); ++index) {
+    EXPECT_EQ(observed->regs[index], expected.regs[index]);
+  }
+
+  EXPECT_EQ(observed->mdlo, expected.mdlo);
+  EXPECT_EQ(observed->mdhi, expected.mdhi);
+  EXPECT_EQ(observed->epc, expected.epc);
+  EXPECT_EQ(observed->badvaddr, expected.badvaddr);
+  EXPECT_EQ(observed->status, expected.status);
+  EXPECT_EQ(observed->cause, expected.cause);
+
+  for (size_t index = 0; index < arraysize(expected.fpregs.fregs); ++index) {
+    EXPECT_EQ(observed->fpregs.fregs[index]._fp_fregs,
+              expected.fpregs.fregs[index]._fp_fregs);
+  }
+  EXPECT_EQ(observed->fpcsr, expected.fpcsr);
+  EXPECT_EQ(observed->fir, expected.fir);
+
+  for (size_t index = 0; index < 3; ++index) {
+    EXPECT_EQ(observed->hi[index], expected.hi[index]);
+    EXPECT_EQ(observed->lo[index], expected.lo[index]);
+  }
+  EXPECT_EQ(observed->dsp_control, expected.dsp_control);
+}
+
+void ExpectMinidumpContextMIPS64(uint32_t expect_seed,
+                                 const MinidumpContextMIPS64* observed,
+                                 bool snapshot) {
+  MinidumpContextMIPS64 expected;
+  InitializeMinidumpContextMIPS64(&expected, expect_seed);
+
+  EXPECT_EQ(observed->context_flags, expected.context_flags);
+
+  for (size_t index = 0; index < arraysize(expected.regs); ++index) {
+    EXPECT_EQ(observed->regs[index], expected.regs[index]);
+  }
+
+  EXPECT_EQ(observed->mdlo, expected.mdlo);
+  EXPECT_EQ(observed->mdhi, expected.mdhi);
+  EXPECT_EQ(observed->epc, expected.epc);
+  EXPECT_EQ(observed->badvaddr, expected.badvaddr);
+  EXPECT_EQ(observed->status, expected.status);
+  EXPECT_EQ(observed->cause, expected.cause);
+
+  for (size_t index = 0; index < arraysize(expected.fpregs.dregs); ++index) {
+    EXPECT_EQ(observed->fpregs.dregs[index], expected.fpregs.dregs[index]);
+  }
+  EXPECT_EQ(observed->fpcsr, expected.fpcsr);
+  EXPECT_EQ(observed->fir, expected.fir);
+
+  for (size_t index = 0; index < 3; ++index) {
+    EXPECT_EQ(observed->hi[index], expected.hi[index]);
+    EXPECT_EQ(observed->lo[index], expected.lo[index]);
+  }
+  EXPECT_EQ(observed->dsp_control, expected.dsp_control);
+}
+
 }  // namespace test
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.h b/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.h
index 64f79cde..080e04a0 100644
--- a/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.h
+++ b/third_party/crashpad/crashpad/minidump/test/minidump_context_test_util.h
@@ -44,6 +44,9 @@
 void InitializeMinidumpContextARM(MinidumpContextARM* context, uint32_t seed);
 void InitializeMinidumpContextARM64(MinidumpContextARM64* context,
                                     uint32_t seed);
+void InitializeMinidumpContextMIPS(MinidumpContextMIPS* context, uint32_t seed);
+void InitializeMinidumpContextMIPS64(MinidumpContextMIPS* context,
+                                     uint32_t seed);
 //! \}
 
 //! \brief Verifies, via gtest assertions, that a context structure contains
@@ -76,6 +79,12 @@
 void ExpectMinidumpContextARM64(uint32_t expect_seed,
                                 const MinidumpContextARM64* observed,
                                 bool snapshot);
+void ExpectMinidumpContextMIPS(uint32_t expect_seed,
+                               const MinidumpContextMIPS* observed,
+                               bool snapshot);
+void ExpectMinidumpContextMIPS64(uint32_t expect_seed,
+                                 const MinidumpContextMIPS64* observed,
+                                 bool snapshot);
 //! \}
 
 }  // namespace test
diff --git a/third_party/crashpad/crashpad/snapshot/BUILD.gn b/third_party/crashpad/crashpad/snapshot/BUILD.gn
index 6bafabb..134df8b1 100644
--- a/third_party/crashpad/crashpad/snapshot/BUILD.gn
+++ b/third_party/crashpad/crashpad/snapshot/BUILD.gn
@@ -416,7 +416,8 @@
     libs = [ "dl" ]
   }
 
-  if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) {
+  if ((crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) &&
+      target_cpu != "mipsel" && target_cpu != "mips64el") {
     data_deps += [ ":crashpad_snapshot_test_both_dt_hash_styles" ]
   }
 
@@ -477,7 +478,8 @@
   deps += [ "../third_party/mini_chromium:base" ]
 }
 
-if (crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) {
+if ((crashpad_is_linux || crashpad_is_android || crashpad_is_fuchsia) &&
+    target_cpu != "mipsel" && target_cpu != "mips64el") {
   crashpad_loadable_module("crashpad_snapshot_test_both_dt_hash_styles") {
     testonly = true
     sources = [
diff --git a/third_party/crashpad/crashpad/snapshot/capture_memory.cc b/third_party/crashpad/crashpad/snapshot/capture_memory.cc
index 4327fbda9..98f400e 100644
--- a/third_party/crashpad/crashpad/snapshot/capture_memory.cc
+++ b/third_party/crashpad/crashpad/snapshot/capture_memory.cc
@@ -106,6 +106,10 @@
       MaybeCaptureMemoryAround(delegate, context.arm->regs[i]);
     }
   }
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+  for (size_t i = 0; i < arraysize(context.mipsel->regs); ++i) {
+    MaybeCaptureMemoryAround(delegate, context.mipsel->regs[i]);
+  }
 #else
 #error Port.
 #endif
diff --git a/third_party/crashpad/crashpad/snapshot/cpu_architecture.h b/third_party/crashpad/crashpad/snapshot/cpu_architecture.h
index 6116d4a1..811a720 100644
--- a/third_party/crashpad/crashpad/snapshot/cpu_architecture.h
+++ b/third_party/crashpad/crashpad/snapshot/cpu_architecture.h
@@ -37,7 +37,13 @@
   kCPUArchitectureARM,
 
   //! \brief 64-bit ARM.
-  kCPUArchitectureARM64
+  kCPUArchitectureARM64,
+
+  //! \brief 32-bit MIPSEL.
+  kCPUArchitectureMIPSEL,
+
+  //! \brief 64-bit MIPSEL.
+  kCPUArchitectureMIPS64EL
 };
 
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/cpu_context.cc b/third_party/crashpad/crashpad/snapshot/cpu_context.cc
index 553a1a5..4d7c1e5 100644
--- a/third_party/crashpad/crashpad/snapshot/cpu_context.cc
+++ b/third_party/crashpad/crashpad/snapshot/cpu_context.cc
@@ -194,9 +194,11 @@
   switch (architecture) {
     case kCPUArchitectureX86_64:
     case kCPUArchitectureARM64:
+    case kCPUArchitectureMIPS64EL:
       return true;
     case kCPUArchitectureX86:
     case kCPUArchitectureARM:
+    case kCPUArchitectureMIPSEL:
       return false;
     default:
       NOTREACHED();
diff --git a/third_party/crashpad/crashpad/snapshot/cpu_context.h b/third_party/crashpad/crashpad/snapshot/cpu_context.h
index b104217..4dde943 100644
--- a/third_party/crashpad/crashpad/snapshot/cpu_context.h
+++ b/third_party/crashpad/crashpad/snapshot/cpu_context.h
@@ -306,6 +306,52 @@
   uint32_t fpcr;
 };
 
+//! \brief A context structure carrying MIPS CPU state.
+struct CPUContextMIPS {
+  uint64_t regs[32];
+  uint32_t mdlo;
+  uint32_t mdhi;
+  uint32_t cp0_epc;
+  uint32_t cp0_badvaddr;
+  uint32_t cp0_status;
+  uint32_t cp0_cause;
+  uint32_t hi[3];
+  uint32_t lo[3];
+  uint32_t dsp_control;
+  union {
+    double dregs[32];
+    struct {
+      float _fp_fregs;
+      uint32_t _fp_pad;
+    } fregs[32];
+  } fpregs;
+  uint32_t fpcsr;
+  uint32_t fir;
+};
+
+//! \brief A context structure carrying MIPS64 CPU state.
+struct CPUContextMIPS64 {
+  uint64_t regs[32];
+  uint64_t mdlo;
+  uint64_t mdhi;
+  uint64_t cp0_epc;
+  uint64_t cp0_badvaddr;
+  uint64_t cp0_status;
+  uint64_t cp0_cause;
+  uint64_t hi[3];
+  uint64_t lo[3];
+  uint64_t dsp_control;
+  union {
+    double dregs[32];
+    struct {
+      float _fp_fregs;
+      uint32_t _fp_pad;
+    } fregs[32];
+  } fpregs;
+  uint64_t fpcsr;
+  uint64_t fir;
+};
+
 //! \brief A context structure capable of carrying the context of any supported
 //!     CPU architecture.
 struct CPUContext {
@@ -334,6 +380,8 @@
     CPUContextX86_64* x86_64;
     CPUContextARM* arm;
     CPUContextARM64* arm64;
+    CPUContextMIPS* mipsel;
+    CPUContextMIPS64* mips64;
   };
 };
 
diff --git a/third_party/crashpad/crashpad/snapshot/fuchsia/process_reader_fuchsia_test.cc b/third_party/crashpad/crashpad/snapshot/fuchsia/process_reader_fuchsia_test.cc
index 63b59e83..546d829 100644
--- a/third_party/crashpad/crashpad/snapshot/fuchsia/process_reader_fuchsia_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/fuchsia/process_reader_fuchsia_test.cc
@@ -18,6 +18,7 @@
 #include <zircon/process.h>
 #include <zircon/syscalls.h>
 #include <zircon/syscalls/port.h>
+#include <zircon/types.h>
 
 #include "gtest/gtest.h"
 #include "test/multiprocess_exec.h"
@@ -103,7 +104,7 @@
   zx_port_packet_t packet = {};
   packet.type = ZX_PKT_TYPE_USER;
   zx_port_queue(*reinterpret_cast<zx_handle_t*>(arg), &packet);
-  zx_nanosleep(UINT64_MAX);
+  zx_nanosleep(ZX_TIME_INFINITE);
   return nullptr;
 }
 
diff --git a/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h b/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h
index 4ca679a..37fbc432 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h
+++ b/third_party/crashpad/crashpad/snapshot/linux/cpu_context_linux.h
@@ -138,6 +138,42 @@
 
 #endif  // ARCH_CPU_ARM_FAMILY || DOXYGEN
 
+#if defined(ARCH_CPU_MIPS_FAMILY) || DOXYGEN
+
+//! \brief Initializes a CPUContextMIPS structure from native context
+//!     structures on Linux.
+//!
+//! This function has template specializations for MIPSEL and MIPS64EL
+//! architecture contexts, using ContextTraits32 or ContextTraits64 as template
+//! parameter, respectively.
+//!
+//! \param[in] thread_context The native thread context.
+//! \param[in] float_context The native float context.
+//! \param[out] context The CPUContextMIPS structure to initialize.
+template <typename Traits>
+void InitializeCPUContextMIPS(
+    const typename Traits::SignalThreadContext& thread_context,
+    const typename Traits::SignalFloatContext& float_context,
+    typename Traits::CPUContext* context) {
+  static_assert(sizeof(context->regs) == sizeof(thread_context.regs),
+                "registers size mismatch");
+  static_assert(sizeof(context->fpregs) == sizeof(float_context.fpregs),
+                "fp registers size mismatch");
+  memcpy(&context->regs, &thread_context.regs, sizeof(context->regs));
+  context->mdlo = thread_context.lo;
+  context->mdhi = thread_context.hi;
+  context->cp0_epc = thread_context.cp0_epc;
+  context->cp0_badvaddr = thread_context.cp0_badvaddr;
+  context->cp0_status = thread_context.cp0_status;
+  context->cp0_cause = thread_context.cp0_cause;
+
+  memcpy(&context->fpregs, &float_context.fpregs, sizeof(context->fpregs));
+  context->fpcsr = float_context.fpcsr;
+  context->fir = float_context.fpu_id;
+};
+
+#endif  // ARCH_CPU_MIPS_FAMILY || DOXYGEN
+
 }  // namespace internal
 }  // namespace crashpad
 
diff --git a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc
index 6e2a927..4256f942 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.cc
@@ -130,7 +130,7 @@
 
   LinuxVMAddress gprs_address =
       context_address + offsetof(UContext<ContextTraits32>, mcontext32) +
-      offsetof(MContext32, gprs);
+      offsetof(ContextTraits32::MContext32, gprs);
 
   SignalThreadContext32 thread_context;
   if (!memory->Read(gprs_address, sizeof(thread_context), &thread_context)) {
@@ -207,7 +207,7 @@
 
   LinuxVMAddress gprs_address =
       context_address + offsetof(UContext<ContextTraits64>, mcontext64) +
-      offsetof(MContext64, gprs);
+      offsetof(ContextTraits64::MContext64, gprs);
 
   ThreadContext::t64_t thread_context;
   if (!memory->Read(gprs_address, sizeof(thread_context), &thread_context)) {
@@ -268,6 +268,61 @@
   } while (true);
 }
 
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+
+template <typename Traits>
+static bool ReadContext(ProcessReaderLinux* reader,
+                        LinuxVMAddress context_address,
+                        typename Traits::CPUContext* dest_context) {
+  ProcessMemory* memory = reader->Memory();
+
+  LinuxVMAddress gregs_address = context_address +
+                                 offsetof(UContext<Traits>, mcontext) +
+                                 offsetof(typename Traits::MContext, gregs);
+
+  typename Traits::SignalThreadContext thread_context;
+  if (!memory->Read(gregs_address, sizeof(thread_context), &thread_context)) {
+    LOG(ERROR) << "Couldn't read gregs";
+    return false;
+  }
+
+  LinuxVMAddress fpregs_address = context_address +
+                                  offsetof(UContext<Traits>, mcontext) +
+                                  offsetof(typename Traits::MContext, fpregs);
+
+  typename Traits::SignalFloatContext fp_context;
+  if (!memory->Read(fpregs_address, sizeof(fp_context), &fp_context)) {
+    LOG(ERROR) << "Couldn't read fpregs";
+    return false;
+  }
+
+  InitializeCPUContextMIPS<Traits>(thread_context, fp_context, dest_context);
+
+  return true;
+}
+
+template <>
+bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
+    ProcessReaderLinux* reader,
+    LinuxVMAddress context_address) {
+  context_.architecture = kCPUArchitectureMIPSEL;
+  context_.mipsel = &context_union_.mipsel;
+
+  return internal::ReadContext<ContextTraits32>(
+      reader, context_address, context_.mipsel);
+}
+
+template <>
+bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
+    ProcessReaderLinux* reader,
+    LinuxVMAddress context_address) {
+  context_.architecture = kCPUArchitectureMIPS64EL;
+  context_.mips64 = &context_union_.mips64;
+
+  return internal::ReadContext<ContextTraits64>(
+      reader, context_address, context_.mips64);
+}
+
 #endif  // ARCH_CPU_X86_FAMILY
 
 bool ExceptionSnapshotLinux::Initialize(ProcessReaderLinux* process_reader,
diff --git a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h
index 0dcead7b..ea0cd210 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h
+++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux.h
@@ -81,6 +81,9 @@
 #elif defined(ARCH_CPU_ARM_FAMILY)
     CPUContextARM arm;
     CPUContextARM64 arm64;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+    CPUContextMIPS mipsel;
+    CPUContextMIPS64 mips64;
 #endif
   } context_union_;
   CPUContext context_;
diff --git a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
index 5a0c6ae1..df9ad9e 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/exception_snapshot_linux_test.cc
@@ -266,6 +266,36 @@
                    sizeof(actual.arm64->fpsimd)),
             0);
 }
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+using NativeCPUContext = ucontext_t;
+
+void InitializeContext(NativeCPUContext* context) {
+  for (size_t reg = 0; reg < arraysize(context->uc_mcontext.gregs); ++reg) {
+    context->uc_mcontext.gregs[reg] = reg;
+  }
+  memset(&context->uc_mcontext.fpregs, 44, sizeof(context->uc_mcontext.fpregs));
+}
+
+void ExpectContext(const CPUContext& actual, const NativeCPUContext& expected) {
+#if defined(ARCH_CPU_MIPSEL)
+  EXPECT_EQ(actual.architecture, kCPUArchitectureMIPSEL);
+#define CPU_ARCH_NAME mipsel
+#elif defined(ARCH_CPU_MIPS64EL)
+  EXPECT_EQ(actual.architecture, kCPUArchitectureMIPS64EL);
+#define CPU_ARCH_NAME mips64
+#endif
+
+  for (size_t reg = 0; reg < arraysize(expected.uc_mcontext.gregs); ++reg) {
+    EXPECT_EQ(actual.CPU_ARCH_NAME->regs[reg], expected.uc_mcontext.gregs[reg]);
+  }
+
+  EXPECT_EQ(memcmp(&actual.CPU_ARCH_NAME->fpregs,
+                   &expected.uc_mcontext.fpregs,
+                   sizeof(actual.CPU_ARCH_NAME->fpregs)),
+            0);
+#undef CPU_ARCH_NAME
+}
+
 #else
 #error Port.
 #endif
diff --git a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc
index 9a5b092..038d5cef 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/process_reader_linux.cc
@@ -100,6 +100,9 @@
 #elif defined(ARCH_CPU_ARM_FAMILY)
   stack_pointer = reader->Is64Bit() ? thread_info.thread_context.t64.sp
                                     : thread_info.thread_context.t32.sp;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+  stack_pointer = reader->Is64Bit() ? thread_info.thread_context.t64.regs[29]
+                                    : thread_info.thread_context.t32.regs[29];
 #else
 #error Port.
 #endif
diff --git a/third_party/crashpad/crashpad/snapshot/linux/signal_context.h b/third_party/crashpad/crashpad/snapshot/linux/signal_context.h
index f9d2cb9..1100246 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/signal_context.h
+++ b/third_party/crashpad/crashpad/snapshot/linux/signal_context.h
@@ -18,7 +18,9 @@
 #include <signal.h>
 #include <stdint.h>
 #include <sys/types.h>
+#include <sys/ucontext.h>
 
+#include <cstddef>
 #include <type_traits>
 
 #include "build/build_config.h"
@@ -39,8 +41,14 @@
 template <class Traits>
 struct Siginfo {
   int32_t signo;
+#ifdef ARCH_CPU_MIPS_FAMILY
+  // Attribute order for signo_t defined in kernel is different for MIPS.
+  int32_t code;
+  int32_t err;
+#else
   int32_t err;
   int32_t code;
+#endif
   typename Traits::UInteger32_64Only padding;
 
   union {
@@ -244,7 +252,7 @@
 
 using SignalThreadContext64 = ThreadContext::t64_t;
 
-struct MContext32 {
+struct MContext32Data {
   uint32_t trap_no;
   uint32_t error_code;
   uint32_t oldmask;
@@ -252,19 +260,19 @@
   uint32_t fault_address;
 };
 
-struct MContext64 {
+struct MContext64Data {
   uint64_t fault_address;
   SignalThreadContext64 gprs;
 };
 
 struct ContextTraits32 : public Traits32 {
-  using MContext32 = MContext32;
+  using MContext32 = MContext32Data;
   using MContext64 = Nothing;
 };
 
 struct ContextTraits64 : public Traits64 {
   using MContext32 = Nothing;
-  using MContext64 = MContext64;
+  using MContext64 = MContext64Data;
 };
 
 template <typename Traits>
@@ -299,6 +307,121 @@
               "reserved space offset mismtach");
 #endif
 
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+
+struct MContext32 {
+  uint32_t regmask;
+  uint32_t status;
+  uint64_t pc;
+  uint64_t gregs[32];
+  struct {
+    float _fp_fregs;
+    unsigned int _fp_pad;
+  } fpregs[32];
+  uint32_t fp_owned;
+  uint32_t fpc_csr;
+  uint32_t fpc_eir;
+  uint32_t used_math;
+  uint32_t dsp;
+  uint64_t mdhi;
+  uint64_t mdlo;
+  uint32_t hi1;
+  uint32_t lo1;
+  uint32_t hi2;
+  uint32_t lo2;
+  uint32_t hi3;
+  uint32_t lo3;
+};
+
+struct MContext64 {
+  uint64_t gregs[32];
+  double fpregs[32];
+  uint64_t mdhi;
+  uint64_t hi1;
+  uint64_t hi2;
+  uint64_t hi3;
+  uint64_t mdlo;
+  uint64_t lo1;
+  uint64_t lo2;
+  uint64_t lo3;
+  uint64_t pc;
+  uint32_t fpc_csr;
+  uint32_t used_math;
+  uint32_t dsp;
+  uint32_t __glibc_reserved1;
+};
+
+struct SignalThreadContext32 {
+  uint64_t regs[32];
+  uint32_t lo;
+  uint32_t hi;
+  uint32_t cp0_epc;
+  uint32_t cp0_badvaddr;
+  uint32_t cp0_status;
+  uint32_t cp0_cause;
+
+  SignalThreadContext32() {}
+  explicit SignalThreadContext32(
+      const struct ThreadContext::t32_t& thread_context) {
+    for (size_t reg = 0; reg < 32; ++reg) {
+      regs[reg] = thread_context.regs[reg];
+    }
+    lo = thread_context.lo;
+    hi = thread_context.hi;
+    cp0_epc = thread_context.cp0_epc;
+    cp0_badvaddr = thread_context.cp0_badvaddr;
+    cp0_status = thread_context.cp0_status;
+    cp0_cause = thread_context.cp0_cause;
+  }
+};
+
+struct ContextTraits32 : public Traits32 {
+  using MContext = MContext32;
+  using SignalThreadContext = SignalThreadContext32;
+  using SignalFloatContext = FloatContext::f32_t;
+  using CPUContext = CPUContextMIPS;
+};
+
+struct ContextTraits64 : public Traits64 {
+  using MContext = MContext64;
+  using SignalThreadContext = ThreadContext::t64_t;
+  using SignalFloatContext = FloatContext::f64_t;
+  using CPUContext = CPUContextMIPS64;
+};
+
+template <typename Traits>
+struct UContext {
+  typename Traits::ULong flags;
+  typename Traits::Address link;
+  SignalStack<Traits> stack;
+  typename Traits::ULong_32Only alignment_padding_;
+  typename Traits::MContext mcontext;
+  Sigset<Traits> sigmask;
+};
+
+#if defined(ARCH_CPU_MIPSEL)
+static_assert(offsetof(UContext<ContextTraits32>, mcontext) ==
+                  offsetof(ucontext_t, uc_mcontext),
+              "context offset mismatch");
+static_assert(offsetof(UContext<ContextTraits32>, mcontext.gregs) ==
+                  offsetof(ucontext_t, uc_mcontext.gregs),
+              "context offset mismatch");
+static_assert(offsetof(UContext<ContextTraits32>, mcontext.fpregs) ==
+                  offsetof(ucontext_t, uc_mcontext.fpregs),
+              "context offset mismatch");
+
+#elif defined(ARCH_CPU_MIPS64EL)
+static_assert(offsetof(UContext<ContextTraits64>, mcontext) ==
+                  offsetof(ucontext_t, uc_mcontext),
+              "context offset mismtach");
+static_assert(offsetof(UContext<ContextTraits64>, mcontext.gregs) ==
+                  offsetof(ucontext_t, uc_mcontext.gregs),
+              "context offset mismatch");
+static_assert(offsetof(UContext<ContextTraits64>, mcontext.fpregs) ==
+                  offsetof(ucontext_t, uc_mcontext.fpregs),
+              "context offset mismatch");
+#endif
+
 #else
 #error Port.
 #endif  // ARCH_CPU_X86_FAMILY
diff --git a/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc
index 4c39288..8564d3d 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/system_snapshot_linux.cc
@@ -200,6 +200,9 @@
 #elif defined(ARCH_CPU_ARM_FAMILY)
   return process_reader_->Is64Bit() ? kCPUArchitectureARM64
                                     : kCPUArchitectureARM;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+  return process_reader_->Is64Bit() ? kCPUArchitectureMIPS64EL
+                                    : kCPUArchitectureMIPSEL;
 #else
 #error port to your architecture
 #endif
@@ -212,6 +215,9 @@
 #elif defined(ARCH_CPU_ARM_FAMILY)
   // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30
   return 0;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+  // Not implementable on MIPS
+  return 0;
 #else
 #error port to your architecture
 #endif
@@ -229,6 +235,9 @@
 #elif defined(ARCH_CPU_ARM_FAMILY)
   // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30
   return std::string();
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+  // Not implementable on MIPS
+  return std::string();
 #else
 #error port to your architecture
 #endif
@@ -359,6 +368,9 @@
 #elif defined(ARCH_CPU_ARM_FAMILY)
   // TODO(jperaza): do this. https://crashpad.chromium.org/bug/30
   return false;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+  // Not implementable on MIPS
+  return false;
 #else
 #error Port.
 #endif  // ARCH_CPU_X86_FAMILY
diff --git a/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc b/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc
index 084ed73..8ffbfe8b 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc
+++ b/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.cc
@@ -69,6 +69,22 @@
                             thread.thread_info.float_context.f32,
                             context_.arm);
   }
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+  if (process_reader->Is64Bit()) {
+    context_.architecture = kCPUArchitectureMIPS64EL;
+    context_.mips64 = &context_union_.mips64;
+    InitializeCPUContextMIPS<ContextTraits64>(
+        thread.thread_info.thread_context.t64,
+        thread.thread_info.float_context.f64,
+        context_.mips64);
+  } else {
+    context_.architecture = kCPUArchitectureMIPSEL;
+    context_.mipsel = &context_union_.mipsel;
+    InitializeCPUContextMIPS<ContextTraits32>(
+        SignalThreadContext32(thread.thread_info.thread_context.t32),
+        thread.thread_info.float_context.f32,
+        context_.mipsel);
+  }
 #else
 #error Port.
 #endif
diff --git a/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h b/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h
index 8fc7e17..17e471f 100644
--- a/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h
+++ b/third_party/crashpad/crashpad/snapshot/linux/thread_snapshot_linux.h
@@ -65,6 +65,9 @@
 #elif defined(ARCH_CPU_ARM_FAMILY)
     CPUContextARM arm;
     CPUContextARM64 arm64;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+    CPUContextMIPS mipsel;
+    CPUContextMIPS64 mips64;
 #else
 #error Port.
 #endif  // ARCH_CPU_X86_FAMILY
diff --git a/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp b/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
index fc746f2..b795d92 100644
--- a/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
+++ b/third_party/crashpad/crashpad/snapshot/snapshot_test.gyp
@@ -52,7 +52,6 @@
       'target_name': 'crashpad_snapshot_test',
       'type': 'executable',
       'dependencies': [
-        'crashpad_snapshot_test_both_dt_hash_styles',
         'crashpad_snapshot_test_lib',
         'crashpad_snapshot_test_module',
         'crashpad_snapshot_test_module_large',
@@ -104,6 +103,10 @@
         'win/system_snapshot_win_test.cc',
       ],
       'conditions': [
+        # .gnu.hash is incompatible with the MIPS ABI
+        ['target_arch!="mips"', {
+          'dependencies': ['crashpad_snapshot_test_both_dt_hash_styles']
+        }],
         ['OS=="mac"', {
           'dependencies': [
             'crashpad_snapshot_test_module_crashy_initializer',
@@ -228,13 +231,17 @@
     {
       'target_name': 'crashpad_snapshot_test_both_dt_hash_styles',
       'type': 'executable',
-      'sources': [
-        'hash_types_test.cc',
-      ],
-
-      'ldflags': [
-        # This makes `ld` emit both .hash and .gnu.hash sections.
-        '-Wl,--hash-style=both',
+      'conditions': [
+        # .gnu.hash is incompatible with the MIPS ABI
+        ['target_arch!="mips"', {
+          'sources': [
+            'hash_types_test.cc',
+          ],
+          'ldflags': [
+            # This makes `ld` emit both .hash and .gnu.hash sections.
+            '-Wl,--hash-style=both',
+          ]},
+        ]
       ],
     },
   ],
diff --git a/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc b/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc
index 09a5e79..1e785af8 100644
--- a/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc
+++ b/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.cc
@@ -220,5 +220,77 @@
   arm64->fpcr = value++;
 }
 
+void InitializeCPUContextMIPS(CPUContext* context, uint32_t seed) {
+  context->architecture = kCPUArchitectureMIPSEL;
+  CPUContextMIPS* mipsel = context->mipsel;
+
+  if (seed == 0) {
+    memset(mipsel, 0, sizeof(*mipsel));
+    return;
+  }
+
+  uint32_t value = seed;
+
+  for (size_t index = 0; index < arraysize(mipsel->regs); ++index) {
+    mipsel->regs[index] = value++;
+  }
+
+  mipsel->mdlo = value++;
+  mipsel->mdhi = value++;
+  mipsel->cp0_epc = value++;
+  mipsel->cp0_badvaddr = value++;
+  mipsel->cp0_status = value++;
+  mipsel->cp0_cause = value++;
+
+  for (size_t index = 0; index < arraysize(mipsel->fpregs.fregs); ++index) {
+    mipsel->fpregs.fregs[index]._fp_fregs = static_cast<float>(value++);
+  }
+
+  mipsel->fpcsr = value++;
+  mipsel->fir = value++;
+
+  for (size_t index = 0; index < 3; ++index) {
+    mipsel->hi[index] = value++;
+    mipsel->lo[index] = value++;
+  }
+  mipsel->dsp_control = value++;
+}
+
+void InitializeCPUContextMIPS64(CPUContext* context, uint32_t seed) {
+  context->architecture = kCPUArchitectureMIPS64EL;
+  CPUContextMIPS64* mips64 = context->mips64;
+
+  if (seed == 0) {
+    memset(mips64, 0, sizeof(*mips64));
+    return;
+  }
+
+  uint64_t value = seed;
+
+  for (size_t index = 0; index < arraysize(mips64->regs); ++index) {
+    mips64->regs[index] = value++;
+  }
+
+  mips64->mdlo = value++;
+  mips64->mdhi = value++;
+  mips64->cp0_epc = value++;
+  mips64->cp0_badvaddr = value++;
+  mips64->cp0_status = value++;
+  mips64->cp0_cause = value++;
+
+  for (size_t index = 0; index < arraysize(mips64->fpregs.dregs); ++index) {
+    mips64->fpregs.dregs[index] = static_cast<double>(value++);
+  }
+
+  mips64->fpcsr = value++;
+  mips64->fir = value++;
+
+  for (size_t index = 0; index < 3; ++index) {
+    mips64->hi[index] = value++;
+    mips64->lo[index] = value++;
+  }
+  mips64->dsp_control = value++;
+}
+
 }  // namespace test
 }  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.h b/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.h
index 0b4b5376..ca1b6b7b 100644
--- a/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.h
+++ b/third_party/crashpad/crashpad/snapshot/test/test_cpu_context.h
@@ -61,6 +61,8 @@
 void InitializeCPUContextX86_64(CPUContext* context, uint32_t seed);
 void InitializeCPUContextARM(CPUContext* context, uint32_t seed);
 void InitializeCPUContextARM64(CPUContext* context, uint32_t seed);
+void InitializeCPUContextMIPS(CPUContext* context, uint32_t seed);
+void InitializeCPUContextMIPS64(CPUContext* context, uint32_t seed);
 //! \}
 
 }  // namespace test
diff --git a/third_party/crashpad/crashpad/test/linux/get_tls.cc b/third_party/crashpad/crashpad/test/linux/get_tls.cc
index 47d041e4..452724de 100644
--- a/third_party/crashpad/crashpad/test/linux/get_tls.cc
+++ b/third_party/crashpad/crashpad/test/linux/get_tls.cc
@@ -35,6 +35,20 @@
   tls = tls_32;
 #elif defined(ARCH_CPU_X86_64)
   asm("movq %%fs:0x0, %0" : "=r"(tls));
+#elif defined(ARCH_CPU_MIPSEL)
+  uint32_t tls_32;
+  asm("rdhwr   $3,$29\n\t"
+      "move    %0,$3\n\t"
+      : "=r"(tls_32)
+      :
+      : "$3");
+  tls = tls_32;
+#elif defined(ARCH_CPU_MIPS64EL)
+  asm("rdhwr   $3,$29\n\t"
+      "move    %0,$3\n\t"
+      : "=r"(tls)
+      :
+      : "$3");
 #else
 #error Port.
 #endif  // ARCH_CPU_ARMEL
diff --git a/third_party/crashpad/crashpad/test/multiprocess.h b/third_party/crashpad/crashpad/test/multiprocess.h
index aac9288..d027502 100644
--- a/third_party/crashpad/crashpad/test/multiprocess.h
+++ b/third_party/crashpad/crashpad/test/multiprocess.h
@@ -89,7 +89,8 @@
   //! \param[in] code If \a reason is TerminationReason::kTerminationNormal,
   //!     this is the expected exit status of the child. If \a reason is
   //!     TerminationReason::kTerminationSignal, this is the signal that is
-  //!     expected to kill the child.
+  //!     expected to kill the child. On Linux platforms, SIG_DFL will be
+  //!     installed for \a code in the child process.
   void SetExpectedChildTermination(TerminationReason reason, int code);
 
 #if !defined(OS_WIN)
diff --git a/third_party/crashpad/crashpad/test/multiprocess_posix.cc b/third_party/crashpad/crashpad/test/multiprocess_posix.cc
index 96b8ad2..2e0c3856 100644
--- a/third_party/crashpad/crashpad/test/multiprocess_posix.cc
+++ b/third_party/crashpad/crashpad/test/multiprocess_posix.cc
@@ -143,6 +143,10 @@
     if (exception_swallower.get()) {
       ExceptionSwallower::SwallowExceptions();
     }
+#elif defined(OS_LINUX) || defined(OS_ANDROID)
+    if (reason_ == kTerminationSignal && Signals::IsCrashSignal(code_)) {
+      Signals::InstallDefaultHandler(code_);
+    }
 #endif  // OS_MACOSX
 
     RunChild();
@@ -158,7 +162,7 @@
 }
 
 void Multiprocess::SetExpectedChildTerminationBuiltinTrap() {
-#if defined(ARCH_CPU_ARM64)
+#if defined(ARCH_CPU_ARM64) || defined(ARCH_CPU_MIPS_FAMILY)
   SetExpectedChildTermination(kTerminationSignal, SIGTRAP);
 #else
   SetExpectedChildTermination(kTerminationSignal, SIGILL);
diff --git a/third_party/crashpad/crashpad/third_party/zlib/zlib.gyp b/third_party/crashpad/crashpad/third_party/zlib/zlib.gyp
index b6a6bc9..df26cc2 100644
--- a/third_party/crashpad/crashpad/third_party/zlib/zlib.gyp
+++ b/third_party/crashpad/crashpad/third_party/zlib/zlib.gyp
@@ -13,18 +13,28 @@
 # limitations under the License.
 
 {
-  'variables': {
-    'conditions': [
-      # Use the system zlib by default where available, as it is on most
-      # platforms. Windows does not have a system zlib, so use “embedded” which
-      # directs the build to use the source code in the zlib subdirectory.
-      ['OS!="win"', {
-        'zlib_source%': 'system',
-      }, {
-        'zlib_source%': 'embedded',
-      }],
-    ],
-  },
+  'includes': [
+    '../../build/crashpad_dependencies.gypi',
+  ],
+  'conditions': [
+    ['1==1', {  # Defer processing until crashpad_dependencies is set
+      'variables': {
+        'conditions': [
+          ['crashpad_dependencies=="external"', {
+            'zlib_source%': 'external',
+          }, 'OS!="win"', {
+            # Use the system zlib by default where available, as it is on most
+            # platforms. Windows does not have a system zlib, so use “embedded”
+            # which directs the build to use the source code in the zlib
+            # subdirectory.
+            'zlib_source%': 'system',
+          }, {
+            'zlib_source%': 'embedded',
+          }],
+        ],
+      },
+    }],
+  ],
   'targets': [
     {
       'target_name': 'zlib',
@@ -141,6 +151,17 @@
             }],
           ],
         }],
+        ['zlib_source=="external"', {
+          'type': 'none',
+          'direct_dependent_settings': {
+            'defines': [
+              'CRASHPAD_ZLIB_SOURCE_EXTERNAL',
+            ],
+          },
+          'dependencies': [
+            '../../../../zlib/zlib.gyp:zlib',
+          ],
+        }],
       ],
     },
   ],
diff --git a/third_party/crashpad/crashpad/third_party/zlib/zlib_crashpad.h b/third_party/crashpad/crashpad/third_party/zlib/zlib_crashpad.h
index d3a2386..fd497a8 100644
--- a/third_party/crashpad/crashpad/third_party/zlib/zlib_crashpad.h
+++ b/third_party/crashpad/crashpad/third_party/zlib/zlib_crashpad.h
@@ -19,9 +19,8 @@
 // available at any other location in the source tree. It will #include the
 // proper <zlib.h> depending on how the build has been configured.
 
-#if defined(CRASHPAD_ZLIB_SOURCE_EXTERNAL)
-#include "third_party/zlib/zlib.h"
-#elif defined(CRASHPAD_ZLIB_SOURCE_SYSTEM)
+#if defined(CRASHPAD_ZLIB_SOURCE_SYSTEM) || \
+    defined(CRASHPAD_ZLIB_SOURCE_EXTERNAL)
 #include <zlib.h>
 #elif defined(CRASHPAD_ZLIB_SOURCE_EMBEDDED)
 #include "third_party/zlib/zlib/zlib.h"
diff --git a/third_party/crashpad/crashpad/util/linux/auxiliary_vector_test.cc b/third_party/crashpad/crashpad/util/linux/auxiliary_vector_test.cc
index 3a69ead..d4cfcb7 100644
--- a/third_party/crashpad/crashpad/util/linux/auxiliary_vector_test.cc
+++ b/third_party/crashpad/crashpad/util/linux/auxiliary_vector_test.cc
@@ -26,6 +26,7 @@
 #include "gtest/gtest.h"
 #include "test/errors.h"
 #include "test/linux/fake_ptrace_connection.h"
+#include "test/main_arguments.h"
 #include "test/multiprocess.h"
 #include "util/linux/address_types.h"
 #include "util/linux/memory_map.h"
@@ -37,7 +38,12 @@
 // TODO(jperaza): This symbol isn't defined when building in chromium for
 // Android. There may be another symbol to use.
 extern "C" {
-extern void _start();
+#if defined(ARCH_CPU_MIPS_FAMILY)
+#define START_SYMBOL __start
+#else
+#define START_SYMBOL _start
+#endif
+extern void START_SYMBOL();
 }  // extern "C"
 #endif
 
@@ -70,7 +76,7 @@
 #if !defined(OS_ANDROID)
   LinuxVMAddress entry_addr;
   ASSERT_TRUE(aux.GetValue(AT_ENTRY, &entry_addr));
-  EXPECT_EQ(entry_addr, FromPointerCast<LinuxVMAddress>(_start));
+  EXPECT_EQ(entry_addr, FromPointerCast<LinuxVMAddress>(START_SYMBOL));
 #endif
 
   uid_t uid;
@@ -123,7 +129,7 @@
   ASSERT_TRUE(aux.GetValue(AT_EXECFN, &filename_addr));
   std::string filename;
   ASSERT_TRUE(memory.ReadCStringSizeLimited(filename_addr, 4096, &filename));
-  EXPECT_TRUE(filename.find("crashpad_util_test") != std::string::npos);
+  EXPECT_TRUE(filename.find(GetMainArguments()[0]) != std::string::npos);
 #endif  // AT_EXECFN
 
   int ignore;
diff --git a/third_party/crashpad/crashpad/util/linux/ptracer.cc b/third_party/crashpad/crashpad/util/linux/ptracer.cc
index 63bee1e0..c6c92299 100644
--- a/third_party/crashpad/crashpad/util/linux/ptracer.cc
+++ b/third_party/crashpad/crashpad/util/linux/ptracer.cc
@@ -269,6 +269,131 @@
   }
   return true;
 }
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+// PTRACE_GETREGSET, introduced in Linux 2.6.34 (2225a122ae26), requires kernel
+// support enabled by HAVE_ARCH_TRACEHOOK. This has been set for x86 (including
+// x86_64) since Linux 2.6.28 (99bbc4b1e677a), but for MIPS only since
+// Linux 3.13 (c0ff3c53d4f99). Older Linux kernels support PTRACE_GETREGS,
+// and PTRACE_GETFPREGS instead, which don't allow checking the size of data
+// copied. Also, PTRACE_GETREGS assumes register size of 64 bits even for 32 bit
+// MIPS CPU (contrary to PTRACE_GETREGSET behavior), so we need buffer
+// structure here.
+
+bool GetGeneralPurposeRegistersLegacy(pid_t tid,
+                                      ThreadContext* context,
+                                      bool can_log) {
+  ThreadContext context_buffer;
+  if (ptrace(PTRACE_GETREGS, tid, nullptr, &context_buffer.t64) != 0) {
+    PLOG_IF(ERROR, can_log) << "ptrace";
+    return false;
+  }
+// Bitness of target process can't be determined through ptrace here, so we
+// assume target process has the same as current process, making cross-bit
+// ptrace unsupported on MIPS for kernels older than 3.13
+#if defined(ARCH_CPU_MIPSEL)
+#define THREAD_CONTEXT_FIELD t32
+#elif defined(ARCH_CPU_MIPS64EL)
+#define THREAD_CONTEXT_FIELD t64
+#endif
+  for (size_t reg = 0; reg < 32; ++reg) {
+    context->THREAD_CONTEXT_FIELD.regs[reg] = context_buffer.t64.regs[reg];
+  }
+  context->THREAD_CONTEXT_FIELD.lo = context_buffer.t64.lo;
+  context->THREAD_CONTEXT_FIELD.hi = context_buffer.t64.hi;
+  context->THREAD_CONTEXT_FIELD.cp0_epc = context_buffer.t64.cp0_epc;
+  context->THREAD_CONTEXT_FIELD.cp0_badvaddr = context_buffer.t64.cp0_badvaddr;
+  context->THREAD_CONTEXT_FIELD.cp0_status = context_buffer.t64.cp0_status;
+  context->THREAD_CONTEXT_FIELD.cp0_cause = context_buffer.t64.cp0_cause;
+#undef THREAD_CONTEXT_FIELD
+  return true;
+}
+
+bool GetFloatingPointRegistersLegacy(pid_t tid,
+                                     FloatContext* context,
+                                     bool can_log) {
+  if (ptrace(PTRACE_GETFPREGS, tid, nullptr, &context->f32.fpregs) != 0) {
+    PLOG_IF(ERROR, can_log) << "ptrace";
+    return false;
+  }
+  return true;
+}
+
+bool GetFloatingPointRegisters32(pid_t tid,
+                                 FloatContext* context,
+                                 bool can_log) {
+  iovec iov;
+  iov.iov_base = &context->f32.fpregs;
+  iov.iov_len = sizeof(context->f32.fpregs);
+  if (ptrace(PTRACE_GETFPREGS, tid, nullptr, &context->f32.fpregs) != 0) {
+    switch (errno) {
+      case EINVAL:
+        // fp may not be present
+        break;
+      case EIO:
+        return GetFloatingPointRegistersLegacy(tid, context, can_log);
+      default:
+        PLOG_IF(ERROR, can_log) << "ptrace";
+        return false;
+    }
+  }
+  return true;
+}
+
+bool GetFloatingPointRegisters64(pid_t tid,
+                                 FloatContext* context,
+                                 bool can_log) {
+  iovec iov;
+  iov.iov_base = &context->f64.fpregs;
+  iov.iov_len = sizeof(context->f64.fpregs);
+  if (ptrace(PTRACE_GETFPREGS, tid, nullptr, &context->f64.fpregs) != 0) {
+    switch (errno) {
+      case EINVAL:
+        // fp may not be present
+        break;
+      case EIO:
+        return GetFloatingPointRegistersLegacy(tid, context, can_log);
+      default:
+        PLOG_IF(ERROR, can_log) << "ptrace";
+        return false;
+    }
+  }
+  return true;
+}
+
+bool GetThreadArea32(pid_t tid,
+                     const ThreadContext& context,
+                     LinuxVMAddress* address,
+                     bool can_log) {
+#if defined(ARCH_CPU_MIPSEL)
+  void* result;
+  if (ptrace(PTRACE_GET_THREAD_AREA, tid, nullptr, &result) != 0) {
+    PLOG_IF(ERROR, can_log) << "ptrace";
+    return false;
+  }
+  *address = FromPointerCast<LinuxVMAddress>(result);
+  return true;
+#else
+  return false;
+#endif
+}
+
+bool GetThreadArea64(pid_t tid,
+                     const ThreadContext& context,
+                     LinuxVMAddress* address,
+                     bool can_log) {
+  void* result;
+#if defined(ARCH_CPU_MIPSEL)
+  if (ptrace(PTRACE_GET_THREAD_AREA_3264, tid, nullptr, &result) != 0) {
+#else
+  if (ptrace(PTRACE_GET_THREAD_AREA, tid, nullptr, &result) != 0) {
+#endif
+    PLOG_IF(ERROR, can_log) << "ptrace";
+    return false;
+  }
+  *address = FromPointerCast<LinuxVMAddress>(result);
+  return true;
+}
+
 #else
 #error Port.
 #endif  // ARCH_CPU_X86_FAMILY
@@ -283,7 +408,7 @@
           PTRACE_GETREGSET, tid, reinterpret_cast<void*>(NT_PRSTATUS), &iov) !=
       0) {
     switch (errno) {
-#if defined(ARCH_CPU_ARMEL)
+#if defined(ARCH_CPU_ARMEL) || defined(ARCH_CPU_MIPS_FAMILY)
       case EIO:
         return GetGeneralPurposeRegistersLegacy(tid, context, can_log)
                    ? sizeof(context->t32)
diff --git a/third_party/crashpad/crashpad/util/linux/thread_info.h b/third_party/crashpad/crashpad/util/linux/thread_info.h
index 91d0082..5b55c24 100644
--- a/third_party/crashpad/crashpad/util/linux/thread_info.h
+++ b/third_party/crashpad/crashpad/util/linux/thread_info.h
@@ -67,6 +67,18 @@
     uint32_t pc;
     uint32_t cpsr;
     uint32_t orig_r0;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+    // Reflects output format of static int gpr32_get(), defined in
+    // arch/mips/kernel/ptrace.c in kernel source
+    uint32_t padding0_[6];
+    uint32_t regs[32];
+    uint32_t lo;
+    uint32_t hi;
+    uint32_t cp0_epc;
+    uint32_t cp0_badvaddr;
+    uint32_t cp0_status;
+    uint32_t cp0_cause;
+    uint32_t padding1_;
 #else
 #error Port.
 #endif  // ARCH_CPU_X86_FAMILY
@@ -110,6 +122,16 @@
     uint64_t sp;
     uint64_t pc;
     uint64_t pstate;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+    // Reflects output format of static int gpr64_get(), defined in
+    // arch/mips/kernel/ptrace.c in kernel source
+    uint64_t regs[32];
+    uint64_t lo;
+    uint64_t hi;
+    uint64_t cp0_epc;
+    uint64_t cp0_badvaddr;
+    uint64_t cp0_status;
+    uint64_t cp0_cause;
 #else
 #error Port.
 #endif  // ARCH_CPU_X86_FAMILY
@@ -119,15 +141,19 @@
   using NativeThreadContext = user_regs_struct;
 #elif defined(ARCH_CPU_ARMEL)
   using NativeThreadContext = user_regs;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+// No appropriate NativeThreadsContext type available for MIPS
 #else
 #error Port.
 #endif  // ARCH_CPU_X86_FAMILY || ARCH_CPU_ARM64
 
+#if !defined(ARCH_CPU_MIPS_FAMILY)
 #if defined(ARCH_CPU_32_BITS)
   static_assert(sizeof(t32_t) == sizeof(NativeThreadContext), "Size mismatch");
 #else  // ARCH_CPU_64_BITS
   static_assert(sizeof(t64_t) == sizeof(NativeThreadContext), "Size mismatch");
 #endif  // ARCH_CPU_32_BITS
+#endif  // !ARCH_CPU_MIPS_FAMILY
 };
 static_assert(std::is_standard_layout<ThreadContext>::value,
               "Not standard layout");
@@ -183,6 +209,15 @@
 
     bool have_fpregs;
     bool have_vfp;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+    // Reflects data format filled by ptrace_getfpregs() in
+    // arch/mips/kernel/ptrace.c
+    struct {
+      float _fp_fregs;
+      unsigned int _fp_pad;
+    } fpregs[32];
+    uint32_t fpcsr;
+    uint32_t fpu_id;
 #else
 #error Port.
 #endif  // ARCH_CPU_X86_FAMILY
@@ -211,6 +246,12 @@
     uint32_t fpsr;
     uint32_t fpcr;
     uint8_t padding[8];
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+    // Reflects data format filled by ptrace_getfpregs() in
+    // arch/mips/kernel/ptrace.c
+    double fpregs[32];
+    uint32_t fpcsr;
+    uint32_t fpu_id;
 #else
 #error Port.
 #endif  // ARCH_CPU_X86_FAMILY
@@ -237,6 +278,8 @@
 #endif
 #elif defined(ARCH_CPU_ARM64)
   static_assert(sizeof(f64) == sizeof(user_fpsimd_struct), "Size mismatch");
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+// No appropriate floating point context native type for available MIPS.
 #else
 #error Port.
 #endif  // ARCH_CPU_X86
diff --git a/third_party/crashpad/crashpad/util/misc/capture_context.h b/third_party/crashpad/crashpad/util/misc/capture_context.h
index 73b80580..541589d 100644
--- a/third_party/crashpad/crashpad/util/misc/capture_context.h
+++ b/third_party/crashpad/crashpad/util/misc/capture_context.h
@@ -65,6 +65,7 @@
 //!     Win                 | x86_64       | `%%rcx`
 //!     macOS/Linux/Fuchsia | x86_64       | `%%rdi`
 //!     Linux               | ARM/ARM64    | `r0`/`x0`
+//!     Linux               | MIPS/MIPS64  | `$a0`
 //!
 //!     Additionally, the value `LR` on ARM/ARM64 will be the return address of
 //!     this function.
diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_linux.S b/third_party/crashpad/crashpad/util/misc/capture_context_linux.S
index b8d6238..42999a90d 100644
--- a/third_party/crashpad/crashpad/util/misc/capture_context_linux.S
+++ b/third_party/crashpad/crashpad/util/misc/capture_context_linux.S
@@ -28,7 +28,7 @@
   .globl CAPTURECONTEXT_SYMBOL2
 #if defined(__i386__) || defined(__x86_64__)
   .balign 16, 0x90
-#elif defined(__arm__) || defined(__aarch64__)
+#elif defined(__arm__) || defined(__aarch64__) || defined(__mips__)
   .balign 4, 0x0
 #endif
 
@@ -331,5 +331,94 @@
   // TODO(jperaza): save floating-point registers.
 
   ret
+#elif defined(__mips__)
+  .set noat
 
+#if _MIPS_SIM == _ABIO32
+#define STORE sw
+#define MCONTEXT_FPREG_SIZE 4
+#define MCONTEXT_PC_OFFSET 32
+#else
+#define STORE sd
+#define MCONTEXT_FPREG_SIZE 8
+#define MCONTEXT_PC_OFFSET 616
+#endif
+
+#define MCONTEXT_REG_SIZE 8
+#define MCONTEXT_GREGS_OFFSET 40
+#define MCONTEXT_FPREGS_OFFSET 296
+
+  // Value of register 0 is always 0.
+  // Registers 26 and 27 are reserved for kernel, and shouldn't be used.
+  STORE $1, (1 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $2, (2 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $3, (3 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $4, (4 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $5, (5 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $6, (6 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $7, (7 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $8, (8 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $9, (9 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $10, (10 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $11, (11 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $12, (12 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $13, (13 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $14, (14 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $15, (15 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $16, (16 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $17, (17 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $18, (18 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $19, (19 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $20, (20 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $21, (21 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $22, (22 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $23, (23 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $24, (24 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $25, (25 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $28, (28 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $29, (29 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $30, (30 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $31, (31 * MCONTEXT_REG_SIZE + MCONTEXT_GREGS_OFFSET)($a0)
+  STORE $31, (MCONTEXT_PC_OFFSET)($a0)
+
+#ifdef __mips_hard_float
+  s.d $f0, (0 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f2, (2 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f4, (4 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f6, (6 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f8, (8 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f10, (10 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f12, (12 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f14, (14 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f16, (16 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f18, (18 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f20, (20 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f22, (22 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f24, (24 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f26, (26 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f28, (28 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f30, (30 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+#if _MIPS_SIM != _ABIO32
+  s.d $f1, (1 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f3, (3 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f5, (5 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f7, (7 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f9, (9 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f11, (11 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f13, (13 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f15, (15 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f17, (17 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f19, (19 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f21, (21 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f23, (23 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f25, (25 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f27, (27 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f29, (29 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+  s.d $f31, (31 * MCONTEXT_FPREG_SIZE + MCONTEXT_FPREGS_OFFSET)($a0)
+#endif  // _MIPS_SIM != _ABIO32
+#endif  // __mips_hard_float
+
+  jr $ra
+
+  .set at
 #endif  // __i386__
diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_test.cc b/third_party/crashpad/crashpad/util/misc/capture_context_test.cc
index deeea9e..1117789d 100644
--- a/third_party/crashpad/crashpad/util/misc/capture_context_test.cc
+++ b/third_party/crashpad/crashpad/util/misc/capture_context_test.cc
@@ -49,7 +49,7 @@
   // reference program counter.
   uintptr_t pc = ProgramCounterFromContext(context_1);
 
-#if !defined(ADDRESS_SANITIZER)
+#if !defined(ADDRESS_SANITIZER) && !defined(ARCH_CPU_MIPS_FAMILY)
   // AddressSanitizer can cause enough code bloat that the “nearby” check would
   // likely fail.
   const uintptr_t kReferencePC =
diff --git a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc
index 3ba13d85..9fc5db2 100644
--- a/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc
+++ b/third_party/crashpad/crashpad/util/misc/capture_context_test_util_linux.cc
@@ -34,6 +34,8 @@
   EXPECT_EQ(context.uc_mcontext.arm_r0, FromPointerCast<uintptr_t>(&context));
 #elif defined(ARCH_CPU_ARM64)
   EXPECT_EQ(context.uc_mcontext.regs[0], FromPointerCast<uintptr_t>(&context));
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+  EXPECT_EQ(context.uc_mcontext.gregs[4], FromPointerCast<uintptr_t>(&context));
 #endif
 }
 
@@ -46,6 +48,8 @@
   return context.uc_mcontext.arm_pc;
 #elif defined(ARCH_CPU_ARM64)
   return context.uc_mcontext.pc;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+  return context.uc_mcontext.pc;
 #endif
 }
 
@@ -58,6 +62,8 @@
   return context.uc_mcontext.arm_sp;
 #elif defined(ARCH_CPU_ARM64)
   return context.uc_mcontext.sp;
+#elif defined(ARCH_CPU_MIPS_FAMILY)
+  return context.uc_mcontext.gregs[29];
 #endif
 }
 
diff --git a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc
index c973c14..8008ffb6 100644
--- a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc
+++ b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix.cc
@@ -65,6 +65,39 @@
     "USR1",
     "USR2",
 #elif defined(OS_LINUX) || defined(OS_ANDROID)
+#if defined(ARCH_CPU_MIPS_FAMILY)
+    "HUP",
+    "INT",
+    "QUIT",
+    "ILL",
+    "TRAP",
+    "ABRT",
+    "EMT",
+    "FPE",
+    "KILL",
+    "BUS",
+    "SEGV",
+    "SYS",
+    "PIPE",
+    "ALRM",
+    "TERM",
+    "USR1",
+    "USR2",
+    "CHLD",
+    "PWR",
+    "WINCH",
+    "URG",
+    "IO",
+    "STOP",
+    "TSTP",
+    "CONT",
+    "TTIN",
+    "TTOU",
+    "VTALRM",
+    "PROF",
+    "XCPU",
+    "XFSZ",
+#else
     // sed -Ene 's/^#define[[:space:]]SIG([[:alnum:]]+)[[:space:]]+[[:digit:]]{1,2}([[:space:]]|$).*/    "\1",/p'
     //     /usr/include/asm-generic/signal.h
     // and fix up by removing SIGIOT, SIGLOST, SIGUNUSED, and SIGRTMIN.
@@ -99,6 +132,7 @@
     "IO",
     "PWR",
     "SYS",
+#endif  // defined(ARCH_CPU_MIPS_FAMILY)
 #endif
 };
 #if defined(OS_LINUX) || defined(OS_ANDROID)
diff --git a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc
index 8478b7b..32c1d43 100644
--- a/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc
+++ b/third_party/crashpad/crashpad/util/posix/symbolic_constants_posix_test.cc
@@ -67,8 +67,10 @@
     {SIGINFO, "SIGINFO", "INFO"},
 #elif defined(OS_LINUX) || defined(OS_ANDROID)
     {SIGPWR, "SIGPWR", "PWR"},
+#if !defined(ARCH_CPU_MIPS_FAMILY)
     {SIGSTKFLT, "SIGSTKFLT", "STKFLT"},
 #endif
+#endif
 };
 
 // If |expect| is nullptr, the conversion is expected to fail. If |expect| is
diff --git a/third_party/feed/README.chromium b/third_party/feed/README.chromium
index 4a4c88b..628f823 100644
--- a/third_party/feed/README.chromium
+++ b/third_party/feed/README.chromium
@@ -2,7 +2,7 @@
 Short name: feed
 URL: https://chromium.googlesource.com/feed
 Version: 0
-Revision: c5468619d8a2098f55f6b8ce2ab9d9530e4a2475
+Revision: 85536a35bac23f2875a3da255ffecd7223f83476
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/third_party/feed/java_sources.gni b/third_party/feed/java_sources.gni
index ee23610d..f2dd8ff 100644
--- a/third_party/feed/java_sources.gni
+++ b/third_party/feed/java_sources.gni
@@ -43,12 +43,12 @@
   "src/src/main/java/com/google/android/libraries/feed/api/stream/Stream.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/BasicStream.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/DeepestContentTracker.java",
-  "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/StreamActionApiImpl.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/StreamContentChangedListener.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/StreamItemAnimator.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/StreamItemTouchCallbacks.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/StreamRecyclerViewAdapter.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/StreamScrollMonitor.java",
+  "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/actions/StreamActionApiImpl.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/drivers/CardDriver.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/drivers/ClusterDriver.java",
   "src/src/main/java/com/google/android/libraries/feed/basicstream/internal/drivers/ContentDriver.java",
diff --git a/third_party/fontconfig/README.chromium b/third_party/fontconfig/README.chromium
index 09a0862..ca56b6a 100644
--- a/third_party/fontconfig/README.chromium
+++ b/third_party/fontconfig/README.chromium
@@ -1,6 +1,6 @@
 Name: fontconfig
 URL: http://www.freedesktop.org/wiki/Software/fontconfig/
-Version: 6cc99d6a82ad67d2f5eac887b28bca13c0dfddde
+Version: d1f48f11d5dffa1d954a1b0abe44ce9e4bfc3709
 License: MIT
 License File: src/COPYING
 Security Critical: yes
diff --git a/third_party/fontconfig/include/src/fcstdint.h b/third_party/fontconfig/include/src/fcstdint.h
index 05a93d5c..2553985 100644
--- a/third_party/fontconfig/include/src/fcstdint.h
+++ b/third_party/fontconfig/include/src/fcstdint.h
@@ -2,7 +2,7 @@
 #define _FONTCONFIG_SRC_FCSTDINT_H 1
 #ifndef _GENERATED_STDINT_H
 #define _GENERATED_STDINT_H "fontconfig 2.13.0"
-/* generated using gnu compiler gcc (Debian 7.3.0-21) 7.3.0 */
+/* generated using gnu compiler gcc (Debian 7.3.0-24) 7.3.0 */
 #define _STDINT_HAVE_STDINT_H 1
 #include <stdint.h>
 #endif
diff --git a/third_party/libaom/README.chromium b/third_party/libaom/README.chromium
index f8b7e145..19fa4d9 100644
--- a/third_party/libaom/README.chromium
+++ b/third_party/libaom/README.chromium
@@ -2,9 +2,9 @@
 Short Name: libaom
 URL: https://aomedia.googlesource.com/aom/
 Version: 0
-Date: Friday July 13 2018
+Date: Monday July 16 2018
 Branch: master
-Commit: 6eecfe927de9e86b4408fa76d83fcffcae2d904b
+Commit: 000f2f686d60385b80ce9d4dd2ca1bfd4de922cb
 License: BSD
 License File: source/libaom/LICENSE
 Security Critical: yes
diff --git a/third_party/libaom/libaom_srcs.gni b/third_party/libaom/libaom_srcs.gni
index 98d2123..99dfb688 100644
--- a/third_party/libaom/libaom_srcs.gni
+++ b/third_party/libaom/libaom_srcs.gni
@@ -30,6 +30,8 @@
   "//third_party/libaom/source/libaom/av1/common/arm/reconinter_neon.c",
   "//third_party/libaom/source/libaom/av1/common/arm/wiener_convolve_neon.c",
   "//third_party/libaom/source/libaom/av1/common/arm/selfguided_neon.c",
+  "//third_party/libaom/source/libaom/av1/common/arm/av1_inv_txfm_neon.c",
+  "//third_party/libaom/source/libaom/av1/common/arm/av1_inv_txfm_neon.h",
   "//third_party/libaom/source/libaom/av1/common/cdef_block_neon.c",
 ]
 
@@ -183,6 +185,7 @@
   "//third_party/libaom/source/libaom/av1/encoder/x86/error_intrin_avx2.c",
   "//third_party/libaom/source/libaom/av1/encoder/x86/av1_fwd_txfm_avx2.h",
   "//third_party/libaom/source/libaom/av1/encoder/x86/av1_fwd_txfm2d_avx2.c",
+  "//third_party/libaom/source/libaom/av1/encoder/x86/wedge_utils_avx2.c",
 ]
 
 aom_av1_encoder_intrin_msa = [
diff --git a/third_party/libaom/source/config/config/aom_version.h b/third_party/libaom/source/config/config/aom_version.h
index 95ee4891..18d957d 100644
--- a/third_party/libaom/source/config/config/aom_version.h
+++ b/third_party/libaom/source/config/config/aom_version.h
@@ -12,8 +12,8 @@
 #define VERSION_MAJOR 1
 #define VERSION_MINOR 0
 #define VERSION_PATCH 0
-#define VERSION_EXTRA "126-g6eecfe927"
+#define VERSION_EXTRA "135-g000f2f686"
 #define VERSION_PACKED \
   ((VERSION_MAJOR << 16) | (VERSION_MINOR << 8) | (VERSION_PATCH))
-#define VERSION_STRING_NOSP "1.0.0-126-g6eecfe927"
-#define VERSION_STRING " 1.0.0-126-g6eecfe927"
+#define VERSION_STRING_NOSP "1.0.0-135-g000f2f686"
+#define VERSION_STRING " 1.0.0-135-g000f2f686"
diff --git a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/av1_rtcd.h b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/av1_rtcd.h
index e6f0211..fb13551 100644
--- a/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/av1_rtcd.h
+++ b/third_party/libaom/source/config/linux/arm-neon-cpu-detect/config/av1_rtcd.h
@@ -782,7 +782,14 @@
                         uint8_t* dst,
                         int stride,
                         const TxfmParam* txfm_param);
-#define av1_inv_txfm_add av1_inv_txfm_add_c
+void av1_inv_txfm_add_neon(const tran_low_t* dqcoeff,
+                           uint8_t* dst,
+                           int stride,
+                           const TxfmParam* txfm_param);
+RTCD_EXTERN void (*av1_inv_txfm_add)(const tran_low_t* dqcoeff,
+                                     uint8_t* dst,
+                                     int stride,
+                                     const TxfmParam* txfm_param);
 
 void av1_jnt_convolve_2d_c(const uint8_t* src,
                            int src_stride,
@@ -1173,6 +1180,9 @@
   av1_convolve_y_sr = av1_convolve_y_sr_c;
   if (flags & HAS_NEON)
     av1_convolve_y_sr = av1_convolve_y_sr_neon;
+  av1_inv_txfm_add = av1_inv_txfm_add_c;
+  if (flags & HAS_NEON)
+    av1_inv_txfm_add = av1_inv_txfm_add_neon;
   av1_jnt_convolve_2d = av1_jnt_convolve_2d_c;
   if (flags & HAS_NEON)
     av1_jnt_convolve_2d = av1_jnt_convolve_2d_neon;
diff --git a/third_party/libaom/source/config/linux/arm-neon/config/av1_rtcd.h b/third_party/libaom/source/config/linux/arm-neon/config/av1_rtcd.h
index 3f79724..1a74a5b 100644
--- a/third_party/libaom/source/config/linux/arm-neon/config/av1_rtcd.h
+++ b/third_party/libaom/source/config/linux/arm-neon/config/av1_rtcd.h
@@ -723,7 +723,11 @@
                         uint8_t* dst,
                         int stride,
                         const TxfmParam* txfm_param);
-#define av1_inv_txfm_add av1_inv_txfm_add_c
+void av1_inv_txfm_add_neon(const tran_low_t* dqcoeff,
+                           uint8_t* dst,
+                           int stride,
+                           const TxfmParam* txfm_param);
+#define av1_inv_txfm_add av1_inv_txfm_add_neon
 
 void av1_jnt_convolve_2d_c(const uint8_t* src,
                            int src_stride,
diff --git a/third_party/libaom/source/config/linux/arm64/config/av1_rtcd.h b/third_party/libaom/source/config/linux/arm64/config/av1_rtcd.h
index 3f79724..1a74a5b 100644
--- a/third_party/libaom/source/config/linux/arm64/config/av1_rtcd.h
+++ b/third_party/libaom/source/config/linux/arm64/config/av1_rtcd.h
@@ -723,7 +723,11 @@
                         uint8_t* dst,
                         int stride,
                         const TxfmParam* txfm_param);
-#define av1_inv_txfm_add av1_inv_txfm_add_c
+void av1_inv_txfm_add_neon(const tran_low_t* dqcoeff,
+                           uint8_t* dst,
+                           int stride,
+                           const TxfmParam* txfm_param);
+#define av1_inv_txfm_add av1_inv_txfm_add_neon
 
 void av1_jnt_convolve_2d_c(const uint8_t* src,
                            int src_stride,
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 379f833..17e09ce9 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -226,8 +226,6 @@
       'Mojo Linux': 'release_trybot',
       'Mojo Windows': 'release_bot_x86_minimal_symbols',
       'Site Isolation Android': 'android_release_bot_minimal_symbols_arm64',
-      'Site Isolation Linux': 'release_trybot',
-      'Site Isolation Win': 'release_trybot_x86',
       'VR Linux': 'vr_release_bot',
       'Win 10 Fast Ring': 'release_trybot',
       'Windows deterministic': 'release_bot_x86_minimal_symbols',
@@ -632,7 +630,6 @@
       'linux_nacl_sdk': 'release_bot',
       'linux_nacl_sdk_build': 'release_bot',
       'linux_optional_gpu_tests_rel': 'gpu_fyi_tests_release_trybot',
-      'linux_site_isolation': 'release_trybot',
       'linux_upload_clang': 'release_bot',
       'linux_vr': 'vr_release_trybot',
     },
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 2de3131..599b7c07 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -5808,986 +5808,51 @@
 </action>
 
 <action name="InProductHelp.Dismissed">
+  <owner>dtrainor@chromium.org</owner>
   <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
   <description>The user dismissed the in-product help.</description>
 </action>
 
 <action name="InProductHelp.NotifyEvent.IPH">
-  <owner>dtrainor@@chromium.org</owner>
+  <owner>dtrainor@chromium.org</owner>
   <owner>nyquist@chromium.org</owner>
   <description>The user triggered an event in in-product help.</description>
 </action>
 
 <action name="InProductHelp.NotifyUsedEvent.IPH">
-  <owner>dtrainor@@chromium.org</owner>
+  <owner>dtrainor@chromium.org</owner>
   <owner>nyquist@chromium.org</owner>
   <description>The user triggered a used event in in-product help.</description>
 </action>
 
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_BadgedReadingList">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
+<action name="InProductHelp.ShouldTriggerHelpUI.IPH">
+  <owner>dtrainor@chromium.org</owner>
+  <owner>nyquist@chromium.org</owner>
   <description>
     The feature engagement tracker tried to determine whether in-product help
     should be shown to the user.
   </description>
 </action>
 
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_Bookmark">
+<action name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH">
+  <owner>dtrainor@chromium.org</owner>
   <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
   <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
+    A user action that could have triggered in-product help did not.
   </description>
 </action>
 
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_BottomToolbarTip">
-  <owner>gambard@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ChromeHomeExpand">
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether the Chrome Home
-    cold start in-product help should be shown to the user. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ChromeHomeMenuHeader">
-  <obsolete>Unused as of 03/2018</obsolete>
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether the Chrome Home
-    menu header in-product help should be shown to the user. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ChromeHomePullToRefresh">
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether the Chrome Home
-    in-product help that is shown after a pull-to-refresh should be shown to the
-    user. See //components/feature_engagement/README.md#Configuring-UMA for
-    details.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearch">
-  <obsolete>
-    Replaced with
-    InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchWebSearch.
-  </obsolete>
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether the Contextual
-    Search in-product help should be shown to the user. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchOptIn">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether the in-product
-    help related to opting-in for Contextual Search should be shown to the user.
-    See //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchPanel">
-  <obsolete>
-    Replaced with
-    InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchPromotePanelOpen.
-  </obsolete>
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether the in-product
-    help related to opening the Contextual Search panel should be shown to the
-    user. See //components/feature_engagement/README.md#Configuring-UMA for
-    details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchPromotePanelOpen">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether the in-product
-    help related to opening the Contextual Search panel should be shown to the
-    user. See //components/feature_engagement/README.md#Configuring-UMA for
-    details.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchPromoteTap">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether the in-product
-    help related to activation by tap for Contextual Search should be shown to
-    the user. See //components/feature_engagement/README.md#Configuring-UMA for
-    details.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchTap">
-  <obsolete>
-    Replaced with
-    InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchPromoteTap.
-  </obsolete>
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether the in-product
-    help related to activation by tap for Contextual Search should be shown to
-    the user. See //components/feature_engagement/README.md#Configuring-UMA for
-    details.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSearchWebSearch">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether the Contextual
-    Search in-product help should be shown to the user. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_ContextualSuggestions">
-  <owner>twellington@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether the contextual
-    suggestions in-product help should be shown to the user. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_DataSaverDetail">
+<action name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH">
+  <owner>dtrainor@chromium.org</owner>
   <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
+  <description>A user action triggered in-product help.</description>
 </action>
 
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_DataSaverPreview">
+<action name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH">
+  <owner>dtrainor@chromium.org</owner>
   <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
   <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_DownloadHome">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_DownloadPage">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_DownloadPageScreenshot">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_HomePageButton">
-  <owner>danielpark@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_IncognitoWindow">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_MediaDownload">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_NewIncognitoTabTip">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_NewTab">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_NewTabPageButton">
-  <owner>danielpark@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUI.IPH_NewTabTip">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_BadgedReadingList">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_Bookmark">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_BottomToolbarTip">
-  <owner>gambard@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ChromeHomeExpand">
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    A user action that could have triggered the Chrome Home cold start
-    in-product help did not. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ChromeHomeMenuHeader">
-  <obsolete>Unused as of 03/2018</obsolete>
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    A user action that could have triggered the Chrome Home menu header
-    in-product help did not. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ChromeHomePullToRefresh">
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    A pull-to-refresh that could have triggered the Chrome Home in-product help
-    did not. See //components/feature_engagement/README.md#Configuring-UMA for
-    details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearch">
-  <obsolete>
-    Replaced with
-    InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchWebSearch.
-  </obsolete>
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action that could have triggered the Contextual Search in-product
-    help did not. See //components/feature_engagement/README.md#Configuring-UMA
-    for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchOptIn">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action that could have triggered the in-product help related to
-    opting-in for Contextual Search did not. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchPanel">
-  <obsolete>
-    Replaced with
-    InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchPromotePanelOpen.
-  </obsolete>
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action that could have triggered the in-product help related to
-    opening the Contextual Search panel did not. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchPromotePanelOpen">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action that could have triggered the in-product help related to
-    opening the Contextual Search panel did not. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchPromoteTap">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action that could have triggered the in-product help related to
-    activation by tap did not. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchTap">
-  <obsolete>
-    Replaced with
-    InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchPromoteTap.
-  </obsolete>
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action that could have triggered the in-product help related to
-    activation by tap did not. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSearchWebSearch">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action that could have triggered the Contextual Search in-product
-    help did not. See //components/feature_engagement/README.md#Configuring-UMA
-    for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_ContextualSuggestions">
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action that could have triggered the contextual suggestions
-    in-product help did not. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_DataSaverDetail">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_DataSaverPreview">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_DownloadHome">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_DownloadPage">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_DownloadPageScreenshot">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_HomePageButton">
-  <owner>danielpark@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_IncognitoWindow">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_MediaDownload">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_NewIncognitoTabTip">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_NewTab">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_NewTabPageButton">
-  <owner>danielpark@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH_NewTabTip">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
-  <description>
-    A user action that could have triggered In-Product Help did not.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_BadgedReadingList">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_Bookmark">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_BottomToolbarTip">
-  <owner>gambard@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ChromeHomeExpand">
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    A user action triggered the Chrome Home cold start in-product help. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ChromeHomeMenuHeader">
-  <obsolete>Unused as of 03/2018</obsolete>
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    A user action triggered the Chrome Home menu header in-product help. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ChromeHomePullToRefresh">
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    A pull-to-refresh triggered the Chrome Home in-product help. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearch">
-  <obsolete>
-    Replaced with
-    InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchWebSearch.
-  </obsolete>
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action triggered the Contextual Search in-product help. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchOptIn">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action triggered the in-product help related to opting-in for
-    Contextual Search. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchPanel">
-  <obsolete>
-    Replaced with
-    InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchPromotePanelOpen.
-  </obsolete>
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action triggered the in-product help related to opening the
-    Contextual Search panel. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchPromotePanelOpen">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action triggered the in-product help related to opening the
-    Contextual Search panel. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchPromoteTap">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action triggered the in-product help related to activation by tap.
-    See //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchTap">
-  <obsolete>
-    Replaced with
-    InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchPromoteTap.
-  </obsolete>
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action triggered the in-product help related to activation by tap.
-    See //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSearchWebSearch">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action triggered the Contextual Search in-product help. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_ContextualSuggestions">
-  <owner>donnd@chromium.org</owner>
-  <owner>mahmoudi@chromium.org</owner>
-  <owner>twellington@chromium.org</owner>
-  <description>
-    A user action triggered the contextual suggestions in-product help. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_DataSaverDetail">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_DataSaverPreview">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_DownloadHome">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_DownloadPage">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_DownloadPageScreenshot">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_HomePageButton">
-  <owner>danielpark@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_IncognitoWindow">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_MediaDownload">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_NewIncognitoTabTip">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_NewTab">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_NewTabPageButton">
-  <owner>danielpark@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH_NewTabTip">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
-  <description>A user action triggered In-Product Help.</description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_BadgedReadingList">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_Bookmark">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_BottomToolbarTip">
-  <owner>gambard@chromium.org</owner>
-  <description>
-    The feature engagement tracker tried to determine whether in-product help
-    should be shown to the user.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_ChromeHomeExpand">
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    A user action would have triggered the Chrome Home cold start in-product
-    help, but the feature was configured for tracking only. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_ChromeHomeMenuHeader">
-  <obsolete>Unused as of 03/2018</obsolete>
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    A user action would have triggered the Chrome Home menu header in-product
-    help, but the feature was configured for tracking only. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_ChromeHomePullToRefresh">
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    A pull-to-refresh would have triggered the Chrome Home in-product help, but
-    the feature was configured for tracking only. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_ContextualSuggestions">
-  <owner>twellington@chromium.org</owner>
-  <owner>mdjones@chromium.org</owner>
-  <description>
-    A user action would have triggered the contextual suggestions in-product
-    help, but the feature was configured for tracking only. See
-    //components/feature_engagement/README.md#Configuring-UMA for details.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_DataSaverDetail">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_DataSaverPreview">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_DownloadHome">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_DownloadPage">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_DownloadPageScreenshot">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_HomePageButton">
-  <owner>danielpark@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_IncognitoWindow">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_MediaDownload">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_NewIncognitoTabTip">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_NewTab">
-  <owner>nyquist@chromium.org</owner>
-  <owner>xingliu@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_NewTabPageButton">
-  <owner>danielpark@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
-    configured for tracking only.
-  </description>
-</action>
-
-<action
-    name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH_NewTabTip">
-  <owner>edchin@chromium.org</owner>
-  <owner>gchatz@chromium.org</owner>
-  <description>
-    A user action would have triggered In-Product Help, but the feature was
+    A user action would have triggered in-product help, but the feature was
     configured for tracking only.
   </description>
 </action>
@@ -20481,6 +19546,7 @@
 <action-suffix separator="_" ordering="suffix">
   <suffix name="BadgedReadingList" label="For BadgedReadingList feature."/>
   <suffix name="Bookmark" label="For Bookmark feature."/>
+  <suffix name="BottomToolbarTip" label="For BottomToolbarTip feature."/>
   <suffix name="ChromeHomeExpand" label="For ChromeHomeExpand feature."/>
   <suffix name="ChromeHomeMenuHeader"
       label="For ChromeHomeMenuHeader feature."/>
@@ -20493,11 +19559,17 @@
       label="For ContextualSearchPanel feature."/>
   <suffix name="ContextualSearchPromotePanelOpen"
       label="For ContextualSearchPromotePanelOpen feature."/>
+  <suffix name="ContextualSearchPromotePanelOpen"
+      label="For ContextualSearchPromotePanelOpen feature."/>
+  <suffix name="ContextualSearchPromoteTap"
+      label="For ContextualSearchPromoteTap feature."/>
   <suffix name="ContextualSearchPromoteTap"
       label="For ContextualSearchPromoteTap feature."/>
   <suffix name="ContextualSearchTap" label="For ContextualSearchTap feature."/>
   <suffix name="ContextualSearchWebSearch"
       label="For ContextualSearchWebSearch feature."/>
+  <suffix name="ContextualSearchWebSearch"
+      label="For ContextualSearchWebSearch feature."/>
   <suffix name="ContextualSuggestions"
       label="For ContextualSuggestions feature."/>
   <suffix name="DataSaverDetail" label="For DataSaverDetail feature."/>
@@ -20515,6 +19587,13 @@
   <suffix name="NewTabTip" label="For NewTabTip feature."/>
   <affected-action name="InProductHelp.NotifyEvent.IPH"/>
   <affected-action name="InProductHelp.NotifyUsedEvent.IPH"/>
+  <affected-action name="InProductHelp.ShouldTriggerHelpUI.IPH"/>
+  <affected-action
+      name="InProductHelp.ShouldTriggerHelpUIResult.NotTriggered.IPH"/>
+  <affected-action
+      name="InProductHelp.ShouldTriggerHelpUIResult.Triggered.IPH"/>
+  <affected-action
+      name="InProductHelp.ShouldTriggerHelpUIResult.WouldHaveTriggered.IPH"/>
 </action-suffix>
 
 </actions>
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 1d1a232..35c98ad0f 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -11298,6 +11298,14 @@
   <int value="307" label="shtm"/>
   <int value="308" label="sht"/>
   <int value="309" label="slk"/>
+  <int value="310" label="applescript"/>
+  <int value="311" label="scpt"/>
+  <int value="312" label="scptd"/>
+  <int value="313" label="seplugin"/>
+  <int value="314" label="osas"/>
+  <int value="315" label="osax"/>
+  <int value="316" label="settingcontent-ms"/>
+  <int value="317" label="oxt"/>
 </enum>
 
 <enum name="DownloadItem.DangerType">
@@ -27470,6 +27478,7 @@
       label="OverlayScrollbarFlashAfterAnyScrollUpdate:enabled"/>
   <int value="-1907565048" label="HtmlBaseUsernameDetector:disabled"/>
   <int value="-1907342706" label="ReadItLaterInMenu:disabled"/>
+  <int value="-1899715534" label="GamepadPollingInterval:enabled"/>
   <int value="-1895719323" label="VrBrowsingTabsView:enabled"/>
   <int value="-1892555086" label="disable-compositor-animation-timelines"/>
   <int value="-1892000374" label="SeccompSandboxAndroid:enabled"/>
@@ -27639,6 +27648,7 @@
   <int value="-1557527869" label="LoadingWithMojo:disabled"/>
   <int value="-1555510175" label="PasswordImport:enabled"/>
   <int value="-1553477903" label="ash-disable-text-filtering-in-overview-mode"/>
+  <int value="-1552898031" label="SingleTabMode:enabled"/>
   <int value="-1549871007" label="OneGoogleBarOnLocalNtp:disabled"/>
   <int value="-1547247328" label="OverrideTranslateTriggerInIndia:disabled"/>
   <int value="-1546903171" label="enable-touch-drag-drop"/>
@@ -27781,6 +27791,7 @@
   <int value="-1311133348" label="VrBrowsingNativeAndroidUi:enabled"/>
   <int value="-1310737697" label="MaterialDesignSettings:enabled"/>
   <int value="-1304957199" label="OfflinePagesShowAlternateDinoPage:enabled"/>
+  <int value="-1303995589" label="shelf-new-ui"/>
   <int value="-1302904242" label="enable-navigation-tracing"/>
   <int value="-1302859198" label="enable-stylus-virtual-keyboard:disabled"/>
   <int value="-1294050129" label="ContentFullscreen:disabled"/>
@@ -27912,6 +27923,7 @@
   <int value="-1031350684" label="PdfIsolation:disabled"/>
   <int value="-1029920490" label="IdleTimeSpellChecking:enabled"/>
   <int value="-1028733699" label="MacViewsWebUIDialogs:disabled"/>
+  <int value="-1028251580" label="GamepadPollingInterval:disabled"/>
   <int value="-1027254093" label="LockScreenNotifications:disabled"/>
   <int value="-1027124889" label="NtlmV2Enabled:enabled"/>
   <int value="-1022971520" label="enable-search-button-in-omnibox-for-str"/>
@@ -28962,6 +28974,7 @@
       label="kAutofillRationalizeRepeatedServerPredictions:enabled"/>
   <int value="1226624874" label="Mus:disabled"/>
   <int value="1228115769" label="SiteCharacteristicsDatabase:disabled"/>
+  <int value="1229299518" label="SingleTabMode:disabled"/>
   <int value="1235800887" label="V8Ignition:enabled"/>
   <int value="1235940786" label="ChromeHomePersistentIph:enabled"/>
   <int value="1237297772" label="no-pings"/>
@@ -41783,6 +41796,7 @@
   <int value="314" label="OSAS"/>
   <int value="315" label="OSAX"/>
   <int value="316" label="SETTINGCONTENT-MS"/>
+  <int value="317" label="OXT"/>
 </enum>
 
 <enum name="SBClientDownloadIsSignedBinary">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 44ca1c2..f6ec479 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -577,6 +577,24 @@
   </summary>
 </histogram>
 
+<histogram name="Ads.Features.AdResourceIsIsolated" enum="AdIsolatedInfo">
+  <owner>csharrison@chromium.org</owner>
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    For a given ad request, logs information related to whether it is isolated
+    from the top-level context. Logged per ad subresource request.
+  </summary>
+</histogram>
+
+<histogram name="Ads.Features.ResourceIsSecure" enum="AdSecureInfo">
+  <owner>csharrison@chromium.org</owner>
+  <owner>jkarlin@chromium.org</owner>
+  <summary>
+    For a given request, logs information related to whether it is marked as an
+    ad, and whether it is secure (e.g. https). Logged per subresource request.
+  </summary>
+</histogram>
+
 <histogram name="AnchorElementMetrics.Clicked.ContainsImage" enum="Boolean">
   <owner>chelu@chromium.org</owner>
   <summary>
@@ -2191,15 +2209,6 @@
   </summary>
 </histogram>
 
-<histogram name="Android.WebView.LoadUrl.DataUriHasOctothorpe" enum="Boolean">
-  <owner>smcgruer@chromium.org</owner>
-  <summary>
-    Records if a data url passed to loadUrl had a '#' character. This is to be
-    used in the effort to deprecate the incorrect treatment of '#' characters in
-    data URIs; see http://crbug.com/823666#c30.
-  </summary>
-</histogram>
-
 <histogram name="Android.WebView.Startup.CreationTime.Stage1.FactoryInit"
     units="ms">
   <owner>changwan@chromium.org</owner>
@@ -97916,6 +97925,9 @@
 </histogram>
 
 <histogram name="SubresourceFilter.AdDelay.IsolatedInfo" enum="AdIsolatedInfo">
+  <obsolete>
+    Deprecated July 2018. Replaced with Ads.Features.AdResourceIsIsolated.
+  </obsolete>
   <owner>csharrison@chromium.org</owner>
   <owner>jkarlin@chromium.org</owner>
   <summary>
@@ -97925,6 +97937,9 @@
 </histogram>
 
 <histogram name="SubresourceFilter.AdDelay.SecureInfo" enum="AdSecureInfo">
+  <obsolete>
+    Deprecated July 2018. Replaced with Ads.Features.ResourceIsSecure.
+  </obsolete>
   <owner>csharrison@chromium.org</owner>
   <owner>jkarlin@chromium.org</owner>
   <summary>
diff --git a/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc b/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc
index 3ac5342..1dd41a4 100644
--- a/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc
+++ b/tools/traffic_annotation/auditor/traffic_annotation_exporter.cc
@@ -77,9 +77,12 @@
     const base::FilePath& source_path)
     : source_path_(source_path), modified_(false) {
   all_supported_platforms_.push_back("linux");
+  all_supported_platforms_.push_back("mac");
   all_supported_platforms_.push_back("windows");
 #if defined(OS_LINUX)
   current_platform_ = "linux";
+#elif defined(OS_MACOSX)
+  current_platform_ = "mac";
 #elif defined(OS_WIN)
   current_platform_ = "windows";
 #else
@@ -469,4 +472,4 @@
       ids->push_back(item.first);
   }
   return true;
-}
\ No newline at end of file
+}
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc
index 901db30..e72f359 100644
--- a/ui/android/delegated_frame_host_android.cc
+++ b/ui/android/delegated_frame_host_android.cc
@@ -320,7 +320,7 @@
 
   expected_pixel_size_ = pixel_size;
   if (registered_parent_compositor_) {
-    if (content_layer_->bounds() != expected_pixel_size_) {
+    if (HasSavedFrame() && content_layer_->bounds() != expected_pixel_size_) {
       compositor_pending_resize_lock_ =
           registered_parent_compositor_->GetCompositorLock(
               this, base::TimeDelta::FromSeconds(kResizeTimeoutSeconds));
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index eb60ca9..35bd151 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -277,6 +277,10 @@
     compositor()->SetVisible(false);
 }
 
+gfx::Size WindowTreeHost::GetCompositorSizeInPixels() const {
+  return GetBoundsInPixels().size();
+}
+
 std::unique_ptr<ScopedKeyboardHook> WindowTreeHost::CaptureSystemKeyEvents(
     base::Optional<base::flat_set<ui::DomCode>> dom_codes) {
   // TODO(joedow): Remove the simple hook class/logic once this flag is removed.
@@ -359,7 +363,8 @@
 
 void WindowTreeHost::InitCompositor() {
   DCHECK(!compositor_->root_layer());
-  compositor_->SetScaleAndSize(device_scale_factor_, GetBoundsInPixels().size(),
+  compositor_->SetScaleAndSize(device_scale_factor_,
+                               GetCompositorSizeInPixels(),
                                window()->GetLocalSurfaceId());
   compositor_->SetRootLayer(window()->layer());
 
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h
index 77c28cf..f4fa860 100644
--- a/ui/aura/window_tree_host.h
+++ b/ui/aura/window_tree_host.h
@@ -197,6 +197,7 @@
       const gfx::Rect& bounds_in_pixels,
       const viz::LocalSurfaceId& local_surface_id = viz::LocalSurfaceId()) = 0;
   virtual gfx::Rect GetBoundsInPixels() const = 0;
+  virtual gfx::Size GetCompositorSizeInPixels() const;
 
   // Sets the OS capture to the root window.
   virtual void SetCapture() = 0;
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc
index a70e6fe..d048f9d 100644
--- a/ui/gfx/render_text_harfbuzz.cc
+++ b/ui/gfx/render_text_harfbuzz.cc
@@ -325,7 +325,7 @@
       segment.run = i;
       segment.char_range = run.range;
       segment.x_range = RangeF(SkScalarToFloat(text_x_),
-                               SkScalarToFloat(text_x_) + run.width);
+                               SkScalarToFloat(text_x_) + run.shape.width);
       AddLineSegment(segment);
     }
   }
@@ -474,7 +474,8 @@
         last_segment.char_range.set_end(segment.char_range.end());
         last_segment.x_range.set_end(SkScalarToFloat(text_x_) +
                                      segment.width());
-        if (run.is_rtl && last_segment.char_range.end() == run.range.end())
+        if (run.common.is_rtl &&
+            last_segment.char_range.end() == run.range.end())
           UpdateRTLSegmentRanges();
         line->size.set_width(line->size.width() + segment.width());
         text_x_ += segment.width();
@@ -486,18 +487,20 @@
     line->size.set_width(line->size.width() + segment.width());
 
     SkPaint paint;
-    paint.setTypeface(run.skia_face);
-    paint.setTextSize(SkIntToScalar(run.font_size));
-    paint.setAntiAlias(run.render_params.antialiasing);
+    paint.setTypeface(run.common.skia_face);
+    paint.setTextSize(SkIntToScalar(run.common.font_size));
+    paint.setAntiAlias(run.common.render_params.antialiasing);
     SkPaint::FontMetrics metrics;
     paint.getFontMetrics(&metrics);
 
     // max_descent_ is y-down, fDescent is y-down, baseline_offset is y-down
-    max_descent_ = std::max(max_descent_, metrics.fDescent+run.baseline_offset);
+    max_descent_ =
+        std::max(max_descent_, metrics.fDescent + run.common.baseline_offset);
     // max_ascent_ is y-up, fAscent is y-down, baseline_offset is y-down
-    max_ascent_ = std::max(max_ascent_, -(metrics.fAscent+run.baseline_offset));
+    max_ascent_ =
+        std::max(max_ascent_, -(metrics.fAscent + run.common.baseline_offset));
 
-    if (run.is_rtl) {
+    if (run.common.is_rtl) {
       rtl_segments_.push_back(
           SegmentHandle(lines_.size() - 1, line->segments.size() - 1));
       // If this is the last segment of an RTL run, reprocess the text-space x
@@ -664,22 +667,71 @@
 }
 #endif
 
+TextRunHarfBuzz::CommonParams::CommonParams() = default;
+TextRunHarfBuzz::CommonParams::CommonParams(const Font& template_font)
+    : font(template_font) {}
+TextRunHarfBuzz::CommonParams::~CommonParams() = default;
+TextRunHarfBuzz::CommonParams::CommonParams(
+    const TextRunHarfBuzz::CommonParams& other) = default;
+TextRunHarfBuzz::CommonParams& TextRunHarfBuzz::CommonParams::operator=(
+    const TextRunHarfBuzz::CommonParams& other) = default;
+
+void TextRunHarfBuzz::CommonParams::ComputeFontSizeAndBaselineOffset(
+    const Font& primary_font) {
+  if (font_size == 0)
+    font_size = primary_font.GetFontSize();
+  baseline_offset = 0;
+  if (baseline_type != NORMAL_BASELINE) {
+    // Calculate a slightly smaller font. The ratio here is somewhat arbitrary.
+    // Proportions from 5/9 to 5/7 all look pretty good.
+    const float ratio = 5.0f / 9.0f;
+    font_size = ToRoundedInt(primary_font.GetFontSize() * ratio);
+    switch (baseline_type) {
+      case SUPERSCRIPT:
+        baseline_offset =
+            primary_font.GetCapHeight() - primary_font.GetHeight();
+        break;
+      case SUPERIOR:
+        baseline_offset = ToRoundedInt(primary_font.GetCapHeight() * ratio) -
+                          primary_font.GetCapHeight();
+        break;
+      case SUBSCRIPT:
+        baseline_offset = primary_font.GetHeight() - primary_font.GetBaseline();
+        break;
+      case INFERIOR:  // Fall through.
+      default:
+        break;
+    }
+  }
+}
+
+bool TextRunHarfBuzz::CommonParams::SetFontAndRenderParams(
+    const Font& new_font,
+    const FontRenderParams& new_render_params) {
+  sk_sp<SkTypeface> new_skia_face(
+      internal::CreateSkiaTypeface(new_font, italic, weight));
+  if (!new_skia_face)
+    return false;
+
+  skia_face = new_skia_face;
+  font = new_font;
+  render_params = new_render_params;
+  return true;
+}
+
+TextRunHarfBuzz::ShapeOutput::ShapeOutput() = default;
+TextRunHarfBuzz::ShapeOutput::~ShapeOutput() = default;
+TextRunHarfBuzz::ShapeOutput::ShapeOutput(
+    const TextRunHarfBuzz::ShapeOutput& other) = default;
+TextRunHarfBuzz::ShapeOutput& TextRunHarfBuzz::ShapeOutput::operator=(
+    const TextRunHarfBuzz::ShapeOutput& other) = default;
+TextRunHarfBuzz::ShapeOutput::ShapeOutput(
+    TextRunHarfBuzz::ShapeOutput&& other) = default;
+TextRunHarfBuzz::ShapeOutput& TextRunHarfBuzz::ShapeOutput::operator=(
+    TextRunHarfBuzz::ShapeOutput&& other) = default;
+
 TextRunHarfBuzz::TextRunHarfBuzz(const Font& template_font)
-    : width(0.0f),
-      preceding_run_widths(0.0f),
-      is_rtl(false),
-      level(0),
-      script(USCRIPT_INVALID_CODE),
-      glyph_count(static_cast<size_t>(-1)),
-      font(template_font),
-      font_size(0),
-      baseline_offset(0),
-      baseline_type(0),
-      italic(false),
-      weight(Font::Weight::NORMAL),
-      strike(false),
-      underline(false),
-      heavy_underline(false) {}
+    : common(template_font) {}
 
 TextRunHarfBuzz::~TextRunHarfBuzz() {}
 
@@ -694,16 +746,12 @@
   GetClusterAt(char_range.start(), &temp_range, &start_glyphs);
   GetClusterAt(char_range.end() - 1, &temp_range, &end_glyphs);
 
-  return is_rtl ? Range(end_glyphs.start(), start_glyphs.end()) :
-      Range(start_glyphs.start(), end_glyphs.end());
+  return common.is_rtl ? Range(end_glyphs.start(), start_glyphs.end())
+                       : Range(start_glyphs.start(), end_glyphs.end());
 }
 
 size_t TextRunHarfBuzz::CountMissingGlyphs() const {
-  static const int kMissingGlyphId = 0;
-  size_t missing = 0;
-  for (size_t i = 0; i < glyph_count; ++i)
-    missing += (glyphs[i] == kMissingGlyphId) ? 1 : 0;
-  return missing;
+  return shape.missing_glyph_count;
 }
 
 void TextRunHarfBuzz::GetClusterAt(size_t pos,
@@ -713,31 +761,38 @@
   DCHECK(glyphs);
 
   bool success = true;
-  if (glyph_count == 0 || !range.Contains(Range(pos, pos + 1))) {
+  if (shape.glyph_count == 0 || !range.Contains(Range(pos, pos + 1))) {
     *chars = range;
     *glyphs = Range();
     success = false;
   }
 
-  if (is_rtl) {
-    success &= GetClusterAtImpl(pos, range, glyph_to_char.rbegin(),
-                                glyph_to_char.rend(), true, chars, glyphs);
+  if (common.is_rtl) {
+    success &=
+        GetClusterAtImpl(pos, range, shape.glyph_to_char.rbegin(),
+                         shape.glyph_to_char.rend(), true, chars, glyphs);
   } else {
-    success &= GetClusterAtImpl(pos, range, glyph_to_char.begin(),
-                                glyph_to_char.end(), false, chars, glyphs);
+    success &=
+        GetClusterAtImpl(pos, range, shape.glyph_to_char.begin(),
+                         shape.glyph_to_char.end(), false, chars, glyphs);
   }
 
   if (!success) {
     std::string glyph_to_char_string;
-    for (size_t i = 0; i < glyph_count && i < glyph_to_char.size(); ++i) {
+    for (size_t i = 0; i < shape.glyph_count && i < shape.glyph_to_char.size();
+         ++i) {
       glyph_to_char_string += base::NumberToString(i) + "->" +
-                              base::UintToString(glyph_to_char[i]) + ", ";
+                              base::UintToString(shape.glyph_to_char[i]) + ", ";
     }
     LOG(ERROR) << " TextRunHarfBuzz error, please report at crbug.com/724880:"
-               << " range: " << range.ToString() << ", rtl: " << is_rtl << ","
-               << " level: '" << level << "', script: " << script << ","
-               << " font: '" << font.GetActualFontNameForTesting() << "',"
-               << " glyph_count: " << glyph_count << ", pos: " << pos << ","
+               << " range: " << range.ToString() << ", rtl: " << common.is_rtl
+               << ","
+               << " level: '" << common.level << "', script: " << common.script
+               << ","
+               << " font: '" << common.font.GetActualFontNameForTesting()
+               << "',"
+               << " glyph_count: " << shape.glyph_count << ", pos: " << pos
+               << ","
                << " glyph_to_char: " << glyph_to_char_string;
   }
 }
@@ -745,15 +800,16 @@
 RangeF TextRunHarfBuzz::GetGraphemeBounds(RenderTextHarfBuzz* render_text,
                                           size_t text_index) const {
   DCHECK_LT(text_index, range.end());
-  if (glyph_count == 0)
-    return RangeF(preceding_run_widths, preceding_run_widths + width);
+  if (shape.glyph_count == 0)
+    return RangeF(preceding_run_widths, preceding_run_widths + shape.width);
 
   Range chars;
   Range glyphs;
   GetClusterAt(text_index, &chars, &glyphs);
-  const float cluster_begin_x = positions[glyphs.start()].x();
-  const float cluster_end_x = glyphs.end() < glyph_count ?
-      positions[glyphs.end()].x() : SkFloatToScalar(width);
+  const float cluster_begin_x = shape.positions[glyphs.start()].x();
+  const float cluster_end_x = glyphs.end() < shape.glyph_count
+                                  ? shape.positions[glyphs.end()].x()
+                                  : SkFloatToScalar(shape.width);
   DCHECK_LE(cluster_begin_x, cluster_end_x);
 
   // A cluster consists of a number of code points and corresponds to a number
@@ -785,7 +841,7 @@
       --before;
 
     if (total > 1) {
-      if (is_rtl)
+      if (common.is_rtl)
         before = total - before - 1;
       DCHECK_GE(before, 0);
       DCHECK_LT(before, total);
@@ -812,7 +868,7 @@
   size_t right_index =
       UTF16OffsetToIndex(render_text->GetDisplayText(), char_range.end(), -1);
   DCHECK_LE(left_index, right_index);
-  if (is_rtl)
+  if (common.is_rtl)
     std::swap(left_index, right_index);
 
   const RangeF left_span = GetGraphemeBounds(render_text, left_index);
@@ -842,10 +898,10 @@
     return 0;
   }
 
-  return ((glyph_range.end() == glyph_count)
-              ? SkFloatToScalar(width)
-              : positions[glyph_range.end()].x()) -
-         positions[glyph_range.start()].x();
+  return ((glyph_range.end() == shape.glyph_count)
+              ? SkFloatToScalar(shape.width)
+              : shape.positions[glyph_range.end()].x()) -
+         shape.positions[glyph_range.start()].x();
 }
 
 TextRunList::TextRunList() : width_(0.0f) {}
@@ -865,7 +921,7 @@
   const size_t num_runs = runs_.size();
   std::vector<UBiDiLevel> levels(num_runs);
   for (size_t i = 0; i < num_runs; ++i)
-    levels[i] = runs_[i]->level;
+    levels[i] = runs_[i]->common.level;
   visual_to_logical_.resize(num_runs);
   ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]);
   logical_to_visual_.resize(num_runs);
@@ -878,7 +934,7 @@
   for (size_t i = 0; i < runs_.size(); ++i) {
     const auto& run = runs_[visual_to_logical_[i]];
     run->preceding_run_widths = width_;
-    width_ += run->width;
+    width_ += run->shape.width;
   }
 }
 
@@ -896,30 +952,26 @@
 // with the same arguments in several places, and typesetting is very expensive.
 // To compensate for this, encapsulate all of the input arguments to
 // ShapeRunWithFont in ShapeRunWithFontInput, all of the output arguments in
-// ShapeRunWithFontOutput, and add ShapeRunCache to map between the two.
+// TextRunHarfBuzz::ShapeOutput, and add ShapeRunCache to map between the two.
 // This is analogous to the blink::ShapeCache.
 // https://crbug.com/826265
 
 // Input for the stateless implementation of ShapeRunWithFont.
 struct ShapeRunWithFontInput {
   ShapeRunWithFontInput(const base::string16& full_text,
-                        sk_sp<SkTypeface> skia_face,
-                        FontRenderParams render_params,
-                        int font_size,
+                        const TextRunHarfBuzz::CommonParams& common_params,
                         Range full_range,
-                        UScriptCode script,
-                        bool is_rtl,
                         bool obscured,
                         float glyph_width_for_test,
                         int glyph_spacing,
                         bool subpixel_rendering_suppressed)
-      : skia_face(skia_face),
-        render_params(render_params),
-        script(script),
-        font_size(font_size),
+      : skia_face(common_params.skia_face),
+        render_params(common_params.render_params),
+        script(common_params.script),
+        font_size(common_params.font_size),
         glyph_spacing(glyph_spacing),
         glyph_width_for_test(glyph_width_for_test),
-        is_rtl(is_rtl),
+        is_rtl(common_params.is_rtl),
         obscured(obscured),
         subpixel_rendering_suppressed(subpixel_rendering_suppressed) {
     // hb_buffer_add_utf16 will read the previous and next 5 unicode characters
@@ -977,36 +1029,11 @@
   size_t hash = 0;
 };
 
-// Output for the stateless implementation of ShapeRunWithFont.
-struct ShapeRunWithFontOutput {
-  // Move the results computed to a TextRunHarfBuzz. This operation is
-  // destructive.
-  void ApplyToRun(internal::TextRunHarfBuzz* run);
-
-  std::vector<uint16_t> glyphs;
-  std::vector<SkPoint> positions;
-  // Note that |glyph_to_char| is indexed with the input range at 0, while the
-  // run's |glyph_to_char| is indexed with the start of the input text at 0.
-  std::vector<uint32_t> glyph_to_char;
-  size_t glyph_count = 0;
-  float width = 0;
-};
-
-void ShapeRunWithFontOutput::ApplyToRun(internal::TextRunHarfBuzz* run) {
-  run->glyph_count = glyph_count;
-  run->glyphs = std::move(glyphs);
-  run->glyph_to_char = std::move(glyph_to_char);
-  for (size_t i = 0; i < run->glyph_to_char.size(); ++i)
-    run->glyph_to_char[i] += run->range.start();
-  run->positions = std::move(positions);
-  run->width = width;
-}
-
 // An MRU cache of the results from calling ShapeRunWithFont. Use the same
 // maximum cache size as is used in blink::ShapeCache.
 constexpr int kShapeRunCacheSize = 10000;
 using ShapeRunCacheBase = base::HashingMRUCache<ShapeRunWithFontInput,
-                                                ShapeRunWithFontOutput,
+                                                TextRunHarfBuzz::ShapeOutput,
                                                 ShapeRunWithFontInput::Hash>;
 class ShapeRunCache : public ShapeRunCacheBase {
  public:
@@ -1014,7 +1041,7 @@
 };
 
 void ShapeRunWithFont(const ShapeRunWithFontInput& in,
-                      ShapeRunWithFontOutput* out) {
+                      TextRunHarfBuzz::ShapeOutput* out) {
   TRACE_EVENT0("ui", "RenderTextHarfBuzz::ShapeRunWithFontInternal");
 
   hb_font_t* harfbuzz_font =
@@ -1060,11 +1087,16 @@
 #else
   constexpr bool force_zero_offset = false;
 #endif
+  constexpr uint16_t kMissingGlyphId = 0;
 
   DCHECK(in.obscured || in.glyph_spacing == 0);
+  out->missing_glyph_count = 0;
   for (size_t i = 0; i < out->glyph_count; ++i) {
     DCHECK_LE(infos[i].codepoint, std::numeric_limits<uint16_t>::max());
-    out->glyphs[i] = static_cast<uint16_t>(infos[i].codepoint);
+    uint16_t glyph = static_cast<uint16_t>(infos[i].codepoint);
+    out->glyphs[i] = glyph;
+    if (glyph == kMissingGlyphId)
+      out->missing_glyph_count += 1;
     DCHECK_GE(infos[i].cluster, in.range.start());
     out->glyph_to_char[i] = infos[i].cluster - in.range.start();
     const SkScalar x_offset =
@@ -1179,30 +1211,31 @@
       run.CharRangeToGlyphRange(segment.char_range).GetMin();
   const float segment_offset_relative_run =
       segment_min_glyph_index != 0
-          ? SkScalarToFloat(run.positions[segment_min_glyph_index].x())
+          ? SkScalarToFloat(run.shape.positions[segment_min_glyph_index].x())
           : 0;
   const float point_offset_relative_run =
       point_offset_relative_segment + segment_offset_relative_run;
 
   // TODO(crbug.com/676287): Use offset within the glyph to return the correct
   // grapheme position within a multi-grapheme glyph.
-  for (size_t i = 0; i < run.glyph_count; ++i) {
-    const float end = i + 1 == run.glyph_count
-                          ? run.width
-                          : SkScalarToFloat(run.positions[i + 1].x());
-    const float middle = (end + SkScalarToFloat(run.positions[i].x())) / 2;
-    const size_t index = DisplayIndexToTextIndex(run.glyph_to_char[i]);
+  for (size_t i = 0; i < run.shape.glyph_count; ++i) {
+    const float end = i + 1 == run.shape.glyph_count
+                          ? run.shape.width
+                          : SkScalarToFloat(run.shape.positions[i + 1].x());
+    const float middle =
+        (end + SkScalarToFloat(run.shape.positions[i].x())) / 2;
+    const size_t index = DisplayIndexToTextIndex(run.shape.glyph_to_char[i]);
     if (point_offset_relative_run < middle) {
-      return run.is_rtl ? SelectionModel(
-                              IndexOfAdjacentGrapheme(index, CURSOR_FORWARD),
-                              CURSOR_BACKWARD)
-                        : SelectionModel(index, CURSOR_FORWARD);
+      return run.common.is_rtl ? SelectionModel(IndexOfAdjacentGrapheme(
+                                                    index, CURSOR_FORWARD),
+                                                CURSOR_BACKWARD)
+                               : SelectionModel(index, CURSOR_FORWARD);
     }
     if (point_offset_relative_run < end) {
-      return run.is_rtl ? SelectionModel(index, CURSOR_FORWARD)
-                        : SelectionModel(
-                              IndexOfAdjacentGrapheme(index, CURSOR_FORWARD),
-                              CURSOR_BACKWARD);
+      return run.common.is_rtl ? SelectionModel(index, CURSOR_FORWARD)
+                               : SelectionModel(IndexOfAdjacentGrapheme(
+                                                    index, CURSOR_FORWARD),
+                                                CURSOR_BACKWARD);
     }
   }
 
@@ -1220,8 +1253,8 @@
   std::vector<RenderText::FontSpan> spans;
   for (const auto& run : run_list->runs()) {
     spans.push_back(RenderText::FontSpan(
-        run->font, Range(DisplayIndexToTextIndex(run->range.start()),
-                         DisplayIndexToTextIndex(run->range.end()))));
+        run->common.font, Range(DisplayIndexToTextIndex(run->range.start()),
+                                DisplayIndexToTextIndex(run->range.end()))));
   }
 
   return spans;
@@ -1254,10 +1287,10 @@
   // If cursor is enabled, extend the last glyph up to the rightmost cursor
   // position since clients expect them to be contiguous.
   if (cursor_enabled() && run_index == run_list->size() - 1 &&
-      index == (run->is_rtl ? run->range.start() : run->range.end() - 1))
+      index == (run->common.is_rtl ? run->range.start() : run->range.end() - 1))
     bounds.set_end(std::ceil(bounds.end()));
-  return run->is_rtl ? RangeF(bounds.end(), bounds.start()).Round()
-                     : bounds.Round();
+  return run->common.is_rtl ? RangeF(bounds.end(), bounds.start()).Round()
+                            : bounds.Round();
 }
 
 base::i18n::BreakIterator* RenderTextHarfBuzz::GetGraphemeIterator() {
@@ -1297,7 +1330,7 @@
     // grapheme in the appropriate direction.
     run = run_list->runs()[run_index].get();
     size_t caret = selection.caret_pos();
-    bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT);
+    bool forward_motion = run->common.is_rtl == (direction == CURSOR_LEFT);
     if (forward_motion) {
       if (caret < DisplayIndexToTextIndex(run->range.end())) {
         caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
@@ -1316,7 +1349,7 @@
       return EdgeSelectionModel(direction);
     run = run_list->runs()[run_list->visual_to_logical(visual_index)].get();
   }
-  bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT);
+  bool forward_motion = run->common.is_rtl == (direction == CURSOR_LEFT);
   return forward_motion ? FirstSelectionModelInsideRun(run) :
                           LastSelectionModelInsideRun(run);
 }
@@ -1348,7 +1381,7 @@
       break;
 #else
     const bool is_forward =
-        run_list->runs()[run]->is_rtl == (direction == CURSOR_LEFT);
+        run_list->runs()[run]->common.is_rtl == (direction == CURSOR_LEFT);
     if (is_forward ? iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor))
       break;
 #endif  // defined(OS_WIN)
@@ -1492,22 +1525,23 @@
         continue;
 
       const internal::TextRunHarfBuzz& run = *run_list->runs()[segment.run];
-      renderer->SetTypeface(run.skia_face);
-      renderer->SetTextSize(SkIntToScalar(run.font_size));
-      renderer->SetFontRenderParams(run.render_params,
+      renderer->SetTypeface(run.common.skia_face);
+      renderer->SetTextSize(SkIntToScalar(run.common.font_size));
+      renderer->SetFontRenderParams(run.common.render_params,
                                     subpixel_rendering_suppressed());
       Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range);
       std::vector<SkPoint> positions(glyphs_range.length());
       SkScalar offset_x = preceding_segment_widths -
                           ((glyphs_range.GetMin() != 0)
-                               ? run.positions[glyphs_range.GetMin()].x()
+                               ? run.shape.positions[glyphs_range.GetMin()].x()
                                : 0);
       for (size_t j = 0; j < glyphs_range.length(); ++j) {
-        positions[j] = run.positions[(glyphs_range.is_reversed()) ?
-                                     (glyphs_range.start() - j) :
-                                     (glyphs_range.start() + j)];
-        positions[j].offset(SkIntToScalar(origin.x()) + offset_x,
-                            SkIntToScalar(origin.y() + run.baseline_offset));
+        positions[j] = run.shape.positions[(glyphs_range.is_reversed())
+                                               ? (glyphs_range.start() - j)
+                                               : (glyphs_range.start() + j)];
+        positions[j].offset(
+            SkIntToScalar(origin.x()) + offset_x,
+            SkIntToScalar(origin.y() + run.common.baseline_offset));
       }
       for (BreakList<SkColor>::const_iterator it =
                colors().GetBreak(segment.char_range.start());
@@ -1527,7 +1561,7 @@
         renderer->SetForegroundColor(it->second);
         renderer->DrawPosText(
             &positions[colored_glyphs.start() - glyphs_range.start()],
-            &run.glyphs[colored_glyphs.start()], colored_glyphs.length());
+            &run.shape.glyphs[colored_glyphs.start()], colored_glyphs.length());
         int start_x = SkScalarRoundToInt(
             positions[colored_glyphs.start() - glyphs_range.start()].x());
         int end_x = SkScalarRoundToInt(
@@ -1535,11 +1569,11 @@
                 ? (SkFloatToScalar(segment.width()) + preceding_segment_widths +
                    SkIntToScalar(origin.x()))
                 : positions[colored_glyphs.end() - glyphs_range.start()].x());
-        if (run.heavy_underline)
+        if (run.common.heavy_underline)
           renderer->DrawUnderline(start_x, origin.y(), end_x - start_x, 2.0);
-        else if (run.underline)
+        else if (run.common.underline)
           renderer->DrawUnderline(start_x, origin.y(), end_x - start_x);
-        if (run.strike)
+        if (run.common.strike)
           renderer->DrawStrike(start_x, origin.y(), end_x - start_x,
                                strike_thickness_factor());
       }
@@ -1620,25 +1654,29 @@
                                 font_size_overrides(), weights(), styles());
 
   for (size_t run_break = 0; run_break < text.length();) {
-    auto run = std::make_unique<internal::TextRunHarfBuzz>(
+    Range run_range;
+    internal::TextRunHarfBuzz::CommonParams common_params(
         font_list().GetPrimaryFont());
-    run->range.set_start(run_break);
-    run->italic = style.style(ITALIC);
-    run->baseline_type = style.baseline();
-    run->font_size = style.font_size_override();
-    run->strike = style.style(STRIKE);
-    run->underline = style.style(UNDERLINE);
-    run->heavy_underline = style.style(HEAVY_UNDERLINE);
-    run->weight = style.weight();
+    run_range.set_start(run_break);
+    common_params.italic = style.style(ITALIC);
+    common_params.baseline_type = style.baseline();
+    common_params.font_size = style.font_size_override();
+    common_params.strike = style.style(STRIKE);
+    common_params.underline = style.style(UNDERLINE);
+    common_params.heavy_underline = style.style(HEAVY_UNDERLINE);
+    common_params.weight = style.weight();
     int32_t script_item_break = 0;
-    bidi_iterator.GetLogicalRun(run_break, &script_item_break, &run->level);
+    bidi_iterator.GetLogicalRun(run_break, &script_item_break,
+                                &common_params.level);
     CHECK_GT(static_cast<size_t>(script_item_break), run_break);
-    ApplyForcedDirection(&run->level);
+    ApplyForcedDirection(&common_params.level);
     // Odd BiDi embedding levels correspond to RTL runs.
-    run->is_rtl = (run->level % 2) == 1;
+    common_params.is_rtl = (common_params.level % 2) == 1;
     // Find the length and script of this script run.
-    script_item_break = ScriptInterval(text, run_break,
-        script_item_break - run_break, &run->script) + run_break;
+    script_item_break =
+        ScriptInterval(text, run_break, script_item_break - run_break,
+                       &common_params.script) +
+        run_break;
 
     // Find the next break and advance the iterators as needed.
     const size_t new_run_break = std::min(
@@ -1652,13 +1690,17 @@
     // prevent either an unusual character from forcing a fallback font on the
     // entire run, or brackets from being affected by a fallback font.
     // http://crbug.com/278913, http://crbug.com/396776
-    if (run_break > run->range.start())
-      run_break = FindRunBreakingCharacter(text, run->range.start(), run_break);
+    if (run_break > run_range.start())
+      run_break = FindRunBreakingCharacter(text, run_range.start(), run_break);
 
     DCHECK(IsValidCodePointIndex(text, run_break));
     style.UpdatePosition(DisplayIndexToTextIndex(run_break));
-    run->range.set_end(run_break);
+    run_range.set_end(run_break);
 
+    auto run = std::make_unique<internal::TextRunHarfBuzz>(
+        font_list().GetPrimaryFont());
+    run->range = run_range;
+    run->common = common_params;
     run_list_out->Add(std::move(run));
   }
 
@@ -1668,72 +1710,31 @@
   run_list_out->InitIndexMap();
 }
 
-bool RenderTextHarfBuzz::CompareFamily(
-    const base::string16& text,
-    const Font& font,
-    const FontRenderParams& render_params,
-    internal::TextRunHarfBuzz* run,
-    Font* best_font,
-    FontRenderParams* best_render_params,
-    size_t* best_missing_glyphs) {
-  if (!ShapeRunWithFont(text, font, render_params, run))
-    return false;
-
-  const size_t missing_glyphs = run->CountMissingGlyphs();
-  if (missing_glyphs < *best_missing_glyphs) {
-    *best_font = font;
-    *best_render_params = render_params;
-    *best_missing_glyphs = missing_glyphs;
-  }
-  return missing_glyphs == 0;
-}
-
 void RenderTextHarfBuzz::ShapeRunList(const base::string16& text,
                                       internal::TextRunList* run_list) {
-  for (const auto& run : run_list->runs())
-    ShapeRun(text, run.get());
+  for (const auto& run : run_list->runs()) {
+    const Font& primary_font = font_list().GetPrimaryFont();
+    internal::TextRunHarfBuzz::CommonParams common_params = run->common;
+    common_params.ComputeFontSizeAndBaselineOffset(primary_font);
+    ShapeRun(text, common_params, run.get());
+  }
   run_list->ComputePrecedingRunWidths();
 }
 
-void RenderTextHarfBuzz::ShapeRun(const base::string16& text,
-                                  internal::TextRunHarfBuzz* run) {
+void RenderTextHarfBuzz::ShapeRun(
+    const base::string16& text,
+    const internal::TextRunHarfBuzz::CommonParams& common_params,
+    internal::TextRunHarfBuzz* run) {
   const Font& primary_font = font_list().GetPrimaryFont();
-  const std::string primary_family = primary_font.GetFontName();
-  if (run->font_size == 0)
-    run->font_size = primary_font.GetFontSize();
-  run->baseline_offset = 0;
-  if (run->baseline_type != NORMAL_BASELINE) {
-    // Calculate a slightly smaller font. The ratio here is somewhat arbitrary.
-    // Proportions from 5/9 to 5/7 all look pretty good.
-    const float ratio = 5.0f / 9.0f;
-    run->font_size = ToRoundedInt(primary_font.GetFontSize() * ratio);
-    switch (run->baseline_type) {
-      case SUPERSCRIPT:
-        run->baseline_offset =
-            primary_font.GetCapHeight() - primary_font.GetHeight();
-        break;
-      case SUPERIOR:
-        run->baseline_offset =
-            ToRoundedInt(primary_font.GetCapHeight() * ratio) -
-            primary_font.GetCapHeight();
-        break;
-      case SUBSCRIPT:
-        run->baseline_offset =
-            primary_font.GetHeight() - primary_font.GetBaseline();
-        break;
-      case INFERIOR:  // Fall through.
-      default:
-        break;
-    }
-  }
-
   Font best_font(primary_font);
-  FontRenderParams best_render_params;
-  size_t best_missing_glyphs = std::numeric_limits<size_t>::max();
 
   for (const Font& font : font_list().GetFonts()) {
-    if (CompareFamily(text, font, font.GetFontRenderParams(), run, &best_font,
-                      &best_render_params, &best_missing_glyphs))
+    internal::TextRunHarfBuzz::CommonParams test_common_params = common_params;
+    if (test_common_params.SetFontAndRenderParams(font,
+                                                  font.GetFontRenderParams())) {
+      ShapeRunWithFont(text, test_common_params, run);
+    }
+    if (run->shape.missing_glyph_count == 0)
       return;
   }
 
@@ -1745,9 +1746,12 @@
   if (GetFallbackFont(primary_font, run_text, run->range.length(),
                       &fallback_font)) {
     preferred_fallback_family = fallback_font.GetFontName();
-    if (CompareFamily(text, fallback_font, fallback_font.GetFontRenderParams(),
-                      run, &best_font, &best_render_params,
-                      &best_missing_glyphs))
+    internal::TextRunHarfBuzz::CommonParams test_common_params = common_params;
+    if (test_common_params.SetFontAndRenderParams(
+            fallback_font, fallback_font.GetFontRenderParams())) {
+      ShapeRunWithFont(text, test_common_params, run);
+    }
+    if (run->shape.missing_glyph_count == 0)
       return;
   }
 #endif
@@ -1794,40 +1798,32 @@
 
     FontRenderParamsQuery query;
     query.families.push_back(font_name);
-    query.pixel_size = run->font_size;
-    query.style = run->italic ? Font::ITALIC : 0;
+    query.pixel_size = common_params.font_size;
+    query.style = common_params.italic ? Font::ITALIC : 0;
     FontRenderParams fallback_render_params = GetFontRenderParams(query, NULL);
-    if (CompareFamily(text, font, fallback_render_params, run, &best_font,
-                      &best_render_params, &best_missing_glyphs))
+    internal::TextRunHarfBuzz::CommonParams test_common_params = common_params;
+    if (test_common_params.SetFontAndRenderParams(font,
+                                                  fallback_render_params)) {
+      ShapeRunWithFont(text, test_common_params, run);
+    }
+    if (run->shape.missing_glyph_count == 0)
       return;
   }
 
-  if (best_missing_glyphs != std::numeric_limits<size_t>::max() &&
-      (best_font.GetFontName() == run->font.GetFontName() ||
-       ShapeRunWithFont(text, best_font, best_render_params, run)))
-    return;
-
-  run->glyph_count = 0;
-  run->width = 0.0f;
+  if (run->shape.missing_glyph_count == std::numeric_limits<size_t>::max()) {
+    run->shape.glyph_count = 0;
+    run->shape.width = 0.0f;
+  }
 }
 
-bool RenderTextHarfBuzz::ShapeRunWithFont(const base::string16& text,
-                                          const Font& font,
-                                          const FontRenderParams& params,
-                                          internal::TextRunHarfBuzz* run) {
-  sk_sp<SkTypeface> skia_face(
-      internal::CreateSkiaTypeface(font, run->italic, run->weight));
-  if (!skia_face)
-    return false;
-
-  run->skia_face = skia_face;
-  run->font = font;
-  run->render_params = params;
+void RenderTextHarfBuzz::ShapeRunWithFont(
+    const base::string16& text,
+    const internal::TextRunHarfBuzz::CommonParams& common_params,
+    internal::TextRunHarfBuzz* run) {
   const internal::ShapeRunWithFontInput in(
-      text, run->skia_face, run->render_params, run->font_size, run->range,
-      run->script, run->is_rtl, obscured(), glyph_width_for_test_,
+      text, common_params, run->range, obscured(), glyph_width_for_test_,
       glyph_spacing(), subpixel_rendering_suppressed());
-  internal::ShapeRunWithFontOutput out;
+  internal::TextRunHarfBuzz::ShapeOutput out;
 
   // ShapeRunWithFont can be extremely slow, so use cached results if possible.
   // Only do this on the UI thread, to avoid synchronization overhead (and
@@ -1847,8 +1843,16 @@
   } else {
     internal::ShapeRunWithFont(in, &out);
   }
-  out.ApplyToRun(run);
-  return true;
+
+  if (out.missing_glyph_count < run->shape.missing_glyph_count) {
+    run->common = common_params;
+    run->shape = out;
+    // Note that |out.glyph_to_char| is indexed from the beginning of
+    // |run->range|, while |run->shape.glyph_to_char| is indexed from
+    // the beginning of |text|.
+    for (size_t i = 0; i < run->shape.glyph_to_char.size(); ++i)
+      run->shape.glyph_to_char[i] += run->range.start();
+  }
 }
 
 void RenderTextHarfBuzz::EnsureLayoutRunList() {
@@ -1907,18 +1911,18 @@
 
     if (!intersection.is_empty()) {
       int style = Font::NORMAL;
-      if (run.italic)
+      if (run.common.italic)
         style |= Font::ITALIC;
-      if (run.underline || run.heavy_underline)
+      if (run.common.underline || run.common.heavy_underline)
         style |= Font::UNDERLINE;
 
       // Get range relative to the decorated text.
       DecoratedText::RangedAttribute attribute(
           Range(intersection.start() - range.GetMin(),
                 intersection.end() - range.GetMin()),
-          run.font.Derive(0, style, run.weight));
+          run.common.font.Derive(0, style, run.common.weight));
 
-      attribute.strike = run.strike;
+      attribute.strike = run.common.strike;
       decorated_text->attributes.push_back(attribute);
     }
   }
diff --git a/ui/gfx/render_text_harfbuzz.h b/ui/gfx/render_text_harfbuzz.h
index ffb2c730..eee7f0e 100644
--- a/ui/gfx/render_text_harfbuzz.h
+++ b/ui/gfx/render_text_harfbuzz.h
@@ -69,29 +69,65 @@
   // text-space (0 corresponds to |GetDisplayText()[0]|).
   SkScalar GetGlyphWidthForCharRange(const Range& char_range) const;
 
-  float width;
-  float preceding_run_widths;
+  // Parameters that may be common to multiple text runs within a text run
+  // list.
+  struct GFX_EXPORT CommonParams {
+    CommonParams();
+    explicit CommonParams(const Font& template_font);
+    ~CommonParams();
+    CommonParams(const CommonParams& other);
+    CommonParams& operator=(const CommonParams& other);
+
+    // Populate |font_size| and |baseline_offset| based on |primary_font|. Note
+    // that this will not populate |font|.
+    void ComputeFontSizeAndBaselineOffset(const Font& primary_font);
+
+    // Populate |font|, |skia_face|, and |render_params|. Return false if
+    // |skia_face| is nullptr.
+    bool SetFontAndRenderParams(const Font& font,
+                                const FontRenderParams& render_params);
+
+    Font font;
+    sk_sp<SkTypeface> skia_face;
+    FontRenderParams render_params;
+    Font::Weight weight = Font::Weight::NORMAL;
+    int font_size = 0;
+    int baseline_offset = 0;
+    int baseline_type = 0;
+    bool italic = false;
+    bool strike = false;
+    bool underline = false;
+    bool heavy_underline = false;
+    bool is_rtl = false;
+    UBiDiLevel level = 0;
+    UScriptCode script = USCRIPT_INVALID_CODE;
+  };
+
+  // Parameters that are set by ShapeRunWithFont.
+  struct GFX_EXPORT ShapeOutput {
+    ShapeOutput();
+    ~ShapeOutput();
+    ShapeOutput(const ShapeOutput& other);
+    ShapeOutput& operator=(const ShapeOutput& other);
+    ShapeOutput(ShapeOutput&& other);
+    ShapeOutput& operator=(ShapeOutput&& other);
+
+    float width = 0.0;
+    float preceding_run_widths = 0.0;
+    std::vector<uint16_t> glyphs;
+    std::vector<SkPoint> positions;
+    // Note that in the context of TextRunHarfBuzz, |glyph_to_char| is indexed
+    // based off of the full string (so it is in the same domain as
+    // TextRunHarfBuzz::range).
+    std::vector<uint32_t> glyph_to_char;
+    size_t glyph_count = 0;
+    size_t missing_glyph_count = std::numeric_limits<size_t>::max();
+  };
+
   Range range;
-  bool is_rtl;
-  UBiDiLevel level;
-  UScriptCode script;
-
-  std::vector<uint16_t> glyphs;
-  std::vector<SkPoint> positions;
-  std::vector<uint32_t> glyph_to_char;
-  size_t glyph_count;
-
-  Font font;
-  sk_sp<SkTypeface> skia_face;
-  FontRenderParams render_params;
-  int font_size;
-  int baseline_offset;
-  int baseline_type;
-  bool italic;
-  Font::Weight weight;
-  bool strike;
-  bool underline;
-  bool heavy_underline;
+  CommonParams common;
+  ShapeOutput shape;
+  float preceding_run_widths = 0.0;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(TextRunHarfBuzz);
@@ -211,30 +247,26 @@
   void ItemizeTextToRuns(const base::string16& string,
                          internal::TextRunList* run_list_out);
 
-  // Helper method for ShapeRun() that calls ShapeRunWithFont() with |text|,
-  // |run|, |font|, and |render_params|, returning true if the font provides
-  // all the glyphs needed for |run|, and false otherwise. Additionally updates
-  // |best_font|, |best_render_params|, and |best_missing_glyphs| if |font|
-  // has fewer than |best_missing_glyphs| missing glyphs.
-  bool CompareFamily(const base::string16& text,
-                     const Font& font,
-                     const FontRenderParams& render_params,
-                     internal::TextRunHarfBuzz* run,
-                     Font* best_font,
-                     FontRenderParams* best_render_params,
-                     size_t* best_missing_glyphs);
-
   // Shape the glyphs of all runs in |run_list| using |text|.
   void ShapeRunList(const base::string16& text,
                     internal::TextRunList* run_list);
 
-  // Shape the glyphs needed for the |run| within the |text|.
+  // Shape the glyphs needed for the |run| within the |text|. This method will
+  // apply a number of fonts to |common_params| and assign to |run->common| and
+  // |run->shape| the common font parameters and resulting shape output with the
+  // smallest number of missing glyphs.
   void ShapeRun(const base::string16& text,
+                const internal::TextRunHarfBuzz::CommonParams& common_params,
                 internal::TextRunHarfBuzz* run);
-  bool ShapeRunWithFont(const base::string16& text,
-                        const Font& font,
-                        const FontRenderParams& params,
-                        internal::TextRunHarfBuzz* run);
+
+  // Shape the glyphs for |run| within |text| using the font specified by
+  // |common_params|. If the resulting shaping has fewer missing glyphs than
+  // |run->shape.missing_glyph_count|, then write |common_params| to
+  // |run->common| and write the shaping output to |run->shape|.
+  void ShapeRunWithFont(
+      const base::string16& text,
+      const internal::TextRunHarfBuzz::CommonParams& common_params,
+      internal::TextRunHarfBuzz* run);
 
   // Makes sure that text runs for layout text are shaped.
   void EnsureLayoutRunList();
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
index d60a30b..c02ab78 100644
--- a/ui/gfx/render_text_unittest.cc
+++ b/ui/gfx/render_text_unittest.cc
@@ -411,7 +411,7 @@
       const internal::TextRunHarfBuzz& run = *run_list->runs()[logical_index];
       if (run.range.length() == 1) {
         result.append(base::StringPrintf("[%d]", run.range.start()));
-      } else if (run.is_rtl) {
+      } else if (run.common.is_rtl) {
         result.append(base::StringPrintf("[%d<-%d]", run.range.end() - 1,
                                          run.range.start()));
       } else {
@@ -551,9 +551,16 @@
 
   bool ShapeRunWithFont(const base::string16& text,
                         const Font& font,
-                        const FontRenderParams& params,
+                        const FontRenderParams& render_params,
                         internal::TextRunHarfBuzz* run) {
-    return GetRenderTextHarfBuzz()->ShapeRunWithFont(text, font, params, run);
+    const Font& primary_font =
+        GetRenderTextHarfBuzz()->font_list().GetPrimaryFont();
+    run->common.ComputeFontSizeAndBaselineOffset(primary_font);
+    if (!run->common.SetFontAndRenderParams(font, render_params))
+      return false;
+    run->shape.missing_glyph_count = static_cast<size_t>(-1);
+    GetRenderTextHarfBuzz()->ShapeRunWithFont(text, run->common, run);
+    return true;
   }
 
   int GetCursorYForTesting(int line_num = 0) {
@@ -3449,9 +3456,9 @@
       EXPECT_EQ(8u, std::max(lines[0].length(), lines[1].length()));
       const internal::TextRunList* run_list = GetHarfBuzzRunList();
       ASSERT_EQ(3U, run_list->runs().size());
-      EXPECT_EQ(lines[0].length(), run_list->runs()[0]->glyph_count);
-      EXPECT_EQ(1u, run_list->runs()[1]->glyph_count);  // \n.
-      EXPECT_EQ(lines[1].length(), run_list->runs()[2]->glyph_count);
+      EXPECT_EQ(lines[0].length(), run_list->runs()[0]->shape.glyph_count);
+      EXPECT_EQ(1u, run_list->runs()[1]->shape.glyph_count);  // \n.
+      EXPECT_EQ(lines[1].length(), run_list->runs()[2]->shape.glyph_count);
 
       int difference = (lines[0].length() - lines[1].length()) * kGlyphSize;
       EXPECT_EQ(test_api()->GetAlignmentOffset(0).x() + difference,
@@ -3699,10 +3706,12 @@
 
     // Verifies the DrawText happens in the visual order and left-to-right.
     // If the text is RTL, the logically first run should be drawn at last.
-    EXPECT_EQ(run_list->runs()[run_list->logical_to_visual(0)]->glyph_count,
-              text_log[0].glyph_count);
-    EXPECT_EQ(run_list->runs()[run_list->logical_to_visual(1)]->glyph_count,
-              text_log[1].glyph_count);
+    EXPECT_EQ(
+        run_list->runs()[run_list->logical_to_visual(0)]->shape.glyph_count,
+        text_log[0].glyph_count);
+    EXPECT_EQ(
+        run_list->runs()[run_list->logical_to_visual(1)]->shape.glyph_count,
+        text_log[1].glyph_count);
     EXPECT_LT(text_log[0].origin.x(), text_log[1].origin.x());
   }
 }
@@ -3743,13 +3752,13 @@
 
   internal::TextRunHarfBuzz run((Font()));
   run.range = Range(0, 4);
-  run.glyph_count = 4;
-  run.glyph_to_char.resize(4);
+  run.shape.glyph_count = 4;
+  run.shape.glyph_to_char.resize(4);
 
   for (size_t i = 0; i < arraysize(cases); ++i) {
     std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 4,
-              run.glyph_to_char.begin());
-    run.is_rtl = cases[i].is_rtl;
+              run.shape.glyph_to_char.begin());
+    run.common.is_rtl = cases[i].is_rtl;
 
     for (size_t j = 0; j < 4; ++j) {
       SCOPED_TRACE(base::StringPrintf("Case %" PRIuS ", char %" PRIuS, i, j));
@@ -3767,9 +3776,9 @@
 TEST_P(RenderTextHarfBuzzTest, HarfBuzz_NoCrashOnTextRunGetClusterAt) {
   internal::TextRunHarfBuzz run((Font()));
   run.range = Range(0, 4);
-  run.glyph_count = 4;
+  run.shape.glyph_count = 4;
   // Construct a |glyph_to_char| map where no glyph maps to the first character.
-  run.glyph_to_char = {1u, 1u, 2u, 3u};
+  run.shape.glyph_to_char = {1u, 1u, 2u, 3u};
 
   Range chars, glyphs;
   // GetClusterAt should not crash asking for the cluster at position 0.
@@ -3837,20 +3846,20 @@
 
   internal::TextRunHarfBuzz run((Font()));
   run.range = Range(0, 4);
-  run.glyph_count = 2;
-  run.glyph_to_char.resize(2);
-  run.positions.resize(4);
-  run.width = 20;
+  run.shape.glyph_count = 2;
+  run.shape.glyph_to_char.resize(2);
+  run.shape.positions.resize(4);
+  run.shape.width = 20;
 
   RenderTextHarfBuzz* render_text = GetRenderTextHarfBuzz();
   render_text->SetText(UTF8ToUTF16("abcd"));
 
   for (size_t i = 0; i < arraysize(cases); ++i) {
     std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 2,
-              run.glyph_to_char.begin());
-    run.is_rtl = cases[i].is_rtl;
+              run.shape.glyph_to_char.begin());
+    run.common.is_rtl = cases[i].is_rtl;
     for (int j = 0; j < 2; ++j)
-      run.positions[j].set(j * 10, 0);
+      run.shape.positions[j].set(j * 10, 0);
 
     for (size_t j = 0; j < 4; ++j) {
       SCOPED_TRACE(base::StringPrintf("Case %" PRIuS ", char %" PRIuS, i, j));
@@ -4136,11 +4145,11 @@
   ASSERT_EQ(1U, run_list->runs().size());
 #if defined(OS_MACOSX)
   // On Mac, the flags should be found, so two glyphs result.
-  EXPECT_EQ(2u, run_list->runs()[0]->glyph_count);
+  EXPECT_EQ(2u, run_list->runs()[0]->shape.glyph_count);
 #else
   // Elsewhere, the flags are not found, so each surrogate pair gets a
   // placeholder glyph. Eventually, all platforms should have 2 glyphs.
-  EXPECT_EQ(4u, run_list->runs()[0]->glyph_count);
+  EXPECT_EQ(4u, run_list->runs()[0]->shape.glyph_count);
 #endif
 }
 
@@ -4177,7 +4186,7 @@
   render_text->SetText(UTF8ToUTF16("abcdefgh"));
 
   run.range = Range(3, 8);
-  run.glyph_count = 0;
+  run.shape.glyph_count = 0;
   EXPECT_EQ(Range(0, 0), run.CharRangeToGlyphRange(Range(4, 5)));
   EXPECT_EQ(Range(0, 0), run.GetGraphemeBounds(render_text, 4).Round());
   Range chars;
@@ -4533,7 +4542,7 @@
   // On Linux, whether subpixel AA is supported is determined by the platform
   // FontConfig. Force it into a particular style after computing runs. Other
   // platforms use a known default FontRenderParams from a static local.
-  GetHarfBuzzRunList()->runs()[0]->render_params.subpixel_rendering =
+  GetHarfBuzzRunList()->runs()[0]->common.render_params.subpixel_rendering =
       FontRenderParams::SUBPIXEL_RENDERING_RGB;
   DrawVisualText();
 #endif
@@ -4546,7 +4555,7 @@
     // SUBPIXEL_RENDERING_RGB set above should now take effect. But, after
     // checking, apply the override anyway to be explicit that it is suppressed.
     EXPECT_FALSE(GetRendererPaint().isLCDRenderText());
-    GetHarfBuzzRunList()->runs()[0]->render_params.subpixel_rendering =
+    GetHarfBuzzRunList()->runs()[0]->common.render_params.subpixel_rendering =
         FontRenderParams::SUBPIXEL_RENDERING_RGB;
     DrawVisualText();
 #endif
@@ -5204,14 +5213,14 @@
   // The default glyph spacing is zero.
   EXPECT_EQ(0, render_text->glyph_spacing());
   ShapeRunWithFont(render_text->text(), Font(), FontRenderParams(), run);
-  const float width_without_glyph_spacing = run->width;
+  const float width_without_glyph_spacing = run->shape.width;
 
   const float kGlyphSpacing = 5;
   render_text->set_glyph_spacing(kGlyphSpacing);
   ShapeRunWithFont(render_text->text(), Font(), FontRenderParams(), run);
   // The new width is the sum of |width_without_glyph_spacing| and the spacing.
   const float total_spacing = seuss.length() * kGlyphSpacing;
-  EXPECT_EQ(width_without_glyph_spacing + total_spacing, run->width);
+  EXPECT_EQ(width_without_glyph_spacing + total_spacing, run->shape.width);
 }
 
 // Ensure font size overrides propagate through to text runs.
@@ -5227,9 +5236,10 @@
   const internal::TextRunList* run_list = GetHarfBuzzRunList();
   ASSERT_EQ(3U, run_list->size());
 
-  EXPECT_EQ(default_font_size, run_list->runs()[0].get()->font_size);
-  EXPECT_EQ(test_font_size_override, run_list->runs()[1].get()->font_size);
-  EXPECT_EQ(default_font_size, run_list->runs()[2].get()->font_size);
+  EXPECT_EQ(default_font_size, run_list->runs()[0].get()->common.font_size);
+  EXPECT_EQ(test_font_size_override,
+            run_list->runs()[1].get()->common.font_size);
+  EXPECT_EQ(default_font_size, run_list->runs()[2].get()->common.font_size);
 }
 
 // Prefix for test instantiations intentionally left blank since each test
diff --git a/ui/views/accessibility/view_ax_platform_node_delegate.cc b/ui/views/accessibility/view_ax_platform_node_delegate.cc
index ae2379b..ebab93e 100644
--- a/ui/views/accessibility/view_ax_platform_node_delegate.cc
+++ b/ui/views/accessibility/view_ax_platform_node_delegate.cc
@@ -179,8 +179,8 @@
 void ViewAXPlatformNodeDelegate::OnMenuEnd() {
   // When a native menu is hidden, restore accessibility focus to the current
   // focus in the document.
-  DCHECK_GE(menu_depth_, 1);
-  --menu_depth_;
+  if (menu_depth_ >= 1)
+    --menu_depth_;
   if (menu_depth_ == 0)
     ui::AXPlatformNode::SetPopupFocusOverride(nullptr);
 }
diff --git a/ui/views/win/pen_event_processor.cc b/ui/views/win/pen_event_processor.cc
index 73129d85..b5e7093 100644
--- a/ui/views/win/pen_event_processor.cc
+++ b/ui/views/win/pen_event_processor.cc
@@ -41,11 +41,17 @@
   // the WM_POINTER message and then setting up an associated pointer
   // details in the MouseEvent which contains the pen's information.
   ui::EventPointerType input_type = ui::EventPointerType::POINTER_TYPE_PEN;
-  // TODO(lanwei): penFlags of PEN_FLAG_INVERTED may also indicate we are using
-  // an eraser, but it is under debate. Please see
-  // https://github.com/w3c/pointerevents/issues/134/.
-  if (pointer_pen_info.penFlags & PEN_FLAG_ERASER)
+  // For the pointerup event, the penFlags is not set to PEN_FLAG_ERASER, so we
+  // have to check if previously the pointer type is an eraser.
+  if (pointer_pen_info.penFlags & PEN_FLAG_ERASER) {
     input_type = ui::EventPointerType::POINTER_TYPE_ERASER;
+    DCHECK(eraser_pointer_id_ == -1 || eraser_pointer_id_ == mapped_pointer_id);
+    eraser_pointer_id_ = mapped_pointer_id;
+  } else if (eraser_pointer_id_ == mapped_pointer_id &&
+             message == WM_POINTERUP) {
+    input_type = ui::EventPointerType::POINTER_TYPE_ERASER;
+    eraser_pointer_id_ = -1;
+  }
 
   // convert pressure into a float [0, 1]. The range of the pressure is
   // [0, 1024] as specified on MSDN.
diff --git a/ui/views/win/pen_event_processor.h b/ui/views/win/pen_event_processor.h
index 60d55489..87d949c 100644
--- a/ui/views/win/pen_event_processor.h
+++ b/ui/views/win/pen_event_processor.h
@@ -54,6 +54,7 @@
   bool send_touch_for_pen_ = false;
   bool sent_mouse_down_ = false;
   bool sent_touch_start_ = false;
+  int eraser_pointer_id_ = -1;
 
   DISALLOW_COPY_AND_ASSIGN(PenEventProcessor);
 };
diff --git a/ui/views/win/pen_event_processor_unittest.cc b/ui/views/win/pen_event_processor_unittest.cc
index 1fa9319..d7fbaf2c 100644
--- a/ui/views/win/pen_event_processor_unittest.cc
+++ b/ui/views/win/pen_event_processor_unittest.cc
@@ -227,4 +227,37 @@
             event->AsMouseEvent()->changed_button_flags());
 }
 
+TEST(PenProcessorTest, PenEraserFlagDMEnabled) {
+  ui::SequentialIDGenerator id_generator(0);
+  PenEventProcessor processor(&id_generator,
+                              /*direct_manipulation_enabled*/ true);
+
+  POINTER_PEN_INFO pen_info;
+  memset(&pen_info, 0, sizeof(POINTER_PEN_INFO));
+  gfx::Point point(100, 100);
+
+  pen_info.pointerInfo.pointerFlags =
+      POINTER_FLAG_INCONTACT | POINTER_FLAG_FIRSTBUTTON;
+  pen_info.pointerInfo.ButtonChangeType = POINTER_CHANGE_FIRSTBUTTON_DOWN;
+  pen_info.penFlags = PEN_FLAG_ERASER;
+
+  std::unique_ptr<ui::Event> event =
+      processor.GenerateEvent(WM_POINTERDOWN, 0, pen_info, point);
+  ASSERT_TRUE(event);
+  ASSERT_TRUE(event->IsTouchEvent());
+  EXPECT_EQ(ui::ET_TOUCH_PRESSED, event->AsTouchEvent()->type());
+  EXPECT_EQ(ui::EventPointerType::POINTER_TYPE_ERASER,
+            event->AsTouchEvent()->pointer_details().pointer_type);
+
+  pen_info.pointerInfo.pointerFlags = POINTER_FLAG_UP;
+  pen_info.pointerInfo.ButtonChangeType = POINTER_CHANGE_FIRSTBUTTON_UP;
+
+  event = processor.GenerateEvent(WM_POINTERUP, 0, pen_info, point);
+  ASSERT_TRUE(event);
+  ASSERT_TRUE(event->IsTouchEvent());
+  EXPECT_EQ(ui::ET_TOUCH_RELEASED, event->AsTouchEvent()->type());
+  EXPECT_EQ(ui::EventPointerType::POINTER_TYPE_ERASER,
+            event->AsTouchEvent()->pointer_details().pointer_type);
+}
+
 }  // namespace views
diff --git a/webrunner/BUILD.gn b/webrunner/BUILD.gn
index 1077f33..7673d94 100644
--- a/webrunner/BUILD.gn
+++ b/webrunner/BUILD.gn
@@ -70,6 +70,11 @@
   ]
 }
 
+fuchsia_package_runner("service_runner") {
+  package = ":service_pkg"
+  package_name_override = "web_service"
+}
+
 component("service_lib") {
   deps = [
     ":service_pak",
@@ -81,7 +86,10 @@
     "//content/public/common",
     "//content/public/renderer",
     "//services/network/public/cpp",
+    "//services/service_manager/embedder:embedder_switches",
+    "//ui/aura",
     "//ui/display",
+    "//ui/platform_window",
   ]
 
   data_deps = [
@@ -96,6 +104,10 @@
   configs += [ ":webrunner_implementation" ]
 
   sources = [
+    "browser/context_impl.cc",
+    "browser/context_impl.h",
+    "browser/frame_impl.cc",
+    "browser/frame_impl.h",
     "browser/webrunner_browser_context.cc",
     "browser/webrunner_browser_context.h",
     "browser/webrunner_browser_main.cc",
@@ -113,14 +125,12 @@
     "common/webrunner_content_client.cc",
     "common/webrunner_content_client.h",
     "common/webrunner_export.h",
-    "service/context_impl.cc",
-    "service/context_impl.h",
+    "service/common.cc",
+    "service/common.h",
     "service/context_provider_impl.cc",
     "service/context_provider_impl.h",
-    "service/frame_impl.cc",
-    "service/frame_impl.h",
-    "service/switches.cc",
-    "service/switches.h",
+    "service/context_provider_main.cc",
+    "service/context_provider_main.h",
     "service/webrunner_main_delegate.cc",
     "service/webrunner_main_delegate.h",
   ]
diff --git a/webrunner/browser/DEPS b/webrunner/browser/DEPS
index fd98921..5791cd1 100644
--- a/webrunner/browser/DEPS
+++ b/webrunner/browser/DEPS
@@ -2,4 +2,5 @@
   "+content/public/browser",
   "+ui/aura",
   "+ui/display",
+  "+ui/platform_window",
 ]
\ No newline at end of file
diff --git a/webrunner/browser/context_impl.cc b/webrunner/browser/context_impl.cc
new file mode 100644
index 0000000..51aeff4e
--- /dev/null
+++ b/webrunner/browser/context_impl.cc
@@ -0,0 +1,30 @@
+// 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.
+
+#include "webrunner/browser/context_impl.h"
+
+#include <memory>
+#include <utility>
+
+#include "content/public/browser/web_contents.h"
+#include "webrunner/browser/frame_impl.h"
+
+namespace webrunner {
+
+ContextImpl::ContextImpl(content::BrowserContext* browser_context)
+    : browser_context_(browser_context) {}
+
+ContextImpl::~ContextImpl() = default;
+
+void ContextImpl::CreateFrame(
+    fidl::InterfaceHandle<chromium::web::FrameObserver> observer,
+    fidl::InterfaceRequest<chromium::web::Frame> frame_request) {
+  auto web_contents = content::WebContents::Create(
+      content::WebContents::CreateParams(browser_context_, nullptr));
+  frame_bindings_.AddBinding(
+      std::make_unique<FrameImpl>(std::move(web_contents), observer.Bind()),
+      std::move(frame_request));
+}
+
+}  // namespace webrunner
diff --git a/webrunner/service/context_impl.h b/webrunner/browser/context_impl.h
similarity index 61%
rename from webrunner/service/context_impl.h
rename to webrunner/browser/context_impl.h
index c13500b..6782796 100644
--- a/webrunner/service/context_impl.h
+++ b/webrunner/browser/context_impl.h
@@ -2,15 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef WEBRUNNER_SERVICE_CONTEXT_IMPL_H_
-#define WEBRUNNER_SERVICE_CONTEXT_IMPL_H_
+#ifndef WEBRUNNER_BROWSER_CONTEXT_IMPL_H_
+#define WEBRUNNER_BROWSER_CONTEXT_IMPL_H_
 
 #include <lib/fidl/cpp/binding_set.h>
 #include <memory>
 
 #include "base/macros.h"
-#include "chromium/web/cpp/fidl.h"
 #include "webrunner/common/webrunner_export.h"
+#include "webrunner/fidl/chromium/web/cpp/fidl.h"
+
+namespace content {
+class BrowserContext;
+}  // namespace content
 
 namespace webrunner {
 
@@ -19,17 +23,18 @@
 // All created Frames are owned by this object.
 class WEBRUNNER_EXPORT ContextImpl : public chromium::web::Context {
  public:
-  ContextImpl();
+  // |browser_context| must outlive ContextImpl.
+  explicit ContextImpl(content::BrowserContext* browser_context);
 
   // Tears down the Context, destroying any active Frames in the process.
   ~ContextImpl() override;
 
   // chromium::web::Context implementation.
-  void CreateFrame(
-      ::fidl::InterfaceHandle<chromium::web::FrameObserver> observer,
-      ::fidl::InterfaceRequest<chromium::web::Frame> frame) override;
+  void CreateFrame(fidl::InterfaceHandle<chromium::web::FrameObserver> observer,
+                   fidl::InterfaceRequest<chromium::web::Frame> frame) override;
 
  private:
+  content::BrowserContext* browser_context_;
   fidl::BindingSet<chromium::web::Frame, std::unique_ptr<chromium::web::Frame>>
       frame_bindings_;
 
@@ -38,4 +43,4 @@
 
 }  // namespace webrunner
 
-#endif  // WEBRUNNER_SERVICE_CONTEXT_IMPL_H_
+#endif  // WEBRUNNER_BROWSER_CONTEXT_IMPL_H_
diff --git a/webrunner/browser/frame_impl.cc b/webrunner/browser/frame_impl.cc
new file mode 100644
index 0000000..b40f2bce
--- /dev/null
+++ b/webrunner/browser/frame_impl.cc
@@ -0,0 +1,126 @@
+// 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.
+
+#include "webrunner/browser/frame_impl.h"
+
+#include "base/logging.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/aura/layout_manager.h"
+#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host_platform.h"
+#include "ui/platform_window/platform_window_init_properties.h"
+#include "url/gurl.h"
+
+namespace webrunner {
+
+namespace {
+
+// Layout manager that allows only one child window and stretches it to fill the
+// parent.
+class LayoutManagerImpl : public aura::LayoutManager {
+ public:
+  LayoutManagerImpl() = default;
+  ~LayoutManagerImpl() override = default;
+
+  // aura::LayoutManager.
+  void OnWindowResized() override {
+    // Resize the child to match the size of the parent
+    if (child_) {
+      SetChildBoundsDirect(child_,
+                           gfx::Rect(child_->parent()->bounds().size()));
+    }
+  }
+  void OnWindowAddedToLayout(aura::Window* child) override {
+    DCHECK(!child_);
+    child_ = child;
+    SetChildBoundsDirect(child_, gfx::Rect(child_->parent()->bounds().size()));
+  }
+
+  void OnWillRemoveWindowFromLayout(aura::Window* child) override {
+    DCHECK_EQ(child, child_);
+    child_ = nullptr;
+  }
+
+  void OnWindowRemovedFromLayout(aura::Window* child) override {}
+  void OnChildWindowVisibilityChanged(aura::Window* child,
+                                      bool visible) override {}
+  void SetChildBounds(aura::Window* child,
+                      const gfx::Rect& requested_bounds) override {}
+
+ private:
+  aura::Window* child_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(LayoutManagerImpl);
+};
+
+}  // namespace
+
+FrameImpl::FrameImpl(std::unique_ptr<content::WebContents> web_contents,
+                     chromium::web::FrameObserverPtr observer)
+    : web_contents_(std::move(web_contents)), observer_(std::move(observer)) {
+  Observe(web_contents.get());
+}
+
+FrameImpl::~FrameImpl() {
+  window_tree_host_->Hide();
+  window_tree_host_->compositor()->SetVisible(false);
+}
+
+void FrameImpl::CreateView(
+    fidl::InterfaceRequest<fuchsia::ui::views_v1_token::ViewOwner> view_owner,
+    fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> services) {
+  ui::PlatformWindowInitProperties properties;
+  properties.view_owner_request = std::move(view_owner);
+
+  window_tree_host_ =
+      std::make_unique<aura::WindowTreeHostPlatform>(std::move(properties));
+  window_tree_host_->InitHost();
+  window_tree_host_->window()->SetLayoutManager(new LayoutManagerImpl());
+  window_tree_host_->window()->AddChild(web_contents_->GetNativeView());
+  window_tree_host_->window()->Show();
+  window_tree_host_->Show();
+  web_contents_->GetNativeView()->Show();
+}
+
+void FrameImpl::GetNavigationController(
+    fidl::InterfaceRequest<chromium::web::NavigationController> controller) {
+  controller_bindings_.AddBinding(this, std::move(controller));
+}
+
+void FrameImpl::LoadUrl(fidl::StringPtr url,
+                        std::unique_ptr<chromium::web::LoadUrlParams> params) {
+  GURL validated_url(*url);
+  if (!validated_url.is_valid()) {
+    DLOG(WARNING) << "Invalid URL: " << *url;
+    return;
+  }
+
+  content::NavigationController::LoadURLParams params_converted(validated_url);
+  params_converted.transition_type = ui::PageTransitionFromInt(
+      ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
+  web_contents_->GetController().LoadURLWithParams(params_converted);
+}
+
+void FrameImpl::GoBack() {
+  NOTIMPLEMENTED();
+}
+
+void FrameImpl::GoForward() {
+  NOTIMPLEMENTED();
+}
+
+void FrameImpl::Stop() {
+  NOTIMPLEMENTED();
+}
+
+void FrameImpl::Reload() {
+  NOTIMPLEMENTED();
+}
+
+void FrameImpl::GetVisibleEntry(GetVisibleEntryCallback callback) {
+  NOTIMPLEMENTED();
+  callback(nullptr);
+}
+
+}  // namespace webrunner
diff --git a/webrunner/browser/frame_impl.h b/webrunner/browser/frame_impl.h
new file mode 100644
index 0000000..e2c109e2
--- /dev/null
+++ b/webrunner/browser/frame_impl.h
@@ -0,0 +1,70 @@
+// 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.
+
+#ifndef WEBRUNNER_BROWSER_FRAME_IMPL_H_
+#define WEBRUNNER_BROWSER_FRAME_IMPL_H_
+
+#include <lib/fidl/cpp/binding_set.h>
+#include <memory>
+#include <utility>
+
+#include "base/macros.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "url/gurl.h"
+#include "webrunner/fidl/chromium/web/cpp/fidl.h"
+
+namespace aura {
+class WindowTreeHost;
+}  // namespace aura
+
+namespace content {
+class BrowserContext;
+class WebContents;
+}  // namespace content
+
+namespace webrunner {
+
+// Implementation of Frame from //webrunner/fidl/frame.fidl.
+// Implements a Frame service, which is a wrapper for a WebContents instance.
+class FrameImpl : public chromium::web::Frame,
+                  public chromium::web::NavigationController,
+                  public content::WebContentsObserver {
+ public:
+  FrameImpl(std::unique_ptr<content::WebContents> web_contents,
+            chromium::web::FrameObserverPtr observer);
+  ~FrameImpl() override;
+
+  // content::WebContentsObserver implementation.
+  void Init(content::BrowserContext* browser_context, const GURL& url);
+
+  // chromium::web::Frame implementation.
+  void CreateView(
+      fidl::InterfaceRequest<fuchsia::ui::views_v1_token::ViewOwner> view_owner,
+      fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> services) override;
+  void GetNavigationController(
+      fidl::InterfaceRequest<chromium::web::NavigationController> controller)
+      override;
+
+  // chromium::web::NavigationController implementation.
+  void LoadUrl(fidl::StringPtr url,
+               std::unique_ptr<chromium::web::LoadUrlParams> params) override;
+  void GoBack() override;
+  void GoForward() override;
+  void Stop() override;
+  void Reload() override;
+  void GetVisibleEntry(GetVisibleEntryCallback callback) override;
+
+ private:
+  std::unique_ptr<aura::WindowTreeHost> window_tree_host_;
+  std::unique_ptr<content::WebContents> web_contents_;
+
+  chromium::web::FrameObserverPtr observer_;
+  fidl::BindingSet<chromium::web::NavigationController> controller_bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameImpl);
+};
+
+}  // namespace webrunner
+
+#endif  // WEBRUNNER_BROWSER_FRAME_IMPL_H_
diff --git a/webrunner/browser/webrunner_browser_context.cc b/webrunner/browser/webrunner_browser_context.cc
index 01ff08fd..84d6141c 100644
--- a/webrunner/browser/webrunner_browser_context.cc
+++ b/webrunner/browser/webrunner_browser_context.cc
@@ -109,7 +109,8 @@
   return nullptr;
 }
 
-content::PermissionManager* WebRunnerBrowserContext::GetPermissionManager() {
+content::PermissionControllerDelegate*
+WebRunnerBrowserContext::GetPermissionControllerDelegate() {
   return nullptr;
 }
 
@@ -163,4 +164,4 @@
   return nullptr;
 }
 
-}  // namespace webrunner
\ No newline at end of file
+}  // namespace webrunner
diff --git a/webrunner/browser/webrunner_browser_context.h b/webrunner/browser/webrunner_browser_context.h
index 6d50834..121ac29 100644
--- a/webrunner/browser/webrunner_browser_context.h
+++ b/webrunner/browser/webrunner_browser_context.h
@@ -29,7 +29,8 @@
   storage::SpecialStoragePolicy* GetSpecialStoragePolicy() override;
   content::PushMessagingService* GetPushMessagingService() override;
   content::SSLHostStateDelegate* GetSSLHostStateDelegate() override;
-  content::PermissionManager* GetPermissionManager() override;
+  content::PermissionControllerDelegate* GetPermissionControllerDelegate()
+      override;
   content::BackgroundFetchDelegate* GetBackgroundFetchDelegate() override;
   content::BackgroundSyncController* GetBackgroundSyncController() override;
   content::BrowsingDataRemoverDelegate* GetBrowsingDataRemoverDelegate()
diff --git a/webrunner/browser/webrunner_browser_main_parts.cc b/webrunner/browser/webrunner_browser_main_parts.cc
index 5ab8d30..b2120581 100644
--- a/webrunner/browser/webrunner_browser_main_parts.cc
+++ b/webrunner/browser/webrunner_browser_main_parts.cc
@@ -4,8 +4,10 @@
 
 #include "webrunner/browser/webrunner_browser_main_parts.h"
 
+#include "webrunner/browser/context_impl.h"
 #include "webrunner/browser/webrunner_browser_context.h"
 #include "webrunner/browser/webrunner_screen.h"
+#include "webrunner/service/common.h"
 
 namespace webrunner {
 
@@ -19,6 +21,26 @@
 
   DCHECK(!browser_context_);
   browser_context_ = std::make_unique<WebRunnerBrowserContext>();
+
+  // Get the Context InterfaceRequest which was passed to the process by
+  // the ContextProvider.
+  zx::channel context_handle{zx_take_startup_handle(kContextRequestHandleId)};
+  CHECK(context_handle) << "Could not find the Context request startup handle.";
+  fidl::InterfaceRequest<chromium::web::Context> context_request(
+      std::move(context_handle));
+
+  context_impl_ = std::make_unique<ContextImpl>(browser_context_.get());
+  context_binding_ = std::make_unique<fidl::Binding<chromium::web::Context>>(
+      context_impl_.get(), std::move(context_request));
+
+  // Quit the context process as soon as context is disconnected.
+  context_binding_->set_error_handler(
+      [this]() { std::move(quit_closure_).Run(); });
+}
+
+void WebRunnerBrowserMainParts::PreDefaultMainMessageLoopRun(
+    base::OnceClosure quit_closure) {
+  quit_closure_ = std::move(quit_closure);
 }
 
 }  // namespace webrunner
diff --git a/webrunner/browser/webrunner_browser_main_parts.h b/webrunner/browser/webrunner_browser_main_parts.h
index 7973dbf..d1c09bf 100644
--- a/webrunner/browser/webrunner_browser_main_parts.h
+++ b/webrunner/browser/webrunner_browser_main_parts.h
@@ -5,13 +5,16 @@
 #ifndef WEBRUNNER_BROWSER_WEBRUNNER_BROWSER_MAIN_PARTS_H_
 #define WEBRUNNER_BROWSER_WEBRUNNER_BROWSER_MAIN_PARTS_H_
 
+#include <lib/fidl/cpp/binding.h>
 #include <memory>
 
 #include "base/macros.h"
 #include "content/public/browser/browser_main_parts.h"
+#include "webrunner/fidl/chromium/web/cpp/fidl.h"
 
 namespace webrunner {
 
+class ContextImpl;
 class WebRunnerBrowserContext;
 class WebRunnerScreen;
 
@@ -22,11 +25,17 @@
 
   // content::BrowserMainParts overrides.
   void PreMainMessageLoopRun() override;
+  void PreDefaultMainMessageLoopRun(base::OnceClosure quit_closure) override;
 
  private:
   std::unique_ptr<WebRunnerScreen> screen_;
   std::unique_ptr<WebRunnerBrowserContext> browser_context_;
 
+  std::unique_ptr<ContextImpl> context_impl_;
+  std::unique_ptr<fidl::Binding<chromium::web::Context>> context_binding_;
+
+  base::OnceClosure quit_closure_;
+
   DISALLOW_COPY_AND_ASSIGN(WebRunnerBrowserMainParts);
 };
 
diff --git a/webrunner/fidl/frame.fidl b/webrunner/fidl/frame.fidl
index e592735..44a94a9 100644
--- a/webrunner/fidl/frame.fidl
+++ b/webrunner/fidl/frame.fidl
@@ -12,7 +12,7 @@
   // |view_owner|: Request for the Frame's ViewOwner.
   // |services|: Request for the Frame's View-related services.
   1: CreateView(request<fuchsia.ui.views_v1_token.ViewOwner> view_owner,
-                request<fuchsia.sys.ServiceProvider> services);
+                request<fuchsia.sys.ServiceProvider>? services);
 
   // Returns an interface through which the frame may be navigated to
   // a desired URL, reloaded, etc.
diff --git a/webrunner/service/DEPS b/webrunner/service/DEPS
index 13789cc..510cf28 100644
--- a/webrunner/service/DEPS
+++ b/webrunner/service/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+chromium/web/cpp",    # FIDL generated headers
   "+content/public/app",
+  "+services/service_manager",
   "+ui/base",
 ]
diff --git a/webrunner/service/switches.cc b/webrunner/service/common.cc
similarity index 68%
rename from webrunner/service/switches.cc
rename to webrunner/service/common.cc
index 187e483..4e1a024 100644
--- a/webrunner/service/switches.cc
+++ b/webrunner/service/common.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "webrunner/service/switches.h"
+#include "webrunner/service/common.h"
 
 namespace webrunner {
 
-const char kContextProcess[] = "context-process";
+constexpr const char kProcessTypeWebContext[] = "web-context";
 
 }  // namespace webrunner
diff --git a/webrunner/service/common.h b/webrunner/service/common.h
index 67ec6ed..868786a07 100644
--- a/webrunner/service/common.h
+++ b/webrunner/service/common.h
@@ -9,7 +9,11 @@
 
 namespace webrunner {
 
-const uint32_t kContextRequestHandleId = PA_HND(PA_USER0, 0);
+constexpr uint32_t kContextRequestHandleId = PA_HND(PA_USER0, 0);
+
+// Process type value used for the web::Context process. It is equivalent to
+// the main browser process in chrome.
+extern const char kProcessTypeWebContext[];
 
 }  // namespace webrunner
 
diff --git a/webrunner/service/context_impl.cc b/webrunner/service/context_impl.cc
deleted file mode 100644
index 93ec376..0000000
--- a/webrunner/service/context_impl.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// 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.
-
-#include "webrunner/service/context_impl.h"
-
-#include <memory>
-#include <utility>
-
-#include "webrunner/service/frame_impl.h"
-
-namespace webrunner {
-
-ContextImpl::ContextImpl() = default;
-
-ContextImpl::~ContextImpl() = default;
-
-void ContextImpl::CreateFrame(
-    ::fidl::InterfaceHandle<chromium::web::FrameObserver> observer,
-    ::fidl::InterfaceRequest<chromium::web::Frame> frame_request) {
-  std::unique_ptr<chromium::web::Frame> frame =
-      std::make_unique<FrameImpl>(observer.Bind());
-  frame_bindings_.AddBinding(std::move(frame), std::move(frame_request));
-}
-
-}  // namespace webrunner
diff --git a/webrunner/service/context_provider_impl.cc b/webrunner/service/context_provider_impl.cc
index 6cf3216..141a6f9 100644
--- a/webrunner/service/context_provider_impl.cc
+++ b/webrunner/service/context_provider_impl.cc
@@ -17,8 +17,8 @@
 #include "base/fuchsia/fuchsia_logging.h"
 #include "base/logging.h"
 #include "base/process/launch.h"
+#include "services/service_manager/embedder/switches.h"
 #include "webrunner/service/common.h"
-#include "webrunner/service/switches.h"
 
 namespace webrunner {
 namespace {
@@ -26,8 +26,9 @@
 // Relaunches the current executable as a Context process.
 base::Process LaunchContextProcess(const base::LaunchOptions& launch_options) {
   base::CommandLine launch_command = *base::CommandLine::ForCurrentProcess();
-  DCHECK(!launch_command.HasSwitch(kContextProcess));
-  launch_command.AppendSwitch(kContextProcess);
+  DCHECK(!launch_command.HasSwitch(service_manager::switches::kProcessType));
+  launch_command.AppendSwitchASCII(service_manager::switches::kProcessType,
+                                   kProcessTypeWebContext);
   return base::LaunchProcess(launch_command, launch_options);
 }
 
diff --git a/webrunner/service/context_provider_main.cc b/webrunner/service/context_provider_main.cc
new file mode 100644
index 0000000..8f9920a
--- /dev/null
+++ b/webrunner/service/context_provider_main.cc
@@ -0,0 +1,28 @@
+// 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.
+
+#include "webrunner/service/context_provider_main.h"
+
+#include "base/fuchsia/scoped_service_binding.h"
+#include "base/fuchsia/service_directory.h"
+#include "base/logging.h"
+#include "base/run_loop.h"
+#include "webrunner/service/context_provider_impl.h"
+
+namespace webrunner {
+
+int ContextProviderMain() {
+  base::fuchsia::ServiceDirectory* directory =
+      base::fuchsia::ServiceDirectory::GetDefault();
+  ContextProviderImpl context_provider;
+  base::fuchsia::ScopedServiceBinding<chromium::web::ContextProvider> binding(
+      directory, &context_provider);
+
+  // TODO(crbug.com/852145): Currently the process will run until it's killed.
+  base::RunLoop().Run();
+
+  return 0;
+}
+
+}  // namespace webrunner
diff --git a/webrunner/service/context_provider_main.h b/webrunner/service/context_provider_main.h
new file mode 100644
index 0000000..ba6e00e7
--- /dev/null
+++ b/webrunner/service/context_provider_main.h
@@ -0,0 +1,19 @@
+// 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.
+
+#ifndef WEBRUNNER_SERVICE_CONTEXT_PROVIDER_MAIN_H_
+#define WEBRUNNER_SERVICE_CONTEXT_PROVIDER_MAIN_H_
+
+#include "webrunner/service/context_provider_main.h"
+
+namespace webrunner {
+
+// Main function for the process that implements web::ContextProvider interface.
+// Called by WebRunnerMainDelegate when the process is started without --type
+// argument.
+int ContextProviderMain();
+
+}  // namespace webrunner
+
+#endif  // WEBRUNNER_SERVICE_CONTEXT_PROVIDER_MAIN_H_
\ No newline at end of file
diff --git a/webrunner/service/frame_impl.cc b/webrunner/service/frame_impl.cc
deleted file mode 100644
index ad8874a..0000000
--- a/webrunner/service/frame_impl.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// 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.
-
-#include "webrunner/service/frame_impl.h"
-
-#include "base/logging.h"
-
-namespace webrunner {
-
-FrameImpl::FrameImpl(chromium::web::FrameObserverPtr observer)
-    : observer_(std::move(observer)) {}
-
-FrameImpl::~FrameImpl() = default;
-
-void FrameImpl::CreateView(
-    ::fidl::InterfaceRequest<fuchsia::ui::views_v1_token::ViewOwner> view_owner,
-    ::fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> services) {
-  NOTIMPLEMENTED();
-}
-
-void FrameImpl::GetNavigationController(
-    ::fidl::InterfaceRequest<chromium::web::NavigationController> controller) {
-  controller_bindings_.AddBinding(this, std::move(controller));
-}
-
-void FrameImpl::LoadUrl(
-    ::fidl::StringPtr url,
-    ::std::unique_ptr<chromium::web::LoadUrlParams> params) {
-  NOTIMPLEMENTED() << "Loading URL " << *url;
-}
-
-void FrameImpl::GoBack() {
-  NOTIMPLEMENTED();
-}
-
-void FrameImpl::GoForward() {
-  NOTIMPLEMENTED();
-}
-
-void FrameImpl::Stop() {
-  NOTIMPLEMENTED();
-}
-
-void FrameImpl::Reload() {
-  NOTIMPLEMENTED();
-}
-
-void FrameImpl::GetVisibleEntry(GetVisibleEntryCallback callback) {
-  NOTIMPLEMENTED();
-  callback(nullptr);
-}
-
-}  // namespace webrunner
diff --git a/webrunner/service/frame_impl.h b/webrunner/service/frame_impl.h
deleted file mode 100644
index 45e867c..0000000
--- a/webrunner/service/frame_impl.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// 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.
-
-#ifndef WEBRUNNER_SERVICE_FRAME_IMPL_H_
-#define WEBRUNNER_SERVICE_FRAME_IMPL_H_
-
-#include <lib/fidl/cpp/binding_set.h>
-#include <memory>
-#include <utility>
-
-#include "base/macros.h"
-#include "chromium/web/cpp/fidl.h"
-
-namespace webrunner {
-
-// Implementation of Frame from //webrunner/fidl/frame.fidl.
-// Implements a Frame service, which is a wrapper for a WebContents instance.
-class FrameImpl : public chromium::web::Frame,
-                  public chromium::web::NavigationController {
- public:
-  explicit FrameImpl(chromium::web::FrameObserverPtr observer);
-  ~FrameImpl() override;
-
-  // chromium::web::Frame implementation.
-  void CreateView(
-      ::fidl::InterfaceRequest<fuchsia::ui::views_v1_token::ViewOwner>
-          view_owner,
-      ::fidl::InterfaceRequest<fuchsia::sys::ServiceProvider> services)
-      override;
-  void GetNavigationController(
-      ::fidl::InterfaceRequest<chromium::web::NavigationController> controller)
-      override;
-
-  // chromium::web::NavigationController implementation.
-  void LoadUrl(::fidl::StringPtr url,
-               ::std::unique_ptr<chromium::web::LoadUrlParams> params) override;
-  void GoBack() override;
-  void GoForward() override;
-  void Stop() override;
-  void Reload() override;
-  void GetVisibleEntry(GetVisibleEntryCallback callback) override;
-
- private:
-  chromium::web::FrameObserverPtr observer_;
-  fidl::BindingSet<chromium::web::NavigationController> controller_bindings_;
-
-  DISALLOW_COPY_AND_ASSIGN(FrameImpl);
-};
-
-}  // namespace webrunner
-
-#endif  // WEBRUNNER_SERVICE_FRAME_IMPL_H_
diff --git a/webrunner/service/switches.h b/webrunner/service/switches.h
deleted file mode 100644
index 94f102b..0000000
--- a/webrunner/service/switches.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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.
-
-#ifndef WEBRUNNER_SERVICE_SWITCHES_H_
-#define WEBRUNNER_SERVICE_SWITCHES_H_
-
-#include "webrunner/common/webrunner_export.h"
-
-namespace webrunner {
-
-// "--context-process" signifies the process should be launched as a Context
-// service.
-// Omitting the switch signifies that the process should be a ContextProvider.
-extern WEBRUNNER_EXPORT const char kContextProcess[];
-
-}  // namespace webrunner
-
-#endif  // WEBRUNNER_SERVICE_SWITCHES_H_
diff --git a/webrunner/service/webrunner_main_delegate.cc b/webrunner/service/webrunner_main_delegate.cc
index b0a5802..32c1ca6 100644
--- a/webrunner/service/webrunner_main_delegate.cc
+++ b/webrunner/service/webrunner_main_delegate.cc
@@ -12,6 +12,8 @@
 #include "webrunner/browser/webrunner_browser_main.h"
 #include "webrunner/browser/webrunner_content_browser_client.h"
 #include "webrunner/common/webrunner_content_client.h"
+#include "webrunner/service/common.h"
+#include "webrunner/service/context_provider_main.h"
 
 namespace webrunner {
 
@@ -64,10 +66,13 @@
 int WebRunnerMainDelegate::RunProcess(
     const std::string& process_type,
     const content::MainFunctionParams& main_function_params) {
+  if (process_type == kProcessTypeWebContext)
+    return WebRunnerBrowserMain(main_function_params);
+
   if (!process_type.empty())
     return -1;
 
-  return WebRunnerBrowserMain(main_function_params);
+  return ContextProviderMain();
 }
 
 content::ContentBrowserClient*