diff --git a/DEPS b/DEPS
index 1ff8db1..12cfd6b 100644
--- a/DEPS
+++ b/DEPS
@@ -1392,7 +1392,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@6b936a2133cd1ba23c2a27657c7d438dc2004e5a',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@4f841753fcf62c678635a459e60642d2cb697c56',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 39a8e6f..e06ba8e 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -579,7 +579,6 @@
         "/DELAYLOAD:dxgi.dll",
         "/DELAYLOAD:dxva2.dll",
         "/DELAYLOAD:esent.dll",
-        "/DELAYLOAD:gdi32.dll",
         "/DELAYLOAD:imm32.dll",
         "/DELAYLOAD:ole32.dll",
         "/DELAYLOAD:oleacc.dll",
diff --git a/chrome/VERSION b/chrome/VERSION
index f7057d3c..783f304 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=76
 MINOR=0
 BUILD=3809
-PATCH=73
+PATCH=74
diff --git a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabMediator.java b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabMediator.java
index 8b7e727..6a95bd41 100644
--- a/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabMediator.java
+++ b/chrome/android/touchless/java/src/org/chromium/chrome/browser/touchless/OpenLastTabMediator.java
@@ -252,8 +252,11 @@
                             SharedPreferences prefs = getSharedPreferences();
                             prefs.edit().remove(LAST_TAB_URL).apply();
                         });
-                        mHistoryBridge.markItemForRemoval(mHistoryItem);
-                        mHistoryBridge.removeItems();
+                        // Don't actually remove the element from history db. This is fine since
+                        // we're tracking it in the pref, the open last tab button will not show it.
+                        // If this history item is backed by 2+ rows a history deletion could
+                        // trigger a clear and suppression of suggested articles, see
+                        // https://crbug.com/982973.
                         mHistoryItem = null;
                         mLastTabUrl = null;
                         updateModel();
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 5842809..939c02e 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -2010,6 +2010,8 @@
     "tpm_firmware_update.h",
     "tpm_firmware_update_notification.cc",
     "tpm_firmware_update_notification.h",
+    "u2f_notification.cc",
+    "u2f_notification.h",
     "ui/echo_dialog_listener.h",
     "ui/echo_dialog_view.cc",
     "ui/echo_dialog_view.h",
diff --git a/chrome/browser/chromeos/extensions/default_web_app_ids.h b/chrome/browser/chromeos/extensions/default_web_app_ids.h
index 196ba26..d403c77 100644
--- a/chrome/browser/chromeos/extensions/default_web_app_ids.h
+++ b/chrome/browser/chromeos/extensions/default_web_app_ids.h
@@ -16,8 +16,8 @@
 constexpr char kShowtimeAppId[] = "eoccpgmpiempcflglfokeengliildkag";
 
 // Generated as
-// web_app::GenerateAppIdFromURL(GURL("https://canvas.apps.chrome/index.html)).
-constexpr char kCanvasAppId[] = "memejfanofdmelnjmboefinndljpifdm";
+// web_app::GenerateAppIdFromURL(GURL("https://canvas.apps.chrome/")).
+constexpr char kCanvasAppId[] = "ieailfmhaghpphfffooibmlghaeopach";
 
 }  // namespace default_web_apps
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/session/chrome_session_manager.cc b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
index fd0fb56..d818255 100644
--- a/chrome/browser/chromeos/login/session/chrome_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/chrome_session_manager.cc
@@ -35,6 +35,7 @@
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/chromeos/tether/tether_service.h"
 #include "chrome/browser/chromeos/tpm_firmware_update_notification.h"
+#include "chrome/browser/chromeos/u2f_notification.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/app_list/app_list_client_impl.h"
@@ -195,6 +196,7 @@
 
   UserSessionManager::GetInstance()->CheckEolStatus(user_profile);
   tpm_firmware_update::ShowNotificationIfNeeded(user_profile);
+  UserSessionManager::GetInstance()->MaybeShowU2FNotification();
   g_browser_process->platform_part()
       ->browser_policy_connector_chromeos()
       ->GetTPMAutoUpdateModePolicyHandler()
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 6b8b4e1..54e5e1d 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -81,6 +81,7 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chrome/browser/chromeos/tether/tether_service.h"
 #include "chrome/browser/chromeos/tpm_firmware_update_notification.h"
+#include "chrome/browser/chromeos/u2f_notification.h"
 #include "chrome/browser/component_updater/crl_set_component_installer.h"
 #include "chrome/browser/component_updater/sth_set_component_remover.h"
 #include "chrome/browser/first_run/first_run.h"
@@ -2179,6 +2180,9 @@
   // and show the message accordingly.
   tpm_firmware_update::ShowNotificationIfNeeded(profile);
 
+  // Show legacy U2F notification if applicable.
+  MaybeShowU2FNotification();
+
   g_browser_process->platform_part()
       ->browser_policy_connector_chromeos()
       ->GetTPMAutoUpdateModePolicyHandler()
@@ -2289,6 +2293,7 @@
   token_handle_util_.reset();
   first_run::GoodiesDisplayer::Delete();
   always_on_vpn_manager_.reset();
+  u2f_notification_.reset();
 }
 
 void UserSessionManager::SetSwitchesForUser(
@@ -2311,6 +2316,13 @@
       all_switches);
 }
 
+void UserSessionManager::MaybeShowU2FNotification() {
+  if (!u2f_notification_) {
+    u2f_notification_ = std::make_unique<U2FNotification>();
+    u2f_notification_->Check();
+  }
+}
+
 void UserSessionManager::CreateTokenUtilIfMissing() {
   if (!token_handle_util_.get())
     token_handle_util_.reset(new TokenHandleUtil());
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.h b/chrome/browser/chromeos/login/session/user_session_manager.h
index 7aa0b09..ed6318e0 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.h
+++ b/chrome/browser/chromeos/login/session/user_session_manager.h
@@ -28,6 +28,7 @@
 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h"
 #include "chrome/browser/chromeos/login/signin/token_handle_util.h"
 #include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/chromeos/u2f_notification.h"
 #include "chromeos/dbus/session_manager/session_manager_client.h"
 #include "chromeos/login/auth/authenticator.h"
 #include "chromeos/login/auth/user_context.h"
@@ -312,6 +313,9 @@
   // password from the UserContext regardless of the value of |send_password|.
   void OnUserNetworkPolicyParsed(bool send_password);
 
+  // Shows U2F notification if necessary.
+  void MaybeShowU2FNotification();
+
  private:
   friend class test::UserSessionManagerTestApi;
   friend struct base::DefaultSingletonTraits<UserSessionManager>;
@@ -611,6 +615,8 @@
 
   std::unique_ptr<ChildPolicyObserver> child_policy_observer_;
 
+  std::unique_ptr<U2FNotification> u2f_notification_;
+
   base::WeakPtrFactory<UserSessionManager> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(UserSessionManager);
diff --git a/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_handler.cc b/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_handler.cc
index 1cb34c8..4332d7c 100644
--- a/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_handler.cc
+++ b/chrome/browser/chromeos/policy/device_wilco_dtc_configuration_handler.cc
@@ -14,7 +14,6 @@
 chromeos::WilcoDtcSupportdManager* GetWilcoDtcSupportdManager() {
   chromeos::WilcoDtcSupportdManager* const wilco_dtc_supportd_manager =
       chromeos::WilcoDtcSupportdManager::Get();
-  DCHECK(wilco_dtc_supportd_manager);
   return wilco_dtc_supportd_manager;
 }
 
@@ -32,14 +31,18 @@
 
 void DeviceWilcoDtcConfigurationHandler::OnDeviceExternalDataCleared(
     const std::string& policy) {
-  GetWilcoDtcSupportdManager()->SetConfigurationData(nullptr);
+  auto* wilco_manager = GetWilcoDtcSupportdManager();
+  if (wilco_manager)
+    wilco_manager->SetConfigurationData(nullptr);
 }
 
 void DeviceWilcoDtcConfigurationHandler::OnDeviceExternalDataFetched(
     const std::string& policy,
     std::unique_ptr<std::string> data,
     const base::FilePath& file_path) {
-  GetWilcoDtcSupportdManager()->SetConfigurationData(std::move(data));
+  auto* wilco_manager = GetWilcoDtcSupportdManager();
+  if (wilco_manager)
+    wilco_manager->SetConfigurationData(std::move(data));
 }
 
 void DeviceWilcoDtcConfigurationHandler::Shutdown() {
diff --git a/chrome/browser/chromeos/settings/device_settings_provider.cc b/chrome/browser/chromeos/settings/device_settings_provider.cc
index 46650a74..189f179 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider.cc
@@ -88,6 +88,7 @@
     kDeviceQuirksDownloadEnabled,
     kDeviceRebootOnUserSignout,
     kDeviceScheduledUpdateCheck,
+    kDeviceSecondFactorAuthenticationMode,
     kDeviceUnaffiliatedCrostiniAllowed,
     kDeviceWiFiAllowed,
     kDeviceWilcoDtcAllowed,
@@ -801,6 +802,13 @@
         kDeviceDockMacAddressSource,
         policy.device_dock_mac_address_source().source());
   }
+
+  if (policy.has_device_second_factor_authentication() &&
+      policy.device_second_factor_authentication().has_mode()) {
+    new_values_cache->SetInteger(
+        kDeviceSecondFactorAuthenticationMode,
+        policy.device_second_factor_authentication().mode());
+  }
 }
 
 void DecodeLogUploadPolicies(const em::ChromeDeviceSettingsProto& policy,
diff --git a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
index c3c22ad..2fbfd62 100644
--- a/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_settings_provider_unittest.cc
@@ -194,7 +194,7 @@
   }
 
   void VerifyPolicyValue(const char* policy_key,
-                         const base::Value* const ptr_to_expected_value) {
+                         const base::Value* ptr_to_expected_value) {
     // The pointer might be null, so check before dereferencing.
     if (ptr_to_expected_value)
       EXPECT_EQ(*ptr_to_expected_value, *provider_->Get(policy_key));
@@ -211,8 +211,7 @@
   }
 
   // Helper routine to check value of the LoginScreenDomainAutoComplete policy.
-  void VerifyDomainAutoComplete(
-      const base::Value* const ptr_to_expected_value) {
+  void VerifyDomainAutoComplete(const base::Value* ptr_to_expected_value) {
     VerifyPolicyValue(kAccountsPrefLoginScreenDomainAutoComplete,
                       ptr_to_expected_value);
   }
@@ -281,7 +280,7 @@
 
   // Helper routine that sets the device DeviceWilcoDtcAllowed policy.
   void SetDeviceWilcoDtcAllowedSetting(bool device_wilco_dtc_allowed) {
-    em::DeviceWilcoDtcAllowedProto* const proto =
+    em::DeviceWilcoDtcAllowedProto* proto =
         device_policy_->payload().mutable_device_wilco_dtc_allowed();
     proto->set_device_wilco_dtc_allowed(device_wilco_dtc_allowed);
     BuildAndInstallDevicePolicy();
@@ -290,12 +289,20 @@
   void SetDeviceDockMacAddressSourceSetting(
       em::DeviceDockMacAddressSourceProto::Source
           device_dock_mac_address_source) {
-    em::DeviceDockMacAddressSourceProto* const proto =
+    em::DeviceDockMacAddressSourceProto* proto =
         device_policy_->payload().mutable_device_dock_mac_address_source();
     proto->set_source(device_dock_mac_address_source);
     BuildAndInstallDevicePolicy();
   }
 
+  void SetDeviceSecondFactorAuthenticationModeSetting(
+      em::DeviceSecondFactorAuthenticationProto::U2fMode mode) {
+    em::DeviceSecondFactorAuthenticationProto* proto =
+        device_policy_->payload().mutable_device_second_factor_authentication();
+    proto->set_mode(mode);
+    BuildAndInstallDevicePolicy();
+  }
+
   ScopedTestingLocalState local_state_;
 
   std::unique_ptr<DeviceSettingsProvider> provider_;
@@ -769,4 +776,29 @@
   EXPECT_EQ(base::Value(3), *provider_->Get(kDeviceDockMacAddressSource));
 }
 
+TEST_F(DeviceSettingsProviderTest,
+       DeviceSecondFactorAuthenticationModeSetting) {
+  VerifyPolicyValue(kDeviceSecondFactorAuthenticationMode, nullptr);
+
+  SetDeviceSecondFactorAuthenticationModeSetting(
+      em::DeviceSecondFactorAuthenticationProto::UNSET);
+  EXPECT_EQ(base::Value(0),
+            *provider_->Get(kDeviceSecondFactorAuthenticationMode));
+
+  SetDeviceSecondFactorAuthenticationModeSetting(
+      em::DeviceSecondFactorAuthenticationProto::DISABLED);
+  EXPECT_EQ(base::Value(1),
+            *provider_->Get(kDeviceSecondFactorAuthenticationMode));
+
+  SetDeviceSecondFactorAuthenticationModeSetting(
+      em::DeviceSecondFactorAuthenticationProto::U2F);
+  EXPECT_EQ(base::Value(2),
+            *provider_->Get(kDeviceSecondFactorAuthenticationMode));
+
+  SetDeviceSecondFactorAuthenticationModeSetting(
+      em::DeviceSecondFactorAuthenticationProto::U2F_EXTENDED);
+  EXPECT_EQ(base::Value(3),
+            *provider_->Get(kDeviceSecondFactorAuthenticationMode));
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/u2f_notification.cc b/chrome/browser/chromeos/u2f_notification.cc
new file mode 100644
index 0000000..58b9918
--- /dev/null
+++ b/chrome/browser/chromeos/u2f_notification.cc
@@ -0,0 +1,172 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/chromeos/u2f_notification.h"
+
+#include <memory>
+
+#include "ash/public/cpp/notification_utils.h"
+#include "base/bind.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
+#include "base/task/post_task.h"
+#include "chrome/browser/chromeos/settings/cros_settings.h"
+#include "chrome/browser/notifications/notification_display_service.h"
+#include "chrome/browser/notifications/notification_display_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/ui/browser_navigator.h"
+#include "chrome/browser/ui/browser_navigator_params.h"
+#include "chrome/grit/generated_resources.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/debug_daemon_client.h"
+#include "components/policy/proto/chrome_device_policy.pb.h"
+#include "components/strings/grit/components_strings.h"
+#include "third_party/cros_system_api/dbus/debugd/dbus-constants.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/message_center/public/cpp/notification.h"
+
+namespace chromeos {
+namespace {
+
+constexpr char kU2FNotificationId[] = "chrome://u2f_notification";
+constexpr char kU2FAdvisoryURL[] =
+    "https://sites.google.com/a/chromium.org/dev/chromium-os/"
+    "u2f-ecdsa-vulnerability";
+
+// Notification button identifiers.
+enum class ButtonIndex : int {
+  kLearnMore = 0,
+  kReset = 1,
+};
+
+}  // namespace
+
+U2FNotification::U2FNotification() {}
+
+U2FNotification::~U2FNotification() {}
+
+void U2FNotification::Check() {
+  DBusThreadManager::Get()->GetDebugDaemonClient()->GetU2fFlags(base::BindOnce(
+      &U2FNotification::CheckStatus, weak_factory_.GetWeakPtr()));
+}
+
+void U2FNotification::CheckStatus(base::Optional<std::set<std::string>> flags) {
+  if (!flags) {
+    LOG(ERROR) << "Failed to get U2F flags.";
+    return;
+  }
+
+  // The legacy implementation is only enabled if either the U2F or G2F flags
+  // are present and the user_keys flag is off (the latter enables the improved
+  // implementation).
+  if (!(base::ContainsKey(*flags, debugd::u2f_flags::kU2f) ||
+        base::ContainsKey(*flags, debugd::u2f_flags::kG2f)) ||
+      base::ContainsKey(*flags, debugd::u2f_flags::kUserKeys)) {
+    return;
+  }
+
+  CrosSettings* settings = CrosSettings::Get();
+  switch (settings->PrepareTrustedValues(base::BindRepeating(
+      &U2FNotification::CheckStatus, weak_factory_.GetWeakPtr(), flags))) {
+    case CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
+      // Retry happens via the callback registered above.
+      return;
+    case CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
+      // No device settings, so they won't take effect.
+      break;
+    case CrosSettingsProvider::TRUSTED:
+      // If the 2FA setting is present and not set to "unset", it disables the
+      // legacy implementation, so bail if that is the case. This corresponds
+      // with behavior in u2fd and should be kept in sync.
+      constexpr auto kU2fModeUnset =
+          enterprise_management::DeviceSecondFactorAuthenticationProto::UNSET;
+      int mode;
+      if (settings->GetInteger(kDeviceSecondFactorAuthenticationMode, &mode) &&
+          mode != kU2fModeUnset) {
+        return;
+      }
+      break;
+  }
+
+  // Legacy implementation is on, notify.
+  ShowNotification();
+}
+
+void U2FNotification::ShowNotification() {
+  Profile* profile = ProfileManager::GetPrimaryUserProfile();
+
+  message_center::RichNotificationData data;
+  data.buttons.emplace_back(l10n_util::GetStringUTF16(IDS_LEARN_MORE));
+  data.buttons.emplace_back(
+      l10n_util::GetStringUTF16(IDS_U2F_INSECURE_NOTIFICATION_RESET));
+  std::unique_ptr<message_center::Notification> notification =
+      ash::CreateSystemNotification(
+          message_center::NOTIFICATION_TYPE_SIMPLE, kU2FNotificationId,
+          l10n_util::GetStringUTF16(IDS_U2F_INSECURE_NOTIFICATION_TITLE),
+          l10n_util::GetStringUTF16(IDS_U2F_INSECURE_NOTIFICATION_MESSAGE),
+          base::string16(), GURL(kU2FNotificationId),
+          message_center::NotifierId(
+              message_center::NotifierType::SYSTEM_COMPONENT,
+              kU2FNotificationId),
+          data,
+          base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
+              base::BindRepeating(&U2FNotification::OnNotificationClick,
+                                  weak_factory_.GetWeakPtr())),
+          gfx::kNoneIcon,
+          message_center::SystemNotificationWarningLevel::WARNING);
+  notification->SetSystemPriority();
+  notification->set_pinned(false);
+
+  NotificationDisplayServiceFactory::GetForProfile(profile)->Display(
+      NotificationHandler::Type::TRANSIENT, *notification,
+      nullptr /* metadata */);
+}
+
+void U2FNotification::OnNotificationClick(
+    const base::Optional<int> button_index) {
+  Profile* profile = ProfileManager::GetPrimaryUserProfile();
+  if (!button_index || !profile) {
+    return;
+  }
+
+  switch (static_cast<ButtonIndex>(*button_index)) {
+    case ButtonIndex::kLearnMore: {
+      // Load the chromium.org advisory page in a new tab.
+      NavigateParams params(profile, GURL(kU2FAdvisoryURL),
+                            ui::PAGE_TRANSITION_LINK);
+      params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
+      params.window_action = NavigateParams::SHOW_WINDOW;
+      Navigate(&params);
+      break;
+    }
+    case ButtonIndex::kReset: {
+      // Add the user_keys flag.
+      DBusThreadManager::Get()->GetDebugDaemonClient()->GetU2fFlags(
+          base::BindOnce([](base::Optional<std::set<std::string>> flags) {
+            if (!flags) {
+              LOG(ERROR) << "Failed to get U2F flags.";
+              return;
+            }
+            flags->insert(debugd::u2f_flags::kUserKeys);
+            DBusThreadManager::Get()->GetDebugDaemonClient()->SetU2fFlags(
+                *flags, base::BindOnce([](bool result) {
+                  if (!result) {
+                    LOG(ERROR) << "Failed to set U2F flags.";
+                    return;
+                  }
+                }));
+          }));
+
+      // TODO: Should we close in all cases?
+      NotificationDisplayServiceFactory::GetForProfile(profile)->Close(
+          NotificationHandler::Type::TRANSIENT, kU2FNotificationId);
+      break;
+    }
+  }
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/u2f_notification.h b/chrome/browser/chromeos/u2f_notification.h
new file mode 100644
index 0000000..03ea6ddd
--- /dev/null
+++ b/chrome/browser/chromeos/u2f_notification.h
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_U2F_NOTIFICATION_H_
+#define CHROME_BROWSER_CHROMEOS_U2F_NOTIFICATION_H_
+
+#include <set>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+
+namespace chromeos {
+
+// Detects whether the legacy, never-officially-launched built-in U2F feature is
+// enabled. If so, shows a notification to tell the user about a security issue.
+class U2FNotification {
+ public:
+  U2FNotification();
+  ~U2FNotification();
+
+  // Asynchronously checks whether the legacy implementation is enabled and if
+  // so, displays a notification.
+  void Check();
+
+ private:
+  // Checks status given the current U2F flags.
+  void CheckStatus(base::Optional<std::set<std::string>> flags);
+
+  // Shows the notification.
+  void ShowNotification();
+
+  // Handles clicks on the notification.
+  void OnNotificationClick(const base::Optional<int> button_index);
+
+  base::WeakPtrFactory<U2FNotification> weak_factory_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(U2FNotification);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_U2F_NOTIFICATION_H_
diff --git a/chrome/browser/extensions/content_verifier_browsertest.cc b/chrome/browser/extensions/content_verifier_browsertest.cc
index faf1971..908bf9d 100644
--- a/chrome/browser/extensions/content_verifier_browsertest.cc
+++ b/chrome/browser/extensions/content_verifier_browsertest.cc
@@ -45,6 +45,11 @@
 
 namespace extensions {
 
+namespace {
+constexpr char kTenMegResourceExtensionId[] =
+    "mibjhafkjlepkpbjleahhallgddpjgle";
+}
+
 class ContentVerifierTest : public ExtensionBrowserTest {
  public:
   ContentVerifierTest() {}
@@ -327,6 +332,52 @@
       extension->id(), extension->GetResourceURL(kResource));
 }
 
+// Tests that a resource reading failure due to FileURLLoader cancellation
+// does not incorrectly result in content verificaton failure.
+// Regression test for: http://crbug.com/977805.
+IN_PROC_BROWSER_TEST_F(ContentVerifierTest,
+                       PRE_ResourceReadCancellationDoesNotFailVerification) {
+  // This test extension is copied from the webstore that has actual
+  // signatures.
+  const Extension* extension = InstallExtensionFromWebstore(
+      test_data_dir_.AppendASCII("content_verifier/ten_meg_resource.crx"), 1);
+  ASSERT_TRUE(extension);
+  EXPECT_EQ(kTenMegResourceExtensionId, extension->id());
+
+  // Navigate to a large resource that *likely* won't complete before
+  // this test ends and results in FileDataPipeProducer shutdown. This results
+  // in FILE_ERROR_ABORT in FileDataPipeProducer::Observer::BytesRead().
+  //
+  // Note that this can produce false-positive results because if the resource
+  // completes loading before shutdown, this test will still pass. There
+  // currently isn't a way to forcefully shut down FileDataPipeProducer.
+  // Also, whether to pursue such effort is debatable as it feels poking into
+  // the implementation detail a little too much.
+  const char kLargeResource[] = "ten_meg_background.js";
+  ui_test_utils::NavigateToURLWithDisposition(
+      browser(), extension->GetResourceURL(kLargeResource),
+      WindowOpenDisposition::NEW_FOREGROUND_TAB,
+      ui_test_utils::BROWSER_TEST_NONE);
+}
+
+IN_PROC_BROWSER_TEST_F(ContentVerifierTest,
+                       ResourceReadCancellationDoesNotFailVerification) {
+  // Expect the extension to not get disabled due to corruption.
+  extensions::ExtensionRegistry* registry =
+      extensions::ExtensionRegistry::Get(profile());
+  {
+    // Add a helpful hint, in case the regression reappears.
+    ExtensionPrefs* prefs = ExtensionPrefs::Get(profile());
+    int reasons = prefs->GetDisableReasons(kTenMegResourceExtensionId);
+    EXPECT_EQ(disable_reason::DISABLE_NONE, reasons)
+        << "Unexpected disable reasons. Includes corruption: "
+        << (reasons & disable_reason::DISABLE_CORRUPTED);
+  }
+  const Extension* extension =
+      registry->enabled_extensions().GetByID(kTenMegResourceExtensionId);
+  ASSERT_TRUE(extension);
+}
+
 class ContentVerifierPolicyTest : public ContentVerifierTest {
  public:
   // We need to do this work here because the force-install policy values are
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index 0506112..f7edc97 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -234,10 +234,10 @@
   else
     base::RecordAction(UserMetricsAction("CloseTab_RecordingIndicator"));
 
-  const CloseTabSource source =
-      (event.type() == ui::ET_MOUSE_RELEASED &&
-       !(event.flags() & ui::EF_FROM_TOUCH)) ? CLOSE_TAB_FROM_MOUSE
-                                             : CLOSE_TAB_FROM_TOUCH;
+  const CloseTabSource source = (event.type() == ui::ET_MOUSE_RELEASED &&
+                                 !(event.flags() & ui::EF_FROM_TOUCH))
+                                    ? CLOSE_TAB_FROM_MOUSE
+                                    : CLOSE_TAB_FROM_TOUCH;
   DCHECK_EQ(close_button_, sender);
   controller_->CloseTab(this, source);
   if (event.type() == ui::ET_GESTURE_TAP)
@@ -525,9 +525,26 @@
 void Tab::OnMouseMoved(const ui::MouseEvent& event) {
   tab_style_->SetHoverLocation(event.location());
   controller_->OnMouseEventInTab(this, event);
+#if defined(OS_LINUX)
+  MaybeUpdateHoverStatus(event);
+#endif
 }
 
 void Tab::OnMouseEntered(const ui::MouseEvent& event) {
+  MaybeUpdateHoverStatus(event);
+}
+
+void Tab::MaybeUpdateHoverStatus(const ui::MouseEvent& event) {
+#if defined(OS_LINUX)
+  // Move the hit test area for hovering up so that it is not overlapped by tab
+  // hover cards when they are shown.
+  // TODO(crbug/978134): Once Linux/CrOS widget transparency is solved, remove
+  // this case.
+  constexpr int kHoverCardOverlap = 6;
+  if (event.location().y() >= height() - kHoverCardOverlap)
+    return;
+#endif
+
   mouse_hovered_ = true;
   tab_style_->ShowHover(TabStyle::ShowHoverStyle::kSubtle);
   UpdateForegroundColors();
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 6c28cd1a..b1155bc 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -35,7 +35,7 @@
 namespace gfx {
 class Animation;
 class LinearAnimation;
-}
+}  // namespace gfx
 namespace views {
 class Label;
 }
@@ -219,6 +219,10 @@
   // and alert icon.
   void UpdateForegroundColors();
 
+  // Considers switching to hovered mode or [re-]showing the hover card based on
+  // the mouse moving over the tab.
+  void MaybeUpdateHoverStatus(const ui::MouseEvent& event);
+
   // The controller, never nullptr.
   TabController* const controller_;
 
diff --git a/chrome/test/data/extensions/content_verifier/ten_meg_resource.crx b/chrome/test/data/extensions/content_verifier/ten_meg_resource.crx
new file mode 100644
index 0000000..7a35a0e
--- /dev/null
+++ b/chrome/test/data/extensions/content_verifier/ten_meg_resource.crx
Binary files differ
diff --git a/chrome/test/data/extensions/content_verifier/ten_meg_resource.crx.INFO b/chrome/test/data/extensions/content_verifier/ten_meg_resource.crx.INFO
new file mode 100644
index 0000000..68c397b
--- /dev/null
+++ b/chrome/test/data/extensions/content_verifier/ten_meg_resource.crx.INFO
@@ -0,0 +1,5 @@
+Fetched from Chrome Web Store.
+CRX ID = mibjhafkjlepkpbjleahhallgddpjgle
+
+This extension has a background script called ten_meg_background.js that is
+10526729 bytes (> 10 meg) in size.
diff --git a/chrome/test/delayload/delayloads_unittest.cc b/chrome/test/delayload/delayloads_unittest.cc
index d2307288..ee97aa1 100644
--- a/chrome/test/delayload/delayloads_unittest.cc
+++ b/chrome/test/delayload/delayloads_unittest.cc
@@ -158,7 +158,7 @@
   EXPECT_EQ(nullptr, ::GetModuleHandle(L"user32.dll"));
 }
 
-TEST_F(DelayloadsTest, ChromeChildDllDelayloadsCheck) {
+TEST_F(DelayloadsTest, DISABLED_ChromeChildDllDelayloadsCheck) {
   base::FilePath dll;
   ASSERT_TRUE(base::PathService::Get(base::DIR_EXE, &dll));
   dll = dll.Append(L"chrome_child.dll");
@@ -209,7 +209,7 @@
   }
 }
 
-TEST_F(DelayloadsTest, ChromeChildDllLoadSanityTest) {
+TEST_F(DelayloadsTest, DISABLED_ChromeChildDllLoadSanityTest) {
   // On Win7 we expect this test to result in user32.dll getting loaded. As a
   // result, we need to ensure it is executed in its own test process. This
   // "test" will re-launch with custom parameters to accomplish that.
diff --git a/chromeos/settings/cros_settings_names.cc b/chromeos/settings/cros_settings_names.cc
index d23a2ce..9fe24df 100644
--- a/chromeos/settings/cros_settings_names.cc
+++ b/chromeos/settings/cros_settings_names.cc
@@ -382,4 +382,10 @@
 // respected when the device is shutdown.
 const char kDeviceScheduledUpdateCheck[] =
     "cros.device.device_scheduled_update_check";
+
+// An enum pref that configures the operation mode of the built-in 2nd factor
+// authenticator.
+const char kDeviceSecondFactorAuthenticationMode[] =
+    "cros.device.device_second_factor_authentication_mode";
+
 }  // namespace chromeos
diff --git a/chromeos/settings/cros_settings_names.h b/chromeos/settings/cros_settings_names.h
index 68c04fb..b1676b604 100644
--- a/chromeos/settings/cros_settings_names.h
+++ b/chromeos/settings/cros_settings_names.h
@@ -222,6 +222,9 @@
 COMPONENT_EXPORT(CHROMEOS_SETTINGS)
 extern const char kDeviceScheduledUpdateCheck[];
 
+COMPONENT_EXPORT(CHROMEOS_SETTINGS)
+extern const char kDeviceSecondFactorAuthenticationMode[];
+
 }  // namespace chromeos
 
 #endif  // CHROMEOS_SETTINGS_CROS_SETTINGS_NAMES_H_
diff --git a/content/browser/file_url_loader_factory.cc b/content/browser/file_url_loader_factory.cc
index 5a2d068..669e3f3 100644
--- a/content/browser/file_url_loader_factory.cc
+++ b/content/browser/file_url_loader_factory.cc
@@ -118,6 +118,23 @@
          network::cors::OriginAccessList::AccessState::kAllowed;
 }
 
+base::File::Error ToFileError(int net_error) {
+  // Note: For now, only return specific errors that our obervers care about.
+  switch (net_error) {
+    case net::OK:
+      return base::File::FILE_OK;
+    case net::ERR_FILE_NOT_FOUND:
+      return base::File::FILE_ERROR_NOT_FOUND;
+    case net::ERR_ACCESS_DENIED:
+      return base::File::FILE_ERROR_ACCESS_DENIED;
+    case net::ERR_ABORTED:
+    case net::ERR_CONNECTION_ABORTED:
+      return base::File::FILE_ERROR_ABORT;
+    default:
+      return base::File::FILE_ERROR_FAILED;
+  }
+}
+
 class FileURLDirectoryLoader
     : public network::mojom::URLLoader,
       public net::DirectoryLister::DirectoryListerDelegate {
@@ -668,8 +685,11 @@
                         std::unique_ptr<FileURLLoaderObserver> observer) {
     client_->OnComplete(network::URLLoaderCompletionStatus(net_error));
     client_.reset();
-    if (observer)
+    if (observer) {
+      if (net_error != net::OK)
+        observer->OnBytesRead(nullptr, 0u, ToFileError(net_error));
       observer->OnDoneReading();
+    }
     MaybeDeleteSelf();
   }
 
diff --git a/extensions/browser/content_verify_job.cc b/extensions/browser/content_verify_job.cc
index a61c47e1..c1471f5 100644
--- a/extensions/browser/content_verify_job.cc
+++ b/extensions/browser/content_verify_job.cc
@@ -42,6 +42,13 @@
   base::ElapsedTimer timer;
 };
 
+bool IsIgnorableReadError(base::File::Error read_result) {
+  // Extension reload, for example, can cause benign
+  // FILE_ERROR_ABORT error. Do not incorrectly fail content verification in
+  // that case. See https://crbug.com/977805 for details.
+  return read_result == base::File::FILE_ERROR_ABORT;
+}
+
 }  // namespace
 
 ContentVerifyJob::ContentVerifyJob(const ExtensionId& extension_id,
@@ -89,10 +96,12 @@
       base::BindOnce(&ContentVerifyJob::OnHashesReady, this));
 }
 
-void ContentVerifyJob::BytesRead(int count, const char* data) {
+void ContentVerifyJob::BytesRead(const char* data,
+                                 int count,
+                                 base::File::Error read_result) {
   base::AutoLock auto_lock(lock_);
   DCHECK(!done_reading_);
-  BytesReadImpl(count, data);
+  BytesReadImpl(data, count, read_result);
 }
 
 void ContentVerifyJob::DoneReading() {
@@ -104,6 +113,9 @@
     return;
   DCHECK(!done_reading_);
   done_reading_ = true;
+  if (has_ignorable_read_error_)
+    return;
+
   if (hashes_ready_) {
     if (!FinishBlock()) {
       DispatchFailureCallback(HASH_MISMATCH);
@@ -114,12 +126,17 @@
   }
 }
 
-void ContentVerifyJob::BytesReadImpl(int count, const char* data) {
+void ContentVerifyJob::BytesReadImpl(const char* data,
+                                     int count,
+                                     base::File::Error read_result) {
   ScopedElapsedTimer timer(&time_spent_);
   if (failed_)
     return;
   if (g_ignore_verification_for_tests)
     return;
+  if (IsIgnorableReadError(read_result))
+    has_ignorable_read_error_ = true;
+
   if (!hashes_ready_) {
     queue_.append(data, count);
     return;
@@ -221,7 +238,7 @@
   if (!queue_.empty()) {
     std::string tmp;
     queue_.swap(tmp);
-    BytesReadImpl(tmp.size(), base::data(tmp));
+    BytesReadImpl(base::data(tmp), tmp.size(), base::File::FILE_OK);
     if (failed_)
       return;
   }
diff --git a/extensions/browser/content_verify_job.h b/extensions/browser/content_verify_job.h
index b91e5e2f..258fe7d 100644
--- a/extensions/browser/content_verify_job.h
+++ b/extensions/browser/content_verify_job.h
@@ -11,6 +11,7 @@
 #include <string>
 
 #include "base/callback.h"
+#include "base/files/file.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
@@ -73,7 +74,7 @@
   // are read. Make sure to call DoneReading so that any final bytes that were
   // read that didn't align exactly on a block size boundary get their hash
   // checked as well.
-  void BytesRead(int count, const char* data);
+  void BytesRead(const char* data, int count, base::File::Error read_result);
 
   // Call once when finished adding bytes via BytesRead.
   void DoneReading();
@@ -104,7 +105,9 @@
   void DidGetContentHashOnIO(scoped_refptr<const ContentHash> hash);
 
   // Same as BytesRead, but is run without acquiring lock.
-  void BytesReadImpl(int count, const char* data);
+  void BytesReadImpl(const char* data,
+                     int count,
+                     base::File::Error read_result);
 
   // Called each time we're done adding bytes for the current block, and are
   // ready to finish the hash operation for those bytes and make sure it
@@ -118,6 +121,10 @@
   // Called when our ContentHashReader has finished initializing.
   void OnHashesReady(std::unique_ptr<const ContentHashReader> hash_reader);
 
+  // True if BytesRead has seen some errors that can be ignored from content
+  // verification's perspective.
+  bool has_ignorable_read_error_ = false;
+
   // Indicates whether the caller has told us they are done calling BytesRead.
   bool done_reading_;
 
diff --git a/extensions/browser/content_verify_job_unittest.cc b/extensions/browser/content_verify_job_unittest.cc
index 8b10d8f..bbddc4c 100644
--- a/extensions/browser/content_verify_job_unittest.cc
+++ b/extensions/browser/content_verify_job_unittest.cc
@@ -93,8 +93,8 @@
     auto run_content_read_step = [](ContentVerifyJob* verify_job,
                                     std::string* resource_contents) {
       // Simulate serving |resource_contents| from |resource_path|.
-      verify_job->BytesRead(resource_contents->size(),
-                            base::data(*resource_contents));
+      verify_job->BytesRead(base::data(*resource_contents),
+                            resource_contents->size(), base::File::FILE_OK);
       verify_job->DoneReading();
     };
 
diff --git a/extensions/browser/extension_protocols.cc b/extensions/browser/extension_protocols.cc
index e0761e1..aea24fb 100644
--- a/extensions/browser/extension_protocols.cc
+++ b/extensions/browser/extension_protocols.cc
@@ -266,7 +266,8 @@
       // proceed; see crbug.com/703888.
       if (verify_job_.get()) {
         std::string tmp;
-        verify_job_->BytesRead(0, base::data(tmp));
+        verify_job_->BytesRead(base::data(tmp), 0,
+                               base::File::FILE_ERROR_FAILED);
         verify_job_->DoneReading();
       }
     }
@@ -292,7 +293,7 @@
     if (result > 0) {
       bytes_read_ += result;
       if (verify_job_.get())
-        verify_job_->BytesRead(result, buffer->data());
+        verify_job_->BytesRead(buffer->data(), result, base::File::FILE_OK);
     }
   }
 
@@ -715,15 +716,22 @@
     if (read_result == base::File::FILE_OK) {
       UMA_HISTOGRAM_COUNTS_1M("ExtensionUrlRequest.OnReadCompleteResult",
                               read_result);
-      base::AutoLock auto_lock(lock_);
-      bytes_read_ += num_bytes_read;
-      if (verify_job_.get())
-        verify_job_->BytesRead(num_bytes_read, static_cast<const char*>(data));
     } else {
       net::Error net_error = net::FileErrorToNetError(read_result);
       base::UmaHistogramSparse("ExtensionUrlRequest.OnReadCompleteError",
                                net_error);
     }
+    {
+      base::AutoLock auto_lock(lock_);
+      bytes_read_ += num_bytes_read;
+      if (verify_job_) {
+        // Note: We still pass the data to |verify_job_|, even if there was a
+        // read error, because some errors are ignorable. See
+        // ContentVerifyJob::BytesRead() for more details.
+        verify_job_->BytesRead(static_cast<const char*>(data), num_bytes_read,
+                               read_result);
+      }
+    }
   }
 
   void OnDoneReading() override {
diff --git a/extensions/browser/extension_user_script_loader.cc b/extensions/browser/extension_user_script_loader.cc
index 9d9e9b1b..db2d224 100644
--- a/extensions/browser/extension_user_script_loader.cc
+++ b/extensions/browser/extension_user_script_loader.cc
@@ -73,7 +73,8 @@
       info.extension_id, info.extension_root, info.relative_path));
   if (job.get()) {
     job->Start(verifier);
-    job->BytesRead(info.content.size(), info.content.data());
+    job->BytesRead(info.content.data(), info.content.size(),
+                   base::File::FILE_OK);
     job->DoneReading();
   }
 }
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index 3d621690..8eed49b 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -47,6 +47,11 @@
 
 const size_t kMaxMessageSize = 1024 * 1024;  // 1MB
 
+constexpr char kBadAuthenticationError[] = "BadAuthentication";
+constexpr char kBadAuthenticationShortError[] = "badauth";
+constexpr char kServiceUnavailableError[] = "ServiceUnavailable";
+constexpr char kServiceUnavailableShortError[] = "ire";
+
 std::unique_ptr<const GaiaAuthConsumer::ClientOAuthResult>
 ExtractOAuth2TokenPairResponse(const std::string& data) {
   std::unique_ptr<base::Value> value = base::JSONReader::ReadDeprecated(data);
@@ -178,13 +183,8 @@
 // static
 const char GaiaAuthFetcher::kAccountDisabledError[] = "AccountDisabled";
 // static
-const char GaiaAuthFetcher::kBadAuthenticationError[] = "BadAuthentication";
-// static
 const char GaiaAuthFetcher::kCaptchaError[] = "CaptchaRequired";
 // static
-const char GaiaAuthFetcher::kServiceUnavailableError[] =
-    "ServiceUnavailable";
-// static
 const char GaiaAuthFetcher::kErrorParam[] = "Error";
 // static
 const char GaiaAuthFetcher::kErrorUrlParam[] = "Url";
@@ -919,13 +919,15 @@
     return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DELETED);
   if (error == kAccountDisabledError)
     return GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED);
-  if (error == kBadAuthenticationError) {
+  if (error == kBadAuthenticationShortError ||
+      error == kBadAuthenticationError) {
     return GoogleServiceAuthError(
         GoogleServiceAuthError::FromInvalidGaiaCredentialsReason(
             GoogleServiceAuthError::InvalidGaiaCredentialsReason::
                 CREDENTIALS_REJECTED_BY_SERVER));
   }
-  if (error == kServiceUnavailableError) {
+  if (error == kServiceUnavailableShortError ||
+      error == kServiceUnavailableError) {
     return GoogleServiceAuthError(
         GoogleServiceAuthError::SERVICE_UNAVAILABLE);
   }
diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h
index ae48d42d..bcab70e8 100644
--- a/google_apis/gaia/gaia_auth_fetcher.h
+++ b/google_apis/gaia/gaia_auth_fetcher.h
@@ -249,12 +249,8 @@
   static const char kAccountDeletedErrorCode[];
   static const char kAccountDisabledError[];
   static const char kAccountDisabledErrorCode[];
-  static const char kBadAuthenticationError[];
-  static const char kBadAuthenticationErrorCode[];
   static const char kCaptchaError[];
   static const char kCaptchaErrorCode[];
-  static const char kServiceUnavailableError[];
-  static const char kServiceUnavailableErrorCode[];
   static const char kErrorParam[];
   static const char kErrorUrlParam[];
   static const char kCaptchaUrlParam[];
@@ -404,8 +400,10 @@
   FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDeletedError);
   FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDisabledError);
   FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, BadAuthenticationError);
+  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, BadAuthenticationShortError);
   FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, IncomprehensibleError);
   FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ServiceUnavailableError);
+  FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, ServiceUnavailableShortError);
   FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckNormalErrorCode);
   FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CheckTwoFactorResponse);
   FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, LoginNetFailure);
diff --git a/google_apis/gaia/gaia_auth_fetcher_unittest.cc b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
index 248392f..8f9c4721 100644
--- a/google_apis/gaia/gaia_auth_fetcher_unittest.cc
+++ b/google_apis/gaia/gaia_auth_fetcher_unittest.cc
@@ -299,6 +299,13 @@
   EXPECT_EQ(error.state(), GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
 }
 
+TEST_F(GaiaAuthFetcherTest, BadAuthenticationShortError) {
+  std::string data = "Error=badauth\n";
+  GoogleServiceAuthError error =
+      GaiaAuthFetcher::GenerateAuthError(data, net::OK);
+  EXPECT_EQ(error.state(), GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS);
+}
+
 TEST_F(GaiaAuthFetcherTest, IncomprehensibleError) {
   std::string data = "Error=Gobbledygook\n";
   GoogleServiceAuthError error =
@@ -313,6 +320,13 @@
   EXPECT_EQ(error.state(), GoogleServiceAuthError::SERVICE_UNAVAILABLE);
 }
 
+TEST_F(GaiaAuthFetcherTest, ServiceUnavailableShortError) {
+  std::string data = "Error=ire\n";
+  GoogleServiceAuthError error =
+      GaiaAuthFetcher::GenerateAuthError(data, net::OK);
+  EXPECT_EQ(error.state(), GoogleServiceAuthError::SERVICE_UNAVAILABLE);
+}
+
 TEST_F(GaiaAuthFetcherTest, StartAuthCodeForOAuth2TokenExchange_Success) {
   MockGaiaConsumer consumer;
   EXPECT_CALL(consumer, OnClientOAuthCode("test-code")).Times(0);
diff --git a/mojo/public/cpp/system/file_data_pipe_producer.cc b/mojo/public/cpp/system/file_data_pipe_producer.cc
index f207e0d..3c928db 100644
--- a/mojo/public/cpp/system/file_data_pipe_producer.cc
+++ b/mojo/public/cpp/system/file_data_pipe_producer.cc
@@ -206,6 +206,8 @@
 
   void Finish(MojoResult result) {
     if (observer_) {
+      if (result != MOJO_RESULT_OK)
+        observer_->OnBytesRead(nullptr, 0u, base::File::FILE_ERROR_ABORT);
       observer_->OnDoneReading();
       observer_ = nullptr;
     }
diff --git a/mojo/public/cpp/system/tests/file_data_pipe_producer_unittest.cc b/mojo/public/cpp/system/tests/file_data_pipe_producer_unittest.cc
index 7c9b6e5..f14e397 100644
--- a/mojo/public/cpp/system/tests/file_data_pipe_producer_unittest.cc
+++ b/mojo/public/cpp/system/tests/file_data_pipe_producer_unittest.cc
@@ -247,7 +247,7 @@
   loop.Run();
 
   EXPECT_EQ(0UL, reader.data().size());
-  EXPECT_EQ(0, observer_data.num_read_errors);
+  EXPECT_EQ(1, observer_data.num_read_errors);
   EXPECT_EQ(0UL, observer_data.bytes_read);
   EXPECT_EQ(1, observer_data.done_called);
 }
diff --git a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
index 6f6cb46..f9a83fb6 100644
--- a/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
+++ b/third_party/blink/renderer/core/html/forms/html_form_control_element.cc
@@ -336,6 +336,9 @@
 }
 
 bool HTMLFormControlElement::IsKeyboardFocusable() const {
+  if (RuntimeEnabledFeatures::FocuslessSpatialNavigationEnabled())
+    return HTMLElement::IsKeyboardFocusable();
+
   // Skip tabIndex check in a parent class.
   return IsFocusable();
 }
diff --git a/third_party/blink/renderer/core/input/fallback_cursor_event_manager.cc b/third_party/blink/renderer/core/input/fallback_cursor_event_manager.cc
index 29233e1f..b691b8bd 100644
--- a/third_party/blink/renderer/core/input/fallback_cursor_event_manager.cc
+++ b/third_party/blink/renderer/core/input/fallback_cursor_event_manager.cc
@@ -349,9 +349,24 @@
 
   DCHECK(scrollable);
 
+  DCHECK(root_frame_->GetDocument());
+  DCHECK(root_frame_->GetDocument()->View());
+  // TODO(bokan): Overly-defensive since we'll be merging, remove from ToT.
+  if (!root_frame_->GetDocument() || !root_frame_->GetDocument()->View())
+    return;
+
   IntPoint location_in_root_frame{e.PositionInRootFrame().x,
                                   e.PositionInRootFrame().y};
 
+  // Make sure we unlock all movement if the cursor is outside our bounds. This
+  // can happen when the cursor is enabled/disabled (e.g. position: -1,-1).
+  IntRect root_frame_rect = root_frame_->GetDocument()->View()->FrameRect();
+  if (!root_frame_rect.Contains(location_in_root_frame)) {
+    ResetCurrentScrollable();
+    LockCursor(false, false, false, false);
+    return;
+  }
+
   IntSize scrollable_clip_size_in_root_frame =
       ScrollableAreaClipSizeInRootFrame(*scrollable);
   IntPoint location_in_scrollable =
@@ -376,6 +391,8 @@
   HitTestResult hit_test_result =
       HitTest(root_frame_->GetDocument()->GetLayoutView(), location);
   Node* node = hit_test_result.InnerNode();
+  if (!node)
+    return;
 
   // Click on input boxes or media node should hide the cursor.
   if (HasEditableStyle(*node) || node->IsMediaElement()) {
diff --git a/third_party/blink/renderer/core/input/fallback_cursor_event_manager_test.cc b/third_party/blink/renderer/core/input/fallback_cursor_event_manager_test.cc
index 2bfadb9..d186267 100644
--- a/third_party/blink/renderer/core/input/fallback_cursor_event_manager_test.cc
+++ b/third_party/blink/renderer/core/input/fallback_cursor_event_manager_test.cc
@@ -148,6 +148,38 @@
   ExpectLock(false, false, false, false);
 }
 
+TEST_F(FallbackCursorEventManagerTest, ResetOnOutOfFrame) {
+  SetBodyInnerHTML(R"HTML(
+    <style>
+    html, body {
+      margin: 0px;
+    }
+    .big {
+      height: 10000px;
+      width: 10000px;
+    }
+    </style>
+    <div class='big'></div>
+  )HTML");
+  TurnOnFallbackCursorMode();
+
+  // Move below the scroll down line.
+  MouseMove(100, 500);
+  ExpectLock(false, false, false, true);
+
+  // Ensure an invalid or out-of-bounds mouse move will reset the lock.
+  MouseMove(-1, -1);
+  ExpectLock(false, false, false, false);
+
+  // Ensure an invalid or out-of-bounds mouse move will reset the lock.
+  MouseMove(790, 590);
+  ExpectLock(false, true, false, true);
+
+  // Ensure an invalid or out-of-bounds mouse move will reset the lock.
+  MouseMove(800, 600);
+  ExpectLock(false, false, false, false);
+}
+
 TEST_F(FallbackCursorEventManagerTest, MouseMoveCursorLockOnRootFrame) {
   SetBodyInnerHTML(R"HTML(
     <style>
diff --git a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index 10a49c1..d0d9c8a 100644
--- a/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -487,10 +487,11 @@
 
   // TODO(crbug.com/927066): We calculate an incorrect intrinsic logical height
   // when percentages are involved, so for now don't apply min-height: auto
-  // in such cases.
+  // in such cases. (This is only a problem if the child has a definite height)
   const LayoutBlock* child_block = DynamicTo<LayoutBlock>(child);
   if (IsColumnFlow() && child_block &&
-      child_block->HasPercentHeightDescendants())
+      child_block->HasPercentHeightDescendants() &&
+      child_block->HasDefiniteLogicalHeight())
     return false;
 
   return !child.ShouldApplySizeContainment() &&
diff --git a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
index 1b93b8db..fefd14dc 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_node_object.cc
@@ -2819,7 +2819,9 @@
       name_sources->back().native_source = kAXTextFromNativeHTMLLabel;
     }
 
-    LabelsNodeList* labels = html_element->labels();
+    LabelsNodeList* labels = nullptr;
+    if (AXObjectCache().MayHaveHTMLLabel(*html_element))
+      labels = html_element->labels();
     if (labels && labels->length() > 0) {
       HeapVector<Member<Element>> label_elements;
       for (unsigned label_index = 0; label_index < labels->length();
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
index 086d54e..c69788a 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.cc
@@ -1017,6 +1017,19 @@
   relation_cache_->UpdateAriaOwns(owner, id_vector, owned_children);
 }
 
+bool AXObjectCacheImpl::MayHaveHTMLLabel(const HTMLElement& elem) {
+  // Return false if this type of element will not accept a <label for> label.
+  if (!elem.IsLabelable())
+    return false;
+
+  // Return true if a <label for> pointed to this element at some point.
+  if (relation_cache_->MayHaveHTMLLabelViaForAttribute(elem))
+    return true;
+
+  // Return true if any amcestor is a label, as in <label><input></label>.
+  return Traversal<HTMLLabelElement>::FirstAncestor(elem);
+}
+
 void AXObjectCacheImpl::CheckedStateChanged(Node* node) {
   PostNotification(node, ax::mojom::Event::kCheckedStateChanged);
 }
@@ -1388,7 +1401,8 @@
 }
 
 void AXObjectCacheImpl::LabelChangedWithCleanLayout(Element* element) {
-  TextChangedWithCleanLayout(ToHTMLLabelElement(element)->control());
+  // Will call back to TextChanged() when done updating relation cache.
+  relation_cache_->LabelChanged(element);
 }
 
 void AXObjectCacheImpl::InlineTextBoxesUpdated(
diff --git a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
index 75901b0..39420ae 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_object_cache_impl.h
@@ -234,6 +234,8 @@
                       const Vector<String>& id_vector,
                       HeapVector<Member<AXObject>>& owned_children);
 
+  bool MayHaveHTMLLabel(const HTMLElement& elem);
+
   // Synchronously returns whether or not we currently have permission to
   // call AOM event listeners.
   bool CanCallAOMEventListeners() const;
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
index 895d5e2..30f0d383 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
+++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.cc
@@ -9,6 +9,8 @@
 
 namespace blink {
 
+using namespace html_names;
+
 AXRelationCache::AXRelationCache(AXObjectCacheImpl* object_cache)
     : object_cache_(object_cache) {}
 
@@ -167,6 +169,14 @@
                                       validated_owned_child_axids);
 }
 
+bool AXRelationCache::MayHaveHTMLLabelViaForAttribute(
+    const HTMLElement& labelable) {
+  const AtomicString& id = labelable.GetIdAttribute();
+  if (id.IsEmpty())
+    return false;
+  return all_previously_seen_label_target_ids_.Contains(id);
+}
+
 // Fill source_objects with AXObjects for relations pointing to target.
 void AXRelationCache::GetReverseRelated(
     Node* target,
@@ -260,8 +270,12 @@
 }
 
 void AXRelationCache::LabelChanged(Node* node) {
-  if (HTMLElement* control = ToHTMLLabelElement(node)->control())
-    TextChanged(Get(control));
+  const AtomicString& id = ToHTMLElement(node)->FastGetAttribute(kForAttr);
+  if (!id.IsEmpty()) {
+    all_previously_seen_label_target_ids_.insert(id);
+    if (HTMLElement* control = ToHTMLLabelElement(node)->control())
+      TextChanged(Get(control));
+  }
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h
index 78d1ef0..86c778da 100644
--- a/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h
+++ b/third_party/blink/renderer/modules/accessibility/ax_relation_cache.h
@@ -38,6 +38,9 @@
                       const Vector<String>& id_vector,
                       HeapVector<Member<AXObject>>& owned_children);
 
+  // Return true if any label ever pointed to the element via the for attribute.
+  bool MayHaveHTMLLabelViaForAttribute(const HTMLElement&);
+
   // Given an element in the DOM tree that was either just added or whose id
   // just changed, check to see if another object wants to be its parent due to
   // aria-owns. If so, update the tree by calling childrenChanged() on the
@@ -54,6 +57,8 @@
   void UpdateReverseRelations(const AXObject* relation_source,
                               const Vector<String>& target_ids);
 
+  void LabelChanged(Node*);
+
  private:
   // If any object is related to this object via <label for>, aria-owns,
   // aria-describedby or aria-labeledby, update the text for the related object.
@@ -90,13 +95,19 @@
   //   and fire the appropriate change events.
   HashMap<String, HashSet<AXID>> id_attr_to_related_mapping_;
 
+  // HTML id attributes that at one time havehad a <label for> pointing to it.
+  // IDs are not necessarily removed from this set. It is not necessary to
+  // remove IDs as false positives are ok. Being able to determine that a
+  // labelable element has never had an associated label allows the accessible
+  // name calculation to be optimized.
+  HashSet<AtomicString> all_previously_seen_label_target_ids_;
+
   // Helpers that call back into object cache
   AXObject* ObjectFromAXID(AXID) const;
   AXObject* GetOrCreate(Node*);
   AXObject* Get(Node*);
   void ChildrenChanged(AXObject*);
   void TextChanged(AXObject*);
-  void LabelChanged(Node*);
 
   DISALLOW_COPY_AND_ASSIGN(AXRelationCache);
 };
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 9764bb33..899bff9 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1471,6 +1471,7 @@
 crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-008.xht [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-012.html [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-014.html [ Failure ]
+crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-015.html [ Failure ]
 crbug.com/249112 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-005.xht [ Failure ]
 crbug.com/249112 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-minimum-width-flex-items-007.xht [ Failure ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/flex-order.html [ Failure ]
diff --git a/third_party/blink/web_tests/accessibility/name-calc-inputs.html b/third_party/blink/web_tests/accessibility/name-calc-inputs.html
index 80b9ce3e..c251c069 100644
--- a/third_party/blink/web_tests/accessibility/name-calc-inputs.html
+++ b/third_party/blink/web_tests/accessibility/name-calc-inputs.html
@@ -79,7 +79,9 @@
 
 <div class="container">
     <label>label-wrapping-text7
-        <input id="text7" type="text" title="text7-title">
+        <span>   <!-- Also testing ancestor label that is not direct parent -->
+            <input id="text7" type="text" title="text7-title">
+        </span>
     </label>
 </div>
 
diff --git a/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-016.html b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-016.html
new file mode 100644
index 0000000..a5dc8763
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-flexbox/flex-minimum-height-flex-items-016.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<title>CSS Flexbox: min-height: auto with flex items containing percentage-sized children</title>
+<link rel="author" title="Google LLC" href="https://www.google.com/" />
+<link rel="help" href="https://drafts.csswg.org/css-flexbox/#min-size-auto" />
+<link rel="issue" href="https://bugs.chromium.org/p/chromium/issues/detail?id=981481" />
+<link rel="issue" href="https://bugs.chromium.org/p/chromium/issues/detail?id=984606" />
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht" />
+
+<style>
+.flexbox {
+  display: flex;
+  width: 100px;
+  flex-direction: column;
+}
+.item {
+  flex-basis: 0;
+  background: green;
+}
+.percentage {
+  height: 100%;
+}
+.fixed {
+  height: 100px;
+}
+
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+
+<div class="flexbox">
+    <div class="item">
+        <div class="percentage"></div>
+        <div class="fixed"></div>
+    </div>
+</div>
diff --git a/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-button-negative-tabindex.html b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-button-negative-tabindex.html
new file mode 100644
index 0000000..bccdec77
--- /dev/null
+++ b/third_party/blink/web_tests/virtual/focusless-spat-nav/fast/spatial-navigation/focusless/snav-focusless-button-negative-tabindex.html
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<script src="../../../../../resources/testharness.js"></script>
+<script src="../../../../../resources/testharnessreport.js"></script>
+<script src="file:///gen/layout_test_data/mojo/public/js/mojo_bindings.js"></script>
+<script src="file:///gen/third_party/blink/public/mojom/page/spatial_navigation.mojom.js"></script>
+<script src="../../../../../fast/spatial-navigation/resources/mock-snav-service.js"></script>
+<script src="../../../../../fast/spatial-navigation/resources/snav-testharness.js"></script>
+
+<style>
+  div {
+    width: 130px;
+    height: 130px;
+    border: 1px solid black;
+  }
+</style>
+<button tabindex="-1" id="unselectable">Unselectable</button>
+<br>
+<br>
+<button id="selectable"">Selectable</button>
+
+<script>
+  const unselectable = document.getElementById("unselectable");
+  const selectable = document.getElementById("selectable");
+
+  // This test checks that tabindex="-1" is effective on a button element,
+  // which overrides Element::IsKeyboardFocusable.
+  test(() => {
+    assert_true(!!window.internals);
+
+    snav.triggerMove('Down');
+    assert_equals(window.internals.interestedElement,
+                  selectable,
+                  "Expected interest to move to |selectable| button.");
+
+    snav.triggerMove('Up');
+    assert_equals(window.internals.interestedElement,
+                  selectable,
+                  "Expected interest to stay on |selectable| button.");
+  }, "Cannot navigate to button with tabindex'-1'");
+</script>
diff --git a/ui/display/display.cc b/ui/display/display.cc
index f2153337b..71d6f3f 100644
--- a/ui/display/display.cc
+++ b/ui/display/display.cc
@@ -215,12 +215,9 @@
       bounds_(bounds),
       work_area_(bounds),
       device_scale_factor_(GetForcedDeviceScaleFactor()) {
-  gfx::ColorSpace color_space = HasForceDisplayColorProfile()
-                                    ? GetForcedDisplayColorProfile()
-                                    : gfx::ColorSpace::CreateSRGB();
-  float sdr_white_level =
-      color_space.IsHDR() ? 200.f : gfx::ColorSpace::kDefaultSDRWhiteLevel;
-  SetColorSpaceAndDepth(color_space, sdr_white_level);
+  SetColorSpaceAndDepth(HasForceDisplayColorProfile()
+                            ? GetForcedDisplayColorProfile()
+                            : gfx::ColorSpace::CreateSRGB());
 #if defined(USE_AURA)
   SetScaleAndBounds(device_scale_factor_, bounds);
 #endif