diff --git a/DEPS b/DEPS
index 1518e5a..a8004ec 100644
--- a/DEPS
+++ b/DEPS
@@ -126,7 +126,7 @@
   # 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': 'd45bb845fdd1a49d40909414533592d55c91c249',
+  'skia_revision': '05ff93c43ea57fd62cd1bc36ab7cd9b6112a7ecf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -138,7 +138,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': 'eef531f1716af901b12b26e597c6ed8e8aaa0acf',
+  'angle_revision': '08573730b75a986c88b774fb9ce98bab45ffc1b1',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -189,7 +189,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': 'b926cccbcca580f67999ad2201720397a77ab02e',
+  'catapult_revision': '3b6663037fd5c1f61087a994df10b0338b4464d6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -241,7 +241,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.
-  'spv_headers_revision': '8bea0a266ac9b718aa0818d9e3a47c0b77c2cb23',
+  'spv_headers_revision': 'e74c389f81915d0a48d6df1af83c3862c5ad85ab',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -253,7 +253,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.
-  'dawn_revision': '11d32c80958a4c3fdf2005bb0a44058ab5c4caf6',
+  'dawn_revision': '203016613717b23f4a54003e62cea8ca8a97f0f7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -737,7 +737,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '36b3514fb564ed54f193e7e545a83caf2060826a',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + '611d1fbc1736114e324d2f341180b33fd0938d38',
       'condition': 'checkout_linux',
   },
 
@@ -762,7 +762,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '385c9b3a3112e964d2c63e37ec9301ae77bb9636',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '9cf1796ae43818259e6babf341ddf389ddb3f597',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1275,7 +1275,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + 'a0f51b2e123f39c9ff12e621b0b47dd28dd64424',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + '76d7ce2752231b396c99d2fb21fe600066c7864b',
+    Var('webrtc_git') + '/src.git' + '@' + '826f2e7f340cc40914ae4561625f7bb6d6e8c87b',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
@@ -1316,7 +1316,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@5ae6915dd7a4e7d8becdfbb5399e1828de199691',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@d55d94e6c8e65105d151f29ccb580bd1fb6312ce',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/tools/cts_config/OWNERS b/android_webview/tools/cts_config/OWNERS
deleted file mode 100644
index 00f4219..0000000
--- a/android_webview/tools/cts_config/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-mikecase@chromium.org
-yolandyan@chromium.org
diff --git a/ash/public/cpp/app_list/app_list_features.cc b/ash/public/cpp/app_list/app_list_features.cc
index c0231c5..db0a6ed 100644
--- a/ash/public/cpp/app_list/app_list_features.cc
+++ b/ash/public/cpp/app_list/app_list_features.cc
@@ -27,8 +27,6 @@
     "EnableZeroStateSuggestions", base::FEATURE_ENABLED_BY_DEFAULT};
 const base::Feature kEnableAppListSearchAutocomplete{
     "EnableAppListSearchAutocomplete", base::FEATURE_ENABLED_BY_DEFAULT};
-const base::Feature kEnableAdaptiveResultRanker{
-    "EnableAdaptiveResultRanker", base::FEATURE_DISABLED_BY_DEFAULT};
 const base::Feature kEnableAppSearchResultRanker{
     "EnableAppSearchResultRanker", base::FEATURE_ENABLED_BY_DEFAULT};
 const base::Feature kEnableAppReinstallZeroState{
@@ -70,10 +68,6 @@
   return base::FeatureList::IsEnabled(kEnableAppListSearchAutocomplete);
 }
 
-bool IsAdaptiveResultRankerEnabled() {
-  return base::FeatureList::IsEnabled(kEnableAdaptiveResultRanker);
-}
-
 bool IsAppSearchResultRankerEnabled() {
   return base::FeatureList::IsEnabled(kEnableAppSearchResultRanker);
 }
diff --git a/ash/public/cpp/app_list/app_list_features.h b/ash/public/cpp/app_list/app_list_features.h
index 3f3eaea..2c192d4 100644
--- a/ash/public/cpp/app_list/app_list_features.h
+++ b/ash/public/cpp/app_list/app_list_features.h
@@ -44,9 +44,6 @@
 // Enables the feature to autocomplete text typed in the AppList search box.
 ASH_PUBLIC_EXPORT extern const base::Feature kEnableAppListSearchAutocomplete;
 
-// Enable an adaptive model that tweaks search result scores.
-ASH_PUBLIC_EXPORT extern const base::Feature kEnableAdaptiveResultRanker;
-
 // Enables the feature to rank app search result using AppSearchResultRanker.
 ASH_PUBLIC_EXPORT extern const base::Feature kEnableAppSearchResultRanker;
 
@@ -65,7 +62,6 @@
 bool ASH_PUBLIC_EXPORT IsSettingsShortcutSearchEnabled();
 bool ASH_PUBLIC_EXPORT IsZeroStateSuggestionsEnabled();
 bool ASH_PUBLIC_EXPORT IsAppListSearchAutocompleteEnabled();
-bool ASH_PUBLIC_EXPORT IsAdaptiveResultRankerEnabled();
 bool ASH_PUBLIC_EXPORT IsAppSearchResultRankerEnabled();
 bool ASH_PUBLIC_EXPORT IsAppReinstallZeroStateEnabled();
 bool ASH_PUBLIC_EXPORT IsEmbeddedAssistantUIEnabled();
diff --git a/base/android/java/src/org/chromium/base/task/TaskTraits.java b/base/android/java/src/org/chromium/base/task/TaskTraits.java
index f95ebba..4b91a32 100644
--- a/base/android/java/src/org/chromium/base/task/TaskTraits.java
+++ b/base/android/java/src/org/chromium/base/task/TaskTraits.java
@@ -23,13 +23,37 @@
     public static final int EXTENSION_STORAGE_SIZE = 8;
 
     // Convenience variables explicitly specifying common priorities
-    public static final TaskTraits USER_BLOCKING =
-            new TaskTraits().taskPriority(TaskPriority.USER_BLOCKING);
-    public static final TaskTraits USER_VISIBLE =
-            new TaskTraits().taskPriority(TaskPriority.USER_VISIBLE);
+
+    // This task will only be scheduled when machine resources are available. Once
+    // running, it may be descheduled if higher priority work arrives (in this
+    // process or another) and its running on a non-critical thread. This is the
+    // lowest possible priority.
     public static final TaskTraits BEST_EFFORT =
             new TaskTraits().taskPriority(TaskPriority.BEST_EFFORT);
 
+    // This is a lowest-priority task which may block, for example non-urgent
+    // logging or deletion of temporary files as clean-up.
+    public static final TaskTraits BEST_EFFORT_MAY_BLOCK =
+            new TaskTraits().taskPriority(TaskPriority.BEST_EFFORT).mayBlock(true);
+
+    // This task affects UI or responsiveness of future user interactions. It is
+    // not an immediate response to a user interaction. Most tasks are likely to
+    // have this priority.
+    // Examples:
+    // - Updating the UI to reflect progress on a long task.
+    // - Loading data that might be shown in the UI after a future user
+    //   interaction.
+    public static final TaskTraits USER_VISIBLE =
+            new TaskTraits().taskPriority(TaskPriority.USER_VISIBLE);
+
+    // This task affects UI immediately after a user interaction.
+    // Example: Generating data shown in the UI immediately after a click.
+    // Is is different from the mMayBlock property in that it doesn't contribute
+    // to the creation of additional thread pool threads. This is the highest
+    // possible priority.
+    public static final TaskTraits USER_BLOCKING =
+            new TaskTraits().taskPriority(TaskPriority.USER_BLOCKING);
+
     public TaskTraits() {}
 
     private TaskTraits(TaskTraits other) {
@@ -56,7 +80,8 @@
      * Tasks with this trait may block. This includes but is not limited to tasks that wait on
      * synchronous file I/O operations: read or write a file from disk, interact with a pipe or a
      * socket, rename or delete a file, enumerate files in a directory, etc. This trait isn't
-     * required for the mere use of locks.
+     * required for the mere use of locks. The thread pool uses this property to work out if
+     * additional threads are required.
      */
     public TaskTraits mayBlock(boolean mayBlock) {
         TaskTraits taskTraits = new TaskTraits(this);
diff --git a/base/metrics/persistent_histogram_allocator.cc b/base/metrics/persistent_histogram_allocator.cc
index 9616911..6ad5739 100644
--- a/base/metrics/persistent_histogram_allocator.cc
+++ b/base/metrics/persistent_histogram_allocator.cc
@@ -14,6 +14,8 @@
 #include "base/lazy_instance.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/memory/shared_memory_mapping.h"
+#include "base/memory/writable_shared_memory_region.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/histogram_base.h"
 #include "base/metrics/histogram_samples.h"
@@ -869,19 +871,18 @@
 #endif  // !defined(OS_NACL)
 
 // static
-void GlobalHistogramAllocator::CreateWithSharedMemoryHandle(
-    const SharedMemoryHandle& handle,
-    size_t size) {
-  std::unique_ptr<SharedMemory> shm(
-      new SharedMemory(handle, /*readonly=*/false));
-  if (!shm->Map(size) ||
-      !SharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(*shm)) {
+void GlobalHistogramAllocator::CreateWithSharedMemoryRegion(
+    const WritableSharedMemoryRegion& region) {
+  base::WritableSharedMemoryMapping mapping = region.Map();
+  if (!mapping.IsValid() ||
+      !WritableSharedPersistentMemoryAllocator::IsSharedMemoryAcceptable(
+          mapping)) {
     return;
   }
 
   Set(WrapUnique(new GlobalHistogramAllocator(
-      std::make_unique<SharedPersistentMemoryAllocator>(
-          std::move(shm), 0, StringPiece(), /*readonly=*/false))));
+      std::make_unique<WritableSharedPersistentMemoryAllocator>(
+          std::move(mapping), 0, StringPiece()))));
 }
 
 // static
diff --git a/base/metrics/persistent_histogram_allocator.h b/base/metrics/persistent_histogram_allocator.h
index 395511f..94cbe74 100644
--- a/base/metrics/persistent_histogram_allocator.h
+++ b/base/metrics/persistent_histogram_allocator.h
@@ -11,9 +11,9 @@
 #include "base/atomicops.h"
 #include "base/base_export.h"
 #include "base/feature_list.h"
-#include "base/memory/shared_memory.h"
 #include "base/metrics/histogram_base.h"
 #include "base/metrics/persistent_memory_allocator.h"
+#include "base/process/process_handle.h"
 #include "base/strings/string_piece.h"
 #include "base/synchronization/lock.h"
 
@@ -23,6 +23,7 @@
 class FilePath;
 class PersistentSampleMapRecords;
 class PersistentSparseHistogramDataManager;
+class WritableSharedMemoryRegion;
 
 // Feature definition for enabling histogram persistence.
 BASE_EXPORT extern const Feature kPersistentHistogramsFeature;
@@ -430,11 +431,11 @@
 #endif
 
   // Create a global allocator using a block of shared memory accessed
-  // through the given |handle| and |size|. The allocator takes ownership
-  // of the handle and closes it upon destruction, though the memory will
-  // continue to live if other processes have access to it.
-  static void CreateWithSharedMemoryHandle(const SharedMemoryHandle& handle,
-                                           size_t size);
+  // through the given |region|. The allocator maps the shared memory into
+  // current process's virtual address space and frees it upon destruction.
+  // The memory will continue to live if other processes have access to it.
+  static void CreateWithSharedMemoryRegion(
+      const WritableSharedMemoryRegion& region);
 
   // Sets a GlobalHistogramAllocator for globally storing histograms in
   // a space that can be persisted or shared between processes. There is only
diff --git a/base/test/scoped_feature_list.cc b/base/test/scoped_feature_list.cc
index 94ec16a3..7ed2ad4 100644
--- a/base/test/scoped_feature_list.cc
+++ b/base/test/scoped_feature_list.cc
@@ -20,6 +20,8 @@
 
 namespace {
 
+constexpr char kTrialGroup[] = "scoped_feature_list_trial_group";
+
 std::vector<StringPiece> GetFeatureVector(
     const std::vector<Feature>& features) {
   std::vector<StringPiece> output;
@@ -89,10 +91,13 @@
   if (!init_called_)
     return;
 
-  if (field_trial_override_) {
-    base::FieldTrialParamAssociator::GetInstance()->ClearParamsForTesting(
-        field_trial_override_->trial_name(),
-        field_trial_override_->group_name());
+  auto* field_trial_param_associator = FieldTrialParamAssociator::GetInstance();
+  for (auto field_trial_override : field_trial_overrides_) {
+    if (field_trial_override) {
+      field_trial_param_associator->ClearParamsForTesting(
+          field_trial_override->trial_name(),
+          field_trial_override->group_name());
+    }
   }
 
   FeatureList::ClearInstanceForTesting();
@@ -132,12 +137,6 @@
   InitWithFeaturesAndFieldTrials({feature}, {}, {});
 }
 
-void ScopedFeatureList::InitAndEnableFeatureWithFieldTrialOverride(
-    const Feature& feature,
-    FieldTrial* trial) {
-  InitWithFeaturesAndFieldTrials({feature}, {trial}, {});
-}
-
 void ScopedFeatureList::InitAndDisableFeature(const Feature& feature) {
   InitWithFeaturesAndFieldTrials({}, {}, {feature});
 }
@@ -203,28 +202,46 @@
 void ScopedFeatureList::InitAndEnableFeatureWithParameters(
     const Feature& feature,
     const std::map<std::string, std::string>& feature_parameters) {
+  InitWithFeaturesAndParameters({{feature, feature_parameters}}, {});
+}
+
+void ScopedFeatureList::InitWithFeaturesAndParameters(
+    const std::vector<FeatureAndParams>& enabled_features,
+    const std::vector<Feature>& disabled_features) {
+  DCHECK(field_trial_overrides_.empty());
+
   if (!FieldTrialList::IsGlobalSetForTesting()) {
     field_trial_list_ = std::make_unique<base::FieldTrialList>(nullptr);
   }
 
+  // Enabled features and field trials to use with
+  // InitWithFeaturesAndFieldTrials.
+  std::vector<Feature> features;
+  std::vector<FieldTrial*> field_trials;
+
+  auto* field_trial_param_associator = FieldTrialParamAssociator::GetInstance();
+
   // TODO(crbug.com/794021) Remove this unique field trial name hack when there
   // is a cleaner solution.
   // Ensure that each call to this method uses a distinct field trial name.
   // Otherwise, nested calls might fail due to the shared FieldTrialList
   // already having the field trial registered.
   static int num_calls = 0;
-  ++num_calls;
-  std::string kTrialName =
-      "scoped_feature_list_trial_name" + base::NumberToString(num_calls);
-  std::string kTrialGroup = "scoped_feature_list_trial_group";
+  for (auto& enabled_feature : enabled_features) {
+    ++num_calls;
+    std::string trial_name =
+        "scoped_feature_list_trial_name" + base::NumberToString(num_calls);
+    scoped_refptr<FieldTrial> field_trial_override =
+        base::FieldTrialList::CreateFieldTrial(trial_name, kTrialGroup);
+    field_trial_overrides_.push_back(field_trial_override);
+    DCHECK(field_trial_overrides_.back());
+    field_trial_param_associator->AssociateFieldTrialParams(
+        trial_name, kTrialGroup, enabled_feature.params);
+    features.push_back(enabled_feature.feature);
+    field_trials.push_back(field_trial_override.get());
+  }
 
-  field_trial_override_ =
-      base::FieldTrialList::CreateFieldTrial(kTrialName, kTrialGroup);
-  DCHECK(field_trial_override_);
-  FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
-      kTrialName, kTrialGroup, feature_parameters);
-  InitAndEnableFeatureWithFieldTrialOverride(feature,
-                                             field_trial_override_.get());
+  InitWithFeaturesAndFieldTrials(features, field_trials, disabled_features);
 }
 
 }  // namespace test
diff --git a/base/test/scoped_feature_list.h b/base/test/scoped_feature_list.h
index 6e13543..5d965bc 100644
--- a/base/test/scoped_feature_list.h
+++ b/base/test/scoped_feature_list.h
@@ -37,6 +37,11 @@
   ScopedFeatureList();
   ~ScopedFeatureList();
 
+  struct FeatureAndParams {
+    const Feature& feature;
+    const std::map<std::string, std::string>& params;
+  };
+
   // WARNING: This method will reset any globally configured features to their
   // default values, which can hide feature interaction bugs. Please use
   // sparingly.  https://crbug.com/713390
@@ -80,6 +85,15 @@
       const std::map<std::string, std::string>& feature_parameters);
 
   // Initializes and registers a FeatureList instance based on present
+  // FeatureList and overridden with the given enabled features and the
+  // specified field trial parameters, and the given disabled features.
+  // Note: This creates a scoped global field trial list if there is not
+  // currently one.
+  void InitWithFeaturesAndParameters(
+      const std::vector<FeatureAndParams>& enabled_features,
+      const std::vector<Feature>& disabled_features);
+
+  // Initializes and registers a FeatureList instance based on present
   // FeatureList and overridden with single disabled feature.
   void InitAndDisableFeature(const Feature& feature);
 
@@ -112,7 +126,7 @@
 
   bool init_called_ = false;
   std::unique_ptr<FeatureList> original_feature_list_;
-  scoped_refptr<FieldTrial> field_trial_override_;
+  std::vector<scoped_refptr<FieldTrial>> field_trial_overrides_;
   std::unique_ptr<base::FieldTrialList> field_trial_list_;
 
   DISALLOW_COPY_AND_ASSIGN(ScopedFeatureList);
diff --git a/base/test/scoped_feature_list_unittest.cc b/base/test/scoped_feature_list_unittest.cc
index 44c44f49..df21a07 100644
--- a/base/test/scoped_feature_list_unittest.cc
+++ b/base/test/scoped_feature_list_unittest.cc
@@ -181,6 +181,65 @@
   EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
 }
 
+TEST_F(ScopedFeatureListTest, OverrideMultipleFeaturesWithParameters) {
+  FieldTrialList field_trial_list(nullptr);
+  scoped_refptr<FieldTrial> trial1 =
+      FieldTrialList::CreateFieldTrial("foo1", "bar1");
+  const char kParam[] = "param_1";
+  const char kValue1[] = "value_1";
+  const char kValue2[] = "value_2";
+  std::map<std::string, std::string> parameters1;
+  parameters1[kParam] = kValue1;
+  std::map<std::string, std::string> parameters2;
+  parameters2[kParam] = kValue2;
+
+  test::ScopedFeatureList feature_list1;
+  feature_list1.InitFromCommandLine("TestFeature1<foo1,TestFeature2",
+                                    std::string());
+
+  // Check initial state.
+  ExpectFeatures("TestFeature1<foo1,TestFeature2", std::string());
+  EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+  EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
+  EXPECT_EQ(trial1.get(), FeatureList::GetFieldTrial(kTestFeature1));
+  EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
+  EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+  EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+
+  {
+    // Override multiple features with parameters.
+    test::ScopedFeatureList feature_list2;
+    feature_list2.InitWithFeaturesAndParameters(
+        {{kTestFeature1, parameters1}, {kTestFeature2, parameters2}}, {});
+
+    EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+    EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
+    EXPECT_EQ(kValue1, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+    EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+  }
+
+  {
+    // Override a feature with a parameter and disable another one.
+    test::ScopedFeatureList feature_list2;
+    feature_list2.InitWithFeaturesAndParameters({{kTestFeature1, parameters2}},
+                                                {kTestFeature2});
+
+    EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+    EXPECT_FALSE(FeatureList::IsEnabled(kTestFeature2));
+    EXPECT_EQ(kValue2, GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+    EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+  }
+
+  // Check that initial state is restored.
+  ExpectFeatures("TestFeature1<foo1,TestFeature2", std::string());
+  EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature1));
+  EXPECT_TRUE(FeatureList::IsEnabled(kTestFeature2));
+  EXPECT_EQ(trial1.get(), FeatureList::GetFieldTrial(kTestFeature1));
+  EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kTestFeature2));
+  EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature1, kParam));
+  EXPECT_EQ("", GetFieldTrialParamValueByFeature(kTestFeature2, kParam));
+}
+
 TEST_F(ScopedFeatureListTest, EnableFeatureOverrideDisable) {
   test::ScopedFeatureList feature_list1;
   feature_list1.InitWithFeatures({}, {kTestFeature1});
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index 711e75c..24ce95d 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -121,7 +121,9 @@
     ]
 
     # Use zh-TW strings for zh-HK (https://crbug.com/780847).
-    support_zh_hk = true
+    if (!defined(support_zh_hk)) {
+      support_zh_hk = true
+    }
 
     optimize_resources = true
 
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 be80ee5..9f7124b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -64,6 +64,7 @@
 import org.chromium.chrome.browser.appmenu.AppMenuPropertiesDelegate;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.KeyboardAccessoryCoordinator;
 import org.chromium.chrome.browser.autofill.keyboard_accessory.ManualFillingCoordinator;
+import org.chromium.chrome.browser.banners.AppBannerManager;
 import org.chromium.chrome.browser.bookmarks.BookmarkModel;
 import org.chromium.chrome.browser.bookmarks.BookmarkUtils;
 import org.chromium.chrome.browser.compositor.CompositorViewHolder;
@@ -2236,7 +2237,7 @@
             // Record whether or not we have finished installability checks for this page when the
             // user clicks the add to homescren menu item. This will let us determine how effective
             // an on page-load check will be in speeding up WebAPK installation.
-            currentTab.getAppBannerManager().recordMenuItemAddToHomescreen();
+            AppBannerManager.forTab(currentTab).recordMenuItemAddToHomescreen();
 
             AddToHomescreenManager addToHomescreenManager =
                     new AddToHomescreenManager(this, currentTab);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
index 6dc7820..73f370f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java
@@ -253,7 +253,7 @@
         // Record whether or not we have finished installability checks for this page when we're
         // preparing the menu to be displayed. This will let us determine if it is feasible to
         // change the add to homescreen menu item based on whether a site is a PWA.
-        currentTab.getAppBannerManager().recordMenuOpen();
+        AppBannerManager.forTab(currentTab).recordMenuOpen();
 
         MenuItem homescreenItem = menu.findItem(R.id.add_to_homescreen_id);
         MenuItem openWebApkItem = menu.findItem(R.id.open_webapk_id);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java
index 22874d4..2e298a7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryModernView.java
@@ -113,11 +113,10 @@
     }
 
     @Override
-    void setVisible(boolean visible) {
-        super.setVisible(visible);
-        // Make sure view doesn't assume that recycler view width is constant when it's brought up
-        // again. This doesn't hold for device orientation changes.
-        if (visible) mBarItemsView.post(mBarItemsView::invalidateItemDecorations);
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        // Request update for the offset of the icons at the end of the accessory bar:
+        mBarItemsView.post(mBarItemsView::invalidateItemDecorations);
     }
 
     void setKeyboardToggleVisibility(boolean hasActiveTab) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java
index 0a78166..ff7599f8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/banners/AppBannerManager.java
@@ -13,6 +13,8 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ShortcutHelper;
+import org.chromium.chrome.browser.tab.EmptyTabObserver;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
 import org.chromium.chrome.browser.webapps.AddToHomescreenDialog;
 import org.chromium.content_public.browser.WebContents;
@@ -25,7 +27,7 @@
  * removal of banners, among other things) is done by the native-side AppBannerManagerAndroid.
  */
 @JNINamespace("banners")
-public class AppBannerManager {
+public class AppBannerManager extends EmptyTabObserver {
     private static final String TAG = "AppBannerManager";
 
     /** Retrieves information about a given package. */
@@ -34,6 +36,9 @@
     /** Whether add to home screen is permitted by the system. */
     private static Boolean sIsSupported;
 
+    /** {@link Tab} this manager is associated with. */
+    private final Tab mTab;
+
     /** Whether the tab to which this manager is attached to is permitted to show banners. */
     private boolean mIsEnabledForTab;
 
@@ -75,19 +80,33 @@
      * Constructs an AppBannerManager.
      * @param nativePointer the native-side object that owns this AppBannerManager.
      */
-    private AppBannerManager(long nativePointer) {
+    private AppBannerManager(Tab tab, long nativePointer) {
+        mTab = tab;
         mNativePointer = nativePointer;
-        mIsEnabledForTab = isSupported();
+        if (mTab != null) {
+            mTab.addObserver(this);
+            mIsEnabledForTab = mTab.getDelegateFactory().canShowAppBanners();
+        } else {
+            mIsEnabledForTab = isSupported();
+        }
     }
 
     @CalledByNative
-    private static AppBannerManager create(long nativePointer) {
-        return new AppBannerManager(nativePointer);
+    private static AppBannerManager create(Tab tab, long nativePointer) {
+        return new AppBannerManager(tab, nativePointer);
     }
 
     @CalledByNative
     private void destroy() {
         mNativePointer = 0;
+        if (mTab != null) mTab.removeObserver(this);
+    }
+
+    // EmptyTabObserver
+
+    @Override
+    public void onActivityAttachmentChanged(Tab tab, boolean isAttached) {
+        if (isAttached) mIsEnabledForTab = mTab.getDelegateFactory().canShowAppBanners();
     }
 
     /**
@@ -127,11 +146,6 @@
         };
     }
 
-    /** Enables or disables app banners. */
-    public void setIsEnabledForTab(boolean state) {
-        mIsEnabledForTab = state;
-    }
-
     /** Returns the language option to use for the add to homescreen dialog and menu item. */
     public static int getHomescreenLanguageOption() {
         int languageOption = nativeGetHomescreenLanguageOption();
@@ -198,8 +212,8 @@
     }
 
     /** Returns the AppBannerManager object. This is owned by the C++ banner manager. */
-    public static AppBannerManager getAppBannerManagerForWebContents(WebContents webContents) {
-        return nativeGetJavaBannerManagerForWebContents(webContents);
+    public static AppBannerManager forTab(Tab tab) {
+        return nativeGetJavaBannerManagerForWebContents(tab.getWebContents());
     }
 
     private static native int nativeGetHomescreenLanguageOption();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java
index bf5dbc22..5139429 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browseractions/BrowserActionActivity.java
@@ -81,7 +81,7 @@
             Log.e(TAG, "Url should only be HTTP or HTTPS scheme");
             return false;
         } else if (mUntrustedCreatorPackageName == null) {
-            Log.e(TAG, "Missing creator's pacakge name");
+            Log.e(TAG, "Missing creator's package name");
             return false;
         } else if (!TextUtils.equals(mUntrustedCreatorPackageName, getPackageName())
                 && (intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
index 201d45a..9ad0175 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabDelegateFactory.java
@@ -288,7 +288,7 @@
     }
 
     @Override
-    public boolean canShowAppBanners(Tab tab) {
+    public boolean canShowAppBanners() {
         return mShouldAllowAppBanners;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index 1271a22..a0b3035 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -44,7 +44,6 @@
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.WarmupManager;
 import org.chromium.chrome.browser.WebContentsFactory;
-import org.chromium.chrome.browser.banners.AppBannerManager;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.content.ContentUtils;
 import org.chromium.chrome.browser.contextmenu.ContextMenuPopulator;
@@ -1244,7 +1243,6 @@
                             mDelegateFactory.createContextMenuPopulator(this), this));
             setInterceptNavigationDelegate(
                     mDelegateFactory.createInterceptNavigationDelegate(this));
-            getAppBannerManager().setIsEnabledForTab(mDelegateFactory.canShowAppBanners(this));
         }
 
         for (TabObserver observer : mObservers) {
@@ -1470,8 +1468,6 @@
 
             setInterceptNavigationDelegate(mDelegateFactory.createInterceptNavigationDelegate(
                     this));
-
-            getAppBannerManager().setIsEnabledForTab(mDelegateFactory.canShowAppBanners(this));
         } finally {
             TraceEvent.end("ChromeTab.initBrowserComponents");
         }
@@ -2464,13 +2460,6 @@
         nativeSetInterceptNavigationDelegate(mNativeTabAndroid, delegate);
     }
 
-    /**
-     * @return the AppBannerManager.
-     */
-    public AppBannerManager getAppBannerManager() {
-        return AppBannerManager.getAppBannerManagerForWebContents(getWebContents());
-    }
-
     @VisibleForTesting
     public boolean hasPrerenderedUrl(String url) {
         return nativeHasPrerenderedUrl(mNativeTabAndroid, url);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java
index 73d2631..53b10e6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabDelegateFactory.java
@@ -42,11 +42,10 @@
     }
 
     /**
-     * Return true if app banners are to be permitted in this tab.
-     * @param tab The associated {@link Tab}.
+     * Return true if app banners are to be permitted in this tab. May need to be overridden.
      * @return true if app banners are permitted, and false otherwise.
      */
-    public boolean canShowAppBanners(Tab tab) {
+    public boolean canShowAppBanners() {
         return true;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java
index 3413378c..8c45ade 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappDelegateFactory.java
@@ -86,7 +86,7 @@
     }
 
     @Override
-    public boolean canShowAppBanners(Tab tab) {
+    public boolean canShowAppBanners() {
         // Do not show banners when we are in a standalone activity.
         return false;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
index a59e8e5..5d883cb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java
@@ -60,8 +60,9 @@
  * All the computation in this file is based off of the bottom of the screen instead of the top
  * for simplicity. This means that the bottom of the screen is 0 on the Y axis.
  */
-public class BottomSheet extends FrameLayout
-        implements BottomSheetSwipeDetector.SwipeableBottomSheet, NativePageHost {
+public class BottomSheet
+        extends FrameLayout implements BottomSheetSwipeDetector.SwipeableBottomSheet,
+                                       NativePageHost, View.OnLayoutChangeListener {
     /** The different states that the bottom sheet can have. */
     @IntDef({SheetState.NONE, SheetState.HIDDEN, SheetState.PEEK, SheetState.HALF, SheetState.FULL,
             SheetState.SCROLLING})
@@ -137,6 +138,9 @@
      */
     private static final float SHEET_SWIPE_MIN_DP_PER_MS = 0.2f;
 
+    /** The desired height of a content that has just been shown or whose height was invalidated. */
+    private static final float HEIGHT_UNSPECIFIED = -1.0f;
+
     /**
      * Information about the different scroll states of the sheet. Order is important for these,
      * they go from smallest to largest.
@@ -185,6 +189,9 @@
     /** The height of the view that contains the bottom sheet. */
     private float mContainerHeight;
 
+    /** The desired height of the current content view. */
+    private float mContentDesiredHeight = HEIGHT_UNSPECIFIED;
+
     /**
      * The current offset of the sheet from the bottom of the screen in px. This does not include
      * added offset from the scrolling of the browser controls which allows the sheet's toolbar to
@@ -306,6 +313,15 @@
         boolean isPeekStateEnabled();
 
         /**
+         * @return Whether the bottom sheet should wrap its content, i.e. its height in the FULL
+         *         state is the minimum height required such that the content is visible. If this
+         *         behavior is enabled, the HALF state of the sheet is disabled.
+         */
+        default boolean wrapContentEnabled() {
+            return false;
+        }
+
+        /**
          * @return The resource id of the content description for the bottom sheet. This is
          *         generally the name of the feature/content that is showing. 'Swipe down to close.'
          *         will be automatically appended after the content description.
@@ -536,6 +552,7 @@
 
                 if (previousWidth != mContainerWidth || previousHeight != mContainerHeight) {
                     updateSheetStateRatios();
+                    invalidateContentDesiredHeight();
                 }
 
                 int heightMinusKeyboard = (int) mContainerHeight;
@@ -751,6 +768,11 @@
         // If the desired content is already showing, do nothing.
         if (mSheetContent == content) return;
 
+        // Remove this as listener from previous content layout changes.
+        if (mSheetContent != null) {
+            mSheetContent.getContentView().removeOnLayoutChangeListener(this);
+        }
+
         List<Animator> animators = new ArrayList<>();
         mContentSwapAnimatorSet = new AnimatorSet();
         mContentSwapAnimatorSet.addListener(new AnimatorListenerAdapter() {
@@ -981,7 +1003,7 @@
         mStateRatios[SheetState.FULL] =
                 (mContainerHeight + mToolbarShadowHeight) / mContainerHeight;
 
-        if (mCurrentState == SheetState.HALF && isSmallScreen()) {
+        if (mCurrentState == SheetState.HALF && shouldSkipHalfState()) {
             setSheetState(SheetState.FULL, false);
         }
     }
@@ -1227,8 +1249,9 @@
             @SheetState int state, boolean animate, @StateChangeReason int reason) {
         assert state != SheetState.SCROLLING && state != SheetState.NONE;
 
-        // Half state is not valid on small screens.
-        if (state == SheetState.HALF && isSmallScreen()) state = SheetState.FULL;
+        if (state == SheetState.HALF && shouldSkipHalfState()) {
+            state = SheetState.FULL;
+        }
 
         mTargetState = state;
 
@@ -1346,6 +1369,18 @@
      * @return The height of the sheet at the provided state.
      */
     public float getSheetHeightForState(@SheetState int state) {
+        if (mSheetContent != null && mSheetContent.wrapContentEnabled()
+                && state == SheetState.FULL) {
+            if (mContentDesiredHeight == HEIGHT_UNSPECIFIED) {
+                mSheetContent.getContentView().measure(
+                        MeasureSpec.makeMeasureSpec((int) mContainerWidth, MeasureSpec.EXACTLY),
+                        MeasureSpec.makeMeasureSpec((int) mContainerHeight, MeasureSpec.AT_MOST));
+                mContentDesiredHeight =
+                        mSheetContent.getContentView().getMeasuredHeight() + mToolbarShadowHeight;
+            }
+            return mContentDesiredHeight;
+        }
+
         return mStateRatios[state] * mContainerHeight;
     }
 
@@ -1379,7 +1414,7 @@
         if (sheetHeight >= getMaxOffsetPx()) return SheetState.FULL;
 
         boolean isMovingDownward = yVelocity < 0;
-        boolean shouldSkipHalfState = isMovingDownward || isSmallScreen();
+        boolean shouldSkipHalfState = isMovingDownward || shouldSkipHalfState();
 
         // First, find the two states that the sheet height is between.
         @SheetState
@@ -1415,6 +1450,11 @@
         return prevState;
     }
 
+    private boolean shouldSkipHalfState() {
+        // Half state is neither valid on small screens nor when wrapping the sheet content.
+        return isSmallScreen() || (mSheetContent != null && mSheetContent.wrapContentEnabled());
+    }
+
     public boolean isSmallScreen() {
         // A small screen is defined by there being less than 160dp between half and full states.
         float fullToHalfDiff = (getFullRatio() - getHalfRatio()) * mContainerHeight;
@@ -1468,9 +1508,46 @@
      */
     protected void onSheetContentChanged(@Nullable final BottomSheetContent content) {
         mSheetContent = content;
+
+        if (content != null && content.wrapContentEnabled()) {
+            content.getContentView().addOnLayoutChangeListener(this);
+            ensureContentIsWrapped();
+
+            // HALF state is forbidden when wrapping the content.
+            if (mCurrentState == SheetState.HALF) {
+                setSheetState(SheetState.FULL, /* animate= */ true);
+            }
+        }
+
         for (BottomSheetObserver o : mObservers) {
             o.onSheetContentChanged(content);
         }
         mToolbarHolder.setBackgroundColor(Color.TRANSPARENT);
     }
+
+    /**
+     * Called when the sheet content layout changed.
+     */
+    @Override
+    public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+            int oldTop, int oldRight, int oldBottom) {
+        ensureContentIsWrapped();
+    }
+
+    private void ensureContentIsWrapped() {
+        invalidateContentDesiredHeight();
+
+        if (mCurrentState == SheetState.HIDDEN || mCurrentState == SheetState.PEEK) return;
+
+        // The SCROLLING state is used when animating the sheet height or when the user is swiping
+        // the sheet. If it is the latter, we should not change the sheet height.
+        cancelAnimation();
+        if (mCurrentState == SheetState.SCROLLING) return;
+
+        createSettleAnimation(mCurrentState, StateChangeReason.NONE);
+    }
+
+    private void invalidateContentDesiredHeight() {
+        mContentDesiredHeight = HEIGHT_UNSPECIFIED;
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
index 9f0f0f2e..14e9aa3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -216,11 +216,15 @@
         });
     }
 
+    private AppBannerManager getAppBannerManager(Tab tab) {
+        return AppBannerManager.forTab(tab);
+    }
+
     private void waitForBannerManager(Tab tab) {
         CriteriaHelper.pollUiThread(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                return !tab.getAppBannerManager().isRunningForTesting();
+                return !getAppBannerManager(tab).isRunningForTesting();
             }
         });
     }
@@ -237,8 +241,7 @@
         CriteriaHelper.pollUiThread(new Criteria() {
             @Override
             public boolean isSatisfied() {
-                AppBannerManager manager =
-                        rule.getActivity().getActivityTab().getAppBannerManager();
+                AppBannerManager manager = getAppBannerManager(rule.getActivity().getActivityTab());
                 return mDetailsDelegate.mNumRetrieved == numExpected
                         && !manager.isRunningForTesting();
             }
@@ -371,7 +374,7 @@
             @Override
             public boolean isSatisfied() {
                 AddToHomescreenDialog dialog =
-                        tab.getAppBannerManager().getAddToHomescreenDialogForTesting();
+                        getAppBannerManager(tab).getAddToHomescreenDialogForTesting();
                 return dialog == null || dialog.getAlertDialogForTesting() == null;
             }
         });
@@ -384,7 +387,7 @@
             @Override
             public boolean isSatisfied() {
                 AddToHomescreenDialog dialog =
-                        tab.getAppBannerManager().getAddToHomescreenDialogForTesting();
+                        getAppBannerManager(tab).getAddToHomescreenDialogForTesting();
                 if (dialog != null) {
                     AlertDialog alertDialog = dialog.getAlertDialogForTesting();
                     return alertDialog != null && alertDialog.isShowing();
@@ -431,7 +434,7 @@
         instrumentation.addMonitor(activityMonitor);
 
         ThreadUtils.runOnUiThreadBlocking(() -> {
-            Button button = tab.getAppBannerManager()
+            Button button = getAppBannerManager(tab)
                                     .getAddToHomescreenDialogForTesting()
                                     .getAlertDialogForTesting()
                                     .getButton(DialogInterface.BUTTON_POSITIVE);
@@ -471,7 +474,7 @@
 
     private void clickButton(final Tab tab, final int button) {
         ThreadUtils.runOnUiThreadBlocking(() -> {
-            tab.getAppBannerManager()
+            getAppBannerManager(tab)
                     .getAddToHomescreenDialogForTesting()
                     .getAlertDialogForTesting()
                     .getButton(button)
@@ -922,7 +925,7 @@
         // Verify metrics calling in the successful case.
         ThreadUtils.runOnUiThread(() -> {
             AppBannerManager manager =
-                    mTabbedActivityTestRule.getActivity().getActivityTab().getAppBannerManager();
+                    getAppBannerManager(mTabbedActivityTestRule.getActivity().getActivityTab());
             manager.recordMenuItemAddToHomescreen();
             Assert.assertEquals(1,
                     RecordHistogram.getHistogramValueCountForTesting(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUpdateWithTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUpdateWithTest.java
index 69f5896..b11962b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUpdateWithTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestUpdateWithTest.java
@@ -64,12 +64,11 @@
         Assert.assertEquals("USD $5.00", mRule.getOrderSummaryTotal());
         Assert.assertEquals("$2.00", mRule.getLineItemAmount(0));
         Assert.assertEquals("$3.00", mRule.getLineItemAmount(1));
-        mRule.clickInShippingAddressAndWait(R.id.payments_section, mRule.getReadyToPay());
-        mRule.clickOnShippingAddressSuggestionOptionAndWait(1, mRule.getReadyToPay());
-        mRule.clickInOrderSummaryAndWait(mRule.getReadyToPay());
+        Assert.assertEquals("$0.00", mRule.getLineItemAmount(2));
         Assert.assertEquals("USD $5.00", mRule.getOrderSummaryTotal());
         Assert.assertEquals("$2.00", mRule.getLineItemAmount(0));
         Assert.assertEquals("$3.00", mRule.getLineItemAmount(1));
+        Assert.assertEquals("$0.00", mRule.getLineItemAmount(2));
         mRule.clickAndWait(R.id.button_primary, mRule.getReadyForUnmaskInput());
         mRule.setTextInCardUnmaskDialogAndWait(
                 R.id.card_unmask_input, "123", mRule.getReadyToUnmask());
@@ -88,12 +87,14 @@
         Assert.assertEquals("USD $5.00", mRule.getOrderSummaryTotal());
         Assert.assertEquals("$2.00", mRule.getLineItemAmount(0));
         Assert.assertEquals("$3.00", mRule.getLineItemAmount(1));
+        Assert.assertEquals("$0.00", mRule.getLineItemAmount(2));
         mRule.clickInShippingAddressAndWait(R.id.payments_section, mRule.getReadyToPay());
         mRule.clickOnShippingAddressSuggestionOptionAndWait(1, mRule.getReadyToPay());
         mRule.clickInOrderSummaryAndWait(mRule.getReadyToPay());
         Assert.assertEquals("USD $10.00", mRule.getOrderSummaryTotal());
         Assert.assertEquals("$2.00", mRule.getLineItemAmount(0));
         Assert.assertEquals("$3.00", mRule.getLineItemAmount(1));
+        Assert.assertEquals("$0.00", mRule.getLineItemAmount(2));
         mRule.clickAndWait(R.id.button_primary, mRule.getReadyForUnmaskInput());
         mRule.setTextInCardUnmaskDialogAndWait(
                 R.id.card_unmask_input, "123", mRule.getReadyToUnmask());
@@ -112,12 +113,14 @@
         Assert.assertEquals("USD $5.00", mRule.getOrderSummaryTotal());
         Assert.assertEquals("$2.00", mRule.getLineItemAmount(0));
         Assert.assertEquals("$3.00", mRule.getLineItemAmount(1));
+        Assert.assertEquals("$0.00", mRule.getLineItemAmount(2));
         mRule.clickInShippingAddressAndWait(R.id.payments_section, mRule.getReadyToPay());
         mRule.clickOnShippingAddressSuggestionOptionAndWait(1, mRule.getReadyToPay());
         mRule.clickInOrderSummaryAndWait(mRule.getReadyToPay());
         Assert.assertEquals("USD $5.00", mRule.getOrderSummaryTotal());
         Assert.assertEquals("$3.00", mRule.getLineItemAmount(0));
         Assert.assertEquals("$2.00", mRule.getLineItemAmount(1));
+        Assert.assertEquals("$0.00", mRule.getLineItemAmount(2));
         mRule.clickAndWait(R.id.button_primary, mRule.getReadyForUnmaskInput());
         mRule.setTextInCardUnmaskDialogAndWait(
                 R.id.card_unmask_input, "123", mRule.getReadyToUnmask());
@@ -136,12 +139,14 @@
         Assert.assertEquals("USD $5.00", mRule.getOrderSummaryTotal());
         Assert.assertEquals("$2.00", mRule.getLineItemAmount(0));
         Assert.assertEquals("$3.00", mRule.getLineItemAmount(1));
+        Assert.assertEquals("$0.00", mRule.getLineItemAmount(2));
         mRule.clickInShippingAddressAndWait(R.id.payments_section, mRule.getReadyToPay());
         mRule.clickOnShippingAddressSuggestionOptionAndWait(1, mRule.getReadyToPay());
         mRule.clickInOrderSummaryAndWait(mRule.getReadyToPay());
         Assert.assertEquals("USD $5.00", mRule.getOrderSummaryTotal());
         Assert.assertEquals("$2.00", mRule.getLineItemAmount(0));
         Assert.assertEquals("$3.00", mRule.getLineItemAmount(1));
+        Assert.assertEquals("$0.00", mRule.getLineItemAmount(2));
         mRule.clickAndWait(R.id.button_primary, mRule.getReadyForUnmaskInput());
         mRule.setTextInCardUnmaskDialogAndWait(
                 R.id.card_unmask_input, "123", mRule.getReadyToUnmask());
@@ -149,4 +154,30 @@
                 ModalDialogProperties.ButtonType.POSITIVE, mRule.getDismissed());
         mRule.expectResultContains(new String[] {"updatedShipping"});
     }
+
+    /** A merchant that calls updateWith() with modifiers will not cause timeouts in UI. */
+    @Test
+    @MediumTest
+    @Feature({"Payments"})
+    public void testUpdateWithModifiers() throws Throwable {
+        mRule.triggerUIAndWait("updateWithModifiers", mRule.getReadyToPay());
+        mRule.clickInOrderSummaryAndWait(mRule.getReadyToPay());
+        Assert.assertEquals("USD $5.00", mRule.getOrderSummaryTotal());
+        Assert.assertEquals("$2.00", mRule.getLineItemAmount(0));
+        Assert.assertEquals("$3.00", mRule.getLineItemAmount(1));
+        Assert.assertEquals("$0.00", mRule.getLineItemAmount(2));
+        mRule.clickInShippingAddressAndWait(R.id.payments_section, mRule.getReadyToPay());
+        mRule.clickOnShippingAddressSuggestionOptionAndWait(1, mRule.getReadyToPay());
+        mRule.clickInOrderSummaryAndWait(mRule.getReadyToPay());
+        Assert.assertEquals("USD $4.00", mRule.getOrderSummaryTotal());
+        Assert.assertEquals("$2.00", mRule.getLineItemAmount(0));
+        Assert.assertEquals("$3.00", mRule.getLineItemAmount(1));
+        Assert.assertEquals("-$1.00", mRule.getLineItemAmount(2));
+        mRule.clickAndWait(R.id.button_primary, mRule.getReadyForUnmaskInput());
+        mRule.setTextInCardUnmaskDialogAndWait(
+                R.id.card_unmask_input, "123", mRule.getReadyToUnmask());
+        mRule.clickCardUnmaskButtonAndWait(
+                ModalDialogProperties.ButtonType.POSITIVE, mRule.getDismissed());
+        mRule.expectResultContains(new String[] {"freeShipping"});
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetObserverTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetObserverTest.java
index 66d1758..947ec5e8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetObserverTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetObserverTest.java
@@ -5,8 +5,12 @@
 package org.chromium.chrome.browser.widget.bottomsheet;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.support.test.filters.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -205,4 +209,55 @@
         callbackHelper.waitForCallback(callbackCount, 1);
         assertEquals(1f, mObserver.getLastPeekToHalfValue(), MathUtils.EPSILON);
     }
+
+    @Test
+    @MediumTest
+    public void testWrapContentBehavior() throws TimeoutException, InterruptedException {
+        // We make sure the height of the wrapped content is smaller than sheetContainerHeight.
+        BottomSheet bottomSheet = mBottomSheetTestRule.getBottomSheet();
+        int wrappedContentHeight = (int) bottomSheet.getSheetContainerHeight() / 2;
+        assertTrue(wrappedContentHeight > 0);
+
+        // Show content that should be wrapped.
+        CallbackHelper callbackHelper = mObserver.mContentChangedCallbackHelper;
+        int callCount = callbackHelper.getCallCount();
+        ThreadUtils.runOnUiThreadBlocking(() -> {
+            bottomSheet.showContent(new TestBottomSheetContent(
+                    mBottomSheetTestRule.getActivity(), BottomSheet.ContentPriority.HIGH) {
+                private final ViewGroup mContentView;
+
+                {
+                    // We wrap the View in a FrameLayout as we need something to read the hard coded
+                    // height in the layout params. There is no way to create a View with a specific
+                    // height on its own as View::onMeasure will by default set its height/width to
+                    // be the minimum height/width of its background (if any) or expand as much as
+                    // it can.
+                    mContentView = new FrameLayout(mBottomSheetTestRule.getActivity());
+                    View child = new View(mBottomSheetTestRule.getActivity());
+                    child.setLayoutParams(new ViewGroup.LayoutParams(
+                            ViewGroup.LayoutParams.MATCH_PARENT, wrappedContentHeight));
+                    mContentView.addView(child);
+                }
+
+                @Override
+                public View getContentView() {
+                    return mContentView;
+                }
+
+                @Override
+                public boolean wrapContentEnabled() {
+                    return true;
+                }
+            });
+        });
+        callbackHelper.waitForCallback(callCount);
+
+        // HALF state is forbidden when wrapping the content.
+        mBottomSheetTestRule.setSheetState(BottomSheet.SheetState.HALF, false);
+        assertEquals(BottomSheet.SheetState.FULL, bottomSheet.getSheetState());
+
+        // Check the offset.
+        assertEquals(wrappedContentHeight + bottomSheet.getToolbarShadowHeight(),
+                bottomSheet.getCurrentOffsetPx(), MathUtils.EPSILON);
+    }
 }
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 7d3ab49..c913257 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1062,6 +1062,8 @@
     "payments/payment_handler_permission_context.cc",
     "payments/payment_handler_permission_context.h",
     "payments/ssl_validity_checker.cc",
+    "performance_manager/browser_child_process_watcher.cc",
+    "performance_manager/browser_child_process_watcher.h",
     "performance_manager/chrome_content_browser_client_performance_manager_part.cc",
     "performance_manager/chrome_content_browser_client_performance_manager_part.h",
     "performance_manager/frame_resource_coordinator.cc",
@@ -1095,6 +1097,8 @@
     "performance_manager/page_resource_coordinator.h",
     "performance_manager/performance_manager.cc",
     "performance_manager/performance_manager.h",
+    "performance_manager/performance_manager_tab_helper.cc",
+    "performance_manager/performance_manager_tab_helper.h",
     "performance_manager/process_resource_coordinator.cc",
     "performance_manager/process_resource_coordinator.h",
     "performance_manager/render_process_user_data.cc",
@@ -1420,8 +1424,6 @@
     "renderer_host/chrome_render_widget_host_view_mac_history_swiper.mm",
     "renderer_preferences_util.cc",
     "renderer_preferences_util.h",
-    "resource_coordinator/browser_child_process_watcher.cc",
-    "resource_coordinator/browser_child_process_watcher.h",
     "resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc",
     "resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h",
     "resource_coordinator/discard_before_unload_helper.cc",
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index c23579d..10be6a7 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -194,7 +194,6 @@
 
   # Allow mojo generated files in WebKit. These files use STL types and
   # don't use WTF types.
-  "+third_party/blink/public/platform/autoplay.mojom.h",
   "+third_party/blink/public/platform/modules/app_banner/app_banner.mojom.h",
   "+third_party/blink/public/platform/modules/badging/badging.mojom.h",
   "+third_party/blink/public/platform/modules/budget_service/budget_service.mojom.h",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index fd2c2fe..e0d7ee3 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -4202,6 +4202,10 @@
      flag_descriptions::kManualPasswordGenerationAndroidDescription, kOsAndroid,
      FEATURE_VALUE_TYPE(
          password_manager::features::kManualPasswordGenerationAndroid)},
+    {"mobile-identity-consistency",
+     flag_descriptions::kMobileIdentityConsistencyName,
+     flag_descriptions::kMobileIdentityConsistencyDescription, kOsAndroid,
+     FEATURE_VALUE_TYPE(signin::kMiceFeature)},
 #endif  // defined(OS_ANDROID)
 
     {"autofill-show-full-disclosure-label",
diff --git a/chrome/browser/android/tab_android.cc b/chrome/browser/android/tab_android.cc
index a521688..25773c1 100644
--- a/chrome/browser/android/tab_android.cc
+++ b/chrome/browser/android/tab_android.cc
@@ -350,6 +350,7 @@
   web_contents_.reset(content::WebContents::FromJavaWebContents(jweb_contents));
   DCHECK(web_contents_.get());
 
+  TabAndroidHelper::SetTabForWebContents(web_contents(), this);
   AttachTabHelpers(web_contents_.get());
   WebContentsObserver::Observe(web_contents_.get());
 
@@ -359,7 +360,6 @@
       jcontext_menu_populator);
   ViewAndroidHelper::FromWebContents(web_contents())->
       SetViewAndroid(web_contents()->GetNativeView());
-  TabAndroidHelper::SetTabForWebContents(web_contents(), this);
   web_contents_delegate_ =
       std::make_unique<android::TabWebContentsDelegateAndroid>(
           env, jweb_contents_delegate);
diff --git a/chrome/browser/banners/app_banner_manager_android.cc b/chrome/browser/banners/app_banner_manager_android.cc
index b5121a1..06c6ccb 100644
--- a/chrome/browser/banners/app_banner_manager_android.cc
+++ b/chrome/browser/banners/app_banner_manager_android.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/android/shortcut_helper.h"
+#include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/android/webapk/chrome_webapk_host.h"
 #include "chrome/browser/android/webapk/webapk_web_manifest_checker.h"
 #include "chrome/browser/banners/app_banner_infobar_delegate_android.h"
@@ -53,7 +54,7 @@
     content::WebContents* web_contents)
     : AppBannerManager(web_contents) {
   can_install_webapk_ = ChromeWebApkHost::CanInstallWebApk();
-  CreateJavaBannerManager();
+  CreateJavaBannerManager(web_contents);
 }
 
 AppBannerManagerAndroid::~AppBannerManagerAndroid() {
@@ -311,10 +312,14 @@
   }
 }
 
-void AppBannerManagerAndroid::CreateJavaBannerManager() {
+void AppBannerManagerAndroid::CreateJavaBannerManager(
+    content::WebContents* web_contents) {
   JNIEnv* env = base::android::AttachCurrentThread();
-  java_banner_manager_.Reset(
-      Java_AppBannerManager_create(env, reinterpret_cast<intptr_t>(this)));
+  TabAndroid* tab = TabAndroid::FromWebContents(web_contents);
+  base::android::ScopedJavaLocalRef<jobject> jtab(tab ? tab->GetJavaObject()
+                                                      : nullptr);
+  java_banner_manager_.Reset(Java_AppBannerManager_create(
+      env, jtab, reinterpret_cast<intptr_t>(this)));
 }
 
 std::string AppBannerManagerAndroid::ExtractQueryValueForName(
diff --git a/chrome/browser/banners/app_banner_manager_android.h b/chrome/browser/banners/app_banner_manager_android.h
index e55a9a7..626d9d4 100644
--- a/chrome/browser/banners/app_banner_manager_android.h
+++ b/chrome/browser/banners/app_banner_manager_android.h
@@ -110,7 +110,7 @@
   friend class content::WebContentsUserData<AppBannerManagerAndroid>;
 
   // Creates the Java-side AppBannerManager.
-  void CreateJavaBannerManager();
+  void CreateJavaBannerManager(content::WebContents* web_contents);
 
   // Returns the query value for |name| in |url|, e.g. example.com?name=value.
   std::string ExtractQueryValueForName(const GURL& url,
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 685acdd3..81c7437 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -400,7 +400,7 @@
       <include name="IDR_INSPECT_JS" file="resources\inspect\inspect.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_INTERVENTIONS_INTERNALS_INDEX_HTML" file="resources\interventions_internals\index.html" flattenhtml="true" allowexternalscript="true" compress="gzip" type="BINDATA" />
       <include name="IDR_INTERVENTIONS_INTERNALS_INDEX_JS" file="resources\interventions_internals\index.js" type="BINDATA" compress="gzip" />
-      <include name="IDR_INTERVENTIONS_INTERNALS_MOJO_INDEX_JS" file="${root_gen_dir}\chrome\browser\ui\webui\interventions_internals\interventions_internals.mojom.js" use_base_dir="false" type="BINDATA" compress="gzip" />
+      <include name="IDR_INTERVENTIONS_INTERNALS_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\ui\webui\interventions_internals\interventions_internals.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
       <include name="IDR_INTERVENTIONS_INTERNALS_UNSUPPORTED_PAGE_HTML" file="resources\interventions_internals\unsupported_page.html" flattenhtml="true" allowexternalscript="true" compress="gzip" type="BINDATA" />
       <include name="IDR_NETWORK_SPEECH_SYNTHESIS_MANIFEST" file="resources\network_speech_synthesis\manifest.json" type="BINDATA" />
       <include name="IDR_PREDICTORS_HTML" file="resources\predictors\predictors.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
@@ -472,9 +472,8 @@
       </if>
       <include name="IDR_SITE_ENGAGEMENT_HTML" file="resources\engagement\site_engagement.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" />
       <include name="IDR_SITE_ENGAGEMENT_JS" file="resources\engagement\site_engagement.js" flattenhtml="true" type="BINDATA" compress="gzip" />
-      <include name="IDR_SITE_ENGAGEMENT_MOJO_JS" file="${root_gen_dir}\chrome\browser\engagement\site_engagement_details.mojom.js" use_base_dir="false" type="BINDATA" compress="gzip" />
-      <include name="IDR_URL_MOJO_JS" file="${root_gen_dir}\url\mojom\url.mojom.js" use_base_dir="false" type="BINDATA" compress="gzip" />
-      <include name="IDR_URL_MOJO_LITE_JS" file="${root_gen_dir}\url\mojom\url.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
+      <include name="IDR_SITE_ENGAGEMENT_DETAILS_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\engagement\site_engagement_details.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
+      <include name="IDR_URL_MOJOM_LITE_JS" file="${root_gen_dir}\url\mojom\url.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
       <include name="IDR_SYNC_CONFIRMATION_CSS" file="resources\signin\sync_confirmation\sync_confirmation.css" type="BINDATA" />
       <include name="IDR_SYNC_CONFIRMATION_HTML" file="resources\signin\sync_confirmation\sync_confirmation.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_SYNC_CONFIRMATION_JS" file="resources\signin\sync_confirmation\sync_confirmation.js" type="BINDATA" />
@@ -696,7 +695,7 @@
       </if>
       <include name="IDR_MEDIA_ENGAGEMENT_HTML" file="resources\media\media_engagement.html" flattenhtml="true" type="BINDATA" compress="gzip" allowexternalscript="true" />
       <include name="IDR_MEDIA_ENGAGEMENT_JS" file="resources\media\media_engagement.js" flattenhtml="true" type="BINDATA" compress="gzip" />
-      <include name="IDR_MEDIA_ENGAGEMENT_MOJO_JS" file="${root_gen_dir}\chrome\browser\media\media_engagement_score_details.mojom.js" use_base_dir="false" type="BINDATA" compress="gzip" />
+      <include name="IDR_MEDIA_ENGAGEMENT_SCORE_DETAILS_MOJOM_LITE_JS" file="${root_gen_dir}\chrome\browser\media\media_engagement_score_details.mojom-lite.js" use_base_dir="false" type="BINDATA" compress="gzip" />
       <include name="IDR_PWA_HTML" file="resources\pwa.html" type="BINDATA" />
       <if expr="chromeos">
         <include name="IDR_SMB_SHARES_DIALOG_CONTAINER_HTML" file="resources\chromeos\smb_shares\smb_share_dialog_container.html" flattenhtml="true" allowexternalscript="true" type="chrome_html" />
diff --git a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
index 0c40ff35..58dbf38 100644
--- a/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
+++ b/chrome/browser/browsing_data/chrome_browsing_data_remover_delegate_unittest.cc
@@ -1060,6 +1060,11 @@
 
   void OnRequest(RequestDetails details) override { NOTREACHED(); }
 
+  void QueueSignedExchangeReport(
+      const SignedExchangeReportDetails& details) override {
+    NOTREACHED();
+  }
+
   void RemoveBrowsingData(const base::RepeatingCallback<bool(const GURL&)>&
                               origin_filter) override {
     ++remove_calls_;
diff --git a/chrome/browser/chrome_navigation_browsertest.cc b/chrome/browser/chrome_navigation_browsertest.cc
index 5c23160..aa53c43 100644
--- a/chrome/browser/chrome_navigation_browsertest.cc
+++ b/chrome/browser/chrome_navigation_browsertest.cc
@@ -992,11 +992,8 @@
   EXPECT_EQ(1, browser()->tab_strip_model()->count());
 }
 
-// TODO(http://crbug.com/632514): This test currently expects opener downloads
-// go through and UMA is logged, but when the linked bug is resolved the
-// download should be disallowed.
 IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
-                       OpenerNavigation_DownloadPolicy) {
+                       OpenerNavigation_DownloadPolicy_Disallowed) {
   browser()->profile()->GetPrefs()->SetBoolean(prefs::kPromptForDownload,
                                                false);
   ui_test_utils::NavigateToURL(
@@ -1024,17 +1021,70 @@
       browser()->tab_strip_model()->GetActiveWebContents();
   EXPECT_NE(popup, opener);
   WaitForLoadStop(popup);
+
+  content::ConsoleObserverDelegate console_observer(
+      opener,
+      "Navigating a cross-origin opener to a download (*) is deprecated*");
+  opener->SetDelegate(&console_observer);
+  EXPECT_TRUE(content::ExecuteScript(
+      popup,
+      "window.opener.location ='data:html/text;base64,'+btoa('payload');"));
+
+  console_observer.Wait();
+  histograms.ExpectBucketCount(
+      "Blink.UseCounter.Features",
+      blink::mojom::WebFeature::kOpenerNavigationDownloadCrossOrigin, 1);
+
+  // Ensure that no download happened.
+  std::vector<download::DownloadItem*> download_items;
+  content::DownloadManager* manager =
+      content::BrowserContext::GetDownloadManager(browser()->profile());
+  manager->GetAllDownloads(&download_items);
+  EXPECT_TRUE(download_items.empty());
+}
+
+// Opener navigations from a same-origin popup should be allowed.
+IN_PROC_BROWSER_TEST_F(ChromeNavigationBrowserTest,
+                       OpenerNavigation_DownloadPolicy_Allowed) {
+  browser()->profile()->GetPrefs()->SetBoolean(prefs::kPromptForDownload,
+                                               false);
+  ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("a.com", "/title1.html"));
+
+  // Open a popup.
+  bool opened = false;
+  content::WebContents* opener =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  const char* kScriptFormat =
+      "window.domAutomationController.send(!!window.open('%s'));";
+  GURL popup_url = embedded_test_server()->GetURL("a.com", "/title1.html");
+  content::TestNavigationObserver popup_waiter(nullptr, 1);
+  popup_waiter.StartWatchingNewWebContents();
+  EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
+      opener, base::StringPrintf(kScriptFormat, popup_url.spec().c_str()),
+      &opened));
+  EXPECT_TRUE(opened);
+  popup_waiter.Wait();
+  EXPECT_EQ(2, browser()->tab_strip_model()->count());
+
+  // Using the popup, navigate its opener to a download.
+  base::HistogramTester histograms;
+  content::WebContents* popup =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  EXPECT_NE(popup, opener);
+  WaitForLoadStop(popup);
+
   content::DownloadTestObserverInProgress observer(
       content::BrowserContext::GetDownloadManager(browser()->profile()),
       1 /* wait_count */);
-  EXPECT_TRUE(content::ExecuteScriptWithoutUserGesture(
+  EXPECT_TRUE(content::ExecuteScript(
       popup,
       "window.opener.location ='data:html/text;base64,'+btoa('payload');"));
   observer.WaitForFinished();
+
   histograms.ExpectBucketCount(
       "Blink.UseCounter.Features",
-      blink::mojom::WebFeature::kOpenerNavigationDownloadCrossOriginNoGesture,
-      1);
+      blink::mojom::WebFeature::kOpenerNavigationDownloadCrossOrigin, 0);
 
   // Delete any pending download.
   std::vector<download::DownloadItem*> download_items;
diff --git a/chrome/browser/chromeos/file_manager/video_player_jstest.cc b/chrome/browser/chromeos/file_manager/video_player_jstest.cc
new file mode 100644
index 0000000..4ab2218
--- /dev/null
+++ b/chrome/browser/chromeos/file_manager/video_player_jstest.cc
@@ -0,0 +1,16 @@
+// 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/file_manager/file_manager_jstest_base.h"
+
+class VideoPlayerJsTest : public FileManagerJsTestBase {
+ protected:
+  VideoPlayerJsTest()
+      : FileManagerJsTestBase(base::FilePath(
+            FILE_PATH_LITERAL("ui/file_manager/video_player/js"))) {}
+};
+
+IN_PROC_BROWSER_TEST_F(VideoPlayerJsTest, SaveResumePlaybackTest) {
+  RunGeneratedTest("/video_player_native_controls_unittest.html");
+}
diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc b/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc
index e89bbf0..ac039c4 100644
--- a/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc
+++ b/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc
@@ -86,7 +86,8 @@
   } else {
     VLOG(1) << "Waiting for OAuth2 refresh token being loaded from database.";
 
-    AccountInfo account_info = identity_manager->GetPrimaryAccountInfo();
+    const CoreAccountInfo account_info =
+        identity_manager->GetPrimaryAccountInfo();
     // Flag user with unknown token status in case there are no saved tokens
     // and OnRefreshTokenAvailable is not called. Flagging it here would
     // cause user to go through Gaia in next login to obtain a new refresh
@@ -161,7 +162,8 @@
   // IdentityManager::SetPrimaryAccountSynchronously(), which seeds the account
   // info with AccountTrackerService. Hence, the primary account info will be
   // available at this point.
-  AccountInfo primary_account_info = identity_manager->GetPrimaryAccountInfo();
+  const CoreAccountInfo primary_account_info =
+      identity_manager->GetPrimaryAccountInfo();
   identity_manager->GetAccountsMutator()->AddOrUpdateAccount(
       primary_account_info.gaia, primary_account_info.email, refresh_token_,
       primary_account_info.is_under_advanced_protection,
diff --git a/chrome/browser/chromeos/policy/system_log_uploader.cc b/chrome/browser/chromeos/policy/system_log_uploader.cc
index 58b41a9..87b095c 100644
--- a/chrome/browser/chromeos/policy/system_log_uploader.cc
+++ b/chrome/browser/chromeos/policy/system_log_uploader.cc
@@ -128,7 +128,7 @@
   }
   return policy::GetAllPolicyValuesAsJSON(
       ProfileManager::GetActiveUserProfile(), include_user_policies,
-      true /* with device identity */);
+      true /* with_device_data */);
 }
 
 void SystemLogDelegate::LoadSystemLogs(LogUploadCallback upload_callback) {
diff --git a/chrome/browser/content_settings/sound_content_setting_observer.cc b/chrome/browser/content_settings/sound_content_setting_observer.cc
index 4fc2e91..c21fd53 100644
--- a/chrome/browser/content_settings/sound_content_setting_observer.cc
+++ b/chrome/browser/content_settings/sound_content_setting_observer.cc
@@ -21,7 +21,7 @@
 #include "media/base/media_switches.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
-#include "third_party/blink/public/platform/autoplay.mojom.h"
+#include "third_party/blink/public/mojom/autoplay/autoplay.mojom.h"
 
 #if !defined(OS_ANDROID)
 #include "chrome/browser/ui/tabs/tab_utils.h"
diff --git a/chrome/browser/extensions/chrome_extension_web_contents_observer.cc b/chrome/browser/extensions/chrome_extension_web_contents_observer.cc
index 57679d4..cc0f9ff 100644
--- a/chrome/browser/extensions/chrome_extension_web_contents_observer.cc
+++ b/chrome/browser/extensions/chrome_extension_web_contents_observer.cc
@@ -29,7 +29,7 @@
 #include "extensions/common/extension_urls.h"
 #include "extensions/common/switches.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
-#include "third_party/blink/public/platform/autoplay.mojom.h"
+#include "third_party/blink/public/mojom/autoplay/autoplay.mojom.h"
 
 using content::BrowserContext;
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index e29488f..68d6525 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2342,6 +2342,11 @@
     "expiry_milestone": 76
   },
   {
+    "name": "mobile-identity-consistency",
+    "owners": [ "bsazonov", "droger", "msarda" ],
+    "expiry_milestone": 80
+  },
+  {
     "name": "modal-permission-prompts",
     // "owners": [ "your-team" ],
     "expiry_milestone": 76
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index f8f968c..01e84793 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -1236,6 +1236,10 @@
 const char kMessageCenterNewStyleNotificationDescription[] =
     "Enables the experiment style of material-design notification";
 
+const char kMobileIdentityConsistencyName[] = "Mobile identity consistency";
+const char kMobileIdentityConsistencyDescription[] =
+    "Enables stronger identity consistency on mobile";
+
 const char kNewAudioRenderingMixingStrategyName[] =
     "New audio rendering mixing strategy";
 const char kNewAudioRenderingMixingStrategyDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index fa67be0..4e32335 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -750,6 +750,9 @@
 extern const char kMessageCenterNewStyleNotificationName[];
 extern const char kMessageCenterNewStyleNotificationDescription[];
 
+extern const char kMobileIdentityConsistencyName[];
+extern const char kMobileIdentityConsistencyDescription[];
+
 extern const char kNewAudioRenderingMixingStrategyName[];
 extern const char kNewAudioRenderingMixingStrategyDescription[];
 
diff --git a/chrome/browser/media/media_engagement_contents_observer.cc b/chrome/browser/media/media_engagement_contents_observer.cc
index c4a563b..fe38126 100644
--- a/chrome/browser/media/media_engagement_contents_observer.cc
+++ b/chrome/browser/media/media_engagement_contents_observer.cc
@@ -20,7 +20,7 @@
 #include "content/public/browser/web_contents.h"
 #include "media/base/media_switches.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
-#include "third_party/blink/public/platform/autoplay.mojom.h"
+#include "third_party/blink/public/mojom/autoplay/autoplay.mojom.h"
 
 #if !defined(OS_ANDROID)
 #include "chrome/browser/ui/browser.h"
diff --git a/chrome/browser/media/unified_autoplay_browsertest.cc b/chrome/browser/media/unified_autoplay_browsertest.cc
index 78c22c4d..3008f00 100644
--- a/chrome/browser/media/unified_autoplay_browsertest.cc
+++ b/chrome/browser/media/unified_autoplay_browsertest.cc
@@ -21,7 +21,7 @@
 #include "media/base/media_switches.h"
 #include "net/dns/mock_host_resolver.h"
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
-#include "third_party/blink/public/platform/autoplay.mojom.h"
+#include "third_party/blink/public/mojom/autoplay/autoplay.mojom.h"
 
 namespace {
 
diff --git a/chrome/browser/metrics/subprocess_metrics_provider.cc b/chrome/browser/metrics/subprocess_metrics_provider.cc
index 31c50af..2f2ecd4 100644
--- a/chrome/browser/metrics/subprocess_metrics_provider.cc
+++ b/chrome/browser/metrics/subprocess_metrics_provider.cc
@@ -177,7 +177,7 @@
 
   // If the render-process-host passed a persistent-memory-allocator to the
   // renderer process, extract it and register it here.
-  std::unique_ptr<base::SharedPersistentMemoryAllocator> allocator =
+  std::unique_ptr<base::PersistentMemoryAllocator> allocator =
       host->TakeMetricsAllocator();
   if (allocator) {
     RegisterSubprocessAllocator(
@@ -216,7 +216,7 @@
   if (!host)
     return nullptr;
 
-  std::unique_ptr<base::SharedPersistentMemoryAllocator> allocator =
+  std::unique_ptr<base::PersistentMemoryAllocator> allocator =
       host->TakeMetricsAllocator();
   if (!allocator)
     return nullptr;
diff --git a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
index cf1edbc..5407752 100644
--- a/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
+++ b/chrome/browser/page_load_metrics/observers/use_counter/ukm_features.cc
@@ -97,7 +97,7 @@
           WebFeature::kDownloadInAdFrameWithoutUserGesture,
           WebFeature::kOpenWebDatabase,
           WebFeature::kV8MediaCapabilities_DecodingInfo_Method,
-          WebFeature::kOpenerNavigationDownloadCrossOriginNoGesture,
+          WebFeature::kOpenerNavigationDownloadCrossOrigin,
           WebFeature::kLinkRelPrerender,
       }));
   return *opt_in_features;
diff --git a/chrome/browser/resource_coordinator/browser_child_process_watcher.cc b/chrome/browser/performance_manager/browser_child_process_watcher.cc
similarity index 79%
rename from chrome/browser/resource_coordinator/browser_child_process_watcher.cc
rename to chrome/browser/performance_manager/browser_child_process_watcher.cc
index 0f31969..d368919 100644
--- a/chrome/browser/resource_coordinator/browser_child_process_watcher.cc
+++ b/chrome/browser/performance_manager/browser_child_process_watcher.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/resource_coordinator/browser_child_process_watcher.h"
+#include "chrome/browser/performance_manager/browser_child_process_watcher.h"
 
 #include <memory>
 
@@ -12,9 +12,11 @@
 #include "content/public/browser/child_process_data.h"
 #include "content/public/common/process_type.h"
 
-namespace resource_coordinator {
+namespace performance_manager {
 
-BrowserChildProcessWatcher::BrowserChildProcessWatcher() {
+BrowserChildProcessWatcher::BrowserChildProcessWatcher()
+    : browser_node_(PerformanceManager::GetInstance()) {
+  browser_node_.OnProcessLaunched(base::Process::Current());
   BrowserChildProcessObserver::Add(this);
 }
 
@@ -26,8 +28,8 @@
     const content::ChildProcessData& data) {
   if (data.process_type == content::PROCESS_TYPE_GPU) {
     gpu_process_resource_coordinator_ =
-        std::make_unique<performance_manager::ProcessResourceCoordinator>(
-            performance_manager::PerformanceManager::GetInstance());
+        std::make_unique<ProcessResourceCoordinator>(
+            PerformanceManager::GetInstance());
     gpu_process_resource_coordinator_->OnProcessLaunched(data.GetProcess());
   }
 }
@@ -56,4 +58,4 @@
   gpu_process_resource_coordinator_.reset();
 }
 
-}  // namespace resource_coordinator
+}  // namespace performance_manager
diff --git a/chrome/browser/resource_coordinator/browser_child_process_watcher.h b/chrome/browser/performance_manager/browser_child_process_watcher.h
similarity index 74%
rename from chrome/browser/resource_coordinator/browser_child_process_watcher.h
rename to chrome/browser/performance_manager/browser_child_process_watcher.h
index 0bb217a..807217f 100644
--- a/chrome/browser/resource_coordinator/browser_child_process_watcher.h
+++ b/chrome/browser/performance_manager/browser_child_process_watcher.h
@@ -2,22 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_BROWSER_CHILD_PROCESS_WATCHER_H_
-#define CHROME_BROWSER_RESOURCE_COORDINATOR_BROWSER_CHILD_PROCESS_WATCHER_H_
+#ifndef CHROME_BROWSER_PERFORMANCE_MANAGER_BROWSER_CHILD_PROCESS_WATCHER_H_
+#define CHROME_BROWSER_PERFORMANCE_MANAGER_BROWSER_CHILD_PROCESS_WATCHER_H_
 
 #include <memory>
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "chrome/browser/performance_manager/process_resource_coordinator.h"
 #include "content/public/browser/browser_child_process_observer.h"
 #include "content/public/common/service_manager_connection.h"
 
 namespace performance_manager {
-class ProcessResourceCoordinator;
-}  // namespace performance_manager
 
-namespace resource_coordinator {
-
+// Responsible for maintaining the process nodes for the browser and the GPU
+// process.
 class BrowserChildProcessWatcher : public content::BrowserChildProcessObserver {
  public:
   BrowserChildProcessWatcher();
@@ -38,12 +37,13 @@
 
   void GPUProcessStopped();
 
+  performance_manager::ProcessResourceCoordinator browser_node_;
   std::unique_ptr<performance_manager::ProcessResourceCoordinator>
       gpu_process_resource_coordinator_;
 
   DISALLOW_COPY_AND_ASSIGN(BrowserChildProcessWatcher);
 };
 
-}  // namespace resource_coordinator
+}  // namespace performance_manager
 
-#endif  // CHROME_BROWSER_RESOURCE_COORDINATOR_BROWSER_CHILD_PROCESS_WATCHER_H_
+#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_BROWSER_CHILD_PROCESS_WATCHER_H_
diff --git a/chrome/browser/performance_manager/performance_manager_tab_helper.cc b/chrome/browser/performance_manager/performance_manager_tab_helper.cc
new file mode 100644
index 0000000..702b545a
--- /dev/null
+++ b/chrome/browser/performance_manager/performance_manager_tab_helper.cc
@@ -0,0 +1,188 @@
+// 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/performance_manager/performance_manager_tab_helper.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/stl_util.h"
+#include "chrome/browser/performance_manager/frame_resource_coordinator.h"
+#include "chrome/browser/performance_manager/performance_manager.h"
+#include "chrome/browser/performance_manager/render_process_user_data.h"
+#include "content/public/browser/navigation_handle.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace performance_manager {
+
+// static
+bool PerformanceManagerTabHelper::GetCoordinationIDForWebContents(
+    content::WebContents* web_contents,
+    resource_coordinator::CoordinationUnitID* id) {
+  PerformanceManagerTabHelper* helper = FromWebContents(web_contents);
+  if (!helper)
+    return false;
+  *id = helper->page_resource_coordinator_.id();
+
+  return true;
+}
+
+PerformanceManagerTabHelper::PerformanceManagerTabHelper(
+    content::WebContents* web_contents)
+    : content::WebContentsObserver(web_contents),
+      performance_manager_(PerformanceManager::GetInstance()),
+      page_resource_coordinator_(PerformanceManager::GetInstance()) {
+  // Make sure to set the visibility property when we create
+  // |page_resource_coordinator_|.
+  UpdatePageNodeVisibility(web_contents->GetVisibility());
+
+  // Dispatch creation notifications for any pre-existing frames.
+  // This seems to occur only in tests, but dealing with this allows asserting
+  // a strong invariant on the |frames_| collection.
+  // TODO(siggi): Eliminate this once test injection is all or nothing.
+  std::vector<content::RenderFrameHost*> existing_frames =
+      web_contents->GetAllFrames();
+  for (content::RenderFrameHost* frame : existing_frames) {
+    // Only send notifications for live frames, the non-live ones will generate
+    // creation notifications when animated.
+    if (frame->IsRenderFrameLive())
+      RenderFrameCreated(frame);
+  }
+}
+
+PerformanceManagerTabHelper::~PerformanceManagerTabHelper() = default;
+
+void PerformanceManagerTabHelper::RenderFrameCreated(
+    content::RenderFrameHost* render_frame_host) {
+  DCHECK_NE(nullptr, render_frame_host);
+  // This must not exist in the map yet.
+  DCHECK(!base::ContainsKey(frames_, render_frame_host));
+
+  std::unique_ptr<FrameResourceCoordinator> frame =
+      std::make_unique<FrameResourceCoordinator>(performance_manager_);
+  content::RenderFrameHost* parent = render_frame_host->GetParent();
+  if (parent) {
+    DCHECK(base::ContainsKey(frames_, parent));
+    auto& parent_frame_node = frames_[parent];
+    parent_frame_node->AddChildFrame(*frame.get());
+  }
+
+  RenderProcessUserData* user_data =
+      RenderProcessUserData::GetForRenderProcessHost(
+          render_frame_host->GetProcess());
+  // In unittests the user data isn't populated as the relevant main parts
+  // is not in play.
+  // TODO(siggi): Figure out how to assert on this when the main parts are
+  //     registered with the content browser client.
+  if (user_data)
+    frame->SetProcess(*user_data->process_resource_coordinator());
+
+  frames_[render_frame_host] = std::move(frame);
+}
+
+void PerformanceManagerTabHelper::RenderFrameDeleted(
+    content::RenderFrameHost* render_frame_host) {
+  DCHECK(base::ContainsKey(frames_, render_frame_host));
+  frames_.erase(render_frame_host);
+}
+
+void PerformanceManagerTabHelper::DidStartLoading() {
+  page_resource_coordinator_.SetIsLoading(true);
+}
+
+void PerformanceManagerTabHelper::DidStopLoading() {
+  page_resource_coordinator_.SetIsLoading(false);
+}
+
+void PerformanceManagerTabHelper::OnVisibilityChanged(
+    content::Visibility visibility) {
+  UpdatePageNodeVisibility(visibility);
+}
+
+void PerformanceManagerTabHelper::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (!navigation_handle->HasCommitted() ||
+      navigation_handle->IsSameDocument()) {
+    return;
+  }
+
+  // Grab the current time up front, as this is as close as we'll get to the
+  // original commit time.
+  base::TimeTicks navigation_committed_time = base::TimeTicks::Now();
+
+  content::RenderFrameHost* render_frame_host =
+      navigation_handle->GetRenderFrameHost();
+  // Make sure the hierarchical structure is constructed before sending signal
+  // to Resource Coordinator.
+  // TODO(siggi): Ideally this would be a DCHECK, but it seems it's possible
+  //     to get a DidFinishNavigation notification for a deleted frame with
+  //     the network service.
+  auto it = frames_.find(render_frame_host);
+  if (it != frames_.end()) {
+    // TODO(siggi): See whether this can be done in RenderFrameCreated.
+    page_resource_coordinator_.AddFrame(*(it->second));
+
+    if (navigation_handle->IsInMainFrame()) {
+      OnMainFrameNavigation(navigation_handle->GetNavigationId());
+      page_resource_coordinator_.OnMainFrameNavigationCommitted(
+          navigation_committed_time, navigation_handle->GetNavigationId(),
+          navigation_handle->GetURL().spec());
+    }
+  }
+}
+
+void PerformanceManagerTabHelper::TitleWasSet(content::NavigationEntry* entry) {
+  // TODO(siggi): This logic belongs in the policy layer rather than here.
+  if (!first_time_title_set_) {
+    first_time_title_set_ = true;
+    return;
+  }
+  page_resource_coordinator_.OnTitleUpdated();
+}
+
+void PerformanceManagerTabHelper::DidUpdateFaviconURL(
+    const std::vector<content::FaviconURL>& candidates) {
+  // TODO(siggi): This logic belongs in the policy layer rather than here.
+  if (!first_time_favicon_set_) {
+    first_time_favicon_set_ = true;
+    return;
+  }
+  page_resource_coordinator_.OnFaviconUpdated();
+}
+
+void PerformanceManagerTabHelper::OnInterfaceRequestFromFrame(
+    content::RenderFrameHost* render_frame_host,
+    const std::string& interface_name,
+    mojo::ScopedMessagePipeHandle* interface_pipe) {
+  if (interface_name !=
+      resource_coordinator::mojom::FrameCoordinationUnit::Name_)
+    return;
+
+  auto it = frames_.find(render_frame_host);
+  DCHECK(it != frames_.end());
+  it->second->AddBinding(
+      resource_coordinator::mojom::FrameCoordinationUnitRequest(
+          std::move(*interface_pipe)));
+}
+
+void PerformanceManagerTabHelper::OnMainFrameNavigation(int64_t navigation_id) {
+  ukm_source_id_ =
+      ukm::ConvertToSourceId(navigation_id, ukm::SourceIdType::NAVIGATION_ID);
+  page_resource_coordinator_.SetUKMSourceId(ukm_source_id_);
+
+  first_time_title_set_ = false;
+  first_time_favicon_set_ = false;
+}
+
+void PerformanceManagerTabHelper::UpdatePageNodeVisibility(
+    content::Visibility visibility) {
+  // TODO(fdoray): An OCCLUDED tab should not be considered visible.
+  const bool is_visible = visibility != content::Visibility::HIDDEN;
+  page_resource_coordinator_.SetVisibility(is_visible);
+}
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(PerformanceManagerTabHelper)
+
+}  // namespace performance_manager
diff --git a/chrome/browser/performance_manager/performance_manager_tab_helper.h b/chrome/browser/performance_manager/performance_manager_tab_helper.h
new file mode 100644
index 0000000..76c1539
--- /dev/null
+++ b/chrome/browser/performance_manager/performance_manager_tab_helper.h
@@ -0,0 +1,96 @@
+// 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_PERFORMANCE_MANAGER_PERFORMANCE_MANAGER_TAB_HELPER_H_
+#define CHROME_BROWSER_PERFORMANCE_MANAGER_PERFORMANCE_MANAGER_TAB_HELPER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "chrome/browser/performance_manager/page_resource_coordinator.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+#include "services/metrics/public/cpp/ukm_source_id.h"
+#include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
+
+namespace performance_manager {
+
+class FrameResourceCoordinator;
+class PageResourceCoordinator;
+class PerformanceManager;
+
+// This tab helper maintains a page node, and its associated tree of frame nodes
+// in the performance manager graph. It also sources a smattering of attributes
+// into the graph, including visibility, title, and favicon bits.
+// In addition it handles forwarding interface requests from the render frame
+// host to the frame graph entity.
+class PerformanceManagerTabHelper
+    : public content::WebContentsObserver,
+      public content::WebContentsUserData<PerformanceManagerTabHelper> {
+ public:
+  // TODO(siggi): Remove this once the PageSignalGenerator has been abolished.
+  static bool GetCoordinationIDForWebContents(
+      content::WebContents* web_contents,
+      resource_coordinator::CoordinationUnitID* id);
+
+  ~PerformanceManagerTabHelper() override;
+
+  PageResourceCoordinator* page_resource_coordinator() {
+    return &page_resource_coordinator_;
+  }
+
+  // WebContentsObserver overrides.
+  void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
+  void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
+  void DidStartLoading() override;
+  void DidStopLoading() override;
+  void OnVisibilityChanged(content::Visibility visibility) override;
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override;
+  void TitleWasSet(content::NavigationEntry* entry) override;
+  void DidUpdateFaviconURL(
+      const std::vector<content::FaviconURL>& candidates) override;
+  void OnInterfaceRequestFromFrame(
+      content::RenderFrameHost* render_frame_host,
+      const std::string& interface_name,
+      mojo::ScopedMessagePipeHandle* interface_pipe) override;
+
+  void SetUkmSourceIdForTesting(ukm::SourceId id) { ukm_source_id_ = id; }
+
+ private:
+  explicit PerformanceManagerTabHelper(content::WebContents* web_contents);
+
+  void OnMainFrameNavigation(int64_t navigation_id);
+  void UpdatePageNodeVisibility(content::Visibility visibility);
+
+  friend class content::WebContentsUserData<PerformanceManagerTabHelper>;
+
+  // The performance manager for this process, if any.
+  PerformanceManager* const performance_manager_;
+
+  PageResourceCoordinator page_resource_coordinator_;
+  ukm::SourceId ukm_source_id_ = ukm::kInvalidSourceId;
+
+  // Favicon and title are set when a page is loaded, we only want to send
+  // signals to the page node about title and favicon update from the previous
+  // title and favicon, thus we want to ignore the very first update since it is
+  // always supposed to happen.
+  bool first_time_favicon_set_ = false;
+  bool first_time_title_set_ = false;
+
+  // Maps from RenderFrameHost to the associated RC node.
+  std::map<content::RenderFrameHost*, std::unique_ptr<FrameResourceCoordinator>>
+      frames_;
+
+  WEB_CONTENTS_USER_DATA_KEY_DECL();
+
+  DISALLOW_COPY_AND_ASSIGN(PerformanceManagerTabHelper);
+};
+
+}  // namespace performance_manager
+
+#endif  // CHROME_BROWSER_PERFORMANCE_MANAGER_PERFORMANCE_MANAGER_TAB_HELPER_H_
diff --git a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
index e012d89..5317703 100644
--- a/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_invalidator.cc
@@ -16,6 +16,7 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "components/invalidation/public/invalidation_service.h"
+#include "components/invalidation/public/invalidation_util.h"
 #include "components/invalidation/public/object_id_invalidation_map.h"
 #include "components/policy/core/common/cloud/cloud_policy_client.h"
 #include "components/policy/core/common/cloud/cloud_policy_refresh_scheduler.h"
@@ -308,7 +309,16 @@
   // Update registration with the invalidation service.
   syncer::ObjectIdSet ids;
   ids.insert(object_id);
-  CHECK(invalidation_service_->UpdateRegisteredInvalidationIds(this, ids));
+  bool success =
+      invalidation_service_->UpdateRegisteredInvalidationIds(this, ids);
+  // Do not crash as server might send duplicate invalidation IDs due to
+  // http://b/119860379.
+  if (!success) {
+    LOG(ERROR) << "Failed to register " << syncer::ObjectIdToString(object_id)
+               << " for policy invalidations";
+  }
+  UMA_HISTOGRAM_BOOLEAN("Enterprise.PolicyInvalidationsRegistrationResult",
+                        success);
 }
 
 void CloudPolicyInvalidator::Unregister() {
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 5209e07..8f3bb0a 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1363,9 +1363,12 @@
   handlers->AddHandler(
       std::make_unique<PrintingAllowedDuplexModesPolicyHandler>());
   handlers->AddHandler(
+      std::make_unique<PrintingAllowedPinModesPolicyHandler>());
+  handlers->AddHandler(
       std::make_unique<PrintingAllowedPageSizesPolicyHandler>());
   handlers->AddHandler(std::make_unique<PrintingColorDefaultPolicyHandler>());
   handlers->AddHandler(std::make_unique<PrintingDuplexDefaultPolicyHandler>());
+  handlers->AddHandler(std::make_unique<PrintingPinDefaultPolicyHandler>());
   handlers->AddHandler(std::make_unique<PrintingSizeDefaultPolicyHandler>());
 
   handlers->AddHandler(std::make_unique<SimpleSchemaValidatingPolicyHandler>(
diff --git a/chrome/browser/policy/policy_conversions.cc b/chrome/browser/policy/policy_conversions.cc
index 5603480..f59d56c 100644
--- a/chrome/browser/policy/policy_conversions.cc
+++ b/chrome/browser/policy/policy_conversions.cc
@@ -267,11 +267,15 @@
 }
 
 #if defined(OS_CHROMEOS)
-void GetDeviceLocalAccountPolicies(bool convert_values, Value* values) {
-  // DeviceLocalAccount policies are not available for not affiliated users
-  if (!user_manager::UserManager::IsInitialized() ||
-      !user_manager::UserManager::Get()->GetPrimaryUser() ||
-      !user_manager::UserManager::Get()->GetPrimaryUser()->IsAffiliated()) {
+void GetDeviceLocalAccountPolicies(bool convert_values,
+                                   Value* values,
+                                   bool with_device_data) {
+  // DeviceLocalAccount policies are only available for affiliated users and for
+  // system logs.
+  if (!with_device_data &&
+      (!user_manager::UserManager::IsInitialized() ||
+       !user_manager::UserManager::Get()->GetPrimaryUser() ||
+       !user_manager::UserManager::Get()->GetPrimaryUser()->IsAffiliated())) {
     return;
   }
 
@@ -335,7 +339,8 @@
 
 Value GetAllPolicyValuesAsDictionary(content::BrowserContext* context,
                                      bool with_user_policies,
-                                     bool convert_values) {
+                                     bool convert_values,
+                                     bool with_device_data) {
   Value all_policies(Value::Type::DICTIONARY);
   if (!context) {
     LOG(ERROR) << "Can not dump policies, null context";
@@ -389,7 +394,8 @@
 
 #if defined(OS_CHROMEOS)
   Value device_local_account_policies(Value::Type::DICTIONARY);
-  GetDeviceLocalAccountPolicies(convert_values, &device_local_account_policies);
+  GetDeviceLocalAccountPolicies(convert_values, &device_local_account_policies,
+                                with_device_data);
   all_policies.SetKey("deviceLocalAccountPolicies",
                       std::move(device_local_account_policies));
 #endif  // defined(OS_CHROMEOS)
@@ -452,10 +458,11 @@
 
 std::string GetAllPolicyValuesAsJSON(content::BrowserContext* context,
                                      bool with_user_policies,
-                                     bool with_device_identity) {
+                                     bool with_device_data) {
   Value all_policies = policy::GetAllPolicyValuesAsDictionary(
-      context, with_user_policies, false /* convert_values */);
-  if (with_device_identity) {
+      context, with_user_policies, false /* convert_values */,
+      with_device_data);
+  if (with_device_data) {
     FillIdentityFields(&all_policies);
   }
   return DictionaryToJSONString(all_policies);
diff --git a/chrome/browser/policy/policy_conversions.h b/chrome/browser/policy/policy_conversions.h
index 08babb0..efc2ffc 100644
--- a/chrome/browser/policy/policy_conversions.h
+++ b/chrome/browser/policy/policy_conversions.h
@@ -17,17 +17,22 @@
 // Returns a dictionary with the values of all set policies, with some values
 // converted to be shown in javascript, if it is specified.
 // |with_user_policies| governs if values with POLICY_SCOPE_USER are included.
+// |with_device_data| governs if device identity data (e.g.
+// enrollment client ID) and device local accounts policies are included,
+// it is used in logs uploads to the server.
 base::Value GetAllPolicyValuesAsDictionary(content::BrowserContext* context,
                                            bool with_user_policies,
-                                           bool convert_values);
+                                           bool convert_values,
+                                           bool with_device_data);
 
 // Returns a JSON with the values of all set policies.
 // |with_user_policies| governs if values with POLICY_SCOPE_USER are included.
-// |with_device_identity| governs if device identity data (e.g.
-// enrollment client ID) is included, it is used in remote logging command.
+// |with_device_data| governs if device identity data (e.g.
+// enrollment client ID) and device local accounts policies are included,
+// it is used in logs uploads to the server.
 std::string GetAllPolicyValuesAsJSON(content::BrowserContext* context,
                                      bool with_user_policies,
-                                     bool with_device_identity);
+                                     bool with_device_data);
 
 }  // namespace policy
 
diff --git a/chrome/browser/policy/printing_restrictions_policy_handler.cc b/chrome/browser/policy/printing_restrictions_policy_handler.cc
index c6c32ec..130fe20 100644
--- a/chrome/browser/policy/printing_restrictions_policy_handler.cc
+++ b/chrome/browser/policy/printing_restrictions_policy_handler.cc
@@ -32,6 +32,9 @@
         *result = mode.value();
 
       return true;
+    } else if (errors) {
+      errors->AddError(key::kPrintingAllowedColorModes,
+                       IDS_POLICY_VALUE_FORMAT_ERROR);
     }
   }
   return false;
@@ -74,6 +77,9 @@
         *result = mode.value();
 
       return true;
+    } else if (errors) {
+      errors->AddError(key::kPrintingAllowedDuplexModes,
+                       IDS_POLICY_VALUE_FORMAT_ERROR);
     }
   }
   return false;
@@ -95,6 +101,47 @@
   }
 }
 
+PrintingAllowedPinModesPolicyHandler::PrintingAllowedPinModesPolicyHandler()
+    : TypeCheckingPolicyHandler(key::kPrintingAllowedPinModes,
+                                base::Value::Type::STRING) {}
+
+PrintingAllowedPinModesPolicyHandler::~PrintingAllowedPinModesPolicyHandler() {}
+
+bool PrintingAllowedPinModesPolicyHandler::GetValue(
+    const PolicyMap& policies,
+    PolicyErrorMap* errors,
+    printing::PinModeRestriction* result) {
+  const base::Value* value;
+  if (CheckAndGetValue(policies, errors, &value) && value) {
+    base::Optional<printing::PinModeRestriction> mode =
+        printing::GetAllowedPinModesForName(value->GetString());
+    if (mode.has_value()) {
+      if (result)
+        *result = mode.value();
+
+      return true;
+    } else if (errors) {
+      errors->AddError(key::kPrintingAllowedPinModes,
+                       IDS_POLICY_VALUE_FORMAT_ERROR);
+    }
+  }
+  return false;
+}
+
+bool PrintingAllowedPinModesPolicyHandler::CheckPolicySettings(
+    const PolicyMap& policies,
+    PolicyErrorMap* errors) {
+  return GetValue(policies, errors, nullptr);
+}
+
+void PrintingAllowedPinModesPolicyHandler::ApplyPolicySettings(
+    const PolicyMap& policies,
+    PrefValueMap* prefs) {
+  printing::PinModeRestriction value;
+  if (GetValue(policies, nullptr, &value))
+    prefs->SetInteger(prefs::kPrintingAllowedPinModes, static_cast<int>(value));
+}
+
 PrintingAllowedPageSizesPolicyHandler::PrintingAllowedPageSizesPolicyHandler()
     : ListPolicyHandler(key::kPrintingAllowedPageSizes,
                         base::Value::Type::DICTIONARY) {}
@@ -138,6 +185,9 @@
         *result = mode.value();
 
       return true;
+    } else if (errors) {
+      errors->AddError(key::kPrintingColorDefault,
+                       IDS_POLICY_VALUE_FORMAT_ERROR);
     }
   }
   return false;
@@ -176,6 +226,9 @@
         *result = mode.value();
 
       return true;
+    } else if (errors) {
+      errors->AddError(key::kPrintingDuplexDefault,
+                       IDS_POLICY_VALUE_FORMAT_ERROR);
     }
   }
   return false;
@@ -195,6 +248,46 @@
     prefs->SetInteger(prefs::kPrintingDuplexDefault, static_cast<int>(value));
 }
 
+PrintingPinDefaultPolicyHandler::PrintingPinDefaultPolicyHandler()
+    : TypeCheckingPolicyHandler(key::kPrintingPinDefault,
+                                base::Value::Type::STRING) {}
+
+PrintingPinDefaultPolicyHandler::~PrintingPinDefaultPolicyHandler() {}
+
+bool PrintingPinDefaultPolicyHandler::GetValue(
+    const PolicyMap& policies,
+    PolicyErrorMap* errors,
+    printing::PinModeRestriction* result) {
+  const base::Value* value;
+  if (CheckAndGetValue(policies, errors, &value) && value) {
+    base::Optional<printing::PinModeRestriction> mode =
+        printing::GetPinModeForName(value->GetString());
+    if (mode.has_value()) {
+      if (result)
+        *result = mode.value();
+
+      return true;
+    } else if (errors) {
+      errors->AddError(key::kPrintingPinDefault, IDS_POLICY_VALUE_FORMAT_ERROR);
+    }
+  }
+  return false;
+}
+
+bool PrintingPinDefaultPolicyHandler::CheckPolicySettings(
+    const PolicyMap& policies,
+    PolicyErrorMap* errors) {
+  return GetValue(policies, errors, nullptr);
+}
+
+void PrintingPinDefaultPolicyHandler::ApplyPolicySettings(
+    const PolicyMap& policies,
+    PrefValueMap* prefs) {
+  printing::PinModeRestriction value;
+  if (GetValue(policies, nullptr, &value))
+    prefs->SetInteger(prefs::kPrintingPinDefault, static_cast<int>(value));
+}
+
 PrintingSizeDefaultPolicyHandler::PrintingSizeDefaultPolicyHandler()
     : TypeCheckingPolicyHandler(key::kPrintingSizeDefault,
                                 base::Value::Type::DICTIONARY) {}
diff --git a/chrome/browser/policy/printing_restrictions_policy_handler.h b/chrome/browser/policy/printing_restrictions_policy_handler.h
index 9c25727..9b5652e 100644
--- a/chrome/browser/policy/printing_restrictions_policy_handler.h
+++ b/chrome/browser/policy/printing_restrictions_policy_handler.h
@@ -52,6 +52,23 @@
                 printing::DuplexModeRestriction* result);
 };
 
+class PrintingAllowedPinModesPolicyHandler : public TypeCheckingPolicyHandler {
+ public:
+  PrintingAllowedPinModesPolicyHandler();
+  ~PrintingAllowedPinModesPolicyHandler() override;
+
+  // ConfigurationPolicyHandler implementation:
+  bool CheckPolicySettings(const PolicyMap& policies,
+                           PolicyErrorMap* errors) override;
+  void ApplyPolicySettings(const PolicyMap& policies,
+                           PrefValueMap* prefs) override;
+
+ private:
+  bool GetValue(const PolicyMap& policies,
+                PolicyErrorMap* errors,
+                printing::PinModeRestriction* result);
+};
+
 class PrintingAllowedPageSizesPolicyHandler : public ListPolicyHandler {
  public:
   PrintingAllowedPageSizesPolicyHandler();
@@ -97,6 +114,23 @@
                 printing::DuplexModeRestriction* result);
 };
 
+class PrintingPinDefaultPolicyHandler : public TypeCheckingPolicyHandler {
+ public:
+  PrintingPinDefaultPolicyHandler();
+  ~PrintingPinDefaultPolicyHandler() override;
+
+  // ConfigurationPolicyHandler implementation:
+  bool CheckPolicySettings(const PolicyMap& policies,
+                           PolicyErrorMap* errors) override;
+  void ApplyPolicySettings(const PolicyMap& policies,
+                           PrefValueMap* prefs) override;
+
+ private:
+  bool GetValue(const PolicyMap& policies,
+                PolicyErrorMap* errors,
+                printing::PinModeRestriction* result);
+};
+
 class PrintingSizeDefaultPolicyHandler : public TypeCheckingPolicyHandler {
  public:
   PrintingSizeDefaultPolicyHandler();
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc
index 1cd874b..cf0c0e0 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.cc
+++ b/chrome/browser/profiles/off_the_record_profile_impl.cc
@@ -51,6 +51,8 @@
 #include "chrome/common/chrome_switches.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/keyed_service/core/simple_dependency_manager.h"
+#include "components/keyed_service/core/simple_keyed_service_factory.h"
 #include "components/prefs/json_pref_store.h"
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "components/user_prefs/user_prefs.h"
@@ -145,6 +147,7 @@
           ->CreateDelegate());
   // Register on BrowserContext.
   user_prefs::UserPrefs::Set(this, prefs_.get());
+  off_the_record_key_ = profile_->GetOffTheRecordKey();
 }
 
 void OffTheRecordProfileImpl::Init() {
@@ -216,6 +219,12 @@
 
   BrowserContextDependencyManager::GetInstance()->DestroyBrowserContextServices(
       this);
+  // The SimpleDependencyManager should always be called after the
+  // BrowserContextDependencyManager. This is because the KeyedService instances
+  // in the BrowserContextDependencyManager's dependency graph can depend on the
+  // ones in the SimpleDependencyManager's graph.
+  SimpleDependencyManager::GetInstance()->DestroyKeyedServices(
+      GetOffTheRecordKey());
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
   base::PostTaskWithTraits(
@@ -532,6 +541,14 @@
   return start_time_;
 }
 
+SimpleFactoryKey* OffTheRecordProfileImpl::GetOriginalKey() const {
+  return off_the_record_key_->original_key();
+}
+
+SimpleFactoryKey* OffTheRecordProfileImpl::GetOffTheRecordKey() const {
+  return off_the_record_key_;
+}
+
 void OffTheRecordProfileImpl::SetExitType(ExitType exit_type) {
 }
 
diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h
index 928e99b..8763baf 100644
--- a/chrome/browser/profiles/off_the_record_profile_impl.h
+++ b/chrome/browser/profiles/off_the_record_profile_impl.h
@@ -76,6 +76,8 @@
       service_manager::mojom::ServiceRequest request) override;
   bool IsSameProfile(Profile* profile) override;
   base::Time GetStartTime() const override;
+  SimpleFactoryKey* GetOriginalKey() const override;
+  SimpleFactoryKey* GetOffTheRecordKey() const override;
   base::FilePath last_selected_directory() override;
   void set_last_selected_directory(const base::FilePath& path) override;
   bool WasCreatedByVersionOrLater(const std::string& version) override;
@@ -153,6 +155,8 @@
 
   base::FilePath last_selected_directory_;
 
+  SimpleFactoryKey* off_the_record_key_;
+
   DISALLOW_COPY_AND_ASSIGN(OffTheRecordProfileImpl);
 };
 
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index f23c4a7..377ea70 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -115,6 +115,13 @@
   return FromBrowserContext(web_ui->GetWebContents()->GetBrowserContext());
 }
 
+// static
+SimpleFactoryKey* Profile::GetSimpleFactoryKey(Profile* profile) {
+  if (profile->IsOffTheRecord())
+    return profile->GetOffTheRecordKey();
+  return profile->GetOriginalKey();
+}
+
 TestingProfile* Profile::AsTestingProfile() {
   return nullptr;
 }
diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h
index 41eae2e..32bab41 100644
--- a/chrome/browser/profiles/profile.h
+++ b/chrome/browser/profiles/profile.h
@@ -14,6 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "build/build_config.h"
 #include "components/domain_reliability/clear_mode.h"
+#include "components/keyed_service/core/simple_factory_key.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/content_browser_client.h"
 #include "services/network/public/mojom/network_service.mojom-forward.h"
@@ -120,6 +121,9 @@
   // Returns the profile corresponding to the given WebUI.
   static Profile* FromWebUI(content::WebUI* web_ui);
 
+  // Returns the SimpleFactoryKey asscociated with this |profile|.
+  static SimpleFactoryKey* GetSimpleFactoryKey(Profile* profile);
+
   // content::BrowserContext implementation ------------------------------------
 
   // Typesafe upcast.
@@ -217,6 +221,13 @@
   // the user started chrome.
   virtual base::Time GetStartTime() const = 0;
 
+  // Returns the key used by the original profile to index KeyedService
+  // instances created by a SimpleKeyedServiceFactory.
+  virtual SimpleFactoryKey* GetOriginalKey() const = 0;
+  // Returns the key used by an incognito profile to index KeyedService
+  // instances created by a SimpleKeyedServiceFactory.
+  virtual SimpleFactoryKey* GetOffTheRecordKey() const = 0;
+
   // Returns the last directory that was chosen for uploading or opening a file.
   virtual base::FilePath last_selected_directory() = 0;
   virtual void set_last_selected_directory(const base::FilePath& path) = 0;
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index c9dc5c3..d64a9b0 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -110,6 +110,8 @@
 #include "components/gcm_driver/gcm_profile_service.h"
 #include "components/history/core/common/pref_names.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "components/keyed_service/core/simple_dependency_manager.h"
+#include "components/keyed_service/core/simple_keyed_service_factory.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/language/core/common/locale_util.h"
 #include "components/metrics/metrics_service.h"
@@ -475,6 +477,12 @@
   DCHECK(!path.empty()) << "Using an empty path will attempt to write "
                         << "profile files to the root directory!";
 
+  // TODO(hanxi): get |key_| and |off_the_record_key_ |from the startup data if
+  // they have been created when this profile is created.
+  key_ = std::make_unique<SimpleFactoryKey>(GetPath());
+  off_the_record_key_ =
+      std::make_unique<SimpleFactoryKey>(GetPath(), key_.get());
+
 #if defined(OS_CHROMEOS)
   if (!chromeos::ProfileHelper::IsSigninProfile(this) &&
       !chromeos::ProfileHelper::IsLockScreenAppProfile(this)) {
@@ -779,6 +787,12 @@
 
   BrowserContextDependencyManager::GetInstance()->DestroyBrowserContextServices(
       this);
+  // The SimpleDependencyManager should always be called after the
+  // BrowserContextDependencyManager. This is because the KeyedService instances
+  // in the BrowserContextDependencyManager's dependency graph can depend on the
+  // ones in the SimpleDependencyManager's graph.
+  SimpleDependencyManager::GetInstance()->DestroyKeyedServices(
+      GetOriginalKey());
 
   // This causes the Preferences file to be written to disk.
   if (prefs_loaded)
@@ -823,6 +837,14 @@
   return false;
 }
 
+SimpleFactoryKey* ProfileImpl::GetOriginalKey() const {
+  return key_.get();
+}
+
+SimpleFactoryKey* ProfileImpl::GetOffTheRecordKey() const {
+  return off_the_record_key_.get();
+}
+
 Profile* ProfileImpl::GetOffTheRecordProfile() {
   if (!off_the_record_profile_) {
     std::unique_ptr<Profile> p(CreateOffTheRecordProfile());
diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h
index 6711bad..7d8fb7b 100644
--- a/chrome/browser/profiles/profile_impl.h
+++ b/chrome/browser/profiles/profile_impl.h
@@ -20,6 +20,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_impl_io_data.h"
 #include "chrome/common/buildflags.h"
+#include "components/keyed_service/core/simple_factory_key.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "content/public/browser/content_browser_client.h"
 #include "extensions/buildflags/buildflags.h"
@@ -136,6 +137,8 @@
 #if !defined(OS_ANDROID)
   ChromeZoomLevelPrefs* GetZoomLevelPrefs() override;
 #endif
+  SimpleFactoryKey* GetOriginalKey() const override;
+  SimpleFactoryKey* GetOffTheRecordKey() const override;
   PrefService* GetOffTheRecordPrefs() override;
   PrefService* GetReadOnlyOffTheRecordPrefs() override;
   net::URLRequestContextGetter* GetRequestContext() override;
@@ -248,6 +251,11 @@
 
   std::unique_ptr<Profile> off_the_record_profile_;
 
+  // The keys to index KeyedService instances created by
+  // SimpleKeyedServiceFactory.
+  std::unique_ptr<SimpleFactoryKey> key_;
+  std::unique_ptr<SimpleFactoryKey> off_the_record_key_;
+
   // See GetStartTime for details.
   base::Time start_time_;
 
diff --git a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
index 0572664..6e8a044 100644
--- a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
+++ b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.cc
@@ -7,9 +7,9 @@
 #include <utility>
 
 #include "base/process/process.h"
+#include "chrome/browser/performance_manager/browser_child_process_watcher.h"
 #include "chrome/browser/performance_manager/performance_manager.h"
 #include "chrome/browser/performance_manager/process_resource_coordinator.h"
-#include "chrome/browser/resource_coordinator/browser_child_process_watcher.h"
 #include "chrome/browser/resource_coordinator/page_signal_receiver.h"
 #include "chrome/browser/resource_coordinator/render_process_probe.h"
 #include "chrome/browser/resource_coordinator/utils.h"
@@ -25,14 +25,8 @@
         content::ServiceManagerConnection* connection) {
   performance_manager_ = performance_manager::PerformanceManager::Create();
 
-  process_resource_coordinator_ =
-      std::make_unique<performance_manager::ProcessResourceCoordinator>(
-          performance_manager_.get());
-
-  process_resource_coordinator_->OnProcessLaunched(base::Process::Current());
-
   browser_child_process_watcher_ =
-      std::make_unique<resource_coordinator::BrowserChildProcessWatcher>();
+      std::make_unique<performance_manager::BrowserChildProcessWatcher>();
 }
 
 void ChromeBrowserMainExtraPartsResourceCoordinator::PreBrowserStart() {
diff --git a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h
index 8ad06f2b2..26b8bd4 100644
--- a/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h
+++ b/chrome/browser/resource_coordinator/chrome_browser_main_extra_parts_resource_coordinator.h
@@ -8,12 +8,11 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "chrome/browser/chrome_browser_main_extra_parts.h"
-#include "chrome/browser/resource_coordinator/browser_child_process_watcher.h"
 #include "chrome/browser/resource_coordinator/performance_measurement_manager.h"
 
 namespace performance_manager {
+class BrowserChildProcessWatcher;
 class PerformanceManager;
-class ProcessResourceCoordinator;
 }  // namespace performance_manager
 
 class ChromeBrowserMainExtraPartsResourceCoordinator
@@ -30,10 +29,8 @@
   void PostMainMessageLoopRun() override;
 
   std::unique_ptr<performance_manager::PerformanceManager> performance_manager_;
-  std::unique_ptr<performance_manager::ProcessResourceCoordinator>
-      process_resource_coordinator_;
 
-  std::unique_ptr<resource_coordinator::BrowserChildProcessWatcher>
+  std::unique_ptr<performance_manager::BrowserChildProcessWatcher>
       browser_child_process_watcher_;
 
   std::unique_ptr<resource_coordinator::PerformanceMeasurementManager>
diff --git a/chrome/browser/resource_coordinator/tab_helper.cc b/chrome/browser/resource_coordinator/tab_helper.cc
index 9ff6188d..0a58032 100644
--- a/chrome/browser/resource_coordinator/tab_helper.cc
+++ b/chrome/browser/resource_coordinator/tab_helper.cc
@@ -13,9 +13,9 @@
 #include "base/strings/string_number_conversions.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/performance_manager/page_resource_coordinator.h"
-#include "chrome/browser/performance_manager/performance_manager.h"
-#include "chrome/browser/performance_manager/render_process_user_data.h"
+// TODO(siggi): This is an abomination, remove this as soon as the page signal
+//     receiver is abolished.
+#include "chrome/browser/performance_manager/performance_manager_tab_helper.h"
 #include "chrome/browser/resource_coordinator/page_signal_receiver.h"
 #include "chrome/browser/resource_coordinator/resource_coordinator_parts.h"
 #include "chrome/browser/resource_coordinator/tab_load_tracker.h"
@@ -35,34 +35,32 @@
 
 ResourceCoordinatorTabHelper::ResourceCoordinatorTabHelper(
     content::WebContents* web_contents)
-    : content::WebContentsObserver(web_contents),
-      performance_manager_(
-          performance_manager::PerformanceManager::GetInstance()) {
+    : content::WebContentsObserver(web_contents) {
   TabLoadTracker::Get()->StartTracking(web_contents);
-  if (performance_manager_) {
-    page_resource_coordinator_ =
-        std::make_unique<performance_manager::PageResourceCoordinator>(
-            performance_manager_);
 
-    // Make sure to set the visibility property when we create
-    // |page_resource_coordinator_|.
-    const bool is_visible =
-        web_contents->GetVisibility() != content::Visibility::HIDDEN;
-    page_resource_coordinator_->SetVisibility(is_visible);
+  // The invalid type is used as sentinel for no CU ID available.
+  DCHECK_EQ(CoordinationUnitType::kInvalidType, page_cu_id_.type);
+  bool have_cu_id = performance_manager::PerformanceManagerTabHelper::
+      GetCoordinationIDForWebContents(web_contents, &page_cu_id_);
 
+  // This can happen in unit tests.
+  if (have_cu_id) {
+    DCHECK_EQ(CoordinationUnitType::kPage, page_cu_id_.type);
     if (auto* page_signal_receiver = GetPageSignalReceiver()) {
       // Gets CoordinationUnitID for this WebContents and adds it to
       // PageSignalReceiver.
       page_signal_receiver->AssociateCoordinationUnitIDWithWebContents(
-          page_resource_coordinator_->id(), web_contents);
+          page_cu_id_, web_contents);
     }
+  } else {
+    DCHECK_EQ(CoordinationUnitType::kInvalidType, page_cu_id_.type);
+  }
 
-    if (memory_instrumentation::MemoryInstrumentation::GetInstance()) {
-      auto* rc_parts = g_browser_process->resource_coordinator_parts();
-      DCHECK(rc_parts);
-      rc_parts->tab_memory_metrics_reporter()->StartReporting(
-          TabLoadTracker::Get());
-    }
+  if (memory_instrumentation::MemoryInstrumentation::GetInstance()) {
+    auto* rc_parts = g_browser_process->resource_coordinator_parts();
+    DCHECK(rc_parts);
+    rc_parts->tab_memory_metrics_reporter()->StartReporting(
+        TabLoadTracker::Get());
   }
 
 #if !defined(OS_ANDROID)
@@ -76,76 +74,11 @@
             web_contents);
   }
 #endif
-
-  // Dispatch creation notifications for any pre-existing frames.
-  // This seems to occur only in tests, but dealing with this allows asserting
-  // a strong invariant on the frames_ collection.
-  std::vector<content::RenderFrameHost*> existing_frames =
-      web_contents->GetAllFrames();
-  for (content::RenderFrameHost* frame : existing_frames) {
-    // Only send notifications for live frames, the non-live ones will generate
-    // creation notifications when animated.
-    if (frame->IsRenderFrameLive())
-      RenderFrameCreated(frame);
-  }
 }
 
 ResourceCoordinatorTabHelper::~ResourceCoordinatorTabHelper() = default;
 
-void ResourceCoordinatorTabHelper::RenderFrameCreated(
-    content::RenderFrameHost* render_frame_host) {
-  DCHECK_NE(nullptr, render_frame_host);
-  // This must not exist in the map yet.
-  DCHECK(!base::ContainsKey(frames_, render_frame_host));
-
-  if (!performance_manager_)
-    return;
-
-  std::unique_ptr<performance_manager::FrameResourceCoordinator> frame =
-      std::make_unique<performance_manager::FrameResourceCoordinator>(
-          performance_manager_);
-  content::RenderFrameHost* parent = render_frame_host->GetParent();
-  if (parent) {
-    DCHECK(base::ContainsKey(frames_, parent));
-    auto& parent_frame_node = frames_[parent];
-    parent_frame_node->AddChildFrame(*frame.get());
-  }
-
-  performance_manager::RenderProcessUserData* user_data =
-      performance_manager::RenderProcessUserData::GetForRenderProcessHost(
-          render_frame_host->GetProcess());
-  // In unittests the user data isn't populated as the relevant main parts
-  // is not in play.
-  // TODO(siggi): Figure out how to assert on this when the main parts are
-  //     registered with the content browser client.
-  if (user_data)
-    frame->SetProcess(*user_data->process_resource_coordinator());
-
-  frames_[render_frame_host] = std::move(frame);
-}
-
-void ResourceCoordinatorTabHelper::RenderFrameDeleted(
-    content::RenderFrameHost* render_frame_host) {
-  if (!performance_manager_)
-    return;
-
-  // TODO(siggi): Ideally this would DCHECK that the deleted render frame host
-  //     is known, e.g. that there was a creation notification for it. This is
-  //     however not always the case. Notably these two unit_tests:
-  //       - TabsApiUnitTest.TabsGoForwardAndBack
-  //       - TabsApiUnitTest.TabsGoForwardAndBackWithoutTabId
-  //     end up issuing deletion notifications for render frame hosts never seen
-  //     before. It appears that the RenderFrameHostManager keeps a queue of
-  //     pending deletions. If a frame is already in this queue at the time
-  //     this tab helper is attached to a WebContents, the eventual deletion
-  //     notification will be singular.
-  // DCHECK(base::ContainsKey(frames_, render_frame_host));
-  frames_.erase(render_frame_host);
-}
-
 void ResourceCoordinatorTabHelper::DidStartLoading() {
-  if (page_resource_coordinator_)
-    page_resource_coordinator_->SetIsLoading(true);
   TabLoadTracker::Get()->DidStartLoading(web_contents());
 }
 
@@ -154,8 +87,6 @@
 }
 
 void ResourceCoordinatorTabHelper::DidStopLoading() {
-  if (page_resource_coordinator_)
-    page_resource_coordinator_->SetIsLoading(false);
   TabLoadTracker::Get()->DidStopLoading(web_contents());
 }
 
@@ -174,24 +105,15 @@
   TabLoadTracker::Get()->RenderProcessGone(web_contents(), status);
 }
 
-void ResourceCoordinatorTabHelper::OnVisibilityChanged(
-    content::Visibility visibility) {
-  if (page_resource_coordinator_) {
-    // TODO(fdoray): An OCCLUDED tab should not be considered visible.
-    const bool is_visible = visibility != content::Visibility::HIDDEN;
-    page_resource_coordinator_->SetVisibility(is_visible);
-  }
-}
-
 void ResourceCoordinatorTabHelper::WebContentsDestroyed() {
-  if (page_resource_coordinator_) {
+  if (page_cu_id_.type == CoordinationUnitType::kPage) {
     if (auto* page_signal_receiver = GetPageSignalReceiver()) {
       // Gets CoordinationUnitID for this WebContents and removes it from
       // PageSignalReceiver.
-      page_signal_receiver->RemoveCoordinationUnitID(
-          page_resource_coordinator_->id());
+      page_signal_receiver->RemoveCoordinationUnitID(page_cu_id_);
     }
   }
+
   TabLoadTracker::Get()->StopTracking(web_contents());
 }
 
@@ -202,83 +124,18 @@
     return;
   }
 
-  if (page_resource_coordinator_) {
-    // Grab the current time up front, as this is as close as we'll get to the
-    // original commit time.
-    base::TimeTicks navigation_committed_time = base::TimeTicks::Now();
-
-    content::RenderFrameHost* render_frame_host =
-        navigation_handle->GetRenderFrameHost();
-    // Make sure the hierarchical structure is constructed before sending signal
-    // to Resource Coordinator.
-    // TODO(siggi): Ideally this would be a DCHECK, but it seems it's possible
-    //     to get a DidFinishNavigation notification for a deleted frame when
-    //     with the network service.
-    auto it = frames_.find(render_frame_host);
-    if (it != frames_.end()) {
-      // TODO(siggi): See whether this can be done in RenderFrameCreated.
-      page_resource_coordinator_->AddFrame(*(it->second));
-    }
-
-    if (navigation_handle->IsInMainFrame()) {
-      if (auto* page_signal_receiver = GetPageSignalReceiver()) {
-        // Update the last observed navigation ID for this WebContents.
-        page_signal_receiver->SetNavigationID(
-            web_contents(), navigation_handle->GetNavigationId());
-      }
-
-      UpdateUkmRecorder(navigation_handle->GetNavigationId());
-      ResetFlag();
-      page_resource_coordinator_->OnMainFrameNavigationCommitted(
-          navigation_committed_time, navigation_handle->GetNavigationId(),
-          navigation_handle->GetURL().spec());
+  if (navigation_handle->IsInMainFrame()) {
+    if (auto* page_signal_receiver = GetPageSignalReceiver()) {
+      // Update the last observed navigation ID for this WebContents.
+      page_signal_receiver->SetNavigationID(
+          web_contents(), navigation_handle->GetNavigationId());
     }
   }
-}
 
-void ResourceCoordinatorTabHelper::TitleWasSet(
-    content::NavigationEntry* entry) {
-  if (!first_time_title_set_) {
-    first_time_title_set_ = true;
-    return;
+  if (navigation_handle->IsInMainFrame()) {
+    ukm_source_id_ = ukm::ConvertToSourceId(
+        navigation_handle->GetNavigationId(), ukm::SourceIdType::NAVIGATION_ID);
   }
-  if (page_resource_coordinator_)
-    page_resource_coordinator_->OnTitleUpdated();
-}
-
-void ResourceCoordinatorTabHelper::DidUpdateFaviconURL(
-    const std::vector<content::FaviconURL>& candidates) {
-  if (!first_time_favicon_set_) {
-    first_time_favicon_set_ = true;
-    return;
-  }
-  if (page_resource_coordinator_)
-    page_resource_coordinator_->OnFaviconUpdated();
-}
-
-void ResourceCoordinatorTabHelper::OnInterfaceRequestFromFrame(
-    content::RenderFrameHost* render_frame_host,
-    const std::string& interface_name,
-    mojo::ScopedMessagePipeHandle* interface_pipe) {
-  if (interface_name != mojom::FrameCoordinationUnit::Name_)
-    return;
-
-  auto it = frames_.find(render_frame_host);
-  DCHECK(it != frames_.end());
-  it->second->AddBinding(
-      mojom::FrameCoordinationUnitRequest(std::move(*interface_pipe)));
-}
-
-void ResourceCoordinatorTabHelper::UpdateUkmRecorder(int64_t navigation_id) {
-  ukm_source_id_ =
-      ukm::ConvertToSourceId(navigation_id, ukm::SourceIdType::NAVIGATION_ID);
-  if (page_resource_coordinator_)
-    page_resource_coordinator_->SetUKMSourceId(ukm_source_id_);
-}
-
-void ResourceCoordinatorTabHelper::ResetFlag() {
-  first_time_title_set_ = false;
-  first_time_favicon_set_ = false;
 }
 
 WEB_CONTENTS_USER_DATA_KEY_IMPL(ResourceCoordinatorTabHelper)
diff --git a/chrome/browser/resource_coordinator/tab_helper.h b/chrome/browser/resource_coordinator/tab_helper.h
index 4188649..71082e7 100644
--- a/chrome/browser/resource_coordinator/tab_helper.h
+++ b/chrome/browser/resource_coordinator/tab_helper.h
@@ -13,17 +13,12 @@
 #include "base/process/kill.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "chrome/browser/performance_manager/frame_resource_coordinator.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 #include "services/metrics/public/cpp/ukm_source_id.h"
+#include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
 #include "url/gurl.h"
 
-namespace performance_manager {
-class PageResourceCoordinator;
-class PerformanceManager;
-}  // namespace performance_manager
-
 namespace resource_coordinator {
 
 class LocalSiteCharacteristicsWebContentsObserver;
@@ -34,16 +29,7 @@
  public:
   ~ResourceCoordinatorTabHelper() override;
 
-  static bool ukm_recorder_initialized;
-
-  performance_manager::PageResourceCoordinator* page_resource_coordinator() {
-    return page_resource_coordinator_.get();
-  }
-
   // WebContentsObserver overrides.
-  void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override;
-  void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
-
   void DidStartLoading() override;
   void DidReceiveResponse() override;
   void DidStopLoading() override;
@@ -52,17 +38,9 @@
                    int error_code,
                    const base::string16& error_description) override;
   void RenderProcessGone(base::TerminationStatus status) override;
-  void OnVisibilityChanged(content::Visibility visibility) override;
   void WebContentsDestroyed() override;
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override;
-  void TitleWasSet(content::NavigationEntry* entry) override;
-  void DidUpdateFaviconURL(
-      const std::vector<content::FaviconURL>& candidates) override;
-  void OnInterfaceRequestFromFrame(
-      content::RenderFrameHost* render_frame_host,
-      const std::string& interface_name,
-      mojo::ScopedMessagePipeHandle* interface_pipe) override;
 
   void UpdateUkmRecorder(int64_t navigation_id);
   ukm::SourceId ukm_source_id() const { return ukm_source_id_; }
@@ -77,36 +55,20 @@
 
  private:
   explicit ResourceCoordinatorTabHelper(content::WebContents* web_contents);
-  // Favicon, title are set the first time a page is loaded, thus we want to
-  // ignore the very first update, and reset the flags when a non same-document
-  // navigation finished in main frame.
-  void ResetFlag();
+
+  // The coordination unit ID of the page node associated with |web_contents()|,
+  // if any.
+  CoordinationUnitID page_cu_id_;
+  // TODO(siggi): This is used by the TabLifecycleUnit, remove this with it.
+  ukm::SourceId ukm_source_id_ = ukm::kInvalidSourceId;
 
   friend class content::WebContentsUserData<ResourceCoordinatorTabHelper>;
 
-  // The performance manager for this process, if any.
-  performance_manager::PerformanceManager* performance_manager_ = nullptr;
-
-  std::unique_ptr<performance_manager::PageResourceCoordinator>
-      page_resource_coordinator_;
-  ukm::SourceId ukm_source_id_ = ukm::kInvalidSourceId;
-
 #if !defined(OS_ANDROID)
   std::unique_ptr<LocalSiteCharacteristicsWebContentsObserver>
       local_site_characteristics_wc_observer_;
 #endif
 
-  // Favicon and title are set when a page is loaded, we only want to send
-  // signals to GRC about title and favicon update from the previous title and
-  // favicon, thus we want to ignore the very first update since it is always
-  // supposed to happen.
-  bool first_time_favicon_set_ = false;
-  bool first_time_title_set_ = false;
-
-  // Maps from RenderFrameHost to the associated RC node.
-  std::map<content::RenderFrameHost*,
-           std::unique_ptr<performance_manager::FrameResourceCoordinator>>
-      frames_;
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 
diff --git a/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
index 2e954d1..d969acb 100644
--- a/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_stats_collector_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/performance_manager/performance_manager_tab_helper.h"
 #include "chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h"
 #include "chrome/browser/resource_coordinator/tab_helper.h"
 #include "chrome/browser/resource_coordinator/tab_load_tracker.h"
@@ -107,6 +108,8 @@
 
   std::unique_ptr<WebContents> CreateWebContentsForUKM(ukm::SourceId id) {
     std::unique_ptr<WebContents> contents(CreateTestWebContents());
+    performance_manager::PerformanceManagerTabHelper::CreateForWebContents(
+        contents.get());
     ResourceCoordinatorTabHelper::CreateForWebContents(contents.get());
     ResourceCoordinatorTabHelper::FromWebContents(contents.get())
         ->SetUkmSourceIdForTest(id);
diff --git a/chrome/browser/resource_coordinator/tab_manager_unittest.cc b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
index 39c35256..bb4be46 100644
--- a/chrome/browser/resource_coordinator/tab_manager_unittest.cc
+++ b/chrome/browser/resource_coordinator/tab_manager_unittest.cc
@@ -25,6 +25,7 @@
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_tracker.h"
+#include "chrome/browser/performance_manager/performance_manager_tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/resource_coordinator/background_tab_navigation_throttle.h"
 #include "chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h"
@@ -146,6 +147,10 @@
 
   std::unique_ptr<WebContents> CreateWebContents() {
     std::unique_ptr<WebContents> web_contents = CreateTestWebContents();
+    // TODO(siggi): This is an abomination, remove this once the
+    //     PageSignalGenerator is folded into the performance manager.
+    performance_manager::PerformanceManagerTabHelper::CreateForWebContents(
+        web_contents.get());
     ResourceCoordinatorTabHelper::CreateForWebContents(web_contents.get());
     // Commit an URL to allow discarding.
     content::WebContentsTester::For(web_contents.get())
@@ -204,12 +209,18 @@
                    const char* url2 = kTestUrl,
                    const char* url3 = kTestUrl) {
     contents1_ = CreateTestWebContents();
+    performance_manager::PerformanceManagerTabHelper::CreateForWebContents(
+        contents1_.get());
     ResourceCoordinatorTabHelper::CreateForWebContents(contents1_.get());
     nav_handle1_ = CreateTabAndNavigation(url1, contents1_.get());
     contents2_ = CreateTestWebContents();
+    performance_manager::PerformanceManagerTabHelper::CreateForWebContents(
+        contents2_.get());
     ResourceCoordinatorTabHelper::CreateForWebContents(contents2_.get());
     nav_handle2_ = CreateTabAndNavigation(url2, contents2_.get());
     contents3_ = CreateTestWebContents();
+    performance_manager::PerformanceManagerTabHelper::CreateForWebContents(
+        contents3_.get());
     ResourceCoordinatorTabHelper::CreateForWebContents(contents3_.get());
     nav_handle3_ = CreateTabAndNavigation(url3, contents3_.get());
 
diff --git a/chrome/browser/resources/chromeos/camera/Makefile b/chrome/browser/resources/chromeos/camera/Makefile
index 9e357b1..6d1a2e3a 100644
--- a/chrome/browser/resources/chromeos/camera/Makefile
+++ b/chrome/browser/resources/chromeos/camera/Makefile
@@ -111,7 +111,9 @@
 	src/images/spinner.svg \
 	src/js/background.js \
 	src/js/gallerybutton.js \
+	src/js/google-analytics-bundle.js \
 	src/js/main.js \
+	src/js/metrics.js \
 	src/js/models/gallery.js \
 	src/js/models/file_system.js \
 	src/js/nav.js \
diff --git a/chrome/browser/resources/chromeos/camera/src/js/google-analytics-bundle.js b/chrome/browser/resources/chromeos/camera/src/js/google-analytics-bundle.js
new file mode 100644
index 0000000..d1a7a62
--- /dev/null
+++ b/chrome/browser/resources/chromeos/camera/src/js/google-analytics-bundle.js
@@ -0,0 +1,106 @@
+// 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.
+(function() { 'use strict';var h,aa=aa||{},k=this,m=function(a){return void 0!==a},ba=function(){},ca=function(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&
+"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if("function"==b&&"undefined"==typeof a.call)return"object";return b},n=function(a){return"array"==ca(a)},da=function(a){var b=ca(a);return"array"==b||"object"==b&&"number"==typeof a.length},p=function(a){return"string"==typeof a},ea=function(a){return"number"==typeof a},q=function(a){return"function"==ca(a)},r=function(a){var b=typeof a;return"object"==b&&null!=a||"function"==b},fa=
+function(a,b,c){return a.call.apply(a.bind,arguments)},ga=function(a,b,c){if(!a)throw Error();if(2<arguments.length){var d=Array.prototype.slice.call(arguments,2);return function(){var c=Array.prototype.slice.call(arguments);Array.prototype.unshift.apply(c,d);return a.apply(b,c)}}return function(){return a.apply(b,arguments)}},t=function(a,b,c){t=Function.prototype.bind&&-1!=Function.prototype.bind.toString().indexOf("native code")?fa:ga;return t.apply(null,arguments)},ha=function(a,b){var c=Array.prototype.slice.call(arguments,
+1);return function(){var b=c.slice();b.push.apply(b,arguments);return a.apply(this,b)}},u=Date.now||function(){return+new Date},v=function(a,b){var c=a.split("."),d=k;c[0]in d||!d.execScript||d.execScript("var "+c[0]);for(var e;c.length&&(e=c.shift());)!c.length&&m(b)?d[e]=b:d=d[e]?d[e]:d[e]={}},w=function(a,b){function c(){}c.prototype=b.prototype;a.W=b.prototype;a.prototype=new c;a.re=function(a,c,f){for(var g=Array(arguments.length-2),l=2;l<arguments.length;l++)g[l-2]=arguments[l];return b.prototype[c].apply(a,
+g)}};var y=function(a){if(Error.captureStackTrace)Error.captureStackTrace(this,y);else{var b=Error().stack;b&&(this.stack=b)}a&&(this.message=String(a))};w(y,Error);y.prototype.name="CustomError";var ia=String.prototype.trim?function(a){return a.trim()}:function(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")},ja=String.prototype.repeat?function(a,b){return a.repeat(b)}:function(a,b){return Array(b+1).join(a)},ka=function(a,b){return a<b?-1:a>b?1:0};var la=Array.prototype.indexOf?function(a,b,c){return Array.prototype.indexOf.call(a,b,c)}:function(a,b,c){c=null==c?0:0>c?Math.max(0,a.length+c):c;if(p(a))return p(b)&&1==b.length?a.indexOf(b,c):-1;for(;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},ma=Array.prototype.forEach?function(a,b,c){Array.prototype.forEach.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=p(a)?a.split(""):a,f=0;f<d;f++)f in e&&b.call(c,e[f],f,a)},na=Array.prototype.some?function(a,b,c){return Array.prototype.some.call(a,
+b,c)}:function(a,b,c){for(var d=a.length,e=p(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&b.call(c,e[f],f,a))return!0;return!1},oa=Array.prototype.every?function(a,b,c){return Array.prototype.every.call(a,b,c)}:function(a,b,c){for(var d=a.length,e=p(a)?a.split(""):a,f=0;f<d;f++)if(f in e&&!b.call(c,e[f],f,a))return!1;return!0},qa=function(a){var b;a:{b=pa;for(var c=a.length,d=p(a)?a.split(""):a,e=0;e<c;e++)if(e in d&&b.call(void 0,d[e],e,a)){b=e;break a}b=-1}return 0>b?null:p(a)?a.charAt(b):a[b]},ra=function(a,
+b){var c=la(a,b),d;(d=0<=c)&&Array.prototype.splice.call(a,c,1);return d},sa=function(a){return Array.prototype.concat.apply(Array.prototype,arguments)},ta=function(a,b,c){return 2>=arguments.length?Array.prototype.slice.call(a,b):Array.prototype.slice.call(a,b,c)};var ua="StopIteration"in k?k.StopIteration:{message:"StopIteration",stack:""},va=function(){};va.prototype.next=function(){throw ua;};va.prototype.Yb=function(){return this};var wa=function(a,b,c){for(var d in a)b.call(c,a[d],d,a)},xa=function(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b},ya=function(a){var b=[],c=0,d;for(d in a)b[c++]=d;return b},za=function(a){return null!==a&&"withCredentials"in a},Aa=function(a,b){var c;a:{for(c in a)if(b.call(void 0,a[c],c,a))break a;c=void 0}return c&&a[c]},Ba="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" "),Ca=function(a,b){for(var c,d,e=1;e<arguments.length;e++){d=
+arguments[e];for(c in d)a[c]=d[c];for(var f=0;f<Ba.length;f++)c=Ba[f],Object.prototype.hasOwnProperty.call(d,c)&&(a[c]=d[c])}};var z=function(a,b){this.B={};this.b=[];this.Qa=this.g=0;var c=arguments.length;if(1<c){if(c%2)throw Error("Uneven number of arguments");for(var d=0;d<c;d+=2)this.set(arguments[d],arguments[d+1])}else a&&this.addAll(a)};z.prototype.v=function(){Da(this);for(var a=[],b=0;b<this.b.length;b++)a.push(this.B[this.b[b]]);return a};z.prototype.L=function(){Da(this);return this.b.concat()};z.prototype.$=function(a){return A(this.B,a)};
+z.prototype.remove=function(a){return A(this.B,a)?(delete this.B[a],this.g--,this.Qa++,this.b.length>2*this.g&&Da(this),!0):!1};var Da=function(a){if(a.g!=a.b.length){for(var b=0,c=0;b<a.b.length;){var d=a.b[b];A(a.B,d)&&(a.b[c++]=d);b++}a.b.length=c}if(a.g!=a.b.length){for(var e={},c=b=0;b<a.b.length;)d=a.b[b],A(e,d)||(a.b[c++]=d,e[d]=1),b++;a.b.length=c}};h=z.prototype;h.get=function(a,b){return A(this.B,a)?this.B[a]:b};
+h.set=function(a,b){A(this.B,a)||(this.g++,this.b.push(a),this.Qa++);this.B[a]=b};h.addAll=function(a){var b;a instanceof z?(b=a.L(),a=a.v()):(b=ya(a),a=xa(a));for(var c=0;c<b.length;c++)this.set(b[c],a[c])};h.forEach=function(a,b){for(var c=this.L(),d=0;d<c.length;d++){var e=c[d],f=this.get(e);a.call(b,f,e,this)}};h.clone=function(){return new z(this)};h.Ub=function(){Da(this);for(var a={},b=0;b<this.b.length;b++){var c=this.b[b];a[c]=this.B[c]}return a};
+h.Yb=function(a){Da(this);var b=0,c=this.Qa,d=this,e=new va;e.next=function(){if(c!=d.Qa)throw Error("The map has changed since the iterator was created");if(b>=d.b.length)throw ua;var e=d.b[b++];return a?e:d.B[e]};return e};var A=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)};var Ea,Fa,Ga={id:"hitType",name:"t",valueType:"text",maxLength:void 0,defaultValue:void 0},Ha={id:"sessionControl",name:"sc",valueType:"text",maxLength:void 0,defaultValue:void 0},Ia={id:"description",name:"cd",valueType:"text",maxLength:2048,defaultValue:void 0},Ja={id:"eventCategory",name:"ec",valueType:"text",maxLength:150,defaultValue:void 0},Ka={id:"eventAction",name:"ea",valueType:"text",maxLength:500,defaultValue:void 0},La={id:"eventLabel",name:"el",valueType:"text",maxLength:500,defaultValue:void 0},
+Ma={id:"eventValue",name:"ev",valueType:"integer",maxLength:void 0,defaultValue:void 0},Na={Id:Ga,Xb:{id:"anonymizeIp",name:"aip",valueType:"boolean",maxLength:void 0,defaultValue:void 0},Td:{id:"queueTime",name:"qt",valueType:"integer",maxLength:void 0,defaultValue:void 0},pd:{id:"cacheBuster",name:"z",valueType:"text",maxLength:void 0,defaultValue:void 0},Zd:Ha,$d:{id:"sessionGroup",name:"sg",valueType:"text",maxLength:void 0,defaultValue:void 0},pe:{id:"userId",name:"uid",valueType:"text",maxLength:void 0,
+defaultValue:void 0},Qd:{id:"nonInteraction",name:"ni",valueType:"boolean",maxLength:void 0,defaultValue:void 0},zd:Ia,ie:{id:"title",name:"dt",valueType:"text",maxLength:1500,defaultValue:void 0},ld:{id:"appId",name:"aid",valueType:"text",maxLength:150,defaultValue:void 0},md:{id:"appInstallerId",name:"aiid",valueType:"text",maxLength:150,defaultValue:void 0},Cd:Ja,Bd:Ka,Dd:La,Ed:Ma,be:{id:"socialNetwork",name:"sn",valueType:"text",maxLength:50,defaultValue:void 0},ae:{id:"socialAction",name:"sa",
+valueType:"text",maxLength:50,defaultValue:void 0},ce:{id:"socialTarget",name:"st",valueType:"text",maxLength:2048,defaultValue:void 0},le:{id:"transactionId",name:"ti",valueType:"text",maxLength:500,defaultValue:void 0},ke:{id:"transactionAffiliation",name:"ta",valueType:"text",maxLength:500,defaultValue:void 0},me:{id:"transactionRevenue",name:"tr",valueType:"currency",maxLength:void 0,defaultValue:void 0},ne:{id:"transactionShipping",name:"ts",valueType:"currency",maxLength:void 0,defaultValue:void 0},
+oe:{id:"transactionTax",name:"tt",valueType:"currency",maxLength:void 0,defaultValue:void 0},xd:{id:"currencyCode",name:"cu",valueType:"text",maxLength:10,defaultValue:void 0},Md:{id:"itemPrice",name:"ip",valueType:"currency",maxLength:void 0,defaultValue:void 0},Nd:{id:"itemQuantity",name:"iq",valueType:"integer",maxLength:void 0,defaultValue:void 0},Kd:{id:"itemCode",name:"ic",valueType:"text",maxLength:500,defaultValue:void 0},Ld:{id:"itemName",name:"in",valueType:"text",maxLength:500,defaultValue:void 0},
+Jd:{id:"itemCategory",name:"iv",valueType:"text",maxLength:500,defaultValue:void 0},vd:{id:"campaignSource",name:"cs",valueType:"text",maxLength:100,defaultValue:void 0},td:{id:"campaignMedium",name:"cm",valueType:"text",maxLength:50,defaultValue:void 0},ud:{id:"campaignName",name:"cn",valueType:"text",maxLength:100,defaultValue:void 0},sd:{id:"campaignKeyword",name:"ck",valueType:"text",maxLength:500,defaultValue:void 0},qd:{id:"campaignContent",name:"cc",valueType:"text",maxLength:500,defaultValue:void 0},
+rd:{id:"campaignId",name:"ci",valueType:"text",maxLength:100,defaultValue:void 0},Hd:{id:"gclid",name:"gclid",valueType:"text",maxLength:void 0,defaultValue:void 0},yd:{id:"dclid",name:"dclid",valueType:"text",maxLength:void 0,defaultValue:void 0},Sd:{id:"pageLoadTime",name:"plt",valueType:"integer",maxLength:void 0,defaultValue:void 0},Ad:{id:"dnsTime",name:"dns",valueType:"integer",maxLength:void 0,defaultValue:void 0},de:{id:"tcpConnectTime",name:"tcp",valueType:"integer",maxLength:void 0,defaultValue:void 0},
+Yd:{id:"serverResponseTime",name:"srt",valueType:"integer",maxLength:void 0,defaultValue:void 0},Rd:{id:"pageDownloadTime",name:"pdt",valueType:"integer",maxLength:void 0,defaultValue:void 0},Ud:{id:"redirectResponseTime",name:"rrt",valueType:"integer",maxLength:void 0,defaultValue:void 0},ee:{id:"timingCategory",name:"utc",valueType:"text",maxLength:150,defaultValue:void 0},he:{id:"timingVar",name:"utv",valueType:"text",maxLength:500,defaultValue:void 0},ge:{id:"timingValue",name:"utt",valueType:"integer",
+maxLength:void 0,defaultValue:void 0},fe:{id:"timingLabel",name:"utl",valueType:"text",maxLength:500,defaultValue:void 0},Fd:{id:"exDescription",name:"exd",valueType:"text",maxLength:150,defaultValue:void 0},Gd:{id:"exFatal",name:"exf",valueType:"boolean",maxLength:void 0,defaultValue:"1"}},Oa=function(a){if(1>a||200<a)throw Error("Expected dimension index range 1-200, but was : "+a);return{id:"dimension"+a,name:"cd"+a,valueType:"text",maxLength:150,defaultValue:void 0}},Pa=function(a){if(1>a||200<
+a)throw Error("Expected metric index range 1-200, but was : "+a);return{id:"metric"+a,name:"cm"+a,valueType:"integer",maxLength:void 0,defaultValue:void 0}};var Qa=function(a){if(1>a)return"0";if(3>a)return"1-2";a=Math.floor(Math.log(a-1)/Math.log(2));return Math.pow(2,a)+1+"-"+Math.pow(2,a+1)},Ra=function(a,b){for(var c=0,d=a.length-1,e=0;c<=d;){var f=Math.floor((c+d)/2),e=a[f];if(b<=e){d=0==f?0:a[f-1];if(b>d)return(d+1).toString()+"-"+e.toString();d=f-1}else if(b>e){if(f>=a.length-1)return(a[a.length-1]+1).toString()+"+";c=f+1}}return"<= 0"};var B=function(){this.mb=[]},Sa=function(){return new B};h=B.prototype;h.when=function(a){this.mb.push(a);return this};h.Wb=function(a){var b=arguments;this.when(function(a){return 0<=la(b,a.Ab())});return this};h.hd=function(a,b){var c=ta(arguments,1);this.when(function(b){b=b.ba().get(a);return 0<=la(c,b)});return this};h.sb=function(a,b){if(r(this.h))throw Error("Filter has already been set.");this.h=r(b)?t(a,b):a;return this};
+h.qa=function(){if(0==this.mb.length)throw Error("Must specify at least one predicate using #when or a helper method.");if(!r(this.h))throw Error("Must specify a delegate filter using #applyFilter.");return t(function(a){oa(this.mb,function(b){return b(a)})&&this.h(a)},this)};var C=function(){this.rb=!1;this.Fb="";this.Rb=!1;this.Ga=null};C.prototype.cc=function(a){this.rb=!0;this.Fb=a||" - ";return this};C.prototype.$c=function(){this.Rb=!0;return this};C.prototype.Kc=function(){return Ta(this,Qa)};C.prototype.Mc=function(a){return Ta(this,ha(Ra,a))};
+var Ta=function(a,b){if(null!=a.Ga)throw Error("LabelerBuilder: Only one labeling strategy may be used.");a.Ga=t(function(a){var d=a.ba().get(Ma),e=a.ba().get(La);ea(d)&&(d=b(d),null!=e&&this.rb&&(d=e+this.Fb+d),a.ba().set(La,d))},a);return a};C.prototype.qa=function(){if(null==this.Ga)throw Error("LabelerBuilder: a labeling strategy must be specified prior to calling build().");return Sa().Wb("event").sb(t(function(a){this.Ga(a);this.Rb&&a.ba().remove(Ma)},this)).qa()};var Ua=function(a,b){var c=Array.prototype.slice.call(arguments),d=c.shift();if("undefined"==typeof d)throw Error("[goog.string.format] Template required");return d.replace(/%([0\-\ \+]*)(\d+)?(\.(\d+))?([%sfdiu])/g,function(a,b,d,l,x,M,V,W){if("%"==M)return"%";var Pb=c.shift();if("undefined"==typeof Pb)throw Error("[goog.string.format] Not enough arguments");arguments[0]=Pb;return D[M].apply(null,arguments)})},D={s:function(a,b,c){return isNaN(c)||""==c||a.length>=Number(c)?a:a=-1<b.indexOf("-",
+0)?a+ja(" ",Number(c)-a.length):ja(" ",Number(c)-a.length)+a},f:function(a,b,c,d,e){d=a.toString();isNaN(e)||""==e||(d=parseFloat(a).toFixed(e));var f;f=0>Number(a)?"-":0<=b.indexOf("+")?"+":0<=b.indexOf(" ")?" ":"";0<=Number(a)&&(d=f+d);if(isNaN(c)||d.length>=Number(c))return d;d=isNaN(e)?Math.abs(Number(a)).toString():Math.abs(Number(a)).toFixed(e);a=Number(c)-d.length-f.length;return d=0<=b.indexOf("-",0)?f+d+ja(" ",a):f+ja(0<=b.indexOf("0",0)?"0":" ",a)+d},d:function(a,b,c,d,e,f,g,l){return D.f(parseInt(a,
+10),b,c,d,0,f,g,l)}};D.i=D.d;D.u=D.d;var Va=function(a){if(a.v&&"function"==typeof a.v)return a.v();if(p(a))return a.split("");if(da(a)){for(var b=[],c=a.length,d=0;d<c;d++)b.push(a[d]);return b}return xa(a)},Wa=function(a,b){if(a.forEach&&"function"==typeof a.forEach)a.forEach(b,void 0);else if(da(a)||p(a))ma(a,b,void 0);else{var c;if(a.L&&"function"==typeof a.L)c=a.L();else if(a.v&&"function"==typeof a.v)c=void 0;else if(da(a)||p(a)){c=[];for(var d=a.length,e=0;e<d;e++)c.push(e)}else c=ya(a);for(var d=Va(a),e=d.length,f=0;f<e;f++)b.call(void 0,
+d[f],c&&c[f],a)}};var E=function(a){this.H=new z;if(0<arguments.length%2)throw Error("Uneven number of arguments to ParameterMap constructor.");for(var b=arguments,c=0;c<b.length;c+=2)this.set(b[c],b[c+1])};E.prototype.set=function(a,b){if(null==b)throw Error("undefined-or-null value for key: "+a.name);this.H.set(a.name,{key:a,value:b})};E.prototype.remove=function(a){this.H.remove(a.name)};E.prototype.get=function(a){a=this.H.get(a.name,null);return null===a?null:a.value};E.prototype.addAll=function(a){this.H.addAll(a.H)};
+var Xa=function(a,b){ma(a.H.v(),function(a){b(a.key,a.value)})};E.prototype.Ub=function(){var a={};Xa(this,function(b,c){a[b.id]=c});return a};E.prototype.clone=function(){var a=new E;a.H=this.H.clone();return a};E.prototype.toString=function(){var a={};Xa(this,function(b,c){a[b.id]=c});return JSON.stringify(a)};var F=function(a){this.h=a};h=F.prototype;h.ec=function(a){var b=new F(t(this.U,this));b.P=Ja;b.X=a;return b};h.action=function(a){var b=new F(t(this.U,this));b.P=Ka;b.X=a;return b};h.label=function(a){var b=new F(t(this.U,this));b.P=La;b.X=a;return b};h.value=function(a){var b=new F(t(this.U,this));b.P=Ma;b.X=a;return b};h.mc=function(a){var b=new F(t(this.U,this));b.P=Oa(a.index);b.X=a.value;return b};h.Cc=function(a){var b=new F(t(this.U,this));b.P=Pa(a.index);b.X=a.value;return b};
+h.send=function(a){var b=new E;this.U(b);return a.send("event",b)};h.U=function(a){null!=this.P&&null!=this.X&&!a.H.$(this.P.name)&&a.set(this.P,this.X);r(this.h)&&this.h(a)};var Ya=new F(ba);var G=function(){this.ia=this.ia;this.Ka=this.Ka};G.prototype.ia=!1;G.prototype.ua=function(){this.ia||(this.ia=!0,this.A())};G.prototype.A=function(){if(this.Ka)for(;this.Ka.length;)this.Ka.shift()()};var H=function(a,b){this.type=a;this.currentTarget=this.target=b;this.defaultPrevented=this.ea=!1;this.Ob=!0};H.prototype.preventDefault=function(){this.defaultPrevented=!0;this.Ob=!1};var Za=function(a){Za[" "](a);return a};Za[" "]=ba;var I;a:{var $a=k.navigator;if($a){var ab=$a.userAgent;if(ab){I=ab;break a}}I=""}var J=function(a){return-1!=I.indexOf(a)};var bb=J("Opera")||J("OPR"),K=J("Trident")||J("MSIE"),cb=J("Edge"),db=J("Gecko")&&!(-1!=I.toLowerCase().indexOf("webkit")&&!J("Edge"))&&!(J("Trident")||J("MSIE"))&&!J("Edge"),eb=-1!=I.toLowerCase().indexOf("webkit")&&!J("Edge"),fb=function(){var a=k.document;return a?a.documentMode:void 0},gb;
+a:{var hb="",ib=function(){var a=I;if(db)return/rv\:([^\);]+)(\)|;)/.exec(a);if(cb)return/Edge\/([\d\.]+)/.exec(a);if(K)return/\b(?:MSIE|rv)[: ]([^\);]+)(\)|;)/.exec(a);if(eb)return/WebKit\/(\S+)/.exec(a);if(bb)return/(?:Version)[ \/]?(\S+)/.exec(a)}();ib&&(hb=ib?ib[1]:"");if(K){var jb=fb();if(null!=jb&&jb>parseFloat(hb)){gb=String(jb);break a}}gb=hb}
+var kb=gb,lb={},L=function(a){var b;if(!(b=lb[a])){b=0;for(var c=ia(String(kb)).split("."),d=ia(String(a)).split("."),e=Math.max(c.length,d.length),f=0;0==b&&f<e;f++){var g=c[f]||"",l=d[f]||"",x=/(\d*)(\D*)/g,M=/(\d*)(\D*)/g;do{var V=x.exec(g)||["","",""],W=M.exec(l)||["","",""];if(0==V[0].length&&0==W[0].length)break;b=ka(0==V[1].length?0:parseInt(V[1],10),0==W[1].length?0:parseInt(W[1],10))||ka(0==V[2].length,0==W[2].length)||ka(V[2],W[2])}while(0==b)}b=lb[a]=0<=b}return b},mb=k.document,nb=mb&&
+K?fb()||("CSS1Compat"==mb.compatMode?parseInt(kb,10):5):void 0;var ob=!K||9<=Number(nb),pb=K&&!L("9"),qb=!eb||L("528"),rb=db&&L("1.9b")||K&&L("8")||bb&&L("9.5")||eb&&L("528"),sb=db&&!L("8")||K&&!L("9");var tb=function(a,b){H.call(this,a?a.type:"");this.relatedTarget=this.currentTarget=this.target=null;this.charCode=this.keyCode=this.button=this.screenY=this.screenX=this.clientY=this.clientX=this.offsetY=this.offsetX=0;this.metaKey=this.shiftKey=this.altKey=this.ctrlKey=!1;this.yb=this.state=null;if(a){var c=this.type=a.type,d=a.changedTouches?a.changedTouches[0]:null;this.target=a.target||a.srcElement;this.currentTarget=b;var e=a.relatedTarget;if(e){if(db){var f;a:{try{Za(e.nodeName);f=!0;break a}catch(g){}f=
+!1}f||(e=null)}}else"mouseover"==c?e=a.fromElement:"mouseout"==c&&(e=a.toElement);this.relatedTarget=e;null===d?(this.offsetX=eb||void 0!==a.offsetX?a.offsetX:a.layerX,this.offsetY=eb||void 0!==a.offsetY?a.offsetY:a.layerY,this.clientX=void 0!==a.clientX?a.clientX:a.pageX,this.clientY=void 0!==a.clientY?a.clientY:a.pageY,this.screenX=a.screenX||0,this.screenY=a.screenY||0):(this.clientX=void 0!==d.clientX?d.clientX:d.pageX,this.clientY=void 0!==d.clientY?d.clientY:d.pageY,this.screenX=d.screenX||
+0,this.screenY=d.screenY||0);this.button=a.button;this.keyCode=a.keyCode||0;this.charCode=a.charCode||("keypress"==c?a.keyCode:0);this.ctrlKey=a.ctrlKey;this.altKey=a.altKey;this.shiftKey=a.shiftKey;this.metaKey=a.metaKey;this.state=a.state;this.yb=a;a.defaultPrevented&&this.preventDefault()}};w(tb,H);
+tb.prototype.preventDefault=function(){tb.W.preventDefault.call(this);var a=this.yb;if(a.preventDefault)a.preventDefault();else if(a.returnValue=!1,pb)try{if(a.ctrlKey||112<=a.keyCode&&123>=a.keyCode)a.keyCode=-1}catch(b){}};var ub="closure_listenable_"+(1E6*Math.random()|0),vb=function(a){return!(!a||!a[ub])},wb=0;var xb=function(a,b,c,d,e){this.listener=a;this.proxy=null;this.src=b;this.type=c;this.sa=!!d;this.Aa=e;this.key=++wb;this.removed=this.ra=!1},yb=function(a){a.removed=!0;a.listener=null;a.proxy=null;a.src=null;a.Aa=null};var N=function(a){this.src=a;this.m={};this.na=0};N.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.m[f];a||(a=this.m[f]=[],this.na++);var g=zb(a,b,d,e);-1<g?(b=a[g],c||(b.ra=!1)):(b=new xb(b,this.src,f,!!d,e),b.ra=c,a.push(b));return b};N.prototype.remove=function(a,b,c,d){a=a.toString();if(!(a in this.m))return!1;var e=this.m[a];b=zb(e,b,c,d);return-1<b?(yb(e[b]),Array.prototype.splice.call(e,b,1),0==e.length&&(delete this.m[a],this.na--),!0):!1};
+var Ab=function(a,b){var c=b.type;c in a.m&&ra(a.m[c],b)&&(yb(b),0==a.m[c].length&&(delete a.m[c],a.na--))};N.prototype.removeAll=function(a){a=a&&a.toString();var b=0,c;for(c in this.m)if(!a||c==a){for(var d=this.m[c],e=0;e<d.length;e++)++b,yb(d[e]);delete this.m[c];this.na--}return b};N.prototype.ja=function(a,b,c,d){a=this.m[a.toString()];var e=-1;a&&(e=zb(a,b,c,d));return-1<e?a[e]:null};
+var zb=function(a,b,c,d){for(var e=0;e<a.length;++e){var f=a[e];if(!f.removed&&f.listener==b&&f.sa==!!c&&f.Aa==d)return e}return-1};var Bb="closure_lm_"+(1E6*Math.random()|0),Cb={},Db=0,Eb=function(a,b,c,d,e){if(n(b)){for(var f=0;f<b.length;f++)Eb(a,b[f],c,d,e);return null}c=Fb(c);return vb(a)?a.listen(b,c,d,e):Gb(a,b,c,!1,d,e)},Gb=function(a,b,c,d,e,f){if(!b)throw Error("Invalid event type");var g=!!e,l=Hb(a);l||(a[Bb]=l=new N(a));c=l.add(b,c,d,e,f);if(c.proxy)return c;d=Ib();c.proxy=d;d.src=a;d.listener=c;if(a.addEventListener)a.addEventListener(b.toString(),d,g);else if(a.attachEvent)a.attachEvent(Jb(b.toString()),d);else throw Error("addEventListener and attachEvent are unavailable.");
+Db++;return c},Ib=function(){var a=Kb,b=ob?function(c){return a.call(b.src,b.listener,c)}:function(c){c=a.call(b.src,b.listener,c);if(!c)return c};return b},Lb=function(a,b,c,d,e){if(n(b)){for(var f=0;f<b.length;f++)Lb(a,b[f],c,d,e);return null}c=Fb(c);return vb(a)?a.jb(b,c,d,e):Gb(a,b,c,!0,d,e)},Mb=function(a,b,c,d,e){if(n(b))for(var f=0;f<b.length;f++)Mb(a,b[f],c,d,e);else c=Fb(c),vb(a)?a.pb(b,c,d,e):a&&(a=Hb(a))&&(b=a.ja(b,c,!!d,e))&&Nb(b)},Nb=function(a){if(!ea(a)&&a&&!a.removed){var b=a.src;
+if(vb(b))Ab(b.J,a);else{var c=a.type,d=a.proxy;b.removeEventListener?b.removeEventListener(c,d,a.sa):b.detachEvent&&b.detachEvent(Jb(c),d);Db--;(c=Hb(b))?(Ab(c,a),0==c.na&&(c.src=null,b[Bb]=null)):yb(a)}}},Jb=function(a){return a in Cb?Cb[a]:Cb[a]="on"+a},Qb=function(a,b,c,d){var e=!0;if(a=Hb(a))if(b=a.m[b.toString()])for(b=b.concat(),a=0;a<b.length;a++){var f=b[a];f&&f.sa==c&&!f.removed&&(f=Ob(f,d),e=e&&!1!==f)}return e},Ob=function(a,b){var c=a.listener,d=a.Aa||a.src;a.ra&&Nb(a);return c.call(d,
+b)},Kb=function(a,b){if(a.removed)return!0;if(!ob){var c;if(!(c=b))a:{c=["window","event"];for(var d=k,e;e=c.shift();)if(null!=d[e])d=d[e];else{c=null;break a}c=d}e=c;c=new tb(e,this);d=!0;if(!(0>e.keyCode||void 0!=e.returnValue)){a:{var f=!1;if(0==e.keyCode)try{e.keyCode=-1;break a}catch(x){f=!0}if(f||void 0==e.returnValue)e.returnValue=!0}e=[];for(f=c.currentTarget;f;f=f.parentNode)e.push(f);for(var f=a.type,g=e.length-1;!c.ea&&0<=g;g--){c.currentTarget=e[g];var l=Qb(e[g],f,!0,c),d=d&&l}for(g=0;!c.ea&&
+g<e.length;g++)c.currentTarget=e[g],l=Qb(e[g],f,!1,c),d=d&&l}return d}return Ob(a,new tb(b,this))},Hb=function(a){a=a[Bb];return a instanceof N?a:null},Rb="__closure_events_fn_"+(1E9*Math.random()>>>0),Fb=function(a){if(q(a))return a;a[Rb]||(a[Rb]=function(b){return a.handleEvent(b)});return a[Rb]};var O=function(){G.call(this);this.J=new N(this);this.Zb=this;this.lb=null};w(O,G);O.prototype[ub]=!0;h=O.prototype;h.addEventListener=function(a,b,c,d){Eb(this,a,b,c,d)};h.removeEventListener=function(a,b,c,d){Mb(this,a,b,c,d)};
+h.dispatchEvent=function(a){var b,c=this.lb;if(c){b=[];for(var d=1;c;c=c.lb)b.push(c),++d}c=this.Zb;d=a.type||a;if(p(a))a=new H(a,c);else if(a instanceof H)a.target=a.target||c;else{var e=a;a=new H(d,c);Ca(a,e)}var e=!0,f;if(b)for(var g=b.length-1;!a.ea&&0<=g;g--)f=a.currentTarget=b[g],e=Sb(f,d,!0,a)&&e;a.ea||(f=a.currentTarget=c,e=Sb(f,d,!0,a)&&e,a.ea||(e=Sb(f,d,!1,a)&&e));if(b)for(g=0;!a.ea&&g<b.length;g++)f=a.currentTarget=b[g],e=Sb(f,d,!1,a)&&e;return e};
+h.A=function(){O.W.A.call(this);this.J&&this.J.removeAll(void 0);this.lb=null};h.listen=function(a,b,c,d){return this.J.add(String(a),b,!1,c,d)};h.jb=function(a,b,c,d){return this.J.add(String(a),b,!0,c,d)};h.pb=function(a,b,c,d){return this.J.remove(String(a),b,c,d)};var Sb=function(a,b,c,d){b=a.J.m[String(b)];if(!b)return!0;b=b.concat();for(var e=!0,f=0;f<b.length;++f){var g=b[f];if(g&&!g.removed&&g.sa==c){var l=g.listener,x=g.Aa||g.src;g.ra&&Ab(a.J,g);e=!1!==l.call(x,d)&&e}}return e&&0!=d.Ob};
+O.prototype.ja=function(a,b,c,d){return this.J.ja(String(a),b,c,d)};var Tb=function(a,b,c){this.Ac=c;this.kc=a;this.Oc=b;this.Ja=0;this.Ba=null};Tb.prototype.get=function(){var a;0<this.Ja?(this.Ja--,a=this.Ba,this.Ba=a.next,a.next=null):a=this.kc();return a};Tb.prototype.put=function(a){this.Oc(a);this.Ja<this.Ac&&(this.Ja++,a.next=this.Ba,this.Ba=a)};var Ub=function(a){k.setTimeout(function(){throw a;},0)},Vb,Wb=function(){var a=k.MessageChannel;"undefined"===typeof a&&"undefined"!==typeof window&&window.postMessage&&window.addEventListener&&!J("Presto")&&(a=function(){var a=document.createElement("IFRAME");a.style.display="none";a.src="";document.documentElement.appendChild(a);var b=a.contentWindow,a=b.document;a.open();a.write("");a.close();var c="callImmediate"+Math.random(),d="file:"==b.location.protocol?"*":b.location.protocol+"//"+b.location.host,
+a=t(function(a){if(("*"==d||a.origin==d)&&a.data==c)this.port1.onmessage()},this);b.addEventListener("message",a,!1);this.port1={};this.port2={postMessage:function(){b.postMessage(c,d)}}});if("undefined"!==typeof a&&!J("Trident")&&!J("MSIE")){var b=new a,c={},d=c;b.port1.onmessage=function(){if(m(c.next)){c=c.next;var a=c.ub;c.ub=null;a()}};return function(a){d.next={ub:a};d=d.next;b.port2.postMessage(0)}}return"undefined"!==typeof document&&"onreadystatechange"in document.createElement("SCRIPT")?
+function(a){var b=document.createElement("SCRIPT");b.onreadystatechange=function(){b.onreadystatechange=null;b.parentNode.removeChild(b);b=null;a();a=null};document.documentElement.appendChild(b)}:function(a){k.setTimeout(a,0)}};var Xb=function(){this.Ra=this.ga=null},Zb=new Tb(function(){return new Yb},function(a){a.reset()},100);Xb.prototype.add=function(a,b){var c=Zb.get();c.set(a,b);this.Ra?this.Ra.next=c:this.ga=c;this.Ra=c};Xb.prototype.remove=function(){var a=null;this.ga&&(a=this.ga,this.ga=this.ga.next,this.ga||(this.Ra=null),a.next=null);return a};var Yb=function(){this.next=this.scope=this.bb=null};Yb.prototype.set=function(a,b){this.bb=a;this.scope=b;this.next=null};
+Yb.prototype.reset=function(){this.next=this.scope=this.bb=null};var dc=function(a,b){$b||ac();bc||($b(),bc=!0);cc.add(a,b)},$b,ac=function(){if(k.Promise&&k.Promise.resolve){var a=k.Promise.resolve(void 0);$b=function(){a.then(ec)}}else $b=function(){var a=ec;!q(k.setImmediate)||k.Window&&k.Window.prototype&&!J("Edge")&&k.Window.prototype.setImmediate==k.setImmediate?(Vb||(Vb=Wb()),Vb(a)):k.setImmediate(a)}},bc=!1,cc=new Xb,ec=function(){for(var a=null;a=cc.remove();){try{a.bb.call(a.scope)}catch(b){Ub(b)}Zb.put(a)}bc=!1};var fc=function(a){a.prototype.then=a.prototype.then;a.prototype.$goog_Thenable=!0},gc=function(a){if(!a)return!1;try{return!!a.$goog_Thenable}catch(b){return!1}};var P=function(a,b){this.C=0;this.M=void 0;this.Z=this.O=this.o=null;this.za=this.ab=!1;if(a!=ba)try{var c=this;a.call(b,function(a){hc(c,2,a)},function(a){hc(c,3,a)})}catch(d){hc(this,3,d)}},ic=function(){this.next=this.context=this.ca=this.la=this.T=null;this.pa=!1};ic.prototype.reset=function(){this.context=this.ca=this.la=this.T=null;this.pa=!1};var jc=new Tb(function(){return new ic},function(a){a.reset()},100),kc=function(a,b,c){var d=jc.get();d.la=a;d.ca=b;d.context=c;return d};
+P.prototype.then=function(a,b,c){return lc(this,q(a)?a:null,q(b)?b:null,c)};fc(P);P.prototype.cancel=function(a){0==this.C&&dc(function(){var b=new mc(a);nc(this,b)},this)};
+var nc=function(a,b){if(0==a.C)if(a.o){var c=a.o;if(c.O){for(var d=0,e=null,f=null,g=c.O;g&&(g.pa||(d++,g.T==a&&(e=g),!(e&&1<d)));g=g.next)e||(f=g);e&&(0==c.C&&1==d?nc(c,b):(f?(d=f,d.next==c.Z&&(c.Z=d),d.next=d.next.next):oc(c),pc(c,e,3,b)))}a.o=null}else hc(a,3,b)},rc=function(a,b){a.O||2!=a.C&&3!=a.C||qc(a);a.Z?a.Z.next=b:a.O=b;a.Z=b},lc=function(a,b,c,d){var e=kc(null,null,null);e.T=new P(function(a,g){e.la=b?function(c){try{var e=b.call(d,c);a(e)}catch(M){g(M)}}:a;e.ca=c?function(b){try{var e=
+c.call(d,b);!m(e)&&b instanceof mc?g(b):a(e)}catch(M){g(M)}}:g});e.T.o=a;rc(a,e);return e.T};P.prototype.ed=function(a){this.C=0;hc(this,2,a)};P.prototype.fd=function(a){this.C=0;hc(this,3,a)};
+var hc=function(a,b,c){if(0==a.C){a==c&&(b=3,c=new TypeError("Promise cannot resolve to itself"));a.C=1;var d;a:{var e=c,f=a.ed,g=a.fd;if(e instanceof P)rc(e,kc(f||ba,g||null,a)),d=!0;else if(gc(e))e.then(f,g,a),d=!0;else{if(r(e))try{var l=e.then;if(q(l)){sc(e,l,f,g,a);d=!0;break a}}catch(x){g.call(a,x);d=!0;break a}d=!1}}d||(a.M=c,a.C=b,a.o=null,qc(a),3!=b||c instanceof mc||tc(a,c))}},sc=function(a,b,c,d,e){var f=!1,g=function(a){f||(f=!0,c.call(e,a))},l=function(a){f||(f=!0,d.call(e,a))};try{b.call(a,
+g,l)}catch(x){l(x)}},qc=function(a){a.ab||(a.ab=!0,dc(a.nc,a))},oc=function(a){var b=null;a.O&&(b=a.O,a.O=b.next,b.next=null);a.O||(a.Z=null);return b};P.prototype.nc=function(){for(var a=null;a=oc(this);)pc(this,a,this.C,this.M);this.ab=!1};
+var pc=function(a,b,c,d){if(3==c&&b.ca&&!b.pa)for(;a&&a.za;a=a.o)a.za=!1;if(b.T)b.T.o=null,uc(b,c,d);else try{b.pa?b.la.call(b.context):uc(b,c,d)}catch(e){vc.call(null,e)}jc.put(b)},uc=function(a,b,c){2==b?a.la.call(a.context,c):a.ca&&a.ca.call(a.context,c)},tc=function(a,b){a.za=!0;dc(function(){a.za&&vc.call(null,b)})},vc=Ub,mc=function(a){y.call(this,a)};w(mc,y);mc.prototype.name="cancel";/*
+ Portions of this code are from MochiKit, received by
+ The Closure Authors under the MIT license. All other code is Copyright
+ 2005-2009 The Closure Authors. All Rights Reserved.
+*/
+var Q=function(a,b){this.Ma=[];this.Ib=a;this.xb=b||null;this.ka=this.K=!1;this.M=void 0;this.nb=this.dc=this.Ua=!1;this.Pa=0;this.o=null;this.Wa=0};Q.prototype.cancel=function(a){if(this.K)this.M instanceof Q&&this.M.cancel();else{if(this.o){var b=this.o;delete this.o;a?b.cancel(a):(b.Wa--,0>=b.Wa&&b.cancel())}this.Ib?this.Ib.call(this.xb,this):this.nb=!0;this.K||this.I(new wc)}};Q.prototype.wb=function(a,b){this.Ua=!1;xc(this,a,b)};
+var xc=function(a,b,c){a.K=!0;a.M=c;a.ka=!b;yc(a)},Ac=function(a){if(a.K){if(!a.nb)throw new zc;a.nb=!1}};Q.prototype.G=function(a){Ac(this);xc(this,!0,a)};Q.prototype.I=function(a){Ac(this);xc(this,!1,a)};Q.prototype.w=function(a,b){return Bc(this,a,null,b)};var Bc=function(a,b,c,d){a.Ma.push([b,c,d]);a.K&&yc(a);return a};Q.prototype.then=function(a,b,c){var d,e,f=new P(function(a,b){d=a;e=b});Bc(this,d,function(a){a instanceof wc?f.cancel():e(a)});return f.then(a,b,c)};fc(Q);
+var Cc=function(a){var b=new Q;Bc(a,b.G,b.I,b);return b},Dc=function(a){return na(a.Ma,function(a){return q(a[1])})},yc=function(a){if(a.Pa&&a.K&&Dc(a)){var b=a.Pa,c=Ec[b];c&&(k.clearTimeout(c.Ca),delete Ec[b]);a.Pa=0}a.o&&(a.o.Wa--,delete a.o);for(var b=a.M,d=c=!1;a.Ma.length&&!a.Ua;){var e=a.Ma.shift(),f=e[0],g=e[1],e=e[2];if(f=a.ka?g:f)try{var l=f.call(e||a.xb,b);m(l)&&(a.ka=a.ka&&(l==b||l instanceof Error),a.M=b=l);if(gc(b)||"function"===typeof k.Promise&&b instanceof k.Promise)d=!0,a.Ua=!0}catch(x){b=
+x,a.ka=!0,Dc(a)||(c=!0)}}a.M=b;d&&(l=t(a.wb,a,!0),d=t(a.wb,a,!1),b instanceof Q?(Bc(b,l,d),b.dc=!0):b.then(l,d));c&&(b=new Fc(b),Ec[b.Ca]=b,a.Pa=b.Ca)},Gc=function(a){var b=new Q;b.G(a);return b},Ic=function(){var a=Hc,b=new Q;b.I(a);return b},zc=function(){y.call(this)};w(zc,y);zc.prototype.message="Deferred has already fired";zc.prototype.name="AlreadyCalledError";var wc=function(){y.call(this)};w(wc,y);wc.prototype.message="Deferred was canceled";wc.prototype.name="CanceledError";
+var Fc=function(a){this.Ca=k.setTimeout(t(this.ad,this),0);this.va=a};Fc.prototype.ad=function(){delete Ec[this.Ca];throw this.va;};var Ec={};var Jc=function(a){this.ya=[];this.h=a};Jc.prototype.Y=function(a){if(!q(a))throw Error("Invalid filter. Must be a function.");this.ya.push(a)};Jc.prototype.send=function(a,b){if(0==this.ya.length)return this.h.send(a,b);var c=new R(a,b);return Kc(this,0,c).w(function(){if(!c.Ya)return this.h.send(a,b)},this)};var Kc=function(a,b,c){return Gc().w(function(){return this.ya[b](c)},a).w(function(){if(++b<this.ya.length&&!c.Ya)return Kc(this,b,c)},a)},R=function(a,b){this.dd=a;this.Jc=b;this.Ya=!1};
+R.prototype.Ab=function(){return this.dd};R.prototype.ba=function(){return this.Jc};R.prototype.cancel=function(){this.Ya=!0};var Lc=function(a,b){this.width=a;this.height=b};Lc.prototype.clone=function(){return new Lc(this.width,this.height)};Lc.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};!db&&!K||K&&9<=Number(nb)||db&&L("1.9.1");K&&L("9");var Mc={id:"anonymizeIp",name:"aip",valueType:"boolean",maxLength:void 0,defaultValue:void 0},Nc={id:"apiVersion",name:"v",valueType:"text",maxLength:void 0,defaultValue:void 0},Oc={id:"appName",name:"an",valueType:"text",maxLength:100,defaultValue:void 0},Pc={id:"appVersion",name:"av",valueType:"text",maxLength:100,defaultValue:void 0},Qc={id:"clientId",name:"cid",valueType:"text",maxLength:void 0,defaultValue:void 0},Rc={id:"language",name:"ul",valueType:"text",maxLength:20,defaultValue:void 0},
+Sc={id:"libVersion",name:"_v",valueType:"text",maxLength:void 0,defaultValue:void 0},Tc={id:"sampleRateOverride",name:"usro",valueType:"integer",maxLength:void 0,defaultValue:void 0},Uc={id:"screenColors",name:"sd",valueType:"text",maxLength:20,defaultValue:void 0},Vc={id:"screenResolution",name:"sr",valueType:"text",maxLength:20,defaultValue:void 0},Wc={id:"trackingId",name:"tid",valueType:"text",maxLength:void 0,defaultValue:void 0},Xc={id:"viewportSize",name:"vp",valueType:"text",maxLength:20,
+defaultValue:void 0},Yc={Xb:Mc,kd:Nc,nd:Oc,od:Pc,wd:Qc,Od:Rc,Pd:Sc,Vd:Tc,Wd:Uc,Xd:Vc,je:Wc,qe:Xc},$c=function(a){if(!p(a))return a;var b=Zc(a,Na);if(r(b))return b;b=Zc(a,Yc);if(r(b))return b;b=/^dimension(\d+)$/.exec(a);if(null!==b)return Oa(parseInt(b[1],10));b=/^metric(\d+)$/.exec(a);if(null!==b)return Pa(parseInt(b[1],10));throw Error(a+" is not a valid parameter name.");},Zc=function(a,b){var c=Aa(b,function(b){return b.id==a&&"metric"!=a&&"dimension"!=a});return r(c)?c:null};var S=function(a,b){this.hc=b;this.D=b.cb();this.Mb=new E;this.$b=this.ob=!1};h=S.prototype;h.set=function(a,b){if(null==b)throw Error("Value must be defined and not null. Parameter="+a.id);var c=$c(a);this.Mb.set(c,b)};h.Y=function(a){this.hc.Y(a)};h.send=function(a,b){if(a instanceof F)return a.send(this);var c=this.Mb.clone();b instanceof E?c.addAll(b):r(b)&&wa(b,function(a,b){null!=a&&c.set($c(b),a)},this);this.ob&&(this.ob=!1,c.set(Ha,"start"));this.$b&&c.set(Mc,!0);return this.D.send(a,c)};
+h.Pc=function(a){var b={description:a};this.set(Ia,a);return this.send("appview",b)};h.Qc=function(a,b,c,d){return this.send("event",{eventCategory:a,eventAction:b,eventLabel:c,eventValue:d})};h.Sc=function(a,b,c){return this.send("social",{socialNetwork:a,socialAction:b,socialTarget:c})};h.Rc=function(a,b){return this.send("exception",{exDescription:a,exFatal:b})};h.Pb=function(a,b,c,d,e){return this.send("timing",{timingCategory:a,timingVar:b,timingLabel:d,timingValue:c,sampleRateOverride:e})};
+h.qc=function(){this.ob=!0};h.Zc=function(a,b,c,d){return new ad(this,a,b,c,d)};var ad=function(a,b,c,d,e){this.Vb=a;this.fc=b;this.gd=c;this.yc=d;this.La=e;this.Yc=u()};ad.prototype.send=function(){var a=this.Vb.Pb(this.fc,this.gd,u()-this.Yc,this.yc,this.La);this.Vb=null;return a};var bd=function(a,b,c,d,e){this.zc=a;this.ac=b;this.bc=c;this.j=d;this.gc=e};
+bd.prototype.tc=function(a){var b=new S(0,this.gc.create());b.set(Sc,this.zc);b.set(Nc,1);b.set(Oc,this.ac);b.set(Pc,this.bc);b.set(Wc,a);(a=navigator.language||navigator.browserLanguage)&&b.set(Rc,a);(a=screen.colorDepth+"-bit")&&b.set(Uc,a);(a=[screen.width,screen.height].join("x"))&&b.set(Vc,a);a=window.document;a="CSS1Compat"==a.compatMode?a.documentElement:a.body;a=new Lc(a.clientWidth,a.clientHeight);(a=[a.width,a.height].join("x"))&&b.set(Xc,a);return b};bd.prototype.rc=function(){return Cc(this.j.ma)};var cd=function(a,b,c,d,e,f){Q.call(this,e,f);this.ib=a;this.Za=[];this.zb=!!b;this.pc=!!c;this.jc=!!d;for(b=this.Hb=0;b<a.length;b++)Bc(a[b],t(this.Bb,this,b,!0),t(this.Bb,this,b,!1));0!=a.length||this.zb||this.G(this.Za)};w(cd,Q);cd.prototype.Bb=function(a,b,c){this.Hb++;this.Za[a]=[b,c];this.K||(this.zb&&b?this.G([a,c]):this.pc&&!b?this.I(c):this.Hb==this.ib.length&&this.G(this.Za));this.jc&&!b&&(c=null);return c};cd.prototype.I=function(a){cd.W.I.call(this,a);for(a=0;a<this.ib.length;a++)this.ib[a].cancel()};
+var dd=function(a){return(new cd(a,!1,!0)).w(function(a){for(var c=[],d=0;d<a.length;d++)c[d]=a[d][1];return c})};var ed=function(){for(var a="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".split(""),b=0,c=a.length;b<c;b++)switch(a[b]){case "x":a[b]=Math.floor(16*Math.random()).toString(16);break;case "y":a[b]=(Math.floor(4*Math.random())+8).toString(16)}return a.join("")};var T=function(a){this.R=a;this.La=100;this.vb=[];this.da=this.oa=null;this.ma=fd(this);this.ma.w(function(){this.Qb=Eb(this.R,"a",t(this.uc,this))},this)},fd=function(a){return gd(a).w(function(){return this},a)},gd=function(a){return dd([hd(a),id(a)])};T.prototype.uc=function(){U(this);var a=jd(this),b=this.Fa();gd(this).w(function(){a!=jd(this)&&kd(this,"analytics.user-id");b!=this.Fa()&&kd(this,"analytics.tracking-permitted")},this)};var ld=function(a,b){U(a);a.vb.push(b)};
+T.prototype.Wc=function(a){U(this);var b=this.da!=a;this.da=a;this.R.set("analytics.tracking-permitted",a.toString());b&&kd(this,"analytics.tracking-permitted")};T.prototype.Fa=function(){U(this);var a;if(a=this.da)a=k._gaUserPrefs,a=!(a&&a.ioo&&a.ioo());return a};
+var hd=function(a){return a.R.get("analytics.tracking-permitted").w(function(a){this.da=!0;if(m(a))switch(a){case "true":this.da=!0;break;case "false":this.da=!1}},a)},jd=function(a){U(a);if(!p(a.oa))throw Error("Invalid state. UserID is not a string.");return a.oa},id=function(a){return a.R.get("analytics.user-id").w(function(a){m(a)?this.oa=a:md(this)},a)},md=function(a){a.oa=ed();return a.R.set("analytics.user-id",a.oa).w(function(){kd(this,"analytics.user-id")},a)};
+T.prototype.Vc=function(a){U(this);this.La=a};var nd=function(a){U(a);return a.La};T.prototype.Nc=function(){return md(this)};var kd=function(a,b){ma(a.vb,function(a){a(b)})};T.prototype.ua=function(){null!=this.Qb&&Nb(this.Qb)};var U=function(a){if(!Cc(a.ma).K)throw Error("Settings object accessed prior to entering ready state.");};var od=function(){O.call(this);this.kb="google-analytics";this.R=chrome.storage.local;chrome.storage.onChanged.addListener(t(this.Hc,this))};w(od,O);od.prototype.Hc=function(a,b){"local"==b&&pd(this,a)&&this.dispatchEvent("a")};var pd=function(a,b){return na(ya(b),function(a){return 0==a.lastIndexOf(this.kb,0)},a)};od.prototype.get=function(a){var b=new Q,c=this.kb+"."+a;this.R.get(c,function(a){chrome.runtime.lastError?b.I(chrome.runtime.lastError):(a=a[c],b.G(null!=a?a.toString():void 0))});return b};
+od.prototype.set=function(a,b){var c=new Q,d={};d[this.kb+"."+a]=b;this.R.set(d,function(){chrome.runtime.lastError?c.I(chrome.runtime.lastError):c.G()});return c};var X=function(){};X.sc=function(){return X.Eb?X.Eb:X.Eb=new X};X.prototype.send=function(){return Gc()};var qd=function(a){this.lc=a};qd.prototype.send=function(a,b){this.lc.push({wc:a,Ic:b});return Gc()};var rd=function(a,b,c){this.j=a;this.aa=[];this.S={enabled:new qd(this.aa),disabled:c};this.D=this.S.enabled;Bc(Cc(this.j.ma),ha(this.Gc,b),this.Fc,this)};rd.prototype.Gc=function(a){if(null===this.aa)throw Error("Channel setup already completed.");this.S.enabled=a();sd(this);ma(this.aa,function(a){this.send(a.wc,a.Ic)},this);this.aa=null;ld(this.j,t(this.Ec,this))};
+rd.prototype.Fc=function(){if(null===this.aa)throw Error("Channel setup already completed.");this.D=this.S.enabled=this.S.disabled;this.aa=null};rd.prototype.send=function(a,b){return this.D.send(a,b)};var sd=function(a){a.D=a.j.Fa()?a.S.enabled:a.S.disabled};rd.prototype.Ec=function(a){switch(a){case "analytics.tracking-permitted":sd(this)}};var td=function(a,b){this.Xa=[];var c=t(function(){this.xa=new Jc(b.cb());ma(this.Xa,function(a){this.xa.Y(a)},this);this.Xa=null;return this.xa},this);this.D=new rd(a,c,X.sc())};td.prototype.cb=function(){return this.D};td.prototype.Y=function(a){this.xa?this.xa.Y(a):this.Xa.push(a)};var ud=function(a,b){this.j=a;this.Xc=b};ud.prototype.create=function(){return new td(this.j,this.Xc)};var vd=function(a,b){O.call(this);this.Ea=a||1;this.fa=b||k;this.Va=t(this.bd,this);this.hb=u()};w(vd,O);h=vd.prototype;h.enabled=!1;h.l=null;h.bd=function(){if(this.enabled){var a=u()-this.hb;0<a&&a<.8*this.Ea?this.l=this.fa.setTimeout(this.Va,this.Ea-a):(this.l&&(this.fa.clearTimeout(this.l),this.l=null),this.dispatchEvent("tick"),this.enabled&&(this.l=this.fa.setTimeout(this.Va,this.Ea),this.hb=u()))}};
+h.start=function(){this.enabled=!0;this.l||(this.l=this.fa.setTimeout(this.Va,this.Ea),this.hb=u())};h.stop=function(){this.enabled=!1;this.l&&(this.fa.clearTimeout(this.l),this.l=null)};h.A=function(){vd.W.A.call(this);this.stop();delete this.fa};var wd=function(a,b,c){if(q(a))c&&(a=t(a,c));else if(a&&"function"==typeof a.handleEvent)a=t(a.handleEvent,a);else throw Error("Invalid listener argument");return 2147483647<Number(b)?-1:k.setTimeout(a,b||0)};var Y=function(a){G.call(this);this.eb=a;this.b={}};w(Y,G);var xd=[];Y.prototype.listen=function(a,b,c,d){n(b)||(b&&(xd[0]=b.toString()),b=xd);for(var e=0;e<b.length;e++){var f=Eb(a,b[e],c||this.handleEvent,d||!1,this.eb||this);if(!f)break;this.b[f.key]=f}return this};Y.prototype.jb=function(a,b,c,d){return yd(this,a,b,c,d)};var yd=function(a,b,c,d,e,f){if(n(c))for(var g=0;g<c.length;g++)yd(a,b,c[g],d,e,f);else{b=Lb(b,c,d||a.handleEvent,e,f||a.eb||a);if(!b)return a;a.b[b.key]=b}return a};
+Y.prototype.pb=function(a,b,c,d,e){if(n(b))for(var f=0;f<b.length;f++)this.pb(a,b[f],c,d,e);else c=c||this.handleEvent,e=e||this.eb||this,c=Fb(c),d=!!d,b=vb(a)?a.ja(b,c,d,e):a?(a=Hb(a))?a.ja(b,c,d,e):null:null,b&&(Nb(b),delete this.b[b.key]);return this};Y.prototype.removeAll=function(){wa(this.b,function(a,b){this.b.hasOwnProperty(b)&&Nb(a)},this);this.b={}};Y.prototype.A=function(){Y.W.A.call(this);this.removeAll()};
+Y.prototype.handleEvent=function(){throw Error("EventHandler.handleEvent not implemented");};var zd=function(){O.call(this);this.wa=new Y(this);qb&&(rb?this.wa.listen(sb?document.body:window,["online","offline"],this.Cb):(this.Lb=qb?navigator.onLine:!0,this.l=new vd(250),this.wa.listen(this.l,"tick",this.vc),this.l.start()))};w(zd,O);zd.prototype.vc=function(){var a=qb?navigator.onLine:!0;a!=this.Lb&&(this.Lb=a,this.Cb())};zd.prototype.Cb=function(){this.dispatchEvent((qb?navigator.onLine:1)?"online":"offline")};
+zd.prototype.A=function(){zd.W.A.call(this);this.wa.ua();this.wa=null;this.l&&(this.l.ua(),this.l=null)};var Ad=function(a,b){this.j=a;this.h=b};Ad.prototype.send=function(a,b){b.set(Qc,jd(this.j));return this.h.send(a,b)};var Bd=function(a){this.h=a};Bd.prototype.send=function(a,b){Cd(b);Dd(b);return this.h.send(a,b)};var Cd=function(a){Xa(a,function(b,c){m(b.maxLength)&&"text"==b.valueType&&0<b.maxLength&&c.length>b.maxLength&&a.set(b,c.substring(0,b.maxLength))})},Dd=function(a){Xa(a,function(b,c){m(b.defaultValue)&&c==b.defaultValue&&a.remove(b)})};var Hc={status:"device-offline",ta:void 0},Ed={status:"rate-limited",ta:void 0},Fd={status:"sampled-out",ta:void 0},Gd={status:"sent",ta:void 0};var Hd=function(a,b){this.cd=a;this.h=b};Hd.prototype.send=function(a,b){var c;c=this.cd;var d=c.Sb(),e=Math.floor((d-c.Gb)*c.oc);0<e&&(c.ha=Math.min(c.ha+e,c.Bc),c.Gb=d);1>c.ha?c=!1:(--c.ha,c=!0);return c||"item"==a||"transaction"==a?this.h.send(a,b):Gc(Ed)};var Id=function(){this.ha=60;this.Bc=500;this.oc=5E-4;this.Sb=function(){return(new Date).getTime()};this.Gb=this.Sb()};var Jd=function(a,b){this.j=a;this.h=b};Jd.prototype.send=function(a,b){var c=b.get(Qc),c=parseInt(c.split("-")[1],16),d;"timing"!=a?d=nd(this.j):((d=b.get(Tc))&&b.remove(Tc),d=d||nd(this.j));return c<655.36*d?this.h.send(a,b):Gc(Fd)};var Kd=/^(?:([^:/?#.]+):)?(?:\/\/(?:([^/?#]*)@)?([^/#?]*?)(?::([0-9]+))?(?=[/#?]|$))?([^?#]+)?(?:\?([^#]*))?(?:#(.*))?$/,Ld=function(a,b){if(a)for(var c=a.split("&"),d=0;d<c.length;d++){var e=c[d].indexOf("="),f=null,g=null;0<=e?(f=c[d].substring(0,e),g=c[d].substring(e+1)):f=c[d];b(f,g?decodeURIComponent(g.replace(/\+/g," ")):"")}};var Md=function(){};Md.prototype.tb=null;var Od=function(a){var b;(b=a.tb)||(b={},Nd(a)&&(b[0]=!0,b[1]=!0),b=a.tb=b);return b};var Pd,Qd=function(){};w(Qd,Md);var Rd=function(a){return(a=Nd(a))?new ActiveXObject(a):new XMLHttpRequest},Nd=function(a){if(!a.Db&&"undefined"==typeof XMLHttpRequest&&"undefined"!=typeof ActiveXObject){for(var b=["MSXML2.XMLHTTP.6.0","MSXML2.XMLHTTP.3.0","MSXML2.XMLHTTP","Microsoft.XMLHTTP"],c=0;c<b.length;c++){var d=b[c];try{return new ActiveXObject(d),a.Db=d}catch(e){}}throw Error("Could not create ActiveXObject. ActiveX might be disabled, or MSXML might not be installed");}return a.Db};Pd=new Qd;var Z=function(a){O.call(this);this.headers=new z;this.Ta=a||null;this.N=!1;this.Sa=this.a=null;this.Ha=this.gb="";this.V=this.fb=this.Da=this.$a=!1;this.Oa=0;this.Na=null;this.Nb="";this.qb=this.Lc=this.jd=!1};w(Z,O);var Sd=/^https?$/i,Td=["POST","PUT"],Ud=[],Vd=function(a,b,c){var d=new Z;Ud.push(d);b&&d.listen("complete",b);d.jb("ready",d.ic);d.send(a,"POST",c,void 0)};Z.prototype.ic=function(){this.ua();ra(Ud,this)};
+Z.prototype.send=function(a,b,c,d){if(this.a)throw Error("[goog.net.XhrIo] Object is active with another request="+this.gb+"; newUri="+a);b=b?b.toUpperCase():"GET";this.gb=a;this.Ha="";this.$a=!1;this.N=!0;this.a=this.Ta?Rd(this.Ta):Rd(Pd);this.Sa=this.Ta?Od(this.Ta):Od(Pd);this.a.onreadystatechange=t(this.Kb,this);this.Lc&&"onprogress"in this.a&&(this.a.onprogress=t(function(a){this.Jb(a,!0)},this),this.a.upload&&(this.a.upload.onprogress=t(this.Jb,this)));try{this.fb=!0,this.a.open(b,String(a),
+!0),this.fb=!1}catch(f){this.va(5,f);return}a=c||"";var e=this.headers.clone();d&&Wa(d,function(a,b){e.set(b,a)});d=qa(e.L());c=k.FormData&&a instanceof k.FormData;!(0<=la(Td,b))||d||c||e.set("Content-Type","application/x-www-form-urlencoded;charset=utf-8");e.forEach(function(a,b){this.a.setRequestHeader(b,a)},this);this.Nb&&(this.a.responseType=this.Nb);za(this.a)&&(this.a.withCredentials=this.jd);try{Wd(this),0<this.Oa&&((this.qb=Xd(this.a))?(this.a.timeout=this.Oa,this.a.ontimeout=t(this.Tb,this)):
+this.Na=wd(this.Tb,this.Oa,this)),this.Da=!0,this.a.send(a),this.Da=!1}catch(f){this.va(5,f)}};var Xd=function(a){return K&&L(9)&&ea(a.timeout)&&m(a.ontimeout)},pa=function(a){return"content-type"==a.toLowerCase()};Z.prototype.Tb=function(){"undefined"!=typeof aa&&this.a&&(this.Ha="Timed out after "+this.Oa+"ms, aborting",this.dispatchEvent("timeout"),this.abort(8))};Z.prototype.va=function(a,b){this.N=!1;this.a&&(this.V=!0,this.a.abort(),this.V=!1);this.Ha=b;Yd(this);Zd(this)};
+var Yd=function(a){a.$a||(a.$a=!0,a.dispatchEvent("complete"),a.dispatchEvent("error"))};Z.prototype.abort=function(){this.a&&this.N&&(this.N=!1,this.V=!0,this.a.abort(),this.V=!1,this.dispatchEvent("complete"),this.dispatchEvent("abort"),Zd(this))};Z.prototype.A=function(){this.a&&(this.N&&(this.N=!1,this.V=!0,this.a.abort(),this.V=!1),Zd(this,!0));Z.W.A.call(this)};Z.prototype.Kb=function(){this.ia||(this.fb||this.Da||this.V?$d(this):this.Dc())};Z.prototype.Dc=function(){$d(this)};
+var $d=function(a){if(a.N&&"undefined"!=typeof aa&&(!a.Sa[1]||4!=ae(a)||2!=be(a)))if(a.Da&&4==ae(a))wd(a.Kb,0,a);else if(a.dispatchEvent("readystatechange"),4==ae(a)){a.N=!1;try{var b=be(a),c;a:switch(b){case 200:case 201:case 202:case 204:case 206:case 304:case 1223:c=!0;break a;default:c=!1}var d;if(!(d=c)){var e;if(e=0===b){var f=String(a.gb).match(Kd)[1]||null;if(!f&&k.self&&k.self.location)var g=k.self.location.protocol,f=g.substr(0,g.length-1);e=!Sd.test(f?f.toLowerCase():"")}d=e}if(d)a.dispatchEvent("complete"),
+a.dispatchEvent("success");else{var l;try{l=2<ae(a)?a.a.statusText:""}catch(x){l=""}a.Ha=l+" ["+be(a)+"]";Yd(a)}}finally{Zd(a)}}};Z.prototype.Jb=function(a,b){this.dispatchEvent(ce(a,"progress"));this.dispatchEvent(ce(a,b?"downloadprogress":"uploadprogress"))};
+var ce=function(a,b){return{type:b,lengthComputable:a.lengthComputable,loaded:a.loaded,total:a.total}},Zd=function(a,b){if(a.a){Wd(a);var c=a.a,d=a.Sa[0]?ba:null;a.a=null;a.Sa=null;b||a.dispatchEvent("ready");try{c.onreadystatechange=d}catch(e){}}},Wd=function(a){a.a&&a.qb&&(a.a.ontimeout=null);ea(a.Na)&&(k.clearTimeout(a.Na),a.Na=null)},ae=function(a){return a.a?a.a.readyState:0},be=function(a){try{return 2<ae(a)?a.a.status:-1}catch(b){return-1}};var de=function(a,b,c){this.g=this.c=null;this.F=a||null;this.xc=!!c},ee=function(a){a.c||(a.c=new z,a.g=0,a.F&&Ld(a.F,function(b,c){a.add(decodeURIComponent(b.replace(/\+/g," ")),c)}))};h=de.prototype;h.add=function(a,b){ee(this);this.F=null;a=fe(this,a);var c=this.c.get(a);c||this.c.set(a,c=[]);c.push(b);this.g+=1;return this};h.remove=function(a){ee(this);a=fe(this,a);return this.c.$(a)?(this.F=null,this.g-=this.c.get(a).length,this.c.remove(a)):!1};h.$=function(a){ee(this);a=fe(this,a);return this.c.$(a)};
+h.L=function(){ee(this);for(var a=this.c.v(),b=this.c.L(),c=[],d=0;d<b.length;d++)for(var e=a[d],f=0;f<e.length;f++)c.push(b[d]);return c};h.v=function(a){ee(this);var b=[];if(p(a))this.$(a)&&(b=sa(b,this.c.get(fe(this,a))));else{a=this.c.v();for(var c=0;c<a.length;c++)b=sa(b,a[c])}return b};h.set=function(a,b){ee(this);this.F=null;a=fe(this,a);this.$(a)&&(this.g-=this.c.get(a).length);this.c.set(a,[b]);this.g+=1;return this};
+h.get=function(a,b){var c=a?this.v(a):[];return 0<c.length?String(c[0]):b};h.toString=function(){if(this.F)return this.F;if(!this.c)return"";for(var a=[],b=this.c.L(),c=0;c<b.length;c++)for(var d=b[c],e=encodeURIComponent(String(d)),d=this.v(d),f=0;f<d.length;f++){var g=e;""!==d[f]&&(g+="="+encodeURIComponent(String(d[f])));a.push(g)}return this.F=a.join("&")};h.clone=function(){var a=new de;a.F=this.F;this.c&&(a.c=this.c.clone(),a.g=this.g);return a};
+var fe=function(a,b){var c=String(b);a.xc&&(c=c.toLowerCase());return c};var ge=function(a,b){this.Uc=a;this.Ia=b};ge.prototype.send=function(a,b){if(qb&&!navigator.onLine)return Ic();var c=new Q,d=he(a,b);d.length>this.Ia?c.I({status:"payload-too-big",ta:Ua("Encoded hit length == %s, but should be <= %s.",d.length,this.Ia)}):Vd(this.Uc,function(){c.G(Gd)},d);return c};var he=function(a,b){var c=new de;c.add(Ga.name,a);Xa(b,function(a,b){c.add(a.name,b.toString())});return c.toString()};var ie=function(a,b,c){this.j=a;this.Tc=b;this.Ia=c};ie.prototype.cb=function(){if(!this.D){if(!Cc(this.j.ma).K)throw Error("Cannot construct shared channel prior to settings being ready.");new zd;var a=new Bd(new ge(this.Tc,this.Ia)),b=new Id;this.D=new Ad(this.j,new Jd(this.j,new Hd(b,a)))}return this.D};var je=new z,ke=function(){Ea||(Ea=new T(new od));return Ea};v("goog.async.Deferred",Q);v("goog.async.Deferred.prototype.addCallback",Q.prototype.w);v("goog.async.Deferred.prototype.callback",Q.prototype.G);v("goog.async.Deferred.prototype.then",Q.prototype.then);v("goog.events.EventTarget",O);v("goog.events.EventTarget.prototype.listen",O.prototype.listen);
+v("analytics.getService",function(a,b){var c=je.get(a,null),d=b||chrome.runtime.getManifest().version;if(null===c){c=ke();if(!Fa){var e=ke();Fa=new ud(e,new ie(e,"https://www.google-analytics.com/collect",8192))}c=new bd("ca1.6.0",a,d,c,Fa);je.set(a,c)}return c});v("analytics.internal.GoogleAnalyticsService",bd);v("analytics.internal.GoogleAnalyticsService.prototype.getTracker",bd.prototype.tc);v("analytics.internal.GoogleAnalyticsService.prototype.getConfig",bd.prototype.rc);
+v("analytics.internal.ServiceSettings",T);v("analytics.internal.ServiceSettings.prototype.setTrackingPermitted",T.prototype.Wc);v("analytics.internal.ServiceSettings.prototype.isTrackingPermitted",T.prototype.Fa);v("analytics.internal.ServiceSettings.prototype.setSampleRate",T.prototype.Vc);v("analytics.internal.ServiceSettings.prototype.resetUserId",T.prototype.Nc);v("analytics.internal.ServiceTracker",S);v("analytics.internal.ServiceTracker.prototype.send",S.prototype.send);
+v("analytics.internal.ServiceTracker.prototype.sendAppView",S.prototype.Pc);v("analytics.internal.ServiceTracker.prototype.sendEvent",S.prototype.Qc);v("analytics.internal.ServiceTracker.prototype.sendSocial",S.prototype.Sc);v("analytics.internal.ServiceTracker.prototype.sendException",S.prototype.Rc);v("analytics.internal.ServiceTracker.prototype.sendTiming",S.prototype.Pb);v("analytics.internal.ServiceTracker.prototype.startTiming",S.prototype.Zc);v("analytics.internal.ServiceTracker.Timing",ad);
+v("analytics.internal.ServiceTracker.Timing.prototype.send",ad.prototype.send);v("analytics.internal.ServiceTracker.prototype.forceSessionStart",S.prototype.qc);v("analytics.internal.ServiceTracker.prototype.addFilter",S.prototype.Y);v("analytics.internal.FilterChannel.Hit",R);v("analytics.internal.FilterChannel.Hit.prototype.getHitType",R.prototype.Ab);v("analytics.internal.FilterChannel.Hit.prototype.getParameters",R.prototype.ba);v("analytics.internal.FilterChannel.Hit.prototype.cancel",R.prototype.cancel);
+v("analytics.ParameterMap",E);v("analytics.ParameterMap.Entry",E.Entry);v("analytics.ParameterMap.prototype.set",E.prototype.set);v("analytics.ParameterMap.prototype.get",E.prototype.get);v("analytics.ParameterMap.prototype.remove",E.prototype.remove);v("analytics.ParameterMap.prototype.toObject",E.prototype.Ub);v("analytics.HitTypes.APPVIEW","appview");v("analytics.HitTypes.EVENT","event");v("analytics.HitTypes.SOCIAL","social");v("analytics.HitTypes.TRANSACTION","transaction");
+v("analytics.HitTypes.ITEM","item");v("analytics.HitTypes.TIMING","timing");v("analytics.HitTypes.EXCEPTION","exception");v("analytics.createDimensionParam",Oa);v("analytics.createMetricParam",Pa);wa(Na,function(a){var b=a.id.replace(/[A-Z]/,"_$&").toUpperCase();v("analytics.Parameters."+b,a)});v("analytics.filters.EventLabelerBuilder",C);v("analytics.filters.EventLabelerBuilder.prototype.appendToExistingLabel",C.prototype.cc);v("analytics.filters.EventLabelerBuilder.prototype.stripValue",C.prototype.$c);
+v("analytics.filters.EventLabelerBuilder.prototype.powersOfTwo",C.prototype.Kc);v("analytics.filters.EventLabelerBuilder.prototype.rangeBounds",C.prototype.Mc);v("analytics.filters.EventLabelerBuilder.prototype.build",C.prototype.qa);v("analytics.filters.FilterBuilder",B);v("analytics.filters.FilterBuilder.builder",Sa);v("analytics.filters.FilterBuilder.prototype.when",B.prototype.when);v("analytics.filters.FilterBuilder.prototype.whenHitType",B.prototype.Wb);
+v("analytics.filters.FilterBuilder.prototype.whenValue",B.prototype.hd);v("analytics.filters.FilterBuilder.prototype.applyFilter",B.prototype.sb);v("analytics.filters.FilterBuilder.prototype.build",B.prototype.qa);v("analytics.EventBuilder",F);v("analytics.EventBuilder.builder",function(){return Ya});v("analytics.EventBuilder.prototype.category",F.prototype.ec);v("analytics.EventBuilder.prototype.action",F.prototype.action);v("analytics.EventBuilder.prototype.label",F.prototype.label);
+v("analytics.EventBuilder.prototype.value",F.prototype.value);v("analytics.EventBuilder.prototype.dimension",F.prototype.mc);v("analytics.EventBuilder.prototype.metric",F.prototype.Cc);v("analytics.EventBuilder.prototype.send",F.prototype.send); }).call(this);
diff --git a/chrome/browser/resources/chromeos/camera/src/js/main.js b/chrome/browser/resources/chromeos/camera/src/js/main.js
index 043b6b4..2ac45ba 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/main.js
+++ b/chrome/browser/resources/chromeos/camera/src/js/main.js
@@ -133,6 +133,7 @@
     // Prompt to migrate pictures if needed.
     var message = chrome.i18n.getMessage('migrate_pictures_msg');
     return cca.nav.open('dialog', message, false).then((acked) => {
+      cca.state.set('migrate-prompted', true);
       if (!acked) {
         throw new Error('no-migrate');
       }
@@ -152,6 +153,8 @@
       return;
     }
     cca.nav.open('warning', 'filesystem-failure');
+  }).finally(() => {
+    cca.metrics.log(cca.metrics.Type.LAUNCH);
   });
 };
 
diff --git a/chrome/browser/resources/chromeos/camera/src/js/metrics.js b/chrome/browser/resources/chromeos/camera/src/js/metrics.js
new file mode 100644
index 0000000..400e499
--- /dev/null
+++ b/chrome/browser/resources/chromeos/camera/src/js/metrics.js
@@ -0,0 +1,104 @@
+// 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.
+
+'use strict';
+
+/**
+ * Namespace for the Camera app.
+ */
+var cca = cca || {};
+
+/**
+ * Namespace for metrics.
+ */
+cca.metrics = cca.metrics || {};
+
+/**
+ * Event builder for basic metrics.
+ * @type {analytics.EventBuilder}
+ * @private
+ */
+cca.metrics.base_ = null;
+
+/**
+ * Promise for Google Analytics tracker.
+ * @type {Promise<analytics.Tracker>}
+ * @private
+ */
+cca.metrics.ga_ = (function() {
+  const analytics = window['analytics'] || {};
+  const id = 'UA-134822711-2';  // TODO(yuli): Use prod id.
+  const service = analytics.getService('chrome-camera-app');
+
+  var getConfig = () =>
+      new Promise((resolve) => service.getConfig().addCallback(resolve));
+  var checkEnabled = () => {
+    return new Promise((resolve) => {
+      try {
+        chrome.metricsPrivate.getIsCrashReportingEnabled(resolve);
+      } catch (e) {
+        resolve(false);  // Disable reporting by default.
+      }
+    });
+  };
+  var initBuilder = () => {
+    return new Promise((resolve) => {
+      try {
+        chrome.chromeosInfoPrivate.get(['board'],
+            (values) => resolve(values['board']));
+      } catch (e) {
+        resolve('');
+      }
+    }).then((board) => {
+      var boardName = /^(x86-)?(\w*)/.exec(board)[0];
+      var match = navigator.appVersion.match(/CrOS\s+\S+\s+([\d.]+)/);
+      var osVer = match ? match[1] : '';
+      cca.metrics.base_ = analytics.EventBuilder.builder()
+          .dimension(1, boardName).dimension(2, osVer);
+    });
+  };
+
+  return Promise.all([getConfig(), checkEnabled(), initBuilder()])
+      .then(([config, enabled]) => {
+        config.setTrackingPermitted(enabled);
+        return service.getTracker(id);
+      });
+})();
+
+/**
+ * Tries to fetch the given states and returns the first existing state.
+ * @param {Array<string>} states States to be fetched.
+ * @return {string} The first existing state among the given states.
+ * @private
+ */
+cca.metrics.state_ = function(states) {
+  return states.find((state) => cca.state.get(state)) || '';
+};
+
+/**
+ * Returns event builder for the metrics type: launch.
+ * @return {analytics.EventBuilder}
+ * @private
+ */
+cca.metrics.launchType_ = function() {
+  return cca.metrics.base_.category('launch').action('launch-app')
+      .label(cca.metrics.state_(['migrate-prompted']));
+};
+
+/**
+ * Metrics types.
+ * @enum {function(*=)}
+ */
+cca.metrics.Type = {
+  LAUNCH: cca.metrics.launchType_,
+};
+
+/**
+ * Logs the given metrics.
+ * @param {cca.metrics.Type} type Metrics type.
+ * @param {...*} args Optional rest parameters for logging metrics.
+ */
+cca.metrics.log = function(type, ...args) {
+  cca.metrics.ga_.then((tracker) => tracker.send(type(...args)));
+};
diff --git a/chrome/browser/resources/chromeos/camera/src/js/util.js b/chrome/browser/resources/chromeos/camera/src/js/util.js
index 0835033..977a59c 100644
--- a/chrome/browser/resources/chromeos/camera/src/js/util.js
+++ b/chrome/browser/resources/chromeos/camera/src/js/util.js
@@ -157,24 +157,6 @@
 };
 
 /**
- * Checks if the current device is in the given device list.
- * @param {Array<string>} ids Device ids.
- * @return {!Promise<boolean>} Promise for the result.
- */
-cca.util.isChromeOSDevice = function(ids) {
-  return new Promise((resolve) => {
-    if (!chrome.chromeosInfoPrivate) {
-      resolve(false);
-      return;
-    }
-    chrome.chromeosInfoPrivate.get(['customizationId'], (values) => {
-      var device = values['customizationId'];
-      resolve(device && ids.indexOf(device) >= 0);
-    });
-  });
-};
-
-/**
  * Returns true if current installed Chrome version is larger than or equal to
  * the given version.
  * @param {number} minVersion the version to be compared with.
diff --git a/chrome/browser/resources/chromeos/camera/src/manifest.json b/chrome/browser/resources/chromeos/camera/src/manifest.json
index b01339e..5805518 100644
--- a/chrome/browser/resources/chromeos/camera/src/manifest.json
+++ b/chrome/browser/resources/chromeos/camera/src/manifest.json
@@ -17,9 +17,11 @@
     "unlimitedStorage",
     "idle",
     "chromeosInfoPrivate",
+    "metricsPrivate",
     "fileManagerPrivate",
     "fileSystem.requestDownloads",
-    {"fileSystem": ["write", "directory"]}
+    {"fileSystem": ["write", "directory"]},
+    "https://www.google-analytics.com/"
   ],
   "app": {
     "background": {
diff --git a/chrome/browser/resources/chromeos/camera/src/views/main.html b/chrome/browser/resources/chromeos/camera/src/views/main.html
index f902321..488092a 100644
--- a/chrome/browser/resources/chromeos/camera/src/views/main.html
+++ b/chrome/browser/resources/chromeos/camera/src/views/main.html
@@ -9,6 +9,8 @@
     <title>&#xfeff;</title>
     <meta charset="utf-8">
     <link rel="stylesheet" href="../css/main.css">
+    <script src="../js/google-analytics-bundle.js"></script>
+    <script src="../js/metrics.js"></script>
     <script src="../js/util.js"></script>
     <script src="../js/toast.js"></script>
     <script src="../js/tooltip.js"></script>
diff --git a/chrome/browser/resources/engagement/BUILD.gn b/chrome/browser/resources/engagement/BUILD.gn
index 84ee321..a98dcfb 100644
--- a/chrome/browser/resources/engagement/BUILD.gn
+++ b/chrome/browser/resources/engagement/BUILD.gn
@@ -12,16 +12,8 @@
 
 js_library("site_engagement") {
   deps = [
+    "//chrome/browser/engagement:mojo_bindings_js_externs",
     "//ui/webui/resources/js:assert",
     "//ui/webui/resources/js:util",
   ]
-  extra_deps = [
-    "//url/mojom:url_mojom_gurl_js",
-    "//chrome/browser/engagement:mojo_bindings_js",
-  ]
-  externs_list = [
-    "$root_gen_dir/chrome/browser/engagement/site_engagement_details.mojom.externs.js",
-    "$root_gen_dir/url/mojom/url.mojom.externs.js",
-    "$externs_path/mojo.js",
-  ]
 }
diff --git a/chrome/browser/resources/engagement/site_engagement.html b/chrome/browser/resources/engagement/site_engagement.html
index c5df80f..987a38b 100644
--- a/chrome/browser/resources/engagement/site_engagement.html
+++ b/chrome/browser/resources/engagement/site_engagement.html
@@ -3,9 +3,10 @@
   <title>Site Engagement</title>
   <meta charset="utf-8">
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-  <script src="chrome://resources/js/mojo_bindings.js"></script>
+  <script src="chrome://resources/js/mojo_bindings_lite.js"></script>
   <script src="chrome://resources/js/util.js"></script>
-  <script src="chrome/browser/engagement/site_engagement_details.mojom.js">
+  <script src="url/mojom/url.mojom-lite.js"></script>
+  <script src="chrome/browser/engagement/site_engagement_details.mojom-lite.js">
   </script>
   <script src="chrome://site-engagement/site_engagement.js"></script>
   <style>
diff --git a/chrome/browser/resources/engagement/site_engagement.js b/chrome/browser/resources/engagement/site_engagement.js
index 82e32d6..f8f0824 100644
--- a/chrome/browser/resources/engagement/site_engagement.js
+++ b/chrome/browser/resources/engagement/site_engagement.js
@@ -11,7 +11,7 @@
 /** @type {function()} */
 let disableAutoupdateForTests;
 
-/** @type {mojom.SiteEngagementDetailsProviderPtr} */
+/** @type {mojom.SiteEngagementDetailsProviderProxy} */
 let uiHandler;
 
 (function() {
@@ -25,10 +25,7 @@
 };
 
 function initialize() {
-  uiHandler = new mojom.SiteEngagementDetailsProviderPtr;
-  Mojo.bindInterface(
-      mojom.SiteEngagementDetailsProvider.name,
-      mojo.makeRequest(uiHandler).handle);
+  uiHandler = mojom.SiteEngagementDetailsProvider.getProxy();
 
   /** @type {?HTMLElement} */
   const engagementTableBody = $('engagement-table-body');
diff --git a/chrome/browser/resources/interventions_internals/index.html b/chrome/browser/resources/interventions_internals/index.html
index dba1b62..614054d 100644
--- a/chrome/browser/resources/interventions_internals/index.html
+++ b/chrome/browser/resources/interventions_internals/index.html
@@ -5,9 +5,10 @@
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <title>Interventions-Internals</title>
     <script src="chrome://resources/js/cr.js"></script>
-    <script src="chrome://resources/js/mojo_bindings.js"></script>
+    <script src="chrome://resources/js/mojo_bindings_lite.js"></script>
     <script src="chrome://resources/js/util.js"></script>
-    <script src="chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom.js">
+    <script src="url/mojom/url.mojom-lite.js"></script>
+    <script src="chrome/browser/ui/webui/interventions_internals/interventions_internals.mojom-lite.js">
     </script>
     <script src="index.js"></script>
     <link rel="stylesheet" type="text/css" href="index.css">
diff --git a/chrome/browser/resources/interventions_internals/index.js b/chrome/browser/resources/interventions_internals/index.js
index c25c1ef..ebd00b9 100644
--- a/chrome/browser/resources/interventions_internals/index.js
+++ b/chrome/browser/resources/interventions_internals/index.js
@@ -450,10 +450,7 @@
 }
 
 /** @constructor */
-const InterventionsInternalPageImpl = function(request) {
-  this.binding_ =
-      new mojo.Binding(mojom.InterventionsInternalsPage, this, request);
-};
+const InterventionsInternalPageImpl = function() {};
 
 InterventionsInternalPageImpl.prototype = {
   /**
@@ -702,15 +699,12 @@
     if (window.testPageHandler) {
       pageHandler = window.testPageHandler;
     } else {
-      pageHandler = new mojom.InterventionsInternalsPageHandlerPtr;
-      Mojo.bindInterface(
-          mojom.InterventionsInternalsPageHandler.name,
-          mojo.makeRequest(pageHandler).handle);
+      pageHandler = mojom.InterventionsInternalsPageHandler.getProxy();
 
       // Set up client side mojo interface.
-      const client = new mojom.InterventionsInternalsPagePtr;
-      pageImpl = new InterventionsInternalPageImpl(mojo.makeRequest(client));
-      pageHandler.setClientPage(client);
+      pageImpl = new InterventionsInternalPageImpl();
+      const client = new mojom.InterventionsInternalsPage(pageImpl);
+      pageHandler.setClientPage(client.createProxy());
     }
 
     interventions_internals.init(pageHandler);
diff --git a/chrome/browser/resources/media/media_engagement.html b/chrome/browser/resources/media/media_engagement.html
index 3fc8168..01a66286 100644
--- a/chrome/browser/resources/media/media_engagement.html
+++ b/chrome/browser/resources/media/media_engagement.html
@@ -4,11 +4,12 @@
   <title>Media Engagement</title>
   <meta charset="utf-8">
   <link rel="stylesheet" href="chrome://resources/css/text_defaults.css">
-  <script src="chrome://resources/js/mojo_bindings.js"></script>
+  <script src="chrome://resources/js/mojo_bindings_lite.js"></script>
   <script src="chrome://resources/js/promise_resolver.js"></script>
   <script src="chrome://resources/js/util.js"></script>
 
-  <script src="chrome/browser/media/media_engagement_score_details.mojom.js">
+  <script src="url/mojom/url.mojom-lite.js"></script>
+  <script src="chrome/browser/media/media_engagement_score_details.mojom-lite.js">
   </script>
 
   <script src="chrome://media-engagement/media-engagement.js"></script>
diff --git a/chrome/browser/resources/media/media_engagement.js b/chrome/browser/resources/media/media_engagement.js
index 249042d..4c4524a 100644
--- a/chrome/browser/resources/media/media_engagement.js
+++ b/chrome/browser/resources/media/media_engagement.js
@@ -184,10 +184,7 @@
 }
 
 document.addEventListener('DOMContentLoaded', function() {
-  uiHandler = new media.mojom.MediaEngagementScoreDetailsProviderPtr;
-  Mojo.bindInterface(
-      media.mojom.MediaEngagementScoreDetailsProvider.name,
-      mojo.makeRequest(uiHandler).handle);
+  uiHandler = media.mojom.MediaEngagementScoreDetailsProvider.getProxy();
   updateEngagementTable();
 
   engagementTableBody = $('engagement-table-body');
@@ -236,6 +233,5 @@
     showNoPlaybacks = e.target.checked;
     renderTable();
   });
-
 });
 })();
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc
index b07dd5c..839c7b8 100644
--- a/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_util.cc
@@ -27,9 +27,7 @@
   syncer::SyncService* sync_service =
       ProfileSyncServiceFactory::GetForProfile(profile);
   return sync_service &&
-         (sync_service->GetUserSettings()->IsSyncEverythingEnabled() ||
-          sync_service->GetUserSettings()->GetChosenDataTypes().Has(
-              syncer::SEND_TAB_TO_SELF));
+         sync_service->GetPreferredDataTypes().Has(syncer::SEND_TAB_TO_SELF);
 }
 
 bool IsSyncingOnMultipleDevices(Profile* profile) {
diff --git a/chrome/browser/send_tab_to_self/send_tab_to_self_util_unittest.cc b/chrome/browser/send_tab_to_self/send_tab_to_self_util_unittest.cc
index 6473a31..eec6f2e 100644
--- a/chrome/browser/send_tab_to_self/send_tab_to_self_util_unittest.cc
+++ b/chrome/browser/send_tab_to_self/send_tab_to_self_util_unittest.cc
@@ -13,13 +13,12 @@
 #include "base/test/scoped_feature_list.h"
 #include "chrome/browser/sync/device_info_sync_service_factory.h"
 #include "chrome/browser/sync/profile_sync_service_factory.h"
-#include "chrome/browser/sync/profile_sync_test_util.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
-#include "components/browser_sync/profile_sync_service.h"
 #include "components/sync/device_info/device_info.h"
 #include "components/sync/device_info/device_info_sync_bridge.h"
 #include "components/sync/device_info/device_info_sync_service.h"
 #include "components/sync/driver/sync_driver_switches.h"
+#include "components/sync/driver/test_sync_service.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -89,6 +88,11 @@
   return std::make_unique<TestDeviceInfoSyncService>();
 }
 
+std::unique_ptr<KeyedService> BuildTestSyncService(
+    content::BrowserContext* context) {
+  return std::make_unique<syncer::TestSyncService>();
+}
+
 class SendTabToSelfUtilTest : public BrowserWithTestWindowTest {
  public:
   SendTabToSelfUtilTest() = default;
@@ -97,10 +101,9 @@
   void SetUp() override {
     BrowserWithTestWindowTest::SetUp();
 
-    mock_profile_sync_service_ =
-        static_cast<browser_sync::ProfileSyncServiceMock*>(
-            ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
-                profile(), base::BindRepeating(&BuildMockProfileSyncService)));
+    test_sync_service_ = static_cast<syncer::TestSyncService*>(
+        ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+            profile(), base::BindRepeating(&BuildTestSyncService)));
     mock_device_sync_service_ = static_cast<TestDeviceInfoSyncService*>(
         DeviceInfoSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse(
             profile(), base::BindRepeating(&BuildMockDeviceInfoSyncService)));
@@ -113,9 +116,7 @@
   void SetUpAllTrueEnv() {
     scoped_feature_list_.InitAndEnableFeature(switches::kSyncSendTabToSelf);
     syncer::ModelTypeSet enabled_modeltype(syncer::SEND_TAB_TO_SELF);
-    EXPECT_CALL(*mock_profile_sync_service_->GetUserSettingsMock(),
-                GetChosenDataTypes())
-        .WillRepeatedly(testing::Return(enabled_modeltype));
+    test_sync_service_->SetPreferredDataTypes(enabled_modeltype);
 
     mock_device_sync_service_->SetTrackerActiveDevices(2);
 
@@ -127,9 +128,7 @@
   void SetUpFeatureDisabledEnv() {
     scoped_feature_list_.InitAndDisableFeature(switches::kSyncSendTabToSelf);
     syncer::ModelTypeSet enabled_modeltype(syncer::SEND_TAB_TO_SELF);
-    EXPECT_CALL(*mock_profile_sync_service_->GetUserSettingsMock(),
-                GetChosenDataTypes())
-        .WillRepeatedly(testing::Return(enabled_modeltype));
+    test_sync_service_->SetPreferredDataTypes(enabled_modeltype);
 
     mock_device_sync_service_->SetTrackerActiveDevices(2);
 
@@ -138,7 +137,7 @@
   }
 
  protected:
-  browser_sync::ProfileSyncServiceMock* mock_profile_sync_service_;
+  syncer::TestSyncService* test_sync_service_;
   TestDeviceInfoSyncService* mock_device_sync_service_;
 
   base::test::ScopedFeatureList scoped_feature_list_;
@@ -159,24 +158,17 @@
 
 TEST_F(SendTabToSelfUtilTest, IsUserSyncTypeEnabled_True) {
   syncer::ModelTypeSet enabled_modeltype(syncer::SEND_TAB_TO_SELF);
-  EXPECT_CALL(*mock_profile_sync_service_->GetUserSettingsMock(),
-              GetChosenDataTypes())
-      .WillRepeatedly(testing::Return(enabled_modeltype));
+  test_sync_service_->SetPreferredDataTypes(enabled_modeltype);
 
   EXPECT_TRUE(IsUserSyncTypeEnabled(profile()));
 
-  EXPECT_CALL(*mock_profile_sync_service_->GetUserSettingsMock(),
-              GetChosenDataTypes())
-      .WillRepeatedly(testing::Return(syncer::ModelTypeSet::All()));
+  test_sync_service_->SetPreferredDataTypes(syncer::ModelTypeSet::All());
 
   EXPECT_TRUE(IsUserSyncTypeEnabled(profile()));
 }
 
 TEST_F(SendTabToSelfUtilTest, IsUserSyncTypeEnabled_False) {
-  syncer::ModelTypeSet disabled_modeltype;
-  EXPECT_CALL(*mock_profile_sync_service_->GetUserSettingsMock(),
-              GetChosenDataTypes())
-      .WillRepeatedly(testing::Return(disabled_modeltype));
+  test_sync_service_->SetPreferredDataTypes(syncer::ModelTypeSet());
 
   EXPECT_FALSE(IsUserSyncTypeEnabled(profile()));
 }
@@ -224,10 +216,7 @@
 
 TEST_F(SendTabToSelfUtilTest, ShouldOfferFeature_IsUserSyncTypeEnabled_False) {
   SetUpAllTrueEnv();
-  syncer::ModelTypeSet disabled_modeltype;
-  EXPECT_CALL(*mock_profile_sync_service_->GetUserSettingsMock(),
-              GetChosenDataTypes())
-      .WillRepeatedly(testing::Return(disabled_modeltype));
+  test_sync_service_->SetPreferredDataTypes(syncer::ModelTypeSet());
 
   EXPECT_FALSE(ShouldOfferFeature(browser()));
 }
diff --git a/chrome/browser/signin/account_reconcilor_factory.cc b/chrome/browser/signin/account_reconcilor_factory.cc
index 26bb66a..3bd5b6c 100644
--- a/chrome/browser/signin/account_reconcilor_factory.cc
+++ b/chrome/browser/signin/account_reconcilor_factory.cc
@@ -7,7 +7,9 @@
 #include <memory>
 #include <utility>
 
+#include "base/feature_list.h"
 #include "base/logging.h"
+#include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/signin/chrome_signin_client_factory.h"
@@ -30,6 +32,10 @@
 #include "google_apis/gaia/google_service_auth_error.h"
 #endif
 
+#if defined(OS_ANDROID)
+#include "components/signin/core/browser/mice_account_reconcilor_delegate.h"
+#endif
+
 #if BUILDFLAG(ENABLE_DICE_SUPPORT)
 #include "components/signin/core/browser/dice_account_reconcilor_delegate.h"
 #endif
@@ -164,6 +170,9 @@
             chromeos::AccountManagerMigratorFactory::GetForBrowserContext(
                 profile));
       }
+#elif defined(OS_ANDROID)
+      if (base::FeatureList::IsEnabled(signin::kMiceFeature))
+        return std::make_unique<signin::MiceAccountReconcilorDelegate>();
 #endif
       return std::make_unique<signin::MirrorAccountReconcilorDelegate>(
           IdentityManagerFactory::GetForProfile(profile));
diff --git a/chrome/browser/ui/app_list/search/mixer.cc b/chrome/browser/ui/app_list/search/mixer.cc
index b011a82..e4893fb 100644
--- a/chrome/browser/ui/app_list/search/mixer.cc
+++ b/chrome/browser/ui/app_list/search/mixer.cc
@@ -16,7 +16,6 @@
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
 #include "chrome/browser/ui/app_list/search/search_provider.h"
 #include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h"
 
 namespace app_list {
 
@@ -109,10 +108,6 @@
   // number* will be kept (e.g., an app result takes priority over a web store
   // result with the same ID).
   RemoveDuplicates(&results);
-
-  // TODO(https://crbug.com/931149): tweak the scores of |results| using
-  // |ranker_|.
-
   std::sort(results.begin(), results.end());
 
   const size_t original_size = results.size();
@@ -161,17 +156,9 @@
     group->FetchResults();
 }
 
-void Mixer::SetRecurrenceRanker(std::unique_ptr<RecurrenceRanker> ranker) {
-  ranker_ = std::move(ranker);
-}
-
 void Mixer::Train(const std::string& id, RankingItemType type) {
-  if (!ranker_)
-    return;
-
-  if (type == RankingItemType::kFile || type == RankingItemType::kOmnibox) {
-    ranker_->Record(std::to_string(static_cast<int>(type)));
-  }
+  // TODO(https://crbug.com/931149)) train a ranking model using this training
+  // signal.
 }
 
 }  // namespace app_list
diff --git a/chrome/browser/ui/app_list/search/mixer.h b/chrome/browser/ui/app_list/search/mixer.h
index 0fd0680..2293429 100644
--- a/chrome/browser/ui/app_list/search/mixer.h
+++ b/chrome/browser/ui/app_list/search/mixer.h
@@ -22,7 +22,6 @@
 FORWARD_DECLARE_TEST(MixerTest, Publish);
 }
 
-class RecurrenceRanker;
 class SearchProvider;
 enum class RankingItemType;
 
@@ -49,9 +48,6 @@
   // Collects the results, sorts and publishes them.
   void MixAndPublish(size_t num_max_results);
 
-  // Add a |RecurrenceRanker| to tweak mixing results.
-  void SetRecurrenceRanker(std::unique_ptr<RecurrenceRanker> ranker);
-
   // Handle a training signal.
   void Train(const std::string& id, RankingItemType type);
 
@@ -85,9 +81,6 @@
 
   Groups groups_;
 
-  // Adaptive category ranking model, which tweaks the score of search results.
-  std::unique_ptr<RecurrenceRanker> ranker_;
-
   DISALLOW_COPY_AND_ASSIGN(Mixer);
 };
 
diff --git a/chrome/browser/ui/app_list/search/search_controller.cc b/chrome/browser/ui/app_list/search/search_controller.cc
index 6692adf..017f707 100644
--- a/chrome/browser/ui/app_list/search/search_controller.cc
+++ b/chrome/browser/ui/app_list/search/search_controller.cc
@@ -17,7 +17,6 @@
 #include "chrome/browser/ui/app_list/app_list_model_updater.h"
 #include "chrome/browser/ui/app_list/search/chrome_search_result.h"
 #include "chrome/browser/ui/app_list/search/search_provider.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h"
 #include "chrome/browser/ui/ash/tablet_mode_client.h"
 
 namespace app_list {
@@ -115,11 +114,6 @@
   return nullptr;
 }
 
-void SearchController::SetRecurrenceRanker(
-    std::unique_ptr<RecurrenceRanker> ranker) {
-  mixer_->SetRecurrenceRanker(std::move(ranker));
-}
-
 void SearchController::Train(const std::string& id, RankingItemType type) {
   for (const auto& provider : providers_)
     provider->Train(id, type);
diff --git a/chrome/browser/ui/app_list/search/search_controller.h b/chrome/browser/ui/app_list/search/search_controller.h
index fe95ee9..8a8340f 100644
--- a/chrome/browser/ui/app_list/search/search_controller.h
+++ b/chrome/browser/ui/app_list/search/search_controller.h
@@ -21,7 +21,6 @@
 
 namespace app_list {
 
-class RecurrenceRanker;
 class SearchProvider;
 enum class RankingItemType;
 
@@ -50,9 +49,6 @@
   ChromeSearchResult* FindSearchResult(const std::string& result_id);
   ChromeSearchResult* GetResultByTitleForTest(const std::string& title);
 
-  // Set a |RecurrenceRanker| to tweak search results.
-  void SetRecurrenceRanker(std::unique_ptr<RecurrenceRanker> ranker);
-
   // Sends training signal to each |providers_|
   void Train(const std::string& id, RankingItemType type);
 
diff --git a/chrome/browser/ui/app_list/search/search_controller_factory.cc b/chrome/browser/ui/app_list/search/search_controller_factory.cc
index c7178d7..ddacd97 100644
--- a/chrome/browser/ui/app_list/search/search_controller_factory.cc
+++ b/chrome/browser/ui/app_list/search/search_controller_factory.cc
@@ -8,12 +8,10 @@
 
 #include "ash/public/cpp/app_list/app_list_features.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
-#include "base/metrics/field_trial_params.h"
 #include "base/strings/string_util.h"
 #include "base/time/default_clock.h"
 #include "build/build_config.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.h"
 #include "chrome/browser/ui/app_list/search/app_search_provider.h"
@@ -26,7 +24,6 @@
 #include "chrome/browser/ui/app_list/search/mixer.h"
 #include "chrome/browser/ui/app_list/search/omnibox_provider.h"
 #include "chrome/browser/ui/app_list/search/search_controller.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/recurrence_ranker.h"
 #include "chrome/browser/ui/app_list/search/settings_shortcut/settings_shortcut_provider.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/chrome_switches.h"
@@ -168,28 +165,6 @@
         std::make_unique<CrostiniRepositorySearchProvider>(profile));
   }
 
-  if (app_list_features::IsAdaptiveResultRankerEnabled()) {
-    RecurrenceRankerConfigProto group_ranker_config;
-    auto* predictor =
-        group_ranker_config.mutable_zero_state_frecency_predictor();
-    predictor->set_target_limit(base::GetFieldTrialParamByFeatureAsInt(
-        app_list_features::kEnableAdaptiveResultRanker, "target_limit", 200));
-    predictor->set_decay_coeff(base::GetFieldTrialParamByFeatureAsDouble(
-        app_list_features::kEnableAdaptiveResultRanker, "decay_coeff", 0.8f));
-    auto* fallback = group_ranker_config.mutable_fallback_predictor();
-    fallback->set_target_limit(base::GetFieldTrialParamByFeatureAsInt(
-        app_list_features::kEnableAdaptiveResultRanker, "fallback_target_limit",
-        200));
-    fallback->set_decay_coeff(base::GetFieldTrialParamByFeatureAsDouble(
-        app_list_features::kEnableAdaptiveResultRanker, "fallback_decay_coeff",
-        0.8f));
-
-    controller->SetRecurrenceRanker(std::make_unique<RecurrenceRanker>(
-        profile->GetPath().AppendASCII("adaptive_result_ranker.proto"),
-        group_ranker_config,
-        chromeos::ProfileHelper::IsEphemeralUserProfile(profile)));
-  }
-
   return controller;
 }
 
diff --git a/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc b/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc
index e244aea..0d797e2 100644
--- a/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc
+++ b/chrome/browser/ui/app_list/search/tests/mixer_unittest.cc
@@ -16,9 +16,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/ui/app_list/search/search_provider.h"
-#include "chrome/browser/ui/app_list/search/search_result_ranker/ranking_item_util.h"
 #include "chrome/browser/ui/app_list/test/fake_app_list_model_updater.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -82,10 +80,6 @@
       // of the canonical [0.0, 1.0] range.
       if (bad_relevance_range_)
         relevance = 10.0 - i * 10;
-      // If |small_relevance_range_|, keep the relevances in the same order, but
-      // make the differences very small: 0.5, 0.499, 0.498, ...
-      if (small_relevance_range_)
-        relevance = 0.5 - i / 100.0;
       TestSearchResult* result = new TestSearchResult(id, relevance);
       result->SetDisplayType(display_type_);
       Add(std::unique_ptr<ChromeSearchResult>(result));
@@ -98,13 +92,11 @@
   }
   void set_count(size_t count) { count_ = count; }
   void set_bad_relevance_range() { bad_relevance_range_ = true; }
-  void set_small_relevance_range() { small_relevance_range_ = true; }
 
  private:
   std::string prefix_;
   size_t count_;
   bool bad_relevance_range_;
-  bool small_relevance_range_;
   ChromeSearchResult::DisplayType display_type_;
 
   DISALLOW_COPY_AND_ASSIGN(TestSearchProvider);
@@ -122,16 +114,6 @@
     providers_.push_back(std::make_unique<TestSearchProvider>("app"));
     providers_.push_back(std::make_unique<TestSearchProvider>("omnibox"));
     providers_.push_back(std::make_unique<TestSearchProvider>("webstore"));
-  }
-
-  void CreateMixer(bool use_adaptive_ranker) {
-    if (use_adaptive_ranker) {
-      scoped_feature_list_.InitWithFeatures(
-          {app_list_features::kEnableAdaptiveResultRanker}, {});
-    } else {
-      scoped_feature_list_.InitWithFeatures(
-          {}, {app_list_features::kEnableAdaptiveResultRanker});
-    }
 
     mixer_ = std::make_unique<Mixer>(model_updater_.get());
 
@@ -168,18 +150,12 @@
     return result;
   }
 
-  void Train(const std::string& id, const RankingItemType& type) {
-    mixer_->Train(id, type);
-  }
-
   Mixer* mixer() { return mixer_.get(); }
   TestSearchProvider* app_provider() { return providers_[0].get(); }
   TestSearchProvider* omnibox_provider() { return providers_[1].get(); }
   TestSearchProvider* webstore_provider() { return providers_[2].get(); }
 
  private:
-  base::test::ScopedFeatureList scoped_feature_list_;
-
   std::unique_ptr<Mixer> mixer_;
   std::unique_ptr<FakeAppListModelUpdater> model_updater_;
 
@@ -189,9 +165,6 @@
 };
 
 TEST_F(MixerTest, Basic) {
-  // Create mixer without adaptive ranker.
-  CreateMixer(false);
-
   // Note: Some cases in |expected| have vastly more results than others, due to
   // the "at least 6" mechanism. If it gets at least 6 results from all
   // providers, it stops at 6. If not, it fetches potentially many more results
@@ -243,9 +216,6 @@
 }
 
 TEST_F(MixerTest, RemoveDuplicates) {
-  // Create mixer without adaptive ranker.
-  CreateMixer(false);
-
   const std::string dup = "dup";
 
   // This gives "dup0,dup1,dup2".
@@ -266,22 +236,5 @@
   EXPECT_EQ("dup0,dup1,dup2", GetResults());
 }
 
-TEST_F(MixerTest, RankerIsDisabledWithFlag) {
-  CreateMixer(false);
-
-  for (int i = 0; i < 20; ++i)
-    Train("omnibox2", RankingItemType::kOmnibox);
-
-  app_provider()->set_count(4);
-  app_provider()->set_small_relevance_range();
-  omnibox_provider()->set_count(4);
-  omnibox_provider()->set_small_relevance_range();
-  RunQuery();
-
-  // Expect training calls to have not affected rankings.
-  EXPECT_EQ(GetResults(),
-            "app0,omnibox0,app1,omnibox1,app2,omnibox2,app3,omnibox3");
-}
-
 }  // namespace test
 }  // namespace app_list
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index d1c7135..fd2c7e7 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/client_hints/client_hints_observer.h"
+#include "chrome/browser/complex_tasks/task_tab_helper.h"
 #include "chrome/browser/content_settings/mixed_content_settings_tab_helper.h"
 #include "chrome/browser/content_settings/sound_content_setting_observer.h"
 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
@@ -35,6 +36,8 @@
 #include "chrome/browser/ntp_snippets/bookmark_last_visit_updater.h"
 #include "chrome/browser/page_load_metrics/page_load_metrics_initialize.h"
 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
+#include "chrome/browser/performance_manager/performance_manager.h"
+#include "chrome/browser/performance_manager/performance_manager_tab_helper.h"
 #include "chrome/browser/permissions/permission_request_manager.h"
 #include "chrome/browser/plugins/pdf_plugin_placeholder_observer.h"
 #include "chrome/browser/predictors/loading_predictor_factory.h"
@@ -53,7 +56,6 @@
 #include "chrome/browser/sync/sessions/sync_sessions_router_tab_helper.h"
 #include "chrome/browser/sync/sessions/sync_sessions_web_contents_router_factory.h"
 #include "chrome/browser/tab_contents/navigation_metrics_recorder.h"
-#include "chrome/browser/complex_tasks/task_tab_helper.h"
 #include "chrome/browser/tracing/navigation_tracing.h"
 #include "chrome/browser/translate/chrome_translate_client.h"
 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
@@ -360,6 +362,13 @@
   if (MediaEngagementService::IsEnabled())
     MediaEngagementService::CreateWebContentsObserver(web_contents);
 
+  if (performance_manager::PerformanceManager::GetInstance()) {
+    performance_manager::PerformanceManagerTabHelper::CreateForWebContents(
+        web_contents);
+  }
+
+  // TODO(siggi): Remove this once the Resource Coordinator refactoring is done.
+  //     See https://crbug.com/910288.
   resource_coordinator::ResourceCoordinatorTabHelper::CreateForWebContents(
       web_contents);
 }
diff --git a/chrome/browser/ui/views/crostini/crostini_installer_view.cc b/chrome/browser/ui/views/crostini/crostini_installer_view.cc
index 6615368..3385414 100644
--- a/chrome/browser/ui/views/crostini/crostini_installer_view.cc
+++ b/chrome/browser/ui/views/crostini/crostini_installer_view.cc
@@ -374,6 +374,16 @@
   return g_crostini_installer_view;
 }
 
+void CrostiniInstallerView::SetCloseCallbackForTesting(
+    base::OnceClosure quit_closure) {
+  quit_closure_for_testing_ = std::move(quit_closure);
+}
+
+void CrostiniInstallerView::SetProgressBarCallbackForTesting(
+    base::RepeatingCallback<void(double)> callback) {
+  progress_bar_callback_for_testing_ = callback;
+}
+
 CrostiniInstallerView::CrostiniInstallerView(Profile* profile)
     : profile_(profile), weak_ptr_factory_(this) {
   // Layout constants from the spec.
@@ -461,6 +471,9 @@
 
 CrostiniInstallerView::~CrostiniInstallerView() {
   g_crostini_installer_view = nullptr;
+  if (quit_closure_for_testing_) {
+    std::move(quit_closure_for_testing_).Run();
+  }
 }
 
 void CrostiniInstallerView::FinishCleanup(CrostiniResult result) {
@@ -576,6 +589,10 @@
       state_start_mark = 0.99;
       state_end_mark = 1;
       break;
+    case State::MOUNT_CONTAINER:
+      state_start_mark = 1;
+      state_end_mark = 1;
+      break;
 
     default:
       break;
@@ -596,6 +613,9 @@
                             base::ClampToRange(state_fraction, 0.0, 1.0) *
                                 (state_end_mark - state_start_mark));
     progress_bar_->SetVisible(true);
+    if (progress_bar_callback_for_testing_) {
+      progress_bar_callback_for_testing_.Run(progress_bar_->current_value());
+    }
   } else {
     progress_bar_->SetVisible(false);
   }
diff --git a/chrome/browser/ui/views/crostini/crostini_installer_view.h b/chrome/browser/ui/views/crostini/crostini_installer_view.h
index 9a1c3b4..96a58e6 100644
--- a/chrome/browser/ui/views/crostini/crostini_installer_view.h
+++ b/chrome/browser/ui/views/crostini/crostini_installer_view.h
@@ -96,6 +96,9 @@
   void OnSshKeysFetched(crostini::CrostiniResult result) override;
 
   static CrostiniInstallerView* GetActiveViewForTesting();
+  void SetCloseCallbackForTesting(base::OnceClosure quit_closure);
+  void SetProgressBarCallbackForTesting(
+      base::RepeatingCallback<void(double)> callback);
 
  private:
   enum class State {
@@ -153,6 +156,9 @@
   // able to hit Cancel after any errors occur.
   bool has_logged_result_ = false;
 
+  base::RepeatingCallback<void(double)> progress_bar_callback_for_testing_;
+  base::OnceClosure quit_closure_for_testing_;
+
   base::WeakPtrFactory<CrostiniInstallerView> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(CrostiniInstallerView);
diff --git a/chrome/browser/ui/views/crostini/crostini_installer_view_browsertest.cc b/chrome/browser/ui/views/crostini/crostini_installer_view_browsertest.cc
index e4aa597..5ded51a 100644
--- a/chrome/browser/ui/views/crostini/crostini_installer_view_browsertest.cc
+++ b/chrome/browser/ui/views/crostini/crostini_installer_view_browsertest.cc
@@ -74,6 +74,20 @@
     std::unique_ptr<base::RunLoop> run_loop_;
   };
 
+  class ProgressBarTracker {
+   public:
+    ProgressBarTracker() : progress_bar_position_(0.0) {}
+    void OnProgressBarUpdated(double value) {
+      EXPECT_LE(value, 1);
+      EXPECT_GE(value, progress_bar_position_);
+      EXPECT_GE(value, 0);
+      progress_bar_position_ = value;
+    }
+
+   private:
+    double progress_bar_position_;
+  };
+
   CrostiniInstallerViewBrowserTest()
       : CrostiniDialogBrowserTest(true /*register_termina*/),
         waiting_fake_concierge_client_(new WaitingFakeConciergeClient()),
@@ -167,6 +181,24 @@
       1);
 }
 
+IN_PROC_BROWSER_TEST_F(CrostiniInstallerViewBrowserTest,
+                       ProgressBarOnlyMovesForwards) {
+  ShowUi("default");
+  EXPECT_NE(nullptr, ActiveView());
+
+  base::RunLoop run_loop;
+  ActiveView()->SetCloseCallbackForTesting(run_loop.QuitClosure());
+
+  ProgressBarTracker progress_bar_tracker;
+  ActiveView()->SetProgressBarCallbackForTesting(
+      base::BindRepeating(&ProgressBarTracker::OnProgressBarUpdated,
+                          base::Unretained(&progress_bar_tracker)));
+  ActiveView()->GetDialogClientView()->AcceptWindow();
+
+  run_loop.Run();
+  EXPECT_EQ(nullptr, ActiveView());
+}
+
 IN_PROC_BROWSER_TEST_F(CrostiniInstallerViewBrowserTest, InstallFlow_Offline) {
   base::HistogramTester histogram_tester;
   SetConnectionType(network::mojom::ConnectionType::CONNECTION_NONE);
diff --git a/chrome/browser/ui/views/payments/payment_request_update_with_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_update_with_browsertest.cc
index b3ad958..e636197b 100644
--- a/chrome/browser/ui/views/payments/payment_request_update_with_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_update_with_browsertest.cc
@@ -48,6 +48,8 @@
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_1));
   EXPECT_EQ(base::ASCIIToUTF16("$3.00"),
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_2));
+  EXPECT_EQ(base::ASCIIToUTF16("$0.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_3));
   ClickOnBackArrow();
 
   OpenShippingAddressSectionScreen();
@@ -72,6 +74,8 @@
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_1));
   EXPECT_EQ(base::ASCIIToUTF16("$3.00"),
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_2));
+  EXPECT_EQ(base::ASCIIToUTF16("$0.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_3));
   ClickOnBackArrow();
 
   PayWithCreditCardAndWait(base::ASCIIToUTF16("123"));
@@ -97,6 +101,8 @@
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_1));
   EXPECT_EQ(base::ASCIIToUTF16("$3.00"),
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_2));
+  EXPECT_EQ(base::ASCIIToUTF16("$0.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_3));
   ClickOnBackArrow();
 
   OpenShippingAddressSectionScreen();
@@ -121,6 +127,8 @@
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_1));
   EXPECT_EQ(base::ASCIIToUTF16("$3.00"),
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_2));
+  EXPECT_EQ(base::ASCIIToUTF16("$0.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_3));
   ClickOnBackArrow();
 
   PayWithCreditCardAndWait(base::ASCIIToUTF16("123"));
@@ -146,6 +154,8 @@
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_1));
   EXPECT_EQ(base::ASCIIToUTF16("$3.00"),
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_2));
+  EXPECT_EQ(base::ASCIIToUTF16("$0.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_3));
   ClickOnBackArrow();
 
   OpenShippingAddressSectionScreen();
@@ -170,6 +180,8 @@
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_1));
   EXPECT_EQ(base::ASCIIToUTF16("$2.00"),
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_2));
+  EXPECT_EQ(base::ASCIIToUTF16("$0.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_3));
   ClickOnBackArrow();
 
   PayWithCreditCardAndWait(base::ASCIIToUTF16("123"));
@@ -196,6 +208,8 @@
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_1));
   EXPECT_EQ(base::ASCIIToUTF16("$3.00"),
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_2));
+  EXPECT_EQ(base::ASCIIToUTF16("$0.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_3));
   ClickOnBackArrow();
 
   OpenShippingAddressSectionScreen();
@@ -220,6 +234,8 @@
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_1));
   EXPECT_EQ(base::ASCIIToUTF16("$3.00"),
             GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_2));
+  EXPECT_EQ(base::ASCIIToUTF16("$0.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_3));
   ClickOnBackArrow();
 
   PayWithCreditCardAndWait(base::ASCIIToUTF16("123"));
@@ -227,4 +243,57 @@
   ExpectBodyContains({"updatedShipping"});
 }
 
+IN_PROC_BROWSER_TEST_F(PaymentRequestUpdateWithTest, UpdateWithModifiers) {
+  NavigateTo("/payment_request_update_with_test.html");
+  autofill::AutofillProfile billing_address = autofill::test::GetFullProfile();
+  AddAutofillProfile(billing_address);
+  AddAutofillProfile(autofill::test::GetFullProfile2());
+  autofill::CreditCard card = autofill::test::GetCreditCard();
+  card.set_billing_address_id(billing_address.guid());
+  AddCreditCard(card);
+
+  RunJavaScriptFunctionToOpenPaymentRequestUI("updateWithModifiers");
+
+  OpenOrderSummaryScreen();
+  EXPECT_EQ(base::ASCIIToUTF16("$5.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_TOTAL_AMOUNT_LABEL));
+  EXPECT_EQ(base::ASCIIToUTF16("$2.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_1));
+  EXPECT_EQ(base::ASCIIToUTF16("$3.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_2));
+  EXPECT_EQ(base::ASCIIToUTF16("$0.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_3));
+  ClickOnBackArrow();
+
+  OpenShippingAddressSectionScreen();
+  ResetEventWaiterForSequence({DialogEvent::PROCESSING_SPINNER_SHOWN,
+                               DialogEvent::PROCESSING_SPINNER_HIDDEN,
+                               DialogEvent::SPEC_DONE_UPDATING,
+                               DialogEvent::BACK_NAVIGATION});
+  ClickOnChildInListViewAndWait(
+      /* child_index=*/1, /*total_num_children=*/2,
+      DialogViewID::SHIPPING_ADDRESS_SHEET_LIST_VIEW,
+      /*wait_for_animation=*/false);
+  // Wait for the animation here explicitly, otherwise
+  // ClickOnChildInListViewAndWait tries to install an AnimationDelegate before
+  // the animation is kicked off (since that's triggered off of the spec being
+  // updated) and this hits a DCHECK.
+  WaitForAnimation();
+
+  OpenOrderSummaryScreen();
+  EXPECT_EQ(base::ASCIIToUTF16("$4.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_TOTAL_AMOUNT_LABEL));
+  EXPECT_EQ(base::ASCIIToUTF16("$2.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_1));
+  EXPECT_EQ(base::ASCIIToUTF16("$3.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_2));
+  EXPECT_EQ(base::ASCIIToUTF16("-$1.00"),
+            GetLabelText(DialogViewID::ORDER_SUMMARY_LINE_ITEM_3));
+  ClickOnBackArrow();
+
+  PayWithCreditCardAndWait(base::ASCIIToUTF16("123"));
+
+  ExpectBodyContains({"freeShipping"});
+}
+
 }  // namespace payments
diff --git a/chrome/browser/ui/webui/browser_switcher/browser_switch_ui.cc b/chrome/browser/ui/webui/browser_switcher/browser_switch_ui.cc
index b7db03b..9f5fd6a 100644
--- a/chrome/browser/ui/webui/browser_switcher/browser_switch_ui.cc
+++ b/chrome/browser/ui/webui/browser_switcher/browser_switch_ui.cc
@@ -68,7 +68,7 @@
   content::WebUIDataSource* source =
       content::WebUIDataSource::Create(chrome::kChromeUIBrowserSwitchHost);
 
-  const auto* service = GetBrowserSwitcherService(web_ui);
+  auto* service = GetBrowserSwitcherService(web_ui);
   source->AddInteger("launchDelay", service->prefs().GetDelay());
 
   source->AddLocalizedString("countdownTitle",
diff --git a/chrome/browser/ui/webui/engagement/site_engagement_ui.cc b/chrome/browser/ui/webui/engagement/site_engagement_ui.cc
index e0fd87e..9f75a1c 100644
--- a/chrome/browser/ui/webui/engagement/site_engagement_ui.cc
+++ b/chrome/browser/ui/webui/engagement/site_engagement_ui.cc
@@ -84,9 +84,9 @@
       content::WebUIDataSource::Create(chrome::kChromeUISiteEngagementHost));
   source->AddResourcePath("site_engagement.js", IDR_SITE_ENGAGEMENT_JS);
   source->AddResourcePath(
-      "chrome/browser/engagement/site_engagement_details.mojom.js",
-      IDR_SITE_ENGAGEMENT_MOJO_JS);
-  source->AddResourcePath("url/mojom/url.mojom.js", IDR_URL_MOJO_JS);
+      "chrome/browser/engagement/site_engagement_details.mojom-lite.js",
+      IDR_SITE_ENGAGEMENT_DETAILS_MOJOM_LITE_JS);
+  source->AddResourcePath("url/mojom/url.mojom-lite.js", IDR_URL_MOJOM_LITE_JS);
   source->SetDefaultResource(IDR_SITE_ENGAGEMENT_HTML);
   source->UseGzip();
   content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source.release());
diff --git a/chrome/browser/ui/webui/interventions_internals/interventions_internals_ui.cc b/chrome/browser/ui/webui/interventions_internals/interventions_internals_ui.cc
index 106ee247..3a141d9 100644
--- a/chrome/browser/ui/webui/interventions_internals/interventions_internals_ui.cc
+++ b/chrome/browser/ui/webui/interventions_internals/interventions_internals_ui.cc
@@ -25,9 +25,9 @@
   source->AddResourcePath("index.js", IDR_INTERVENTIONS_INTERNALS_INDEX_JS);
   source->AddResourcePath(
       "chrome/browser/ui/webui/interventions_internals/"
-      "interventions_internals.mojom.js",
-      IDR_INTERVENTIONS_INTERNALS_MOJO_INDEX_JS);
-  source->AddResourcePath("url/mojom/url.mojom.js", IDR_URL_MOJO_JS);
+      "interventions_internals.mojom-lite.js",
+      IDR_INTERVENTIONS_INTERNALS_MOJOM_LITE_JS);
+  source->AddResourcePath("url/mojom/url.mojom-lite.js", IDR_URL_MOJOM_LITE_JS);
   source->SetDefaultResource(IDR_INTERVENTIONS_INTERNALS_INDEX_HTML);
   source->UseGzip();
   return source;
diff --git a/chrome/browser/ui/webui/media/media_engagement_ui.cc b/chrome/browser/ui/webui/media/media_engagement_ui.cc
index 81cbfb7..63baadb 100644
--- a/chrome/browser/ui/webui/media/media_engagement_ui.cc
+++ b/chrome/browser/ui/webui/media/media_engagement_ui.cc
@@ -143,9 +143,9 @@
       content::WebUIDataSource::Create(chrome::kChromeUIMediaEngagementHost));
   source->AddResourcePath("media-engagement.js", IDR_MEDIA_ENGAGEMENT_JS);
   source->AddResourcePath(
-      "chrome/browser/media/media_engagement_score_details.mojom.js",
-      IDR_MEDIA_ENGAGEMENT_MOJO_JS);
-  source->AddResourcePath("url/mojom/url.mojom.js", IDR_URL_MOJO_JS);
+      "chrome/browser/media/media_engagement_score_details.mojom-lite.js",
+      IDR_MEDIA_ENGAGEMENT_SCORE_DETAILS_MOJOM_LITE_JS);
+  source->AddResourcePath("url/mojom/url.mojom-lite.js", IDR_URL_MOJOM_LITE_JS);
   source->SetDefaultResource(IDR_MEDIA_ENGAGEMENT_HTML);
   source->UseGzip();
   content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), source.release());
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
index c900de6..1748ee0 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui.cc
@@ -434,7 +434,7 @@
   base::FilePath policies_path = path.Append("policies.json");
   std::string json_policies = policy::GetAllPolicyValuesAsJSON(
       web_ui()->GetWebContents()->GetBrowserContext(),
-      true /* with_user_policies */, false /* with device identity */);
+      true /* with_user_policies */, false /* with_device_data */);
   base::PostTaskWithTraitsAndReply(
       FROM_HERE,
       {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
diff --git a/chrome/browser/ui/webui/policy_ui_handler.cc b/chrome/browser/ui/webui/policy_ui_handler.cc
index 030562d..8a6eb89 100644
--- a/chrome/browser/ui/webui/policy_ui_handler.cc
+++ b/chrome/browser/ui/webui/policy_ui_handler.cc
@@ -844,7 +844,8 @@
 void PolicyUIHandler::SendPolicyValues() const {
   base::Value all_policies = policy::GetAllPolicyValuesAsDictionary(
       web_ui()->GetWebContents()->GetBrowserContext(),
-      true /* with_user_policies */, true /* convert_values */);
+      true /* with_user_policies */, true /* convert_values */,
+      false /* with_device_data */);
   web_ui()->CallJavascriptFunctionUnsafe("policy.Page.setPolicyValues",
                                          all_policies);
 }
@@ -921,7 +922,7 @@
     const base::FilePath& path) const {
   std::string json_policies = policy::GetAllPolicyValuesAsJSON(
       web_ui()->GetWebContents()->GetBrowserContext(),
-      true /* with_user_policies */, false /* with device identity */);
+      true /* with_user_policies */, false /* with_device_data */);
 
   base::PostTaskWithTraits(
       FROM_HERE,
diff --git a/chrome/browser/ui/webui/print_preview/policy_settings.cc b/chrome/browser/ui/webui/print_preview/policy_settings.cc
index 5d19127..dbaa090 100644
--- a/chrome/browser/ui/webui/print_preview/policy_settings.cc
+++ b/chrome/browser/ui/webui/print_preview/policy_settings.cc
@@ -16,9 +16,11 @@
 #if defined(OS_CHROMEOS)
   registry->RegisterIntegerPref(prefs::kPrintingAllowedColorModes, 0);
   registry->RegisterIntegerPref(prefs::kPrintingAllowedDuplexModes, 0);
+  registry->RegisterIntegerPref(prefs::kPrintingAllowedPinModes, 0);
   registry->RegisterListPref(prefs::kPrintingAllowedPageSizes);
   registry->RegisterIntegerPref(prefs::kPrintingColorDefault, 0);
   registry->RegisterIntegerPref(prefs::kPrintingDuplexDefault, 0);
+  registry->RegisterIntegerPref(prefs::kPrintingPinDefault, 0);
   registry->RegisterDictionaryPref(prefs::kPrintingSizeDefault);
 #endif
 }
diff --git a/chrome/browser/ui/webui/usb_internals/usb_internals_ui.cc b/chrome/browser/ui/webui/usb_internals/usb_internals_ui.cc
index 8b61315..79e9818 100644
--- a/chrome/browser/ui/webui/usb_internals/usb_internals_ui.cc
+++ b/chrome/browser/ui/webui/usb_internals/usb_internals_ui.cc
@@ -24,7 +24,7 @@
   source->AddResourcePath(
       "chrome/browser/ui/webui/usb_internals/usb_internals.mojom-lite.js",
       IDR_USB_INTERNALS_MOJO_JS);
-  source->AddResourcePath("url/mojom/url.mojom-lite.js", IDR_URL_MOJO_LITE_JS);
+  source->AddResourcePath("url/mojom/url.mojom-lite.js", IDR_URL_MOJOM_LITE_JS);
   source->SetDefaultResource(IDR_USB_INTERNALS_HTML);
   source->UseGzip();
 
diff --git a/chrome/browser/web_applications/components/install_finalizer.h b/chrome/browser/web_applications/components/install_finalizer.h
index 84b0483..319cc4e 100644
--- a/chrome/browser/web_applications/components/install_finalizer.h
+++ b/chrome/browser/web_applications/components/install_finalizer.h
@@ -12,6 +12,10 @@
 
 struct WebApplicationInfo;
 
+namespace content {
+class WebContents;
+}
+
 namespace web_app {
 
 enum class InstallResultCode;
@@ -24,9 +28,15 @@
   using InstallFinalizedCallback =
       base::OnceCallback<void(const AppId& app_id, InstallResultCode code)>;
 
-  virtual void FinalizeInstall(std::unique_ptr<WebApplicationInfo> web_app_info,
+  // Write the WebApp data to disk and register the app.
+  virtual void FinalizeInstall(const WebApplicationInfo& web_app_info,
                                InstallFinalizedCallback callback) = 0;
 
+  virtual void CreateOsShortcuts(const AppId& app_id) = 0;
+  virtual void ReparentTab(const WebApplicationInfo& web_app_info,
+                           const AppId& app_id,
+                           content::WebContents* web_contents) = 0;
+
   virtual ~InstallFinalizer() = default;
 };
 
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
index 9519633..1b86c35 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "chrome/browser/extensions/bookmark_app_extension_util.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/launch_util.h"
 #include "chrome/browser/profiles/profile.h"
@@ -16,23 +17,38 @@
 #include "chrome/browser/web_applications/extensions/bookmark_app_util.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/web_application_info.h"
+#include "extensions/browser/extension_registry.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_id.h"
+#include "extensions/common/extension_set.h"
 #include "url/gurl.h"
 
 namespace extensions {
 
+namespace {
+
+LaunchType GetLaunchType(const WebApplicationInfo& web_app_info) {
+  return web_app_info.open_as_window ? LAUNCH_TYPE_WINDOW : LAUNCH_TYPE_REGULAR;
+}
+
+const Extension* GetExtensionById(Profile* profile,
+                                  const web_app::AppId& app_id) {
+  const Extension* app =
+      ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(app_id);
+  DCHECK(app);
+  return app;
+}
+
+}  // namespace
+
 BookmarkAppInstallFinalizer::BookmarkAppInstallFinalizer(Profile* profile)
     : profile_(profile) {}
 
 BookmarkAppInstallFinalizer::~BookmarkAppInstallFinalizer() = default;
 
 void BookmarkAppInstallFinalizer::FinalizeInstall(
-    std::unique_ptr<WebApplicationInfo> web_app_info,
+    const WebApplicationInfo& web_app_info,
     InstallFinalizedCallback callback) {
-  // Concurrent calls are not allowed.
-  DCHECK(!web_app_info_);
-
   if (!crx_installer_) {
     ExtensionService* extension_service =
         ExtensionSystem::Get(profile_)->extension_service();
@@ -40,13 +56,11 @@
     crx_installer_ = CrxInstaller::CreateSilent(extension_service);
   }
 
-  web_app_info_ = std::move(web_app_info);
-
-  crx_installer_->set_installer_callback(
-      base::BindOnce(&BookmarkAppInstallFinalizer::OnExtensionInstalled,
-                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
-                     web_app_info_->app_url));
-  crx_installer_->InstallWebApp(*web_app_info_);
+  crx_installer_->set_installer_callback(base::BindOnce(
+      &BookmarkAppInstallFinalizer::OnExtensionInstalled,
+      weak_ptr_factory_.GetWeakPtr(),
+      std::make_unique<WebApplicationInfo>(web_app_info), std::move(callback)));
+  crx_installer_->InstallWebApp(web_app_info);
 }
 
 void BookmarkAppInstallFinalizer::SetCrxInstallerForTesting(
@@ -55,35 +69,46 @@
 }
 
 void BookmarkAppInstallFinalizer::OnExtensionInstalled(
+    std::unique_ptr<WebApplicationInfo> web_app_info,
     InstallFinalizedCallback callback,
-    const GURL& app_url,
     const base::Optional<CrxInstallError>& error) {
-  DCHECK(web_app_info_);
-
   if (error) {
     std::move(callback).Run(web_app::AppId(),
                             web_app::InstallResultCode::kFailedUnknownReason);
-  } else {
-    auto* extension = crx_installer_->extension();
-    DCHECK(extension);
-    DCHECK_EQ(AppLaunchInfo::GetLaunchWebURL(extension), app_url);
-
-    LaunchType launch_type = web_app_info_->open_as_window
-                                 ? LAUNCH_TYPE_WINDOW
-                                 : LAUNCH_TYPE_REGULAR;
-
-    // Set the launcher type for the app.
-    SetLaunchType(profile_, extension->id(), launch_type);
-
-    // Set this app to be locally installed, as it was installed from this
-    // machine.
-    SetBookmarkAppIsLocallyInstalled(profile_, extension, true);
-
-    std::move(callback).Run(extension->id(),
-                            web_app::InstallResultCode::kSuccess);
+    return;
   }
 
-  web_app_info_ = nullptr;
+  auto* extension = crx_installer_->extension();
+  DCHECK(extension);
+  DCHECK_EQ(AppLaunchInfo::GetLaunchWebURL(extension), web_app_info->app_url);
+
+  const LaunchType launch_type = GetLaunchType(*web_app_info);
+
+  // Set the launcher type for the app.
+  SetLaunchType(profile_, extension->id(), launch_type);
+
+  // Set this app to be locally installed, as it was installed from this
+  // machine.
+  SetBookmarkAppIsLocallyInstalled(profile_, extension, true);
+
+  std::move(callback).Run(extension->id(),
+                          web_app::InstallResultCode::kSuccess);
+}
+
+void BookmarkAppInstallFinalizer::CreateOsShortcuts(
+    const web_app::AppId& app_id) {
+  const Extension* app = GetExtensionById(profile_, app_id);
+  BookmarkAppCreateOsShortcuts(profile_, app);
+}
+
+void BookmarkAppInstallFinalizer::ReparentTab(
+    const WebApplicationInfo& web_app_info,
+    const web_app::AppId& app_id,
+    content::WebContents* web_contents) {
+  DCHECK(web_contents);
+  const Extension* app = GetExtensionById(profile_, app_id);
+  const LaunchType launch_type = GetLaunchType(web_app_info);
+  BookmarkAppReparentTab(profile_, web_contents, app, launch_type);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h
index 9b1afb1..44a1959 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h
+++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer.h
@@ -11,11 +11,14 @@
 #include "base/optional.h"
 #include "chrome/browser/web_applications/components/install_finalizer.h"
 
-class GURL;
 class Profile;
 
 struct WebApplicationInfo;
 
+namespace content {
+class WebContents;
+}
+
 namespace extensions {
 
 class CrxInstaller;
@@ -30,17 +33,20 @@
   ~BookmarkAppInstallFinalizer() override;
 
   // InstallFinalizer:
-  void FinalizeInstall(std::unique_ptr<WebApplicationInfo> web_app_info,
+  void FinalizeInstall(const WebApplicationInfo& web_app_info,
                        InstallFinalizedCallback callback) override;
+  void CreateOsShortcuts(const web_app::AppId& app_id) override;
+  void ReparentTab(const WebApplicationInfo& web_app_info,
+                   const web_app::AppId& app_id,
+                   content::WebContents* web_contents) override;
 
   void SetCrxInstallerForTesting(scoped_refptr<CrxInstaller> crx_installer);
 
  private:
-  void OnExtensionInstalled(InstallFinalizedCallback callback,
-                            const GURL& app_url,
+  void OnExtensionInstalled(std::unique_ptr<WebApplicationInfo> web_app_info,
+                            InstallFinalizedCallback callback,
                             const base::Optional<CrxInstallError>& error);
 
-  std::unique_ptr<WebApplicationInfo> web_app_info_;
   scoped_refptr<CrxInstaller> crx_installer_;
   Profile* profile_;
 
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
index 93a44ae..b313935c 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_install_finalizer_unittest.cc
@@ -12,8 +12,10 @@
 #include "base/files/file_path.h"
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/bind_test_util.h"
 #include "chrome/browser/extensions/crx_installer.h"
 #include "chrome/browser/extensions/test_extension_system.h"
+#include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/common/web_application_info.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
@@ -83,19 +85,7 @@
                                         false /* autoupdate_enabled */);
   }
 
-  void InstallCallback(base::OnceClosure quit_closure,
-                       const web_app::AppId& app_id,
-                       web_app::InstallResultCode code) {
-    app_installed_ = !app_id.empty();
-    std::move(quit_closure).Run();
-  }
-
-  bool app_installed() { return app_installed_.value(); }
-  bool install_callback_called() { return app_installed_.has_value(); }
-
  private:
-  base::Optional<bool> app_installed_;
-
   DISALLOW_COPY_AND_ASSIGN(BookmarkAppInstallFinalizerTest);
 };
 
@@ -107,12 +97,21 @@
   info->title = base::ASCIIToUTF16(kWebAppTitle);
 
   base::RunLoop run_loop;
+  web_app::AppId app_id;
+  bool callback_called = false;
+
   installer.FinalizeInstall(
-      std::move(info),
-      base::BindOnce(&BookmarkAppInstallFinalizerTest::InstallCallback,
-                     base::Unretained(this), run_loop.QuitClosure()));
+      *info,
+      base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
+                                     web_app::InstallResultCode code) {
+        EXPECT_EQ(web_app::InstallResultCode::kSuccess, code);
+        app_id = installed_app_id;
+        callback_called = true;
+        run_loop.Quit();
+      }));
   run_loop.Run();
-  EXPECT_TRUE(app_installed());
+
+  EXPECT_TRUE(callback_called);
 }
 
 TEST_F(BookmarkAppInstallFinalizerTest, BasicInstallFails) {
@@ -123,21 +122,28 @@
           profile());
   installer.SetCrxInstallerForTesting(fake_crx_installer);
 
-  base::RunLoop run_loop;
-
   auto info = std::make_unique<WebApplicationInfo>();
   info->app_url = GURL(kWebAppUrl);
   info->title = base::ASCIIToUTF16(kWebAppTitle);
+
+  base::RunLoop run_loop;
+  bool callback_called = false;
+
   installer.FinalizeInstall(
-      std::move(info),
-      base::BindOnce(&BookmarkAppInstallFinalizerTest::InstallCallback,
-                     base::Unretained(this), run_loop.QuitClosure()));
+      *info,
+      base::BindLambdaForTesting([&](const web_app::AppId& installed_app_id,
+                                     web_app::InstallResultCode code) {
+        EXPECT_EQ(web_app::InstallResultCode::kFailedUnknownReason, code);
+        EXPECT_TRUE(installed_app_id.empty());
+        callback_called = true;
+        run_loop.Quit();
+      }));
 
   fake_crx_installer->WaitForInstallToTrigger();
   fake_crx_installer->SimulateInstallFailed();
   run_loop.Run();
 
-  EXPECT_FALSE(app_installed());
+  EXPECT_TRUE(callback_called);
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/web_applications/test/test_install_finalizer.cc b/chrome/browser/web_applications/test/test_install_finalizer.cc
index 32aefb4..587c864 100644
--- a/chrome/browser/web_applications/test/test_install_finalizer.cc
+++ b/chrome/browser/web_applications/test/test_install_finalizer.cc
@@ -19,15 +19,42 @@
 TestInstallFinalizer::~TestInstallFinalizer() = default;
 
 void TestInstallFinalizer::FinalizeInstall(
-    std::unique_ptr<WebApplicationInfo> web_app_info,
+    const WebApplicationInfo& web_app_info,
     InstallFinalizedCallback callback) {
-  const AppId app_id = GenerateAppIdFromURL(web_app_info->app_url);
+  AppId app_id = GenerateAppIdFromURL(web_app_info.app_url);
+  if (next_app_id_.has_value()) {
+    app_id = next_app_id_.value();
+    next_app_id_.reset();
+  }
 
-  web_app_info_ = std::move(web_app_info);
+  InstallResultCode code = InstallResultCode::kSuccess;
+  if (next_result_code_.has_value()) {
+    code = next_result_code_.value();
+    next_result_code_.reset();
+  }
+
+  // Store a copy for inspecting in tests.
+  web_app_info_copy_ = std::make_unique<WebApplicationInfo>(web_app_info);
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(std::move(callback), app_id, InstallResultCode::kSuccess));
+      FROM_HERE, base::BindOnce(std::move(callback), app_id, code));
+}
+
+void TestInstallFinalizer::CreateOsShortcuts(const AppId& app_id) {
+  ++num_create_os_shortcuts_calls_;
+}
+
+void TestInstallFinalizer::ReparentTab(const WebApplicationInfo& web_app_info,
+                                       const AppId& app_id,
+                                       content::WebContents* web_contents) {
+  ++num_reparent_tab_num_calls_;
+}
+
+void TestInstallFinalizer::SetNextFinalizeInstallResult(
+    const AppId& app_id,
+    InstallResultCode code) {
+  next_app_id_ = app_id;
+  next_result_code_ = code;
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/test/test_install_finalizer.h b/chrome/browser/web_applications/test/test_install_finalizer.h
index 1be83de..8b769fc 100644
--- a/chrome/browser/web_applications/test/test_install_finalizer.h
+++ b/chrome/browser/web_applications/test/test_install_finalizer.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "base/optional.h"
 #include "chrome/browser/web_applications/components/install_finalizer.h"
 
 struct WebApplicationInfo;
@@ -20,15 +21,31 @@
   ~TestInstallFinalizer() override;
 
   // InstallFinalizer:
-  void FinalizeInstall(std::unique_ptr<WebApplicationInfo> web_app_info,
+  void FinalizeInstall(const WebApplicationInfo& web_app_info,
                        InstallFinalizedCallback callback) override;
+  void CreateOsShortcuts(const AppId& app_id) override;
+  void ReparentTab(const WebApplicationInfo& web_app_info,
+                   const AppId& app_id,
+                   content::WebContents* web_contents) override;
+
+  void SetNextFinalizeInstallResult(const AppId& app_id,
+                                    InstallResultCode code);
 
   std::unique_ptr<WebApplicationInfo> web_app_info() {
-    return std::move(web_app_info_);
+    return std::move(web_app_info_copy_);
   }
 
+  int num_create_os_shortcuts_calls() { return num_create_os_shortcuts_calls_; }
+  int num_reparent_tab_num_calls() { return num_reparent_tab_num_calls_; }
+
  private:
-  std::unique_ptr<WebApplicationInfo> web_app_info_;
+  std::unique_ptr<WebApplicationInfo> web_app_info_copy_;
+
+  base::Optional<AppId> next_app_id_;
+  base::Optional<InstallResultCode> next_result_code_;
+
+  int num_create_os_shortcuts_calls_ = 0;
+  int num_reparent_tab_num_calls_ = 0;
 
   DISALLOW_COPY_AND_ASSIGN(TestInstallFinalizer);
 };
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.cc b/chrome/browser/web_applications/web_app_install_finalizer.cc
index 1d6b349..bbb96c4 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.cc
+++ b/chrome/browser/web_applications/web_app_install_finalizer.cc
@@ -52,11 +52,11 @@
 WebAppInstallFinalizer::~WebAppInstallFinalizer() = default;
 
 void WebAppInstallFinalizer::FinalizeInstall(
-    std::unique_ptr<WebApplicationInfo> web_app_info,
+    const WebApplicationInfo& web_app_info,
     InstallFinalizedCallback callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
-  AppId app_id = GenerateAppIdFromURL(web_app_info->app_url);
+  AppId app_id = GenerateAppIdFromURL(web_app_info.app_url);
   if (registrar_->GetAppById(app_id)) {
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::BindOnce(std::move(callback), app_id,
@@ -66,15 +66,15 @@
 
   auto web_app = std::make_unique<WebApp>(app_id);
 
-  web_app->SetName(base::UTF16ToUTF8(web_app_info->title));
-  web_app->SetDescription(base::UTF16ToUTF8(web_app_info->description));
-  web_app->SetLaunchUrl(web_app_info->app_url);
-  web_app->SetScope(web_app_info->scope);
-  web_app->SetThemeColor(web_app_info->theme_color);
-  SetIcons(*web_app_info, web_app.get());
+  web_app->SetName(base::UTF16ToUTF8(web_app_info.title));
+  web_app->SetDescription(base::UTF16ToUTF8(web_app_info.description));
+  web_app->SetLaunchUrl(web_app_info.app_url);
+  web_app->SetScope(web_app_info.scope);
+  web_app->SetThemeColor(web_app_info.theme_color);
+  SetIcons(web_app_info, web_app.get());
 
   icon_manager_->WriteData(
-      std::move(app_id), std::move(web_app_info),
+      std::move(app_id), std::make_unique<WebApplicationInfo>(web_app_info),
       base::BindOnce(&WebAppInstallFinalizer::OnDataWritten,
                      weak_ptr_factory_.GetWeakPtr(), std::move(callback),
                      std::move(web_app)));
@@ -96,4 +96,16 @@
   std::move(callback).Run(std::move(app_id), InstallResultCode::kSuccess);
 }
 
+void WebAppInstallFinalizer::CreateOsShortcuts(const AppId& app_id) {
+  // TODO(loyso): Implement it.
+  NOTIMPLEMENTED();
+}
+
+void WebAppInstallFinalizer::ReparentTab(const WebApplicationInfo& web_app_info,
+                                         const AppId& app_id,
+                                         content::WebContents* web_contents) {
+  // TODO(loyso): Implement it.
+  NOTIMPLEMENTED();
+}
+
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/web_app_install_finalizer.h b/chrome/browser/web_applications/web_app_install_finalizer.h
index d7f13d3..78b5cb8 100644
--- a/chrome/browser/web_applications/web_app_install_finalizer.h
+++ b/chrome/browser/web_applications/web_app_install_finalizer.h
@@ -26,8 +26,12 @@
   ~WebAppInstallFinalizer() override;
 
   // InstallFinalizer:
-  void FinalizeInstall(std::unique_ptr<WebApplicationInfo> web_app_info,
+  void FinalizeInstall(const WebApplicationInfo& web_app_info,
                        InstallFinalizedCallback callback) override;
+  void CreateOsShortcuts(const AppId& app_id) override;
+  void ReparentTab(const WebApplicationInfo& web_app_info,
+                   const AppId& app_id,
+                   content::WebContents* web_contents) override;
 
  private:
   void OnDataWritten(InstallFinalizedCallback callback,
diff --git a/chrome/browser/web_applications/web_app_install_manager.cc b/chrome/browser/web_applications/web_app_install_manager.cc
index 5fb4dd2..01d0696c 100644
--- a/chrome/browser/web_applications/web_app_install_manager.cc
+++ b/chrome/browser/web_applications/web_app_install_manager.cc
@@ -14,6 +14,7 @@
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_data_retriever.h"
 #include "chrome/browser/web_applications/components/web_app_icon_generator.h"
+#include "chrome/browser/web_applications/components/web_app_install_utils.h"
 #include "chrome/browser/web_applications/web_app_utils.h"
 #include "chrome/common/web_application_info.h"
 #include "content/public/browser/browser_thread.h"
@@ -108,7 +109,6 @@
     bool force_shortcut_app,
     std::unique_ptr<WebApplicationInfo> web_app_info) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  // If interrupted, install_callback_ is already invoked or may invoke later.
   if (InstallInterrupted())
     return;
 
@@ -127,7 +127,6 @@
     bool force_shortcut_app,
     const blink::Manifest& manifest,
     bool is_installable) {
-  // If interrupted, install_callback_ is already invoked or may invoke later.
   if (InstallInterrupted())
     return;
 
@@ -162,7 +161,6 @@
     std::unique_ptr<WebApplicationInfo> web_app_info,
     ForInstallableSite for_installable_site,
     IconsMap icons_map) {
-  // If interrupted, install_callback_ is already invoked or may invoke later.
   if (InstallInterrupted())
     return;
 
@@ -184,31 +182,48 @@
     ForInstallableSite for_installable_site,
     bool user_accepted,
     std::unique_ptr<WebApplicationInfo> web_app_info) {
-  // If interrupted, install_callback_ is already invoked or may invoke later.
   if (InstallInterrupted())
     return;
 
   if (!user_accepted)
     return ReturnError(InstallResultCode::kUserInstallDeclined);
 
+  WebApplicationInfo web_app_info_copy = *web_app_info;
+
   install_finalizer_->FinalizeInstall(
-      std::move(web_app_info),
+      web_app_info_copy,
       base::BindOnce(&WebAppInstallManager::OnInstallFinalized,
-                     weak_ptr_factory_.GetWeakPtr(), for_installable_site));
+                     weak_ptr_factory_.GetWeakPtr(), std::move(web_app_info),
+                     for_installable_site));
 
   // Check that the finalizer hasn't called OnInstallFinalized synchronously:
   DCHECK(install_callback_);
+  DCHECK(install_source_ != kNoInstallSource);
+
+  // In BookmarkAppHelper this tracking happens right after
+  // crx_installer_->InstallWebApp call (not in FinishInstallation).
+  // TODO(loyso): Consider to shift this recording to OnInstallFinalized.
+  if (InstallableMetrics::IsReportableInstallSource(install_source_) &&
+      for_installable_site == ForInstallableSite::kYes) {
+    InstallableMetrics::TrackInstallEvent(install_source_);
+  }
 }
 
 void WebAppInstallManager::OnInstallFinalized(
+    std::unique_ptr<WebApplicationInfo> web_app_info,
     ForInstallableSite for_installable_site,
     const AppId& app_id,
     InstallResultCode code) {
-  DCHECK(install_source_ != kNoInstallSource);
+  if (InstallInterrupted())
+    return;
 
-  if (InstallableMetrics::IsReportableInstallSource(install_source_) &&
-      for_installable_site == web_app::ForInstallableSite::kYes) {
-    InstallableMetrics::TrackInstallEvent(install_source_);
+  if (code == InstallResultCode::kSuccess) {
+    RecordAppBanner(web_contents(), web_app_info->app_url);
+
+    // TODO(loyso): Implement |create_shortcuts| to skip OS shortcuts creation.
+    install_finalizer_->CreateOsShortcuts(app_id);
+    // TODO(loyso): Implement |reparent_tab| to skip tab reparenting logic.
+    install_finalizer_->ReparentTab(*web_app_info, app_id, web_contents());
   }
 
   CallInstallCallback(app_id, code);
diff --git a/chrome/browser/web_applications/web_app_install_manager.h b/chrome/browser/web_applications/web_app_install_manager.h
index 341c8dc..122be84f 100644
--- a/chrome/browser/web_applications/web_app_install_manager.h
+++ b/chrome/browser/web_applications/web_app_install_manager.h
@@ -57,7 +57,9 @@
   void CallInstallCallback(const AppId& app_id, InstallResultCode code);
   void ReturnError(InstallResultCode code);
 
-  // Checks typical errors like WebContents destroyed.
+  // Checks typical errors like WebContents destroyed. Callers must return
+  // early if this is true. Note that if install interrupted, install_callback_
+  // is already invoked or may be invoked later - no actions needed from caller.
   bool InstallInterrupted() const;
 
   void OnGetWebApplicationInfo(
@@ -74,7 +76,8 @@
   void OnDialogCompleted(ForInstallableSite for_installable_site,
                          bool user_accepted,
                          std::unique_ptr<WebApplicationInfo> web_app_info);
-  void OnInstallFinalized(ForInstallableSite for_installable_site,
+  void OnInstallFinalized(std::unique_ptr<WebApplicationInfo> web_app_info,
+                          ForInstallableSite for_installable_site,
                           const AppId& app_id,
                           InstallResultCode code);
 
diff --git a/chrome/browser/web_applications/web_app_install_manager_unittest.cc b/chrome/browser/web_applications/web_app_install_manager_unittest.cc
index f0bd718..584fe5b 100644
--- a/chrome/browser/web_applications/web_app_install_manager_unittest.cc
+++ b/chrome/browser/web_applications/web_app_install_manager_unittest.cc
@@ -167,8 +167,13 @@
     data_retriever_->SetIcons(std::move(icons_map));
   }
 
-  AppId InstallWebApp() {
+  struct InstallResult {
     AppId app_id;
+    InstallResultCode code;
+  };
+
+  InstallResult InstallWebAppAndGetResults() {
+    InstallResult result;
     base::RunLoop run_loop;
     const bool force_shortcut_app = false;
     install_manager_->InstallWebApp(
@@ -177,12 +182,29 @@
         base::BindOnce(TestAcceptDialogCallback),
         base::BindLambdaForTesting(
             [&](const AppId& installed_app_id, InstallResultCode code) {
-              EXPECT_EQ(InstallResultCode::kSuccess, code);
-              app_id = installed_app_id;
+              result.app_id = installed_app_id;
+              result.code = code;
               run_loop.Quit();
             }));
     run_loop.Run();
-    return app_id;
+    return result;
+  }
+
+  AppId InstallWebApp() {
+    InstallResult result = InstallWebAppAndGetResults();
+    DCHECK_EQ(InstallResultCode::kSuccess, result.code);
+    return result.app_id;
+  }
+
+  void PrepareTestAppInstall() {
+    CreateRendererAppInfo(GURL("https://example.com/path"), "Name",
+                          "Description");
+    CreateDefaultInstallableManager();
+
+    SetInstallFinalizerForTesting();
+
+    IconsMap icons_map;
+    SetIconsMapToRetrieve(std::move(icons_map));
   }
 
  protected:
@@ -585,6 +607,29 @@
   EXPECT_EQ(nullptr, web_app);
 }
 
+TEST_F(WebAppInstallManagerTest, FinalizerMethodsCalled) {
+  PrepareTestAppInstall();
+
+  InstallWebApp();
+
+  EXPECT_EQ(1, install_finalizer_->num_create_os_shortcuts_calls());
+  EXPECT_EQ(1, install_finalizer_->num_reparent_tab_num_calls());
+}
+
+TEST_F(WebAppInstallManagerTest, FinalizerMethodsNotCalled) {
+  PrepareTestAppInstall();
+  install_finalizer_->SetNextFinalizeInstallResult(
+      AppId(), InstallResultCode::kFailedUnknownReason);
+
+  InstallResult result = InstallWebAppAndGetResults();
+
+  EXPECT_TRUE(result.app_id.empty());
+  EXPECT_EQ(InstallResultCode::kFailedUnknownReason, result.code);
+
+  EXPECT_EQ(0, install_finalizer_->num_create_os_shortcuts_calls());
+  EXPECT_EQ(0, install_finalizer_->num_reparent_tab_num_calls());
+}
+
 // TODO(loyso): Convert more tests from bookmark_app_helper_unittest.cc
 
 }  // namespace web_app
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index fb11f205..ebaea16 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1200,6 +1200,9 @@
 // of |printing::DuplexModeRestriction| values. 0 is no restriction.
 const char kPrintingAllowedDuplexModes[] = "printing.allowed_duplex_modes";
 
+// A pref holding the allowed PIN printing modes.
+const char kPrintingAllowedPinModes[] = "printing.allowed_pin_modes";
+
 // A pref holding the list of allowed printing duplex mode.
 // Empty list is no restriction.
 const char kPrintingAllowedPageSizes[] = "printing.allowed_page_sizes";
@@ -1210,6 +1213,9 @@
 // A pref holding the default duplex mode.
 const char kPrintingDuplexDefault[] = "printing.duplex_default";
 
+// A pref holding the default PIN mode.
+const char kPrintingPinDefault[] = "printing.pin_default";
+
 // A pref holding the default page size.
 const char kPrintingSizeDefault[] = "printing.size_default";
 
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index ffead15..f5305d3 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -398,9 +398,11 @@
 
 extern const char kPrintingAllowedColorModes[];
 extern const char kPrintingAllowedDuplexModes[];
+extern const char kPrintingAllowedPinModes[];
 extern const char kPrintingAllowedPageSizes[];
 extern const char kPrintingColorDefault[];
 extern const char kPrintingDuplexDefault[];
+extern const char kPrintingPinDefault[];
 extern const char kPrintingSizeDefault[];
 extern const char kPrintingSendUsernameAndFilenameEnabled[];
 #endif  // OS_CHROMEOS
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index addef4b..a7e5d6cc 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -494,6 +494,7 @@
       "//ui/file_manager/gallery/",
       "//ui/file_manager/image_loader/",
       "//ui/file_manager/integration_tests/",
+      "//ui/file_manager/video_player",
       "//third_party/polymer/v1_0/components-chromium/polymer/",
       "$root_gen_dir/ui/file_manager/file_manager/",
       "$root_gen_dir/ui/login/login_resources.pak",
@@ -1169,7 +1170,6 @@
     if (include_js_tests) {
       deps += [
         "//chrome/test/data/webui:browser_tests_js_mojo_lite_webui",
-        "//chrome/test/data/webui:browser_tests_js_mojo_webui",
         "//chrome/test/data/webui:browser_tests_js_webui",
       ]
     }
@@ -1778,6 +1778,7 @@
         "../browser/chromeos/file_manager/mount_test_util.cc",
         "../browser/chromeos/file_manager/mount_test_util.h",
         "../browser/chromeos/file_manager/video_player_browsertest.cc",
+        "../browser/chromeos/file_manager/video_player_jstest.cc",
         "../browser/chromeos/first_run/chromeos_first_run_browsertest.cc",
         "../browser/chromeos/first_run/drive_first_run_browsertest.cc",
         "../browser/chromeos/first_run/goodies_displayer_browsertest.cc",
diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc
index 9d8812c..5cc0e9b 100644
--- a/chrome/test/base/testing_profile.cc
+++ b/chrome/test/base/testing_profile.cc
@@ -77,6 +77,8 @@
 #include "components/history/core/test/history_service_test_util.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/keyed_service/core/refcounted_keyed_service.h"
+#include "components/keyed_service/core/simple_dependency_manager.h"
+#include "components/keyed_service/core/simple_factory_key.h"
 #include "components/offline_pages/buildflags/buildflags.h"
 #include "components/omnibox/browser/autocomplete_classifier.h"
 #include "components/omnibox/browser/history_index_restore_observer.h"
@@ -300,8 +302,10 @@
       delegate_(delegate),
       profile_name_(profile_name),
       policy_service_(policy_service.release()) {
-  if (parent)
+  if (parent) {
     parent->SetOffTheRecordProfile(std::unique_ptr<Profile>(this));
+    off_the_record_key_ = parent->GetOffTheRecordKey();
+  }
 
   // If no profile path was supplied, create one.
   if (profile_path_.empty()) {
@@ -373,6 +377,11 @@
                           profile_manager->GetSystemProfilePath());
   }
 
+  if (!IsOffTheRecord()) {
+    owned_key_ = std::make_unique<SimpleFactoryKey>(profile_path_);
+    owned_off_the_record_key_ =
+        std::make_unique<SimpleFactoryKey>(profile_path_, owned_key_.get());
+  }
   BrowserContext::Initialize(this, profile_path_);
 
 #if defined(OS_ANDROID)
@@ -515,6 +524,9 @@
 
   browser_context_dependency_manager_->DestroyBrowserContextServices(this);
 
+  SimpleFactoryKey* key = Profile::GetSimpleFactoryKey(this);
+  SimpleDependencyManager::GetInstance()->DestroyKeyedServices(key);
+
   if (host_content_settings_map_.get())
     host_content_settings_map_->ShutdownOnUIThread();
 
@@ -873,6 +885,18 @@
   return start_time_;
 }
 
+SimpleFactoryKey* TestingProfile::GetOriginalKey() const {
+  if (IsOffTheRecord())
+    return off_the_record_key_->original_key();
+  return owned_key_.get();
+}
+
+SimpleFactoryKey* TestingProfile::GetOffTheRecordKey() const {
+  if (IsOffTheRecord())
+    return off_the_record_key_;
+  return owned_off_the_record_key_.get();
+}
+
 base::FilePath TestingProfile::last_selected_directory() {
   return last_selected_directory_;
 }
diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h
index dc026c6..8c1f0b0 100644
--- a/chrome/test/base/testing_profile.h
+++ b/chrome/test/base/testing_profile.h
@@ -18,6 +18,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "components/domain_reliability/clear_mode.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+#include "components/keyed_service/core/simple_factory_key.h"
 #include "content/public/browser/browser_thread.h"
 #include "extensions/buildflags/buildflags.h"
 #include "services/network/public/mojom/network_context.mojom.h"
@@ -316,6 +317,8 @@
   }
   bool IsSameProfile(Profile* profile) override;
   base::Time GetStartTime() const override;
+  SimpleFactoryKey* GetOriginalKey() const override;
+  SimpleFactoryKey* GetOffTheRecordKey() const override;
   base::FilePath last_selected_directory() override;
   void set_last_selected_directory(const base::FilePath& path) override;
   bool WasCreatedByVersionOrLater(const std::string& version) override;
@@ -447,6 +450,14 @@
 #endif  // defined(OS_CHROMEOS)
 
   std::unique_ptr<policy::PolicyService> policy_service_;
+
+  // The keys to index KeyedService instances created by
+  // SimpleKeyedServiceFactory if this is an original profile.
+  std::unique_ptr<SimpleFactoryKey> owned_key_;
+  std::unique_ptr<SimpleFactoryKey> owned_off_the_record_key_;
+  // The key to index KeyedService instances created by
+  // SimpleKeyedServiceFactory if this is an incognito profile.
+  SimpleFactoryKey* off_the_record_key_ = nullptr;
 };
 
 #endif  // CHROME_TEST_BASE_TESTING_PROFILE_H_
diff --git a/chrome/test/data/extensions/api_test/input_method/basic/background.js b/chrome/test/data/extensions/api_test/input_method/basic/background.js
index ccfc67e..1f22a50 100644
--- a/chrome/test/data/extensions/api_test/input_method/basic/background.js
+++ b/chrome/test/data/extensions/api_test/input_method/basic/background.js
@@ -85,7 +85,7 @@
   console.log('getListTest: Getting input method list.');
 
   chrome.inputMethodPrivate.getInputMethods(function(inputMethods) {
-    chrome.test.assertEq(6, inputMethods.length);
+    chrome.test.assertEq(7, inputMethods.length);
     var foundInitialInputMethod = false;
     var foundNewInputMethod = false;
     for (var i = 0; i < inputMethods.length; ++i) {
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index e61520b..a208dbe 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -324,6 +324,14 @@
     ]
   },
 
+  "PrintingAllowedPinModes": {
+    "os": ["chromeos"],
+    "test_policy": { "PrintingAllowedPinModes": "secure" },
+    "pref_mappings": [
+      { "pref": "printing.allowed_pin_modes" }
+    ]
+  },
+
   "PrintingAllowedPageSizes": {
     "os": ["chromeos"],
     "test_policy": { "PrintingAllowedPageSizes": [{"WidthUm": 210000, "HeightUm": 297000}] },
@@ -348,6 +356,14 @@
     ]
   },
 
+  "PrintingPinDefault": {
+    "os": ["chromeos"],
+    "test_policy": { "PrintingPinDefault": "secure" },
+    "pref_mappings": [
+      { "pref": "printing.pin_default" }
+    ]
+  },
+
   "PrintingSizeDefault": {
     "os": ["chromeos"],
     "test_policy": { "PrintingSizeDefault": {"WidthUm": 210000, "HeightUm": 297000} },
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index c3d2574..2ca1d96 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -131,23 +131,6 @@
   defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
 }
 
-js2gtest("browser_tests_js_mojo_webui") {
-  test_type = "mojo_webui"
-
-  sources = [
-    "engagement/site_engagement_browsertest.js",
-    "interventions_internals_browsertest.js",
-    "media/media_engagement_browsertest.js",
-  ]
-
-  deps = [
-    "//chrome/browser/ui",
-    "//skia",
-  ]
-
-  defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ]
-}
-
 js2gtest("browser_tests_js_mojo_lite_webui") {
   test_type = "mojo_lite_webui"
 
@@ -155,6 +138,9 @@
     "app_management/app_management_browsertest.js",
     "bluetooth_internals_browsertest.js",
     "downloads/downloads_browsertest.js",
+    "engagement/site_engagement_browsertest.js",
+    "interventions_internals_browsertest.js",
+    "media/media_engagement_browsertest.js",
   ]
 
   if (is_win || is_mac || is_desktop_linux || is_chromeos) {
diff --git a/chromeos/ime/input_methods.txt b/chromeos/ime/input_methods.txt
index 11f39e2..ab7e717 100644
--- a/chromeos/ime/input_methods.txt
+++ b/chromeos/ime/input_methods.txt
@@ -34,8 +34,10 @@
 # U.S. English
 xkb:us::eng             us               en,en-US,en-AU,en-NZ US   login
 xkb:us:intl:eng         us(intl)         en,en-US             INTL login
+xkb:us:intl_pc:eng      us(intl_pc)      en,en-US             INTL
 xkb:us:altgr-intl:eng   us(altgr-intl)   en,en-US             EXTD login
 xkb:us:dvorak:eng       us(dvorak)       en,en-US             DV   login
+xkb:us:dvp:eng          us(dvp)          en,en-US             DVP  login
 xkb:us:colemak:eng      us(colemak)      en,en-US             CO   login
 xkb:us:workman:eng      us(workman)      en,en-US             WM   login
 xkb:us:workman-intl:eng us(workman-intl) en,en-US             WMI  login
@@ -53,11 +55,12 @@
 # We don't support xkb:nl::nld. See b/4430951.
 
 # French
-xkb:fr::fra       fr         fr,fr-FR FR login
-xkb:be::fra       be         fr       BE login
-xkb:ca::fra       ca         fr,fr-CA CA login
-xkb:ch:fr:fra     ch(fr)     fr,fr-CH CH login
-xkb:ca:multix:fra ca(multix) fr,fr-CA CA login
+xkb:fr::fra       fr(oss)    fr,fr-FR FR   login
+xkb:fr:bepo:fra   fr(bepo)   fr,fr-FR BEPO login
+xkb:be::fra       be         fr       BE   login
+xkb:ca::fra       ca         fr,fr-CA CA   login
+xkb:ch:fr:fra     ch(fr)     fr,fr-CH CH   login
+xkb:ca:multix:fra ca(multix) fr,fr-CA CA   login
 
 # German
 xkb:de::ger     de      de,de-DE DE  login
@@ -85,8 +88,10 @@
 xkb:es::spa           es             es        ES login
 xkb:es:cat:cat        es(cat)        ca        CAS login
 xkb:dk::dan           dk             da        DK login
+xkb:fo::fao           fo             fo        FO
 xkb:gr::gre           gr             el        GR
 xkb:il::heb           il             he        IL
+xkb:kz::kaz           kz             kk        KZ
 xkb:latam::spa        latam          es,es-419 LA login
 xkb:lt::lit           lt             lt        LT login
 xkb:lv:apostrophe:lav lv(apostrophe) lv        LV login
@@ -95,6 +100,7 @@
 xkb:gb:dvorak:eng     gb(dvorak)     en,en-GB  DV login
 xkb:fi::fin           fi             fi        FI login
 xkb:hu::hun           hu             hu        HU login
+xkb:hu:qwerty:hun     hu(qwerty)     hu        HU
 xkb:it::ita           it             it,it-IT  IT login
 xkb:is::ice           is             is        IS login
 xkb:no::nob           no             nb,nn,no  NO login
@@ -107,6 +113,7 @@
 xkb:si::slv           si             sl        SI login
 xkb:rs::srp           rs             sr        RS
 xkb:tr::tur           tr             tr        TR login
+xkb:tr:f:tur          tr(f)          tr        TR
 xkb:ua::ukr           ua             uk        UA
 xkb:by::bel           by             be        BY
 xkb:am:phonetic:arm   am             hy        AM
diff --git a/components/keyed_service/core/BUILD.gn b/components/keyed_service/core/BUILD.gn
index 9a52d82..ae58817 100644
--- a/components/keyed_service/core/BUILD.gn
+++ b/components/keyed_service/core/BUILD.gn
@@ -24,6 +24,12 @@
     "refcounted_keyed_service_factory.cc",
     "refcounted_keyed_service_factory.h",
     "service_access_type.h",
+    "simple_dependency_manager.cc",
+    "simple_dependency_manager.h",
+    "simple_factory_key.cc",
+    "simple_factory_key.h",
+    "simple_keyed_service_factory.cc",
+    "simple_keyed_service_factory.h",
   ]
 
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
diff --git a/components/keyed_service/core/simple_dependency_manager.cc b/components/keyed_service/core/simple_dependency_manager.cc
new file mode 100644
index 0000000..a70d694
--- /dev/null
+++ b/components/keyed_service/core/simple_dependency_manager.cc
@@ -0,0 +1,49 @@
+// 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 "components/keyed_service/core/simple_dependency_manager.h"
+
+#include "base/no_destructor.h"
+#include "components/keyed_service/core/simple_factory_key.h"
+
+#ifndef NDEBUG
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+
+namespace {
+
+// Dumps dependency information about our simple keyed services
+// into a dot file in the browser context directory.
+const char kDumpSimpleDependencyGraphFlag[] = "dump-simple-graph";
+
+}  // namespace
+#endif  // NDEBUG
+
+void SimpleDependencyManager::DestroyKeyedServices(SimpleFactoryKey* key) {
+  DependencyManager::DestroyContextServices(key);
+}
+
+// static
+SimpleDependencyManager* SimpleDependencyManager::GetInstance() {
+  static base::NoDestructor<SimpleDependencyManager> factory;
+  return factory.get();
+}
+
+SimpleDependencyManager::SimpleDependencyManager() = default;
+
+SimpleDependencyManager::~SimpleDependencyManager() = default;
+
+#ifndef NDEBUG
+void SimpleDependencyManager::DumpContextDependencies(void* context) const {
+  // Whenever we try to build a destruction ordering, we should also dump a
+  // dependency graph to "/path/to/context/context-dependencies.dot".
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          kDumpSimpleDependencyGraphFlag)) {
+    base::FilePath dot_file =
+        static_cast<const SimpleFactoryKey*>(context)->path().AppendASCII(
+            "simple-dependencies.dot");
+    DumpDependenciesAsGraphviz("SimpleDependencyManager", dot_file);
+  }
+}
+#endif  // NDEBUG
diff --git a/components/keyed_service/core/simple_dependency_manager.h b/components/keyed_service/core/simple_dependency_manager.h
new file mode 100644
index 0000000..4358b1c2
--- /dev/null
+++ b/components/keyed_service/core/simple_dependency_manager.h
@@ -0,0 +1,35 @@
+// 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 COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_DEPENDENCY_MANAGER_H_
+#define COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_DEPENDENCY_MANAGER_H_
+
+#include "components/keyed_service/core/dependency_manager.h"
+#include "components/keyed_service/core/keyed_service_export.h"
+
+class SimpleFactoryKey;
+
+// A singleton that listens for owners of SimpleFactoryKey' destruction
+// notifications and rebroadcasts them to each SimpleKeyedBaseFactory in a safe
+// order based on the stated dependencies by each service.
+class KEYED_SERVICE_EXPORT SimpleDependencyManager : public DependencyManager {
+ public:
+  SimpleDependencyManager();
+
+  // Called by each owners of SimpleFactoryKey before it is destroyed in order
+  // to destroy all services associated with |key|.
+  void DestroyKeyedServices(SimpleFactoryKey* key);
+
+  static SimpleDependencyManager* GetInstance();
+
+ private:
+  ~SimpleDependencyManager() override;
+
+#ifndef NDEBUG
+  // DependencyManager:
+  void DumpContextDependencies(void* context) const final;
+#endif  // NDEBUG
+};
+
+#endif  // COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_DEPENDENCY_MANAGER_H_
diff --git a/components/keyed_service/core/simple_factory_key.cc b/components/keyed_service/core/simple_factory_key.cc
new file mode 100644
index 0000000..17d891c
--- /dev/null
+++ b/components/keyed_service/core/simple_factory_key.cc
@@ -0,0 +1,11 @@
+// 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 "components/keyed_service/core/simple_factory_key.h"
+
+SimpleFactoryKey::SimpleFactoryKey(const base::FilePath& path,
+                                   SimpleFactoryKey* original_key)
+    : path_(path), original_key_(original_key) {}
+
+SimpleFactoryKey::~SimpleFactoryKey() = default;
diff --git a/components/keyed_service/core/simple_factory_key.h b/components/keyed_service/core/simple_factory_key.h
new file mode 100644
index 0000000..1274adf
--- /dev/null
+++ b/components/keyed_service/core/simple_factory_key.h
@@ -0,0 +1,37 @@
+// 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 COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_FACTORY_KEY_H_
+#define COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_FACTORY_KEY_H_
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "components/keyed_service/core/keyed_service_export.h"
+
+// A key used by SimpleKeyedServiceFactory is used to associated the
+// KeyedService instances. It is a way to have KeyedService without depending on
+// a more complex context. It can be mixed with more heavy-weight
+// KeyedServiceFactories if there is a unique mapping between the
+// SimpleFactoryKey and the more complex context. This mapping is the
+// responsibility of the embedder.
+class KEYED_SERVICE_EXPORT SimpleFactoryKey {
+ public:
+  explicit SimpleFactoryKey(const base::FilePath& path,
+                            SimpleFactoryKey* original_key = nullptr);
+  ~SimpleFactoryKey();
+
+  const base::FilePath& path() const { return path_; }
+  bool is_off_the_record() const { return original_key_ != nullptr; }
+  SimpleFactoryKey* original_key() { return original_key_; }
+
+ private:
+  base::FilePath path_;
+
+  // Points to the original (non off-the-record) SimpleFactoryKey.
+  SimpleFactoryKey* original_key_ = nullptr;
+
+  DISALLOW_COPY_AND_ASSIGN(SimpleFactoryKey);
+};
+
+#endif  // COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_FACTORY_KEY_H_
diff --git a/components/keyed_service/core/simple_keyed_service_factory.cc b/components/keyed_service/core/simple_keyed_service_factory.cc
new file mode 100644
index 0000000..4582f9c
--- /dev/null
+++ b/components/keyed_service/core/simple_keyed_service_factory.cc
@@ -0,0 +1,114 @@
+// 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 "components/keyed_service/core/simple_keyed_service_factory.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "components/keyed_service/core/simple_dependency_manager.h"
+#include "components/keyed_service/core/simple_factory_key.h"
+
+void SimpleKeyedServiceFactory::SetTestingFactory(
+    SimpleFactoryKey* key,
+    TestingFactory testing_factory) {
+  KeyedServiceFactory::TestingFactory wrapped_factory;
+  if (testing_factory) {
+    wrapped_factory = base::BindRepeating(
+        [](const TestingFactory& testing_factory, void* context) {
+          return testing_factory.Run(static_cast<SimpleFactoryKey*>(context));
+        },
+        std::move(testing_factory));
+  }
+  KeyedServiceFactory::SetTestingFactory(key, std::move(wrapped_factory));
+}
+
+KeyedService* SimpleKeyedServiceFactory::SetTestingFactoryAndUse(
+    SimpleFactoryKey* key,
+    PrefService* prefs,
+    TestingFactory testing_factory) {
+  DCHECK(testing_factory);
+  return KeyedServiceFactory::SetTestingFactoryAndUse(
+      key, prefs,
+      base::BindRepeating(
+          [](const TestingFactory& testing_factory, void* context) {
+            return testing_factory.Run(static_cast<SimpleFactoryKey*>(context));
+          },
+          std::move(testing_factory)));
+}
+
+SimpleKeyedServiceFactory::SimpleKeyedServiceFactory(
+    const char* name,
+    SimpleDependencyManager* manager)
+    : KeyedServiceFactory(name, manager) {}
+
+SimpleKeyedServiceFactory::~SimpleKeyedServiceFactory() {}
+
+KeyedService* SimpleKeyedServiceFactory::GetServiceForKey(SimpleFactoryKey* key,
+                                                          PrefService* prefs,
+                                                          bool create) {
+  return KeyedServiceFactory::GetServiceForContext(key, prefs, create);
+}
+
+SimpleFactoryKey* SimpleKeyedServiceFactory::GetKeyToUse(
+    SimpleFactoryKey* key) const {
+  // TODO(crbug.com/701326): This DCHECK should be moved to GetContextToUse().
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // Safe default for Incognito mode: no service.
+  if (key->is_off_the_record())
+    return nullptr;
+
+  return key;
+}
+
+void SimpleKeyedServiceFactory::SimpleContextShutdown(SimpleFactoryKey* key) {
+  KeyedServiceFactory::ContextShutdown(key);
+}
+
+void SimpleKeyedServiceFactory::SimpleContextDestroyed(SimpleFactoryKey* key) {
+  KeyedServiceFactory::ContextDestroyed(key);
+}
+
+std::unique_ptr<KeyedService>
+SimpleKeyedServiceFactory::BuildServiceInstanceFor(void* context,
+                                                   void* side_parameter) const {
+  return BuildServiceInstanceFor(static_cast<SimpleFactoryKey*>(context),
+                                 static_cast<PrefService*>(side_parameter));
+}
+
+bool SimpleKeyedServiceFactory::IsOffTheRecord(void* context) const {
+  return static_cast<SimpleFactoryKey*>(context)->is_off_the_record();
+}
+
+void* SimpleKeyedServiceFactory::GetContextToUse(void* context) const {
+  AssertContextWasntDestroyed(context);
+  return GetKeyToUse(static_cast<SimpleFactoryKey*>(context));
+}
+
+bool SimpleKeyedServiceFactory::ServiceIsCreatedWithContext() const {
+  return false;
+}
+
+void SimpleKeyedServiceFactory::ContextShutdown(void* context) {
+  SimpleContextShutdown(static_cast<SimpleFactoryKey*>(context));
+}
+
+void SimpleKeyedServiceFactory::ContextDestroyed(void* context) {
+  SimpleContextDestroyed(static_cast<SimpleFactoryKey*>(context));
+}
+
+void SimpleKeyedServiceFactory::RegisterPrefs(
+    user_prefs::PrefRegistrySyncable* registry) {
+  RegisterProfilePrefs(registry);
+}
+
+void SimpleKeyedServiceFactory::SetEmptyTestingFactory(void* context) {}
+
+bool SimpleKeyedServiceFactory::HasTestingFactory(void* context) {
+  return false;
+}
+
+void SimpleKeyedServiceFactory::CreateServiceNow(void* context) {}
diff --git a/components/keyed_service/core/simple_keyed_service_factory.h b/components/keyed_service/core/simple_keyed_service_factory.h
new file mode 100644
index 0000000..18584bb
--- /dev/null
+++ b/components/keyed_service/core/simple_keyed_service_factory.h
@@ -0,0 +1,118 @@
+// 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 COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_KEYED_SERVICE_FACTORY_H_
+#define COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_KEYED_SERVICE_FACTORY_H_
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "components/keyed_service/core/keyed_service_export.h"
+#include "components/keyed_service/core/keyed_service_factory.h"
+
+class KeyedService;
+class PrefService;
+class SimpleDependencyManager;
+class SimpleFactoryKey;
+
+// Base class for Factories that take a SimpleFactoryKey object and return some
+// service on a one-to-one mapping. Each factory that derives from this class
+// *must* be a Singleton (only unit tests don't do that).
+//
+// We do this because services depend on each other and we need to control
+// shutdown/destruction order. In each derived classes' constructors, the
+// implementors must explicitly state on which services they depend.
+class KEYED_SERVICE_EXPORT SimpleKeyedServiceFactory
+    : public KeyedServiceFactory {
+ public:
+  // A callback that supplies the instance of a KeyedService for a given
+  // SimpleFactoryKey. This is used primarily for testing, where we want to feed
+  // a specific test double into the SKSF system.
+  using TestingFactory = base::RepeatingCallback<std::unique_ptr<KeyedService>(
+      SimpleFactoryKey* key)>;
+
+  // Associates |testing_factory| with |key| so that |testing_factory| is
+  // used to create the KeyedService when requested.  |testing_factory| can be
+  // empty to signal that KeyedService should be null. Multiple calls to
+  // SetTestingFactory() are allowed; previous services will be shut down.
+  void SetTestingFactory(SimpleFactoryKey* key, TestingFactory testing_factory);
+
+  // Associates |testing_factory| with |key| and immediately returns the
+  // created KeyedService. Since the factory will be used immediately, it may
+  // not be empty.
+  KeyedService* SetTestingFactoryAndUse(SimpleFactoryKey* key,
+                                        PrefService* prefs,
+                                        TestingFactory testing_factory);
+
+ protected:
+  SimpleKeyedServiceFactory(const char* name, SimpleDependencyManager* manager);
+  ~SimpleKeyedServiceFactory() override;
+
+  // Common implementation that maps |key| to some service object. Deals
+  // with incognito contexts per subclass instructions with
+  // GetBrowserContextRedirectedInIncognito() and
+  // GetBrowserContextOwnInstanceInIncognito() through the
+  // GetBrowserContextToUse() method on the base.  If |create| is true, the
+  // service will be created using BuildServiceInstanceFor() if it doesn't
+  // already exist.
+  KeyedService* GetServiceForKey(SimpleFactoryKey* key,
+                                 PrefService* prefs,
+                                 bool create);
+
+  // Interface for people building a concrete FooServiceFactory: --------------
+
+  // Finds which SimpleFactoryKey (if any) to use.
+  virtual SimpleFactoryKey* GetKeyToUse(SimpleFactoryKey* key) const;
+
+  // Interface for people building a type of SimpleKeyedFactory: -------
+
+  // All subclasses of SimpleKeyedServiceFactory must return a
+  // KeyedService.
+  virtual std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      SimpleFactoryKey* key,
+      PrefService* prefs) const = 0;
+
+  // A helper object actually listens for notifications about BrowserContext
+  // destruction, calculates the order in which things are destroyed and then
+  // does a two pass shutdown.
+  //
+  // First, SimpleContextShutdown() is called on every ServiceFactory and will
+  // usually call KeyedService::Shutdown(), which gives each
+  // KeyedService a chance to remove dependencies on other
+  // services that it may be holding.
+  //
+  // Secondly, SimpleContextDestroyed() is called on every ServiceFactory
+  // and the default implementation removes it from |mapping_| and deletes
+  // the pointer.
+  virtual void SimpleContextShutdown(SimpleFactoryKey* key);
+  virtual void SimpleContextDestroyed(SimpleFactoryKey* key);
+
+ private:
+  // Registers any user preferences on this service. This is called by
+  // RegisterPrefsIfNecessaryForContext() and should be overriden by any service
+  // that wants to register profile-specific preferences.
+  virtual void RegisterProfilePrefs(
+      user_prefs::PrefRegistrySyncable* registry) {}
+
+  // KeyedServiceFactory:
+  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
+      void* context,
+      void* side_parameter) const final;
+  bool IsOffTheRecord(void* context) const final;
+
+  // KeyedServiceBaseFactory:
+  void* GetContextToUse(void* context) const final;
+  bool ServiceIsCreatedWithContext() const final;
+  void ContextShutdown(void* context) final;
+  void ContextDestroyed(void* context) final;
+  void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry) final;
+  void SetEmptyTestingFactory(void* context) final;
+  bool HasTestingFactory(void* context) final;
+  void CreateServiceNow(void* context) final;
+
+  DISALLOW_COPY_AND_ASSIGN(SimpleKeyedServiceFactory);
+};
+
+#endif  // COMPONENTS_KEYED_SERVICE_CORE_SIMPLE_KEYED_SERVICE_FACTORY_H_
diff --git a/components/omnibox/browser/clipboard_provider.cc b/components/omnibox/browser/clipboard_provider.cc
index 9b8d945..68f5d59 100644
--- a/components/omnibox/browser/clipboard_provider.cc
+++ b/components/omnibox/browser/clipboard_provider.cc
@@ -13,6 +13,7 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/weak_ptr.h"
+#include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
@@ -42,6 +43,8 @@
       clipboard_content_(clipboard_content),
       history_url_provider_(history_url_provider),
       current_url_suggested_times_(0),
+      field_trial_triggered_(false),
+      field_trial_triggered_in_session_(false),
       callback_weak_ptr_factory_(this) {
   DCHECK(clipboard_content_);
 }
@@ -51,6 +54,7 @@
 void ClipboardProvider::Start(const AutocompleteInput& input,
                               bool minimal_changes) {
   matches_.clear();
+  field_trial_triggered_ = false;
 
   // If the user started typing, do not offer clipboard based match.
   if (!input.from_omnibox_focus()) {
@@ -80,6 +84,11 @@
   AutocompleteProvider::Stop(clear_cached_results, due_to_user_inactivity);
 }
 
+void ClipboardProvider::ResetSession() {
+  field_trial_triggered_ = false;
+  field_trial_triggered_in_session_ = false;
+}
+
 void ClipboardProvider::AddCreatedMatchWithTracking(
     const AutocompleteInput& input,
     const AutocompleteMatch& match,
@@ -204,6 +213,16 @@
   match.keyword = default_url->keyword();
   match.transition = ui::PAGE_TRANSITION_GENERATED;
 
+  // Some users may be in a counterfactual study arm in which we perform all
+  // necessary work but do not forward the autocomplete matches.
+  bool in_counterfactual_group = base::GetFieldTrialParamByFeatureAsBool(
+      omnibox::kEnableClipboardProviderTextSuggestions,
+      "ClipboardProviderTextSuggestionsCounterfactualArm", false);
+  field_trial_triggered_ = true;
+  field_trial_triggered_in_session_ = true;
+  if (in_counterfactual_group) {
+    return base::nullopt;
+  }
   return match;
 }
 
@@ -285,8 +304,17 @@
 
   match.transition = ui::PAGE_TRANSITION_GENERATED;
 
-  AddCreatedMatchWithTracking(input, match, clipboard_contents_age);
-  listener_->OnProviderUpdate(true);
+  // Some users may be in a counterfactual study arm in which we perform all
+  // necessary work but do not forward the autocomplete matches.
+  bool in_counterfactual_group = base::GetFieldTrialParamByFeatureAsBool(
+      omnibox::kEnableClipboardProviderImageSuggestions,
+      "ClipboardProviderImageSuggestionsCounterfactualArm", false);
+  if (!in_counterfactual_group) {
+    AddCreatedMatchWithTracking(input, match, clipboard_contents_age);
+    listener_->OnProviderUpdate(true);
+  }
+  field_trial_triggered_ = true;
+  field_trial_triggered_in_session_ = true;
   done_ = true;
 }
 
@@ -301,5 +329,19 @@
   provider_info->push_back(metrics::OmniboxEventProto_ProviderInfo());
   metrics::OmniboxEventProto_ProviderInfo& new_entry = provider_info->back();
   new_entry.set_provider(AsOmniboxEventProviderType());
+  new_entry.set_provider_done(done_);
   new_entry.set_times_returned_results_in_session(current_url_suggested_times_);
+
+  if (field_trial_triggered_ || field_trial_triggered_in_session_) {
+    std::vector<uint32_t> field_trial_hashes;
+    OmniboxFieldTrial::GetActiveSuggestFieldTrialHashes(&field_trial_hashes);
+    for (uint32_t trial : field_trial_hashes) {
+      if (field_trial_triggered_) {
+        new_entry.mutable_field_trial_triggered()->Add(trial);
+      }
+      if (field_trial_triggered_in_session_) {
+        new_entry.mutable_field_trial_triggered_in_session()->Add(trial);
+      }
+    }
+  }
 }
diff --git a/components/omnibox/browser/clipboard_provider.h b/components/omnibox/browser/clipboard_provider.h
index bfd38b5..022df7d 100644
--- a/components/omnibox/browser/clipboard_provider.h
+++ b/components/omnibox/browser/clipboard_provider.h
@@ -26,6 +26,7 @@
   void Start(const AutocompleteInput& input, bool minimal_changes) override;
   void Stop(bool clear_cached_results, bool due_to_user_inactivity) override;
   void AddProviderInfo(ProvidersInfo* provider_info) const override;
+  void ResetSession() override;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(ClipboardProviderTest, MatchesImage);
@@ -76,6 +77,12 @@
   GURL current_url_suggested_;
   size_t current_url_suggested_times_;
 
+  // Whether a field trial has triggered for this query and this session,
+  // respectively. Works similarly to BaseSearchProvider, though this class does
+  // not inherit from it.
+  bool field_trial_triggered_;
+  bool field_trial_triggered_in_session_;
+
   // Used to cancel image construction callbacks if autocomplete Stop() is
   // called.
   base::WeakPtrFactory<ClipboardProvider> callback_weak_ptr_factory_;
diff --git a/components/password_manager/ios/password_form_helper.h b/components/password_manager/ios/password_form_helper.h
index f6df76f..d619c0a 100644
--- a/components/password_manager/ios/password_form_helper.h
+++ b/components/password_manager/ios/password_form_helper.h
@@ -19,6 +19,7 @@
 namespace autofill {
 struct PasswordForm;
 struct PasswordFormFillData;
+struct FormData;
 }  // namespace autofill
 
 namespace password_manager {
@@ -89,6 +90,14 @@
                            completionHandler:
                                (nullable void (^)(BOOL))completionHandler;
 
+// Finds the password form named |formName| and calls
+// |completionHandler| with the populated |FormData| data structure. |found| is
+// YES if the current form was found successfully, NO otherwise.
+- (void)extractPasswordFormData:(const std::string&)formName
+              completionHandler:
+                  (void (^)(BOOL found,
+                            const autofill::FormData& form))completionHandler;
+
 // Creates a instance with the given WebState, observer and delegate.
 - (instancetype)initWithWebState:(web::WebState*)webState
                         delegate:
diff --git a/components/password_manager/ios/password_form_helper.mm b/components/password_manager/ios/password_form_helper.mm
index dd30c6d..5aceefd 100644
--- a/components/password_manager/ios/password_form_helper.mm
+++ b/components/password_manager/ios/password_form_helper.mm
@@ -424,4 +424,43 @@
   }];
 }
 
+// Finds the password form named |formName| and calls
+// |completionHandler| with the populated |FormData| data structure. |found| is
+// YES if the current form was found successfully, NO otherwise.
+- (void)extractPasswordFormData:(const std::string&)formName
+              completionHandler:(void (^)(BOOL found, const FormData& form))
+                                    completionHandler {
+  DCHECK(completionHandler);
+
+  if (!_webState) {
+    return;
+  }
+
+  GURL pageURL;
+  if (!GetPageURLAndCheckTrustLevel(_webState, &pageURL)) {
+    completionHandler(NO, FormData());
+    return;
+  }
+
+  id extractFormDataCompletionHandler = ^(NSString* jsonString) {
+    std::unique_ptr<base::Value> formValue = autofill::ParseJson(jsonString);
+    if (!formValue) {
+      completionHandler(NO, FormData());
+      return;
+    }
+
+    FormData formData;
+    if (!autofill::ExtractFormData(*formValue, false, base::string16(), pageURL,
+                                   pageURL.GetOrigin(), &formData)) {
+      completionHandler(NO, FormData());
+      return;
+    }
+
+    completionHandler(YES, formData);
+  };
+
+  [self.jsPasswordManager extractForm:base::SysUTF8ToNSString(formName)
+                    completionHandler:extractFormDataCompletionHandler];
+}
+
 @end
diff --git a/components/password_manager/ios/password_form_helper_unittest.mm b/components/password_manager/ios/password_form_helper_unittest.mm
index cec663f..bcb2e44 100644
--- a/components/password_manager/ios/password_form_helper_unittest.mm
+++ b/components/password_manager/ios/password_form_helper_unittest.mm
@@ -10,6 +10,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/ios/wait_util.h"
+#include "components/autofill/core/common/form_data.h"
 #include "components/autofill/core/common/password_form_fill_data.h"
 #include "components/password_manager/core/browser/log_manager.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
@@ -30,6 +31,7 @@
 
 NS_ASSUME_NONNULL_BEGIN
 
+using autofill::FormData;
 using autofill::PasswordForm;
 using autofill::PasswordFormFillData;
 using base::test::ios::kWaitForJSCompletionTimeout;
@@ -733,6 +735,53 @@
       result);
 }
 
+// Tests that extractPasswordFormData extracts wanted form on page with mutiple
+// forms.
+TEST_F(PasswordFormHelperTest, ExtractPasswordFormData) {
+  MockJsPasswordManager* mockJsPasswordManager = [[MockJsPasswordManager alloc]
+      initWithReceiver:web_state()->GetJSInjectionReceiver()];
+  [helper_ setJsPasswordManager:mockJsPasswordManager];
+  LoadHtml(@"<form><input id='u1' type='text' name='un1'>"
+            "<input id='p1' type='password' name='pw1'></form>"
+            "<form><input id='u2' type='text' name='un2'>"
+            "<input id='p2' type='password' name='pw2'></form>"
+            "<form><input id='u3' type='text' name='un3'>"
+            "<input id='p3' type='password' name='pw3'></form>");
+  __block int call_counter = 0;
+  __block int success_counter = 0;
+  __block FormData result = FormData();
+  [helper_ extractPasswordFormData:GetFormId(1)
+                 completionHandler:^(BOOL complete, const FormData& form) {
+                   ++call_counter;
+                   if (complete) {
+                     ++success_counter;
+                     result = form;
+                   }
+                 }];
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return call_counter == 1;
+  }));
+  EXPECT_EQ(1, success_counter);
+  EXPECT_EQ(result.name, base::ASCIIToUTF16(GetFormId(1)));
+
+  call_counter = 0;
+  success_counter = 0;
+  result = FormData();
+
+  [helper_ extractPasswordFormData:"unknown"
+                 completionHandler:^(BOOL complete, const FormData& form) {
+                   ++call_counter;
+                   if (complete) {
+                     ++success_counter;
+                     result = form;
+                   }
+                 }];
+  EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForJSCompletionTimeout, ^{
+    return call_counter == 1;
+  }));
+  EXPECT_EQ(0, success_counter);
+}
+
 }  // namespace
 
 NS_ASSUME_NONNULL_END
diff --git a/components/payments/content/payment_request_spec.cc b/components/payments/content/payment_request_spec.cc
index 7a6a1529..c8dee60 100644
--- a/components/payments/content/payment_request_spec.cc
+++ b/components/payments/content/payment_request_spec.cc
@@ -106,7 +106,8 @@
     details_->display_items = std::move(details->display_items);
   if (details->shipping_options)
     details_->shipping_options = std::move(details->shipping_options);
-  details_->modifiers = std::move(details->modifiers);
+  if (!details->modifiers.empty())
+    details_->modifiers = std::move(details->modifiers);
   details_->error = std::move(details->error);
   if (details->shipping_address_errors)
     details_->shipping_address_errors =
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 5bc3638..326820d 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -890,9 +890,11 @@
         'CloudPrintProxyEnabled',
         'PrintingAllowedColorModes',
         'PrintingAllowedDuplexModes',
+        'PrintingAllowedPinModes',
         'PrintingAllowedPageSizes',
         'PrintingColorDefault',
         'PrintingDuplexDefault',
+        'PrintingPinDefault',
         'PrintingSizeDefault',
         'PrintingSendUsernameAndFilenameEnabled',
         'CloudPrintSubmitEnabled',
@@ -1922,6 +1924,47 @@
       'desc': '''Restricts printing duplex mode. Unset policy and empty set are treated as no restriction.''',
     },
     {
+      'name': 'PrintingAllowedPinModes',
+      'type': 'string-enum',
+      'schema': {
+        'type': 'string',
+        'enum': [
+          'any',
+          'secure',
+          'unsecure',
+        ],
+      },
+      'items': [
+        {
+          'name': 'any',
+          'value': 'any',
+          'caption': '''Allow printing both with and without PIN''',
+        },
+        {
+          'name': 'secure',
+          'value': 'secure',
+          'caption': '''Allow printing only with PIN''',
+        },
+        {
+          'name': 'unsecure',
+          'value': 'unsecure',
+          'caption': '''Allow printing only without PIN''',
+        },
+      ],
+      'supported_on': ['chrome_os:74-'],
+      'future': True,
+      'features': {
+        'can_be_recommended': False,
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'example_value': 'secure',
+      'id': 525,
+      'caption': '''Restrict PIN printing mode''',
+      'tags': [],
+      'desc': '''Restricts PIN printing mode. Unset policy is treated as no restriction. If the mode is unavailable this policy is ignored.''',
+    },
+    {
       'name': 'PrintingAllowedPageSizes',
       'type': 'dict',
       'schema': {
@@ -2029,6 +2072,41 @@
       'desc': '''Overrides default printing duplex mode. If the mode is unavailable this policy is ignored.''',
     },
     {
+      'name': 'PrintingPinDefault',
+      'type': 'string-enum',
+      'schema': {
+        'type': 'string',
+        'enum': [
+          'secure',
+          'unsecure',
+        ],
+      },
+      'items': [
+        {
+          'name': 'secure',
+          'value': 'secure',
+          'caption': '''Enable PIN printing by default''',
+        },
+        {
+          'name': 'unsecure',
+          'value': 'unsecure',
+          'caption': '''Disable PIN printing by default''',
+        },
+      ],
+      'supported_on': ['chrome_os:74-'],
+      'future': True,
+      'features': {
+        'can_be_recommended': False,
+        'dynamic_refresh': True,
+        'per_profile': True,
+      },
+      'example_value': 'secure',
+      'id': 526,
+      'caption': '''Default PIN printing mode''',
+      'tags': [],
+      'desc': '''Overrides default PIN printing mode. If the mode is unavailable this policy is ignored.''',
+    },
+    {
       'name': 'PrintingSizeDefault',
       'type': 'dict',
       'schema': {
@@ -14858,5 +14936,5 @@
   },
   'placeholders': [],
   'deleted_policy_ids': [412],
-  'highest_id_currently_used':  524
+  'highest_id_currently_used':  526
 }
diff --git a/components/signin/core/browser/BUILD.gn b/components/signin/core/browser/BUILD.gn
index cac9425..8d2f99a 100644
--- a/components/signin/core/browser/BUILD.gn
+++ b/components/signin/core/browser/BUILD.gn
@@ -134,6 +134,8 @@
     "dice_account_reconcilor_delegate.h",
     "dice_header_helper.cc",
     "dice_header_helper.h",
+    "mice_account_reconcilor_delegate.cc",
+    "mice_account_reconcilor_delegate.h",
     "mirror_account_reconcilor_delegate.cc",
     "mirror_account_reconcilor_delegate.h",
     "mutable_profile_oauth2_token_service_delegate.cc",
diff --git a/components/signin/core/browser/account_consistency_method.cc b/components/signin/core/browser/account_consistency_method.cc
index f5ac557..b0b031a 100644
--- a/components/signin/core/browser/account_consistency_method.cc
+++ b/components/signin/core/browser/account_consistency_method.cc
@@ -15,6 +15,11 @@
 }
 }  // namespace
 
+#if defined(OS_ANDROID)
+const base::Feature kMiceFeature{"MobileIdentityConsistency",
+                                 base::FEATURE_DISABLED_BY_DEFAULT};
+#endif
+
 bool DiceMethodGreaterOrEqual(AccountConsistencyMethod a,
                               AccountConsistencyMethod b) {
   DCHECK_NE(AccountConsistencyMethod::kMirror, a);
diff --git a/components/signin/core/browser/account_consistency_method.h b/components/signin/core/browser/account_consistency_method.h
index bee4dc3..c46becf 100644
--- a/components/signin/core/browser/account_consistency_method.h
+++ b/components/signin/core/browser/account_consistency_method.h
@@ -9,8 +9,17 @@
 #ifndef COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_CONSISTENCY_METHOD_H_
 #define COMPONENTS_SIGNIN_CORE_BROWSER_ACCOUNT_CONSISTENCY_METHOD_H_
 
+#include "base/feature_list.h"
+#include "build/build_config.h"
+
 namespace signin {
 
+#if defined(OS_ANDROID)
+// Mice is similar to Mirror but also works when the user is not opted into
+// Sync.
+extern const base::Feature kMiceFeature;
+#endif
+
 // TODO(https://crbug.com/777774): Cleanup this enum and remove related
 // functions once Dice is fully rolled out, and/or Mirror code is removed on
 // desktop.
diff --git a/components/signin/core/browser/account_reconcilor.cc b/components/signin/core/browser/account_reconcilor.cc
index aaf1c25..ac52a27 100644
--- a/components/signin/core/browser/account_reconcilor.cc
+++ b/components/signin/core/browser/account_reconcilor.cc
@@ -120,7 +120,8 @@
 }
 
 // Returns true if current array of existing accounts in cookie is different
-// from the desired one.
+// from the desired one. If this returns false, the multilogin call would be a
+// no-op.
 bool AccountsNeedUpdate(
     const signin::MultiloginParameters& parameters,
     const std::vector<gaia::ListedAccount>& existing_accounts) {
@@ -585,9 +586,11 @@
                            signin_metrics::SourceForRefreshTokenOperation::
                                kAccountReconcilor_GaiaCookiesUpdated);
 
+  std::vector<std::string> chrome_accounts =
+      LoadValidAccountsFromTokenService();
+
   if (delegate_->ShouldAbortReconcileIfPrimaryHasError() &&
-      identity_manager_->HasAccountWithRefreshTokenInPersistentErrorState(
-          primary_account)) {
+      !base::ContainsValue(chrome_accounts, primary_account)) {
     VLOG(1) << "Primary account has error, abort.";
     DCHECK(is_reconcile_started_);
     AbortReconcile();
@@ -595,11 +598,10 @@
   }
 
   if (IsMultiloginEndpointEnabled()) {
-    FinishReconcileWithMultiloginEndpoint(primary_account,
-                                          LoadValidAccountsFromTokenService(),
+    FinishReconcileWithMultiloginEndpoint(primary_account, chrome_accounts,
                                           std::move(verified_gaia_accounts));
   } else {
-    FinishReconcile(primary_account, LoadValidAccountsFromTokenService(),
+    FinishReconcile(primary_account, chrome_accounts,
                     std::move(verified_gaia_accounts));
   }
 }
@@ -948,5 +950,10 @@
   if (!is_wkhttp_system_cookie_store_enabled_)
     return false;
 #endif  // defined(OS_IOS)
+
+#if defined(OS_ANDROID)
+  if (base::FeatureList::IsEnabled(signin::kMiceFeature))
+    return true;  // Mice is only implemented with multilogin.
+#endif
   return base::FeatureList::IsEnabled(kUseMultiloginEndpoint);
 }
diff --git a/components/signin/core/browser/mice_account_reconcilor_delegate.cc b/components/signin/core/browser/mice_account_reconcilor_delegate.cc
new file mode 100644
index 0000000..8fd952473
--- /dev/null
+++ b/components/signin/core/browser/mice_account_reconcilor_delegate.cc
@@ -0,0 +1,62 @@
+// 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 "components/signin/core/browser/mice_account_reconcilor_delegate.h"
+
+#include "base/logging.h"
+#include "components/signin/core/browser/account_reconcilor.h"
+
+namespace signin {
+
+MiceAccountReconcilorDelegate::MiceAccountReconcilorDelegate() = default;
+
+MiceAccountReconcilorDelegate::~MiceAccountReconcilorDelegate() = default;
+
+bool MiceAccountReconcilorDelegate::IsReconcileEnabled() const {
+  return true;
+}
+
+bool MiceAccountReconcilorDelegate::IsAccountConsistencyEnforced() const {
+  return true;
+}
+
+gaia::GaiaSource MiceAccountReconcilorDelegate::GetGaiaApiSource() const {
+  return gaia::GaiaSource::kAccountReconcilorMirror;
+}
+
+bool MiceAccountReconcilorDelegate::ShouldAbortReconcileIfPrimaryHasError()
+    const {
+  return false;
+}
+
+std::string MiceAccountReconcilorDelegate::GetFirstGaiaAccountForReconcile(
+    const std::vector<std::string>& chrome_accounts,
+    const std::vector<gaia::ListedAccount>& gaia_accounts,
+    const std::string& primary_account,
+    bool first_execution,
+    bool will_logout) const {
+  // This flow is deprecated and will be removed when multilogin is fully
+  // launched.
+  NOTREACHED() << "Mice requires multilogin";
+  return std::string();
+}
+
+std::vector<std::string>
+MiceAccountReconcilorDelegate::GetChromeAccountsForReconcile(
+    const std::vector<std::string>& chrome_accounts,
+    const std::string& primary_account,
+    const std::vector<gaia::ListedAccount>& gaia_accounts,
+    const gaia::MultiloginMode mode) const {
+  return chrome_accounts;
+}
+
+gaia::MultiloginMode MiceAccountReconcilorDelegate::CalculateModeForReconcile(
+    const std::vector<gaia::ListedAccount>& gaia_accounts,
+    const std::string primary_account,
+    bool first_execution,
+    bool primary_has_error) const {
+  return gaia::MultiloginMode::MULTILOGIN_UPDATE_COOKIE_ACCOUNTS_ORDER;
+}
+
+}  // namespace signin
diff --git a/components/signin/core/browser/mice_account_reconcilor_delegate.h b/components/signin/core/browser/mice_account_reconcilor_delegate.h
new file mode 100644
index 0000000..88a1f15
--- /dev/null
+++ b/components/signin/core/browser/mice_account_reconcilor_delegate.h
@@ -0,0 +1,50 @@
+// 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 COMPONENTS_SIGNIN_CORE_BROWSER_MICE_ACCOUNT_RECONCILOR_DELEGATE_H_
+#define COMPONENTS_SIGNIN_CORE_BROWSER_MICE_ACCOUNT_RECONCILOR_DELEGATE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "components/signin/core/browser/account_reconcilor_delegate.h"
+
+namespace signin {
+
+// AccountReconcilorDelegate specialized for Mice.
+class MiceAccountReconcilorDelegate : public AccountReconcilorDelegate {
+ public:
+  MiceAccountReconcilorDelegate();
+  ~MiceAccountReconcilorDelegate() override;
+
+ private:
+  // AccountReconcilorDelegate:
+  bool IsReconcileEnabled() const override;
+  bool IsAccountConsistencyEnforced() const override;
+  gaia::GaiaSource GetGaiaApiSource() const override;
+  bool ShouldAbortReconcileIfPrimaryHasError() const override;
+  std::string GetFirstGaiaAccountForReconcile(
+      const std::vector<std::string>& chrome_accounts,
+      const std::vector<gaia::ListedAccount>& gaia_accounts,
+      const std::string& primary_account,
+      bool first_execution,
+      bool will_logout) const override;
+  std::vector<std::string> GetChromeAccountsForReconcile(
+      const std::vector<std::string>& chrome_accounts,
+      const std::string& primary_account,
+      const std::vector<gaia::ListedAccount>& gaia_accounts,
+      const gaia::MultiloginMode mode) const override;
+  gaia::MultiloginMode CalculateModeForReconcile(
+      const std::vector<gaia::ListedAccount>& gaia_accounts,
+      const std::string primary_account,
+      bool first_execution,
+      bool primary_has_error) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(MiceAccountReconcilorDelegate);
+};
+
+}  // namespace signin
+
+#endif  // COMPONENTS_SIGNIN_CORE_BROWSER_MICE_ACCOUNT_RECONCILOR_DELEGATE_H_
diff --git a/components/test/data/payments/payment_request_update_with_test.html b/components/test/data/payments/payment_request_update_with_test.html
index 87fa0e6..c30f3ab 100644
--- a/components/test/data/payments/payment_request_update_with_test.html
+++ b/components/test/data/payments/payment_request_update_with_test.html
@@ -16,6 +16,7 @@
 <button class="small" onclick="updateWithTotal()" id="updateWithTotal">updateWithTotal</button>
 <button class="small" onclick="updateWithDisplayItems()" id="updateWithDisplayItems">updateWithDisplayItems</button>
 <button class="small" onclick="updateWithShippingOptions()" id="updateWithShippingOptions">updateWithShippingOptions</button>
+<button class="small" onclick="updateWithModifiers()" id="updateWithModifiers">updateWithModifiers</button>
 <pre id="result"></pre>
 <script src="util.js"></script>
 <script src="update_with.js"></script>
diff --git a/components/test/data/payments/update_with.js b/components/test/data/payments/update_with.js
index 93f810b..9791173 100644
--- a/components/test/data/payments/update_with.js
+++ b/components/test/data/payments/update_with.js
@@ -23,6 +23,13 @@
             label: 'Free shipping',
             amount: {currency: 'USD', value: '0.00'},
           }],
+          modifiers: [{
+            supportedMethods: 'basic-card',
+            additionalDisplayItems: [{
+              label: 'Discount',
+              amount: {currency: 'USD', value: '0.00'},
+            }],
+          }],
         },
         {requestShipping: true});
   } catch (error) {
@@ -123,3 +130,30 @@
   });
   showPaymentRequest(pr);
 }
+
+/**
+ * Calls updateWith() with modifiers
+ */
+function updateWithModifiers() {  // eslint-disable-line no-unused-vars
+  var pr = buildPaymentRequest();
+  var updatedDetails = {
+    modifiers: [{
+      supportedMethods: 'basic-card',
+      total: {
+        label: 'Modifier total',
+        amount: {currency: 'USD', value: '4.00'},
+      },
+      additionalDisplayItems: [{
+        label: 'Discount',
+        amount: {currency: 'USD', value: '-1.00'},
+      }],
+    }],
+  };
+  pr.addEventListener('shippingaddresschange', function(e) {
+    e.updateWith(updatedDetails);
+  });
+  pr.addEventListener('shippingoptionchange', function(e) {
+    e.updateWith(updatedDetails);
+  });
+  showPaymentRequest(pr);
+}
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index 23a010b..fdf8174 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -266,7 +266,7 @@
   return child_process_->GetProcess();
 }
 
-std::unique_ptr<base::SharedPersistentMemoryAllocator>
+std::unique_ptr<base::PersistentMemoryAllocator>
 BrowserChildProcessHostImpl::TakeMetricsAllocator() {
   return std::move(metrics_allocator_);
 }
@@ -568,25 +568,25 @@
   // Create the shared memory segment and attach an allocator to it.
   // Mapping the memory shouldn't fail but be safe if it does; everything
   // will continue to work but just as if persistence weren't available.
-  std::unique_ptr<base::SharedMemory> shm(new base::SharedMemory());
-  if (!shm->CreateAndMapAnonymous(memory_size))
+  base::WritableSharedMemoryRegion shm_region =
+      base::WritableSharedMemoryRegion::Create(memory_size);
+  base::WritableSharedMemoryMapping shm_mapping = shm_region.Map();
+  if (!shm_region.IsValid() || !shm_mapping.IsValid())
     return;
-  metrics_allocator_.reset(new base::SharedPersistentMemoryAllocator(
-      std::move(shm), static_cast<uint64_t>(data_.id), metrics_name,
-      /*readonly=*/false));
+  metrics_allocator_ =
+      std::make_unique<base::WritableSharedPersistentMemoryAllocator>(
+          std::move(shm_mapping), static_cast<uint64_t>(data_.id),
+          metrics_name);
+  metrics_shared_region_ = std::move(shm_region);
 }
 
 void BrowserChildProcessHostImpl::ShareMetricsAllocatorToProcess() {
   if (metrics_allocator_) {
     HistogramController::GetInstance()->SetHistogramMemory<ChildProcessHost>(
-        GetHost(),
-        mojo::WrapSharedMemoryHandle(
-            metrics_allocator_->shared_memory()->handle().Duplicate(),
-            metrics_allocator_->shared_memory()->mapped_size(),
-            mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite));
+        GetHost(), std::move(metrics_shared_region_));
   } else {
     HistogramController::GetInstance()->SetHistogramMemory<ChildProcessHost>(
-        GetHost(), mojo::ScopedSharedBufferHandle());
+        GetHost(), base::WritableSharedMemoryRegion());
   }
 }
 
diff --git a/content/browser/browser_child_process_host_impl.h b/content/browser/browser_child_process_host_impl.h
index 947e3a5..5c07d1b 100644
--- a/content/browser/browser_child_process_host_impl.h
+++ b/content/browser/browser_child_process_host_impl.h
@@ -12,8 +12,8 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
 #include "base/memory/weak_ptr.h"
+#include "base/memory/writable_shared_memory_region.h"
 #include "base/process/process.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event_watcher.h"
@@ -76,7 +76,7 @@
   const ChildProcessData& GetData() const override;
   ChildProcessHost* GetHost() const override;
   ChildProcessTerminationInfo GetTerminationInfo(bool known_dead) override;
-  std::unique_ptr<base::SharedPersistentMemoryAllocator> TakeMetricsAllocator()
+  std::unique_ptr<base::PersistentMemoryAllocator> TakeMetricsAllocator()
       override;
   void SetName(const base::string16& name) override;
   void SetMetricsName(const std::string& metrics_name) override;
@@ -181,7 +181,11 @@
 #endif
 
   // The memory allocator, if any, in which the process will write its metrics.
-  std::unique_ptr<base::SharedPersistentMemoryAllocator> metrics_allocator_;
+  std::unique_ptr<base::PersistentMemoryAllocator> metrics_allocator_;
+
+  // The shared memory region used by |metrics_allocator_| that should be
+  // transferred to the child process.
+  base::WritableSharedMemoryRegion metrics_shared_region_;
 
   IPC::Channel* channel_ = nullptr;
   bool is_channel_connected_;
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index 08c67f5..1f34a9b 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -1027,12 +1027,17 @@
 
   // Log UseCounters for opener navigations.
   if (is_download &&
-      download_policy ==
-          NavigationDownloadPolicy::kAllowOpenerCrossOriginNoGesture) {
+      download_policy == NavigationDownloadPolicy::kDisallowOpenerCrossOrigin) {
+    content::RenderFrameHost* rfh = frame_tree_node_->current_frame_host();
+    rfh->AddMessageToConsole(
+        CONSOLE_MESSAGE_LEVEL_ERROR,
+        base::StringPrintf(
+            "Navigating a cross-origin opener to a download (%s) is "
+            "deprecated, see "
+            "https://www.chromestatus.com/feature/5742188281462784.",
+            navigation_handle_->GetURL().spec().c_str()));
     GetContentClient()->browser()->LogWebFeatureForCurrentPage(
-        frame_tree_node_->current_frame_host(),
-        blink::mojom::WebFeature::
-            kOpenerNavigationDownloadCrossOriginNoGesture);
+        rfh, blink::mojom::WebFeature::kOpenerNavigationDownloadCrossOrigin);
   }
 
   // TODO(https://crbug.com/880741): Remove this once the bug is fixed.
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 1376c91..8d44d70 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -5803,6 +5803,12 @@
 std::unique_ptr<NavigationRequest>
 RenderFrameHostImpl::TakeNavigationRequestForCommit(
     const FrameHostMsg_DidCommitProvisionalLoad_Params& params) {
+  // TODO(ahemery): Once we have IsPerNavigationMojoInterfaceEnabled() always
+  // true, it becomes obsolete to match the NavigationRequest since we are
+  // sure it is the correct one. However using the same request even though
+  // url might have changed ("" becomes "about:blank", etc.) requires some
+  // updating.
+
   // Determine if the current NavigationRequest can be used.
   NavigationHandleImpl* navigation_handle =
       navigation_request_ ? navigation_request_->navigation_handle() : nullptr;
@@ -6199,6 +6205,11 @@
   DCHECK_EQ(ui::PageTransitionIsMainFrame(validated_params->transition),
             !GetParent());
 
+  if (navigation_request) {
+    OnCrossDocumentCommitProcessed(navigation_request,
+                                   blink::mojom::CommitResult::Ok);
+  }
+
   if (!ValidateDidCommitParams(validated_params, is_same_document_navigation))
     return false;
 
@@ -6217,23 +6228,11 @@
     was_discarded_ = navigation_request_->commit_params().was_discarded;
 
   std::unique_ptr<NavigationRequest> committed_request;
-  // |navigation_request| is committed, we pass full ownership to the Navigator.
-  if (navigation_request) {
-    auto it = navigation_requests_.find(navigation_request);
-    // If we provided a navigation_request and it committed, it should always
-    // be in the map.
-    CHECK(it != navigation_requests_.end());
-    committed_request = std::move(it->second);
-    navigation_requests_.erase(it);
-  }
-
-  if (!committed_request) {
-    if (is_same_document_navigation) {
-      committed_request =
-          TakeNavigationRequestForSameDocumentCommit(*validated_params);
-    } else {
-      committed_request = TakeNavigationRequestForCommit(*validated_params);
-    }
+  if (is_same_document_navigation) {
+    committed_request =
+        TakeNavigationRequestForSameDocumentCommit(*validated_params);
+  } else {
+    committed_request = TakeNavigationRequestForCommit(*validated_params);
   }
 
   DCHECK(committed_request);
diff --git a/content/browser/histogram_controller.cc b/content/browser/histogram_controller.cc
index 0963415..495edaf 100644
--- a/content/browser/histogram_controller.cc
+++ b/content/browser/histogram_controller.cc
@@ -91,22 +91,22 @@
 
 template void HistogramController::SetHistogramMemory(
     ChildProcessHost* host,
-    mojo::ScopedSharedBufferHandle shared_buffer);
+    base::WritableSharedMemoryRegion shared_region);
 
 template void HistogramController::SetHistogramMemory(
     RenderProcessHost* host,
-    mojo::ScopedSharedBufferHandle shared_buffer);
+    base::WritableSharedMemoryRegion shared_region);
 
 template <class T>
 void HistogramController::SetHistogramMemory(
     T* host,
-    mojo::ScopedSharedBufferHandle shared_buffer) {
+    base::WritableSharedMemoryRegion shared_region) {
   content::mojom::ChildHistogramFetcherFactoryPtr
       child_histogram_fetcher_factory;
   content::mojom::ChildHistogramFetcherPtr child_histogram_fetcher;
   content::BindInterface(host, &child_histogram_fetcher_factory);
   child_histogram_fetcher_factory->CreateFetcher(
-      std::move(shared_buffer), mojo::MakeRequest(&child_histogram_fetcher));
+      std::move(shared_region), mojo::MakeRequest(&child_histogram_fetcher));
   InsertChildHistogramFetcherInterface(host,
                                        std::move(child_histogram_fetcher));
 }
diff --git a/content/browser/histogram_controller.h b/content/browser/histogram_controller.h
index f080736..76bb24c 100644
--- a/content/browser/histogram_controller.h
+++ b/content/browser/histogram_controller.h
@@ -11,6 +11,7 @@
 
 #include "base/macros.h"
 #include "base/memory/singleton.h"
+#include "base/memory/writable_shared_memory_region.h"
 #include "content/common/histogram_fetcher.mojom.h"
 
 namespace content {
@@ -60,7 +61,7 @@
       const std::vector<std::string>& pickled_histograms);
 
   template <class T>
-  void SetHistogramMemory(T*, mojo::ScopedSharedBufferHandle);
+  void SetHistogramMemory(T*, base::WritableSharedMemoryRegion);
 
   // Some hosts can be re-used before Mojo recognizes that their connections
   // are invalid because the previous child process died.
diff --git a/content/browser/navigation_browsertest.cc b/content/browser/navigation_browsertest.cc
index 0dadf66..43fb95b 100644
--- a/content/browser/navigation_browsertest.cc
+++ b/content/browser/navigation_browsertest.cc
@@ -1550,8 +1550,7 @@
       "window.opener.location ='data:html/text;base64,'+btoa('payload');"));
   observer.WaitForFinished();
   histograms.ExpectUniqueSample("Navigation.DownloadPolicy",
-                                NavigationDownloadPolicy::kAllowOpenerNoGesture,
-                                1);
+                                NavigationDownloadPolicy::kAllow, 1);
 }
 
 // A variation of the OpenerNavigation_DownloadPolicy test above, but uses a
@@ -1589,16 +1588,24 @@
 
   // Using the popup, navigate its opener to a download.
   base::HistogramTester histograms;
-  DownloadTestObserverInProgress observer(
-      BrowserContext::GetDownloadManager(opener->GetBrowserContext()),
-      1 /* wait_count */);
-  EXPECT_TRUE(ExecuteScriptWithoutUserGesture(
-      popup,
-      "window.opener.location ='data:html/text;base64,'+btoa('payload');"));
-  observer.WaitForFinished();
-  histograms.ExpectUniqueSample(
-      "Navigation.DownloadPolicy",
-      NavigationDownloadPolicy::kAllowOpenerCrossOriginNoGesture, 1);
+  const GURL data_url("data:html/text;base64,cGF5bG9hZA==");
+  TestNavigationManager manager(shell()->web_contents(), data_url);
+  EXPECT_TRUE(
+      ExecuteScript(popup, base::StringPrintf("window.opener.location ='%s'",
+                                              data_url.spec().c_str())));
+  manager.WaitForNavigationFinished();
+
+  EXPECT_FALSE(manager.was_successful());
+
+  // Navigations downloads that go through ResourceDispatcherHost do not trigger
+  // metrics collection, since the "cancellation reason" is collapsed to a
+  // boolean before the navigation turns into a download. Just expect metrics
+  // when the network service is enabled.
+  if (base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+    histograms.ExpectUniqueSample(
+        "Navigation.DownloadPolicy",
+        NavigationDownloadPolicy::kDisallowOpenerCrossOrigin, 1);
+  }
 }
 
 // Regression test for https://crbug.com/872284.
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index ed77305..7ad5129 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -32,8 +32,8 @@
 #include "base/memory/memory_pressure_monitor.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
-#include "base/memory/shared_memory_handle.h"
+#include "base/memory/shared_memory_mapping.h"
+#include "base/memory/writable_shared_memory_region.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_base.h"
@@ -2356,7 +2356,7 @@
   return child_connection_->child_identity();
 }
 
-std::unique_ptr<base::SharedPersistentMemoryAllocator>
+std::unique_ptr<base::PersistentMemoryAllocator>
 RenderProcessHostImpl::TakeMetricsAllocator() {
   return std::move(metrics_allocator_);
 }
@@ -4080,7 +4080,7 @@
   if (!base::GlobalHistogramAllocator::Get()) {
     if (is_initialized_) {
       HistogramController::GetInstance()->SetHistogramMemory<RenderProcessHost>(
-          this, mojo::ScopedSharedBufferHandle());
+          this, base::WritableSharedMemoryRegion());
     }
     return;
   }
@@ -4090,27 +4090,26 @@
   if (destination == base::kNullProcessHandle)
     return;
 
+  // Create persistent/shared memory and allow histograms to be stored in
+  // it. Memory that is not actually used won't be physically mapped by the
+  // system. RendererMetrics usage, as reported in UMA, peaked around 0.7MiB
+  // as of 2016-12-20.
+  base::WritableSharedMemoryRegion shm_region =
+      base::WritableSharedMemoryRegion::Create(2 << 20);  // 2 MiB
+  base::WritableSharedMemoryMapping shm_mapping = shm_region.Map();
+  if (!shm_region.IsValid() || !shm_mapping.IsValid())
+    return;
+
   // If a renderer crashes before completing startup and gets restarted, this
   // method will get called a second time meaning that a metrics-allocator
-  // already exists. Don't recreate it.
-  if (!metrics_allocator_) {
-    // Create persistent/shared memory and allow histograms to be stored in
-    // it. Memory that is not actualy used won't be physically mapped by the
-    // system. RendererMetrics usage, as reported in UMA, peaked around 0.7MiB
-    // as of 2016-12-20.
-    auto shm = std::make_unique<base::SharedMemory>();
-    if (!shm->CreateAndMapAnonymous(2 << 20))  // 2 MiB
-      return;
-    metrics_allocator_ =
-        std::make_unique<base::SharedPersistentMemoryAllocator>(
-            std::move(shm), GetID(), "RendererMetrics", /*readonly=*/false);
-  }
+  // already exists. We have to recreate it here because previously used
+  // |shm_region| is gone.
+  metrics_allocator_ =
+      std::make_unique<base::WritableSharedPersistentMemoryAllocator>(
+          std::move(shm_mapping), GetID(), "RendererMetrics");
 
   HistogramController::GetInstance()->SetHistogramMemory<RenderProcessHost>(
-      this, mojo::WrapSharedMemoryHandle(
-                metrics_allocator_->shared_memory()->handle().Duplicate(),
-                metrics_allocator_->shared_memory()->mapped_size(),
-                mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite));
+      this, std::move(shm_region));
 }
 
 void RenderProcessHostImpl::ProcessDied(
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 0f9c864..7434784 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -73,7 +73,7 @@
 
 namespace base {
 class CommandLine;
-class SharedPersistentMemoryAllocator;
+class PersistentMemoryAllocator;
 }
 
 namespace viz {
@@ -207,7 +207,7 @@
   void BindInterface(const std::string& interface_name,
                      mojo::ScopedMessagePipeHandle interface_pipe) override;
   const service_manager::Identity& GetChildIdentity() override;
-  std::unique_ptr<base::SharedPersistentMemoryAllocator> TakeMetricsAllocator()
+  std::unique_ptr<base::PersistentMemoryAllocator> TakeMetricsAllocator()
       override;
   const base::TimeTicks& GetInitTimeForNavigationMetrics() override;
   bool IsProcessBackgrounded() override;
@@ -863,7 +863,7 @@
   std::unique_ptr<PermissionServiceContext> permission_service_context_;
 
   // The memory allocator, if any, in which the renderer will write its metrics.
-  std::unique_ptr<base::SharedPersistentMemoryAllocator> metrics_allocator_;
+  std::unique_ptr<base::PersistentMemoryAllocator> metrics_allocator_;
 
   std::unique_ptr<IndexedDBDispatcherHost, base::OnTaskRunnerDeleter>
       indexed_db_factory_;
diff --git a/content/browser/web_package/signed_exchange_error.cc b/content/browser/web_package/signed_exchange_error.cc
index c9c9148..ead94ba 100644
--- a/content/browser/web_package/signed_exchange_error.cc
+++ b/content/browser/web_package/signed_exchange_error.cc
@@ -13,23 +13,29 @@
   switch (verify_result) {
     case SignedExchangeSignatureVerifier::Result::kSuccess:
       return base::nullopt;
-    case SignedExchangeSignatureVerifier::Result::kErrNoCertificate:
-      return base::nullopt;
-    case SignedExchangeSignatureVerifier::Result::kErrNoCertificateSHA256:
-      return Field::kSignatureCertSha256;
     case SignedExchangeSignatureVerifier::Result::kErrCertificateSHA256Mismatch:
       return Field::kSignatureCertSha256;
-    case SignedExchangeSignatureVerifier::Result::kErrInvalidSignatureFormat:
-      return base::nullopt;
     case SignedExchangeSignatureVerifier::Result::
         kErrSignatureVerificationFailed:
       return Field::kSignatureSig;
     case SignedExchangeSignatureVerifier::Result::kErrInvalidSignatureIntegrity:
       return Field::kSignatureIintegrity;
-    case SignedExchangeSignatureVerifier::Result::kErrInvalidTimestamp:
-      return Field::kSignatureTimestamps;
     case SignedExchangeSignatureVerifier::Result::kErrUnsupportedCertType:
       return Field::kSignatureCertUrl;
+    case SignedExchangeSignatureVerifier::Result::kErrValidityPeriodTooLong:
+    case SignedExchangeSignatureVerifier::Result::kErrFutureDate:
+    case SignedExchangeSignatureVerifier::Result::kErrExpired:
+      return Field::kSignatureTimestamps;
+
+    // Deprecated error results.
+    case SignedExchangeSignatureVerifier::Result::kErrNoCertificate_deprecated:
+    case SignedExchangeSignatureVerifier::Result::
+        kErrNoCertificateSHA256_deprecated:
+    case SignedExchangeSignatureVerifier::Result::
+        kErrInvalidSignatureFormat_deprecated:
+    case SignedExchangeSignatureVerifier::Result::
+        kErrInvalidTimestamp_deprecated:
+      NOTREACHED();
   }
 
   NOTREACHED();
diff --git a/content/browser/web_package/signed_exchange_error.h b/content/browser/web_package/signed_exchange_error.h
index de84ce2..13e3595 100644
--- a/content/browser/web_package/signed_exchange_error.h
+++ b/content/browser/web_package/signed_exchange_error.h
@@ -45,7 +45,9 @@
   kSXGServedWithoutNosniff,
   // Merkle integrity error.
   kMerkleIntegrityError,
-  kMaxValue = kMerkleIntegrityError
+  // Invalid integrity header error.
+  kInvalidIntegrityHeader,
+  kMaxValue = kInvalidIntegrityHeader
 };
 
 struct SignedExchangeError {
diff --git a/content/browser/web_package/signed_exchange_handler.cc b/content/browser/web_package/signed_exchange_handler.cc
index 68172c7..67b52a1 100644
--- a/content/browser/web_package/signed_exchange_handler.cc
+++ b/content/browser/web_package/signed_exchange_handler.cc
@@ -510,8 +510,10 @@
         error_field ? base::make_optional(
                           std::make_pair(0 /* signature_index */, *error_field))
                     : base::nullopt);
-    RunErrorCallback(SignedExchangeLoadResult::kSignatureVerificationError,
-                     net::ERR_INVALID_SIGNED_EXCHANGE);
+    RunErrorCallback(
+        signed_exchange_utils::GetLoadResultFromSignatureVerifierResult(
+            verify_result),
+        net::ERR_INVALID_SIGNED_EXCHANGE);
     return;
   }
 
diff --git a/content/browser/web_package/signed_exchange_loader.cc b/content/browser/web_package/signed_exchange_loader.cc
index ffb4223..2226e0f 100644
--- a/content/browser/web_package/signed_exchange_loader.cc
+++ b/content/browser/web_package/signed_exchange_loader.cc
@@ -397,7 +397,7 @@
   }
 
   if (reporter_)
-    reporter_->ReportResult(result);
+    reporter_->ReportResultAndFinish(result);
 }
 
 void SignedExchangeLoader::SetSignedExchangeHandlerFactoryForTest(
diff --git a/content/browser/web_package/signed_exchange_reporter.cc b/content/browser/web_package/signed_exchange_reporter.cc
index c1ec58c..5d00675 100644
--- a/content/browser/web_package/signed_exchange_reporter.cc
+++ b/content/browser/web_package/signed_exchange_reporter.cc
@@ -10,13 +10,133 @@
 #include "base/callback.h"
 #include "base/feature_list.h"
 #include "base/memory/ptr_util.h"
+#include "base/task/post_task.h"
+#include "content/browser/frame_host/frame_tree_node.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/site_instance.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "net/base/ip_endpoint.h"
 #include "services/network/public/cpp/features.h"
-#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/cpp/resource_response_info.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "url/origin.h"
 
 namespace content {
 
+namespace {
+
+constexpr char kSXGResultOk[] = "ok";
+constexpr char kSXGResultFailed[] = "sxg.failed";
+constexpr char kSXGResultMiError[] = "sxg.mi_error";
+constexpr char kSXGResultNonSecureDistributor[] = "sxg.non_secure_distributor";
+constexpr char kSXGResultParseError[] = "sxg.parse_error";
+constexpr char kSXGResultInvalidIntegrityHeader[] =
+    "sxg.invalid_integrity_header";
+constexpr char kSXGResultSignatureVerificationError[] =
+    "sxg.signature_verification_error";
+constexpr char kSXGResultCertVerificationError[] =
+    "sxg.cert_verification_error";
+constexpr char kSXGResultCertFetchError[] = "sxg.cert_fetch_error";
+constexpr char kSXGResultCertParseError[] = "sxg.cert_parse_error";
+
+const char* GetResultTypeString(SignedExchangeLoadResult result) {
+  switch (result) {
+    case SignedExchangeLoadResult::kSuccess:
+      return kSXGResultOk;
+    case SignedExchangeLoadResult::kSXGServedFromNonHTTPS:
+      return kSXGResultNonSecureDistributor;
+    case SignedExchangeLoadResult::kFallbackURLParseError:
+    case SignedExchangeLoadResult::kVersionMismatch:
+    case SignedExchangeLoadResult::kHeaderParseError:
+    case SignedExchangeLoadResult::kSXGHeaderNetError:
+      return kSXGResultParseError;
+    case SignedExchangeLoadResult::kCertFetchError:
+      return kSXGResultCertFetchError;
+    case SignedExchangeLoadResult::kCertParseError:
+      return kSXGResultCertParseError;
+    case SignedExchangeLoadResult::kSignatureVerificationError:
+      return kSXGResultSignatureVerificationError;
+    case SignedExchangeLoadResult::kCertVerificationError:
+      return kSXGResultCertVerificationError;
+    case SignedExchangeLoadResult::kCTVerificationError:
+      return kSXGResultCertVerificationError;
+    case SignedExchangeLoadResult::kOCSPError:
+      return kSXGResultCertVerificationError;
+    case SignedExchangeLoadResult::kCertRequirementsNotMet:
+      return kSXGResultCertVerificationError;
+    case SignedExchangeLoadResult::kMerkleIntegrityError:
+      return kSXGResultMiError;
+    case SignedExchangeLoadResult::kSXGServedWithoutNosniff:
+      // TODO(crbug/910516): Need to update the spec to send the report in this
+      // case.
+      return kSXGResultParseError;
+    case SignedExchangeLoadResult::kInvalidIntegrityHeader:
+      return kSXGResultInvalidIntegrityHeader;
+  }
+  NOTREACHED();
+  return kSXGResultFailed;
+}
+
+bool IsCertRelatedErrorResult(const char* result_string) {
+  return result_string == kSXGResultSignatureVerificationError ||
+         result_string == kSXGResultCertVerificationError ||
+         result_string == kSXGResultCertFetchError ||
+         result_string == kSXGResultCertParseError;
+}
+
+// [spec text]
+// - If report body’s "sxg"'s "cert_url"'s scheme is not "data" and report’s
+//   result is "signature_verification_error" or "cert_verification_error" or
+//   "cert_fetch_error" or "cert_parse_error":
+//   - If report’s outer request's url's origin is different from any origin
+//     of the URLs in report’s cert URL list, or report’s server IP is
+//     different from any of the IP address in report’s cert server IP list:
+bool ShouldDowngradeReport(const char* result_string,
+                           const network::mojom::SignedExchangeReport& report,
+                           const net::IPAddress& cert_server_ip_address) {
+  if (report.cert_url.SchemeIs("data"))
+    return false;
+  if (!IsCertRelatedErrorResult(result_string))
+    return false;
+  if (url::Origin::Create(report.outer_url) !=
+      url::Origin::Create(report.cert_url)) {
+    return true;
+  }
+  if (!cert_server_ip_address.empty() &&
+      cert_server_ip_address != report.server_ip_address) {
+    return true;
+  }
+  return false;
+}
+
+void ReportResultOnUI(base::OnceCallback<int(void)> frame_tree_node_id_getter,
+                      network::mojom::SignedExchangeReportPtr report) {
+  int frame_tree_node_id = std::move(frame_tree_node_id_getter).Run();
+  FrameTreeNode* frame_tree_node =
+      FrameTreeNode::GloballyFindByID(frame_tree_node_id);
+  if (!frame_tree_node)
+    return;
+  RenderFrameHostImpl* frame_host = frame_tree_node->current_frame_host();
+  if (!frame_host)
+    return;
+  SiteInstance* site_instance = frame_host->GetSiteInstance();
+  DCHECK(site_instance);
+  WebContents* web_contents = WebContents::FromRenderFrameHost(frame_host);
+  if (!web_contents)
+    return;
+  StoragePartition* partition = BrowserContext::GetStoragePartition(
+      web_contents->GetBrowserContext(), site_instance);
+  DCHECK(partition);
+  partition->GetNetworkContext()->QueueSignedExchangeReport(std::move(report));
+}
+
+}  // namespace
+
 // static
 std::unique_ptr<SignedExchangeReporter> SignedExchangeReporter::MaybeCreate(
     const GURL& outer_url,
@@ -37,11 +157,21 @@
     const std::string& referrer,
     const network::ResourceResponseHead& response,
     base::OnceCallback<int(void)> frame_tree_node_id_getter)
-    : outer_url_(outer_url),
-      referrer_(referrer),
-      server_ip_address_(response.remote_endpoint.address()),
-      status_code_(response.headers ? response.headers->response_code() : 0),
-      frame_tree_node_id_getter_(std::move(frame_tree_node_id_getter)) {}
+    : report_(network::mojom::SignedExchangeReport::New()),
+      request_start_(response.load_timing.request_start),
+      frame_tree_node_id_getter_(std::move(frame_tree_node_id_getter)) {
+  report_->outer_url = outer_url;
+  report_->referrer = referrer;
+  report_->server_ip_address = response.remote_endpoint.address();
+  // If we got response headers, assume that the connection used HTTP/1.1
+  // unless ALPN negotiation tells us otherwise (handled below).
+  report_->protocol = response.was_alpn_negotiated
+                          ? response.alpn_negotiated_protocol
+                          : std::string("http/1.1");
+  report_->status_code =
+      response.headers ? response.headers->response_code() : 0;
+  report_->method = "GET";
+}
 
 SignedExchangeReporter::~SignedExchangeReporter() = default;
 
@@ -51,16 +181,40 @@
 }
 
 void SignedExchangeReporter::set_inner_url(const GURL& inner_url) {
-  inner_url_ = inner_url;
+  DCHECK(report_);
+  report_->inner_url = inner_url;
 }
 
 void SignedExchangeReporter::set_cert_url(const GURL& cert_url) {
-  cert_url_ = cert_url;
+  DCHECK(report_);
+  report_->cert_url = cert_url;
 }
 
-void SignedExchangeReporter::ReportResult(SignedExchangeLoadResult result) {
-  // TODO(910516):Implement this. |frame_tree_node_id_getter_| will be used
-  // to get mojom::NetworkContext and call a method to queue the report.
+void SignedExchangeReporter::ReportResultAndFinish(
+    SignedExchangeLoadResult result) {
+  DCHECK(report_);
+  DCHECK(frame_tree_node_id_getter_);
+
+  const char* result_string = GetResultTypeString(result);
+  report_->success = result == SignedExchangeLoadResult::kSuccess;
+
+  if (ShouldDowngradeReport(result_string, *report_, cert_server_ip_address_)) {
+    // If the report should be downgraded (See the comment of
+    // ShouldDowngradeReport):
+    // [spec text]
+    //   - Set report body’s "type" to "sxg.failed".
+    //   - Set report body’s "elapsed_time" to 0.
+    report_->type = kSXGResultFailed;
+    report_->elapsed_time = base::TimeDelta();
+  } else {
+    report_->type = result_string;
+    report_->elapsed_time = base::TimeTicks::Now() - request_start_;
+  }
+
+  base::PostTaskWithTraits(
+      FROM_HERE, {BrowserThread::UI},
+      base::BindOnce(&ReportResultOnUI, std::move(frame_tree_node_id_getter_),
+                     std::move(report_)));
 }
 
 }  // namespace content
diff --git a/content/browser/web_package/signed_exchange_reporter.h b/content/browser/web_package/signed_exchange_reporter.h
index 84ea328..d7abf43 100644
--- a/content/browser/web_package/signed_exchange_reporter.h
+++ b/content/browser/web_package/signed_exchange_reporter.h
@@ -13,6 +13,7 @@
 #include "content/browser/web_package/signed_exchange_error.h"
 #include "content/common/content_export.h"
 #include "net/base/ip_address.h"
+#include "services/network/public/mojom/network_context.mojom.h"
 #include "url/gurl.h"
 
 namespace network {
@@ -21,6 +22,9 @@
 
 namespace content {
 
+// SignedExchangeReporter sends a signed exchange report for distributor when
+// the distributor of signed exchange has set Network Error Logging (NEL) policy
+// using HTTP header.
 class CONTENT_EXPORT SignedExchangeReporter {
  public:
   static std::unique_ptr<SignedExchangeReporter> MaybeCreate(
@@ -35,7 +39,9 @@
   void set_inner_url(const GURL& inner_url);
   void set_cert_url(const GURL& cert_url);
 
-  void ReportResult(SignedExchangeLoadResult result);
+  // Queues the signed exchange report. This method must be called at the last
+  // method to be called on |this|, and must be called only once.
+  void ReportResultAndFinish(SignedExchangeLoadResult result);
 
  private:
   SignedExchangeReporter(
@@ -44,14 +50,10 @@
       const network::ResourceResponseHead& response,
       base::OnceCallback<int(void)> frame_tree_node_id_getter);
 
-  const GURL outer_url_;
-  const std::string referrer_;
-  const net::IPAddress server_ip_address_;
-  const int status_code_;
+  network::mojom::SignedExchangeReportPtr report_;
+  const base::TimeTicks request_start_;
   base::OnceCallback<int(void)> frame_tree_node_id_getter_;
   net::IPAddress cert_server_ip_address_;
-  GURL inner_url_;
-  GURL cert_url_;
 
   DISALLOW_COPY_AND_ASSIGN(SignedExchangeReporter);
 };
diff --git a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
index d652e8960..a960320 100644
--- a/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
+++ b/content/browser/web_package/signed_exchange_request_handler_browsertest.cc
@@ -366,7 +366,7 @@
       SignedExchangeLoadResult::kSignatureVerificationError, 1);
   histogram_tester_.ExpectUniqueSample(
       "SignedExchange.SignatureVerificationResult",
-      SignedExchangeSignatureVerifier::Result::kErrInvalidTimestamp, 1);
+      SignedExchangeSignatureVerifier::Result::kErrExpired, 1);
 }
 
 IN_PROC_BROWSER_TEST_P(SignedExchangeRequestHandlerBrowserTest,
diff --git a/content/browser/web_package/signed_exchange_signature_verifier.cc b/content/browser/web_package/signed_exchange_signature_verifier.cc
index 1310d14..d67d9a3 100644
--- a/content/browser/web_package/signed_exchange_signature_verifier.cc
+++ b/content/browser/web_package/signed_exchange_signature_verifier.cc
@@ -136,7 +136,7 @@
   buf->insert(buf->end(), std::begin(encoded), std::end(encoded));
 }
 
-base::Optional<std::vector<uint8_t>> GenerateSignedMessage(
+std::vector<uint8_t> GenerateSignedMessage(
     SignedExchangeVersion version,
     const SignedExchangeEnvelope& envelope) {
   TRACE_EVENT_BEGIN0(TRACE_DISABLED_BY_DEFAULT("loading"),
@@ -198,8 +198,9 @@
 
 // Implements steps 3-4 of
 // https://wicg.github.io/webpackage/draft-yasskin-httpbis-origin-signed-exchanges-impl.html#signature-validity
-bool VerifyTimestamps(const SignedExchangeEnvelope& envelope,
-                      const base::Time& verification_time) {
+SignedExchangeSignatureVerifier::Result VerifyTimestamps(
+    const SignedExchangeEnvelope& envelope,
+    const base::Time& verification_time) {
   base::Time expires_time =
       TimeFromSignedExchangeUnixTime(envelope.signature().expires);
   base::Time creation_time =
@@ -207,8 +208,9 @@
 
   // 3. "If expires is more than 7 days (604800 seconds) after date, return
   // "invalid"." [spec text]
-  if ((expires_time - creation_time).InSeconds() > kOneWeek.InSeconds())
-    return false;
+  if ((expires_time - creation_time).InSeconds() > kOneWeek.InSeconds()) {
+    return SignedExchangeSignatureVerifier::Result::kErrValidityPeriodTooLong;
+  }
 
   // 4. "If the current time is before date or after expires, return
   // "invalid"."
@@ -217,20 +219,20 @@
         "SignedExchange.SignatureVerificationError.NotYetValid",
         (creation_time - verification_time).InSeconds(), 1,
         kFourWeeks.InSeconds(), 50);
-    return false;
+    return SignedExchangeSignatureVerifier::Result::kErrFutureDate;
   }
   if (expires_time < verification_time) {
     UMA_HISTOGRAM_CUSTOM_COUNTS(
         "SignedExchange.SignatureVerificationError.Expired",
         (verification_time - expires_time).InSeconds(), 1,
         kFourWeeks.InSeconds(), 50);
-    return false;
+    return SignedExchangeSignatureVerifier::Result::kErrExpired;
   }
 
   UMA_HISTOGRAM_CUSTOM_COUNTS("SignedExchange.TimeUntilExpiration",
                               (expires_time - verification_time).InSeconds(), 1,
                               kOneWeek.InSeconds(), 50);
-  return true;
+  return SignedExchangeSignatureVerifier::Result::kSuccess;
 }
 
 // Returns true if SPKI hash of |certificate| is included in the
@@ -255,8 +257,9 @@
   SCOPED_UMA_HISTOGRAM_TIMER("SignedExchange.Time.SignatureVerify");
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("loading"),
                "SignedExchangeSignatureVerifier::Verify");
-
-  if (!VerifyTimestamps(envelope, verification_time) &&
+  DCHECK(certificate);
+  const auto timestamp_result = VerifyTimestamps(envelope, verification_time);
+  if (timestamp_result != Result::kSuccess &&
       !ShouldIgnoreTimestampError(certificate)) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
         devtools_proxy,
@@ -265,20 +268,10 @@
             ", expires_time: %" PRIu64 ", verification_time: %" PRIu64,
             envelope.signature().date, envelope.signature().expires,
             (verification_time - base::Time::UnixEpoch()).InSeconds()));
-    return Result::kErrInvalidTimestamp;
+    return timestamp_result;
   }
-
-  if (!certificate) {
-    signed_exchange_utils::ReportErrorAndTraceEvent(devtools_proxy,
-                                                    "No certificate set.");
-    return Result::kErrNoCertificate;
-  }
-
-  if (!envelope.signature().cert_sha256.has_value()) {
-    signed_exchange_utils::ReportErrorAndTraceEvent(devtools_proxy,
-                                                    "No cert-sha256 set.");
-    return Result::kErrNoCertificateSHA256;
-  }
+  // Currently we don't support ed25519key. So |cert_sha256| must be set.
+  DCHECK(envelope.signature().cert_sha256.has_value());
 
   // The main-certificate is the first certificate in certificate-chain.
   if (*envelope.signature().cert_sha256 !=
@@ -290,11 +283,6 @@
   }
 
   auto message = GenerateSignedMessage(version, envelope);
-  if (!message) {
-    signed_exchange_utils::ReportErrorAndTraceEvent(
-        devtools_proxy, "Failed to reconstruct signed message.");
-    return Result::kErrInvalidSignatureFormat;
-  }
 
   base::Optional<crypto::SignatureVerifier::SignatureAlgorithm> algorithm =
       GetSignatureAlgorithm(certificate, devtools_proxy);
@@ -305,7 +293,7 @@
   if (!VerifySignature(
           base::make_span(reinterpret_cast<const uint8_t*>(sig.data()),
                           sig.size()),
-          *message, certificate, *algorithm, devtools_proxy)) {
+          message, certificate, *algorithm, devtools_proxy)) {
     signed_exchange_utils::ReportErrorAndTraceEvent(
         devtools_proxy, "Failed to verify signature \"sig\".");
     return Result::kErrSignatureVerificationFailed;
diff --git a/content/browser/web_package/signed_exchange_signature_verifier.h b/content/browser/web_package/signed_exchange_signature_verifier.h
index a922598..e0dc96a 100644
--- a/content/browser/web_package/signed_exchange_signature_verifier.h
+++ b/content/browser/web_package/signed_exchange_signature_verifier.h
@@ -37,15 +37,18 @@
   // This enum is used for recording histograms. Treat as append-only.
   enum class Result {
     kSuccess,
-    kErrNoCertificate,
-    kErrNoCertificateSHA256,
+    kErrNoCertificate_deprecated,
+    kErrNoCertificateSHA256_deprecated,
     kErrCertificateSHA256Mismatch,
-    kErrInvalidSignatureFormat,
+    kErrInvalidSignatureFormat_deprecated,
     kErrSignatureVerificationFailed,
     kErrInvalidSignatureIntegrity,
-    kErrInvalidTimestamp,
+    kErrInvalidTimestamp_deprecated,
     kErrUnsupportedCertType,
-    kMaxValue = kErrUnsupportedCertType
+    kErrValidityPeriodTooLong,
+    kErrFutureDate,
+    kErrExpired,
+    kMaxValue = kErrExpired
   };
 
   // An utility class which holds a set of certificates which errors should be
diff --git a/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc b/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
index 25d8ebc..a0083e8 100644
--- a/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
+++ b/content/browser/web_package/signed_exchange_signature_verifier_unittest.cc
@@ -127,7 +127,7 @@
     }
     {
       base::HistogramTester histogram_tester;
-      EXPECT_EQ(SignedExchangeSignatureVerifier::Result::kErrInvalidTimestamp,
+      EXPECT_EQ(SignedExchangeSignatureVerifier::Result::kErrFutureDate,
                 SignedExchangeSignatureVerifier::Verify(
                     GetParam(), envelope, certificate,
                     base::Time::UnixEpoch() +
@@ -160,7 +160,7 @@
     }
     {
       base::HistogramTester histogram_tester;
-      EXPECT_EQ(SignedExchangeSignatureVerifier::Result::kErrInvalidTimestamp,
+      EXPECT_EQ(SignedExchangeSignatureVerifier::Result::kErrExpired,
                 SignedExchangeSignatureVerifier::Verify(
                     GetParam(), envelope, certificate,
                     base::Time::UnixEpoch() + base::TimeDelta::FromSeconds(
@@ -183,11 +183,12 @@
     ASSERT_EQ(1u, invalid_expires_signature->size());
     invalid_expires_envelope.SetSignatureForTesting(
         (*invalid_expires_signature)[0]);
-    EXPECT_EQ(SignedExchangeSignatureVerifier::Result::kErrInvalidTimestamp,
-              SignedExchangeSignatureVerifier::Verify(
-                  GetParam(), invalid_expires_envelope, certificate,
-                  VerificationTime(), nullptr /* devtools_proxy */
-                  ));
+    EXPECT_EQ(
+        SignedExchangeSignatureVerifier::Result::kErrValidityPeriodTooLong,
+        SignedExchangeSignatureVerifier::Verify(
+            GetParam(), invalid_expires_envelope, certificate,
+            VerificationTime(), nullptr /* devtools_proxy */
+            ));
 
     SignedExchangeEnvelope corrupted_envelope(envelope);
     corrupted_envelope.set_request_url(signed_exchange_utils::URLWithRawString(
diff --git a/content/browser/web_package/signed_exchange_utils.cc b/content/browser/web_package/signed_exchange_utils.cc
index 0765350..2683195 100644
--- a/content/browser/web_package/signed_exchange_utils.cc
+++ b/content/browser/web_package/signed_exchange_utils.cc
@@ -155,5 +155,94 @@
   return base::nullopt;
 }
 
+SignedExchangeLoadResult GetLoadResultFromSignatureVerifierResult(
+    SignedExchangeSignatureVerifier::Result verify_result) {
+  switch (verify_result) {
+    case SignedExchangeSignatureVerifier::Result::kSuccess:
+      return SignedExchangeLoadResult::kSuccess;
+    case SignedExchangeSignatureVerifier::Result::kErrCertificateSHA256Mismatch:
+      // "Handling the certificate reference
+      //   ...
+      //   - If the SHA-256 hash of chain’s leaf's certificate is not equal to
+      //     certSha256, return "signature_verification_error"." [spec text]
+      return SignedExchangeLoadResult::kSignatureVerificationError;
+    case SignedExchangeSignatureVerifier::Result::
+        kErrSignatureVerificationFailed:
+      // "Validating a signature
+      //   ...
+      //   - If parsedSignature’s signature is not a valid signature of message
+      //     by publicKey using the ecdsa_secp256r1_sha256 algorithm, return
+      //     invalid." [spec text]
+      //
+      // "Parsing signed exchanges
+      //   - ...
+      //   - If parsedSignature is not valid for headerBytes and
+      //     requestUrlBytes, and signed exchange version version, return
+      //     "signature_verification_error"." [spec text]
+      return SignedExchangeLoadResult::kSignatureVerificationError;
+    case SignedExchangeSignatureVerifier::Result::kErrInvalidSignatureIntegrity:
+      // "Creating the response stream.
+      //   - If signature’s integrity header is:
+      //     - "digest", "mi-sha256-03"
+      //       ...
+      //     - Anything else
+      //       Return an error string "invalid_integrity_header". " [spec text]
+      return SignedExchangeLoadResult::kInvalidIntegrityHeader;
+    case SignedExchangeSignatureVerifier::Result::kErrUnsupportedCertType:
+      // "Validating a signature
+      //   ...
+      //   - If parsedSignature’s signature is not a valid signature of message
+      //     by publicKey using the ecdsa_secp256r1_sha256 algorithm, return
+      //     invalid." [spec text]
+      //
+      // "Parsing signed exchanges
+      //   - ...
+      //   - If parsedSignature is not valid for headerBytes and
+      //     requestUrlBytes, and signed exchange version version, return
+      //     "signature_verification_error"." [spec text]
+      return SignedExchangeLoadResult::kSignatureVerificationError;
+    case SignedExchangeSignatureVerifier::Result::kErrValidityPeriodTooLong:
+      // "Cross-origin trust
+      //   ...
+      //   - If signature’s expiration time is more than 604800 seconds (7 days)
+      //     after signature’s date, return "untrusted"." [spec text]
+      //
+      // "Parsing signed exchanges
+      //   - ...
+      //   - If parsedSignature does not establish cross-origin trust for
+      //     parsedExchange, return "cert_verification_error"." [spec text]
+      return SignedExchangeLoadResult::kCertVerificationError;
+    case SignedExchangeSignatureVerifier::Result::kErrFutureDate:
+    case SignedExchangeSignatureVerifier::Result::kErrExpired:
+      // "Validating a signature
+      //   ...
+      //   - If the UA’s estimate of the current time is more than clockSkew
+      //     before signature’s date, return "untrusted".
+      //   - If the UA’s estimate of the current time is after signature’s
+      //     expiration time, return "untrusted"." [spec text]
+      //
+      // "Parsing signed exchanges
+      //   - ...
+      //   - If parsedSignature is not valid for headerBytes and
+      //     requestUrlBytes, and signed exchange version version, return
+      //     "signature_verification_error"." [spec text]
+      return SignedExchangeLoadResult::kSignatureVerificationError;
+
+    // Deprecated error results.
+    case SignedExchangeSignatureVerifier::Result::kErrNoCertificate_deprecated:
+    case SignedExchangeSignatureVerifier::Result::
+        kErrNoCertificateSHA256_deprecated:
+    case SignedExchangeSignatureVerifier::Result::
+        kErrInvalidSignatureFormat_deprecated:
+    case SignedExchangeSignatureVerifier::Result::
+        kErrInvalidTimestamp_deprecated:
+      NOTREACHED();
+      return SignedExchangeLoadResult::kSignatureVerificationError;
+  }
+
+  NOTREACHED();
+  return SignedExchangeLoadResult::kSignatureVerificationError;
+}
+
 }  // namespace signed_exchange_utils
 }  // namespace content
diff --git a/content/browser/web_package/signed_exchange_utils.h b/content/browser/web_package/signed_exchange_utils.h
index c2f8cdd..96848246 100644
--- a/content/browser/web_package/signed_exchange_utils.h
+++ b/content/browser/web_package/signed_exchange_utils.h
@@ -11,6 +11,7 @@
 #include "content/browser/web_package/origins_list.h"
 #include "content/browser/web_package/signed_exchange_consts.h"
 #include "content/browser/web_package/signed_exchange_error.h"
+#include "content/browser/web_package/signed_exchange_signature_verifier.h"
 #include "content/common/content_export.h"
 #include "url/gurl.h"
 
@@ -75,6 +76,14 @@
 CONTENT_EXPORT base::Optional<SignedExchangeVersion> GetSignedExchangeVersion(
     const std::string& content_type);
 
+// Returns the matching SignedExchangeLoadResult for the verifier's result.
+// There is a gap between the logic of SignedExchangeSignatureVerifier and the
+// spec of Loading Signed Exchanges [1]. This method is used to fill the gap
+// and send a correct signed exchange report.
+// [1] https://wicg.github.io/webpackage/loading.html
+SignedExchangeLoadResult GetLoadResultFromSignatureVerifierResult(
+    SignedExchangeSignatureVerifier::Result verify_result);
+
 }  // namespace signed_exchange_utils
 }  // namespace content
 
diff --git a/content/browser/worker_host/dedicated_worker_host.cc b/content/browser/worker_host/dedicated_worker_host.cc
index 93e9548..9014f36 100644
--- a/content/browser/worker_host/dedicated_worker_host.cc
+++ b/content/browser/worker_host/dedicated_worker_host.cc
@@ -64,7 +64,7 @@
   }
 
   // PlzDedicatedWorker:
-  void LoadDedicatedWorker(
+  void StartScriptLoad(
       const GURL& script_url,
       const url::Origin& request_initiator_origin,
       blink::mojom::BlobURLTokenPtr blob_url_token,
@@ -74,22 +74,25 @@
 
     auto* render_process_host = RenderProcessHost::FromID(process_id_);
     if (!render_process_host) {
-      client->OnScriptLoadFailed();
+      client->OnScriptLoadStartFailed();
       return;
     }
     auto* storage_partition_impl = static_cast<StoragePartitionImpl*>(
         render_process_host->GetStoragePartition());
 
     scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory;
-    if (blob_url_token) {
-      if (!script_url.SchemeIsBlob()) {
-        mojo::ReportBadMessage("DWH_NOT_BLOB_URL");
+    if (script_url.SchemeIsBlob()) {
+      if (!blob_url_token) {
+        mojo::ReportBadMessage("DWH_NO_BLOB_URL_TOKEN");
         return;
       }
       blob_url_loader_factory =
           ChromeBlobStorageContext::URLLoaderFactoryForToken(
               storage_partition_impl->browser_context(),
               std::move(blob_url_token));
+    } else if (blob_url_token) {
+      mojo::ReportBadMessage("DWH_NOT_BLOB_URL");
+      return;
     }
 
     appcache_handle_ = std::make_unique<AppCacheNavigationHandle>(
@@ -100,7 +103,7 @@
         storage_partition_impl->GetServiceWorkerContext(),
         appcache_handle_->core(), std::move(blob_url_loader_factory),
         storage_partition_impl,
-        base::BindOnce(&DedicatedWorkerHost::DidLoadDedicatedWorker,
+        base::BindOnce(&DedicatedWorkerHost::DidStartScriptLoad,
                        weak_factory_.GetWeakPtr(), std::move(client)));
   }
 
@@ -115,7 +118,7 @@
         &DedicatedWorkerHost::CreateDedicatedWorker, base::Unretained(this)));
   }
 
-  void DidLoadDedicatedWorker(
+  void DidStartScriptLoad(
       blink::mojom::DedicatedWorkerHostFactoryClientPtr client,
       blink::mojom::ServiceWorkerProviderInfoForWorkerPtr
           service_worker_provider_info,
@@ -132,13 +135,13 @@
     DCHECK(!main_script_loader_factory);
 
     if (!success) {
-      client->OnScriptLoadFailed();
+      client->OnScriptLoadStartFailed();
       return;
     }
 
     auto* render_process_host = RenderProcessHost::FromID(process_id_);
     if (!render_process_host) {
-      client->OnScriptLoadFailed();
+      client->OnScriptLoadStartFailed();
       return;
     }
 
@@ -167,10 +170,10 @@
       }
     }
 
-    client->OnScriptLoaded(std::move(service_worker_provider_info),
-                           std::move(main_script_load_params),
-                           std::move(subresource_loader_factories),
-                           std::move(controller));
+    client->OnScriptLoadStarted(std::move(service_worker_provider_info),
+                                std::move(main_script_load_params),
+                                std::move(subresource_loader_factories),
+                                std::move(controller));
 
     // |service_worker_remote_object| is an associated interface ptr, so calls
     // can't be made on it until its request endpoint is sent. Now that the
@@ -268,7 +271,7 @@
   }
 
   // blink::mojom::DedicatedWorkerHostFactory:
-  void CreateDedicatedWorker(
+  void CreateWorkerHost(
       const url::Origin& origin,
       service_manager::mojom::InterfaceProviderRequest request) override {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -289,7 +292,7 @@
   }
 
   // PlzDedicatedWorker:
-  void CreateAndStartLoad(
+  void CreateWorkerHostAndStartScriptLoad(
       const GURL& script_url,
       const url::Origin& request_initiator_origin,
       blink::mojom::BlobURLTokenPtr blob_url_token,
@@ -314,8 +317,8 @@
             blink::mojom::kNavigation_DedicatedWorkerSpec, process_id_,
             mojo::MakeRequest(&interface_provider)));
     client->OnWorkerHostCreated(std::move(interface_provider));
-    host_raw->LoadDedicatedWorker(script_url, request_initiator_origin,
-                                  std::move(blob_url_token), std::move(client));
+    host_raw->StartScriptLoad(script_url, request_initiator_origin,
+                              std::move(blob_url_token), std::move(client));
   }
 
  private:
diff --git a/content/child/child_histogram_fetcher_impl.cc b/content/child/child_histogram_fetcher_impl.cc
index 9728320..f881a6a 100644
--- a/content/child/child_histogram_fetcher_impl.cc
+++ b/content/child/child_histogram_fetcher_impl.cc
@@ -30,18 +30,12 @@
 }
 
 void ChildHistogramFetcherFactoryImpl::CreateFetcher(
-    mojo::ScopedSharedBufferHandle buffer_handle,
+    base::WritableSharedMemoryRegion shared_memory,
     content::mojom::ChildHistogramFetcherRequest request) {
-  base::SharedMemoryHandle memory_handle;
-  size_t memory_size;
-  const MojoResult result = mojo::UnwrapSharedMemoryHandle(
-      std::move(buffer_handle), &memory_handle, &memory_size, nullptr);
-
-  if (result == MOJO_RESULT_OK && memory_handle.IsValid()) {
+  if (shared_memory.IsValid()) {
     // This message must be received only once. Multiple calls to create a
     // global allocator will cause a CHECK() failure.
-    base::GlobalHistogramAllocator::CreateWithSharedMemoryHandle(memory_handle,
-                                                                 memory_size);
+    base::GlobalHistogramAllocator::CreateWithSharedMemoryRegion(shared_memory);
   }
 
   base::PersistentHistogramAllocator* global_allocator =
diff --git a/content/child/child_histogram_fetcher_impl.h b/content/child/child_histogram_fetcher_impl.h
index 9c2b795..68860d9 100644
--- a/content/child/child_histogram_fetcher_impl.h
+++ b/content/child/child_histogram_fetcher_impl.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_CHILD_CHILD_HISTOGRAM_IMPL_H
-#define CONTENT_CHILD_CHILD_HISTOGRAM_IMPL_H
+#ifndef CONTENT_CHILD_CHILD_HISTOGRAM_FETCHER_IMPL_H
+#define CONTENT_CHILD_CHILD_HISTOGRAM_FETCHER_IMPL_H
 
 #include <memory>
 #include <string>
 #include <vector>
 
 #include "base/macros.h"
-#include "base/memory/shared_memory.h"
+#include "base/memory/writable_shared_memory_region.h"
 #include "content/common/histogram_fetcher.mojom.h"
 #include "ipc/message_filter.h"
 
@@ -29,7 +29,7 @@
   static void Create(content::mojom::ChildHistogramFetcherFactoryRequest);
 
  private:
-  void CreateFetcher(mojo::ScopedSharedBufferHandle,
+  void CreateFetcher(base::WritableSharedMemoryRegion,
                      content::mojom::ChildHistogramFetcherRequest) override;
 };
 
@@ -61,4 +61,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_CHILD_CHILD_HISTOGRAM_IMPL_H
+#endif  // CONTENT_CHILD_CHILD_HISTOGRAM_FETCHER_IMPL_H
diff --git a/content/common/histogram_fetcher.mojom b/content/common/histogram_fetcher.mojom
index aa78cc9..76c0d25 100644
--- a/content/common/histogram_fetcher.mojom
+++ b/content/common/histogram_fetcher.mojom
@@ -4,10 +4,12 @@
 
 module content.mojom;
 
+import "mojo/public/mojom/base/shared_memory.mojom";
+
 interface ChildHistogramFetcherFactory {
   // Creates a ChildHistogram interface that uses shared memory buffer to
   // store histograms that are to be reported by the browser process to UMA.
-  CreateFetcher(handle<shared_buffer>? shm_handle,
+  CreateFetcher(mojo_base.mojom.WritableSharedMemoryRegion? shared_memory,
                        ChildHistogramFetcher& child_histogram_fetcher);
 };
 
diff --git a/content/common/navigation_params.cc b/content/common/navigation_params.cc
index 8d13cbc..a0b1fa0 100644
--- a/content/common/navigation_params.cc
+++ b/content/common/navigation_params.cc
@@ -40,13 +40,10 @@
   switch (policy) {
     case NavigationDownloadPolicy::kDisallowViewSource:
     case NavigationDownloadPolicy::kDisallowInterstitial:
+    case NavigationDownloadPolicy::kDisallowOpenerCrossOrigin:
     case NavigationDownloadPolicy::kDisallowSandbox:
       return ResourceInterceptPolicy::kAllowNone;
     case NavigationDownloadPolicy::kAllow:
-    case NavigationDownloadPolicy::kAllowOpener:
-    case NavigationDownloadPolicy::kAllowOpenerNoGesture:
-    case NavigationDownloadPolicy::kAllowOpenerCrossOrigin:
-    case NavigationDownloadPolicy::kAllowOpenerCrossOriginNoGesture:
       return ResourceInterceptPolicy::kAllowAll;
   }
 }
diff --git a/content/common/navigation_params.h b/content/common/navigation_params.h
index c2d76c9..0f349a9 100644
--- a/content/common/navigation_params.h
+++ b/content/common/navigation_params.h
@@ -91,20 +91,9 @@
   kDisallowViewSource = 1,
   kDisallowInterstitial = 2,
 
-  // TODO(csharrison): Temporary to collect metrics. Some opener navigations
-  // should be disallowed from creating downloads. See http://crbug.com/632514.
-  // All of these policies are mutually exclusive, and more specific policies
-  // will be set if their conditions match.
-  //
-  // The navigation was initiated on an opener.
-  kAllowOpener = 3,
-  // Opener navigation without a user gesture.
-  kAllowOpenerNoGesture = 4,
-  // Opener navigation initiated by a site that is cross origin from the target.
-  kAllowOpenerCrossOrigin = 5,
-  // Opener navigation initiated by a site that is cross origin from the target,
-  // and without a user gesture.
-  kAllowOpenerCrossOriginNoGesture = 6,
+  // The navigation was initiated on a x-origin opener. Downloads should not be
+  // allowed.
+  kDisallowOpenerCrossOrigin = 5,
 
   // Download should be prevented when the navigation occurs in an iframe with
   // |kSandboxDownloads| flag set, and the runtime-enabled-feature
diff --git a/content/public/browser/browser_child_process_host.h b/content/public/browser/browser_child_process_host.h
index 71a2123..b07bb6aa 100644
--- a/content/public/browser/browser_child_process_host.h
+++ b/content/public/browser/browser_child_process_host.h
@@ -23,7 +23,7 @@
 
 namespace base {
 class CommandLine;
-class SharedPersistentMemoryAllocator;
+class PersistentMemoryAllocator;
 }
 
 namespace content {
@@ -77,7 +77,7 @@
   virtual ChildProcessTerminationInfo GetTerminationInfo(bool known_dead) = 0;
 
   // Take ownership of a "shared" metrics allocator (if one exists).
-  virtual std::unique_ptr<base::SharedPersistentMemoryAllocator>
+  virtual std::unique_ptr<base::PersistentMemoryAllocator>
   TakeMetricsAllocator() = 0;
 
   // Sets the user-visible name of the process.
diff --git a/content/public/browser/render_process_host.h b/content/public/browser/render_process_host.h
index 4f0b36f..262be704 100644
--- a/content/public/browser/render_process_host.h
+++ b/content/public/browser/render_process_host.h
@@ -37,7 +37,7 @@
 class GURL;
 
 namespace base {
-class SharedPersistentMemoryAllocator;
+class PersistentMemoryAllocator;
 class TimeDelta;
 class Token;
 }
@@ -341,7 +341,7 @@
   // between the Renderer and the Browser, the allocator is created when the
   // process is created and later retrieved by the SubprocessMetricsProvider
   // for management.
-  virtual std::unique_ptr<base::SharedPersistentMemoryAllocator>
+  virtual std::unique_ptr<base::PersistentMemoryAllocator>
   TakeMetricsAllocator() = 0;
 
   // PlzNavigate
diff --git a/content/public/test/mock_render_process_host.cc b/content/public/test/mock_render_process_host.cc
index 2843986..0da619e 100644
--- a/content/public/test/mock_render_process_host.cc
+++ b/content/public/test/mock_render_process_host.cc
@@ -347,7 +347,7 @@
   return child_identity_;
 }
 
-std::unique_ptr<base::SharedPersistentMemoryAllocator>
+std::unique_ptr<base::PersistentMemoryAllocator>
 MockRenderProcessHost::TakeMetricsAllocator() {
   return nullptr;
 }
diff --git a/content/public/test/mock_render_process_host.h b/content/public/test/mock_render_process_host.h
index 57bce31..a963922 100644
--- a/content/public/test/mock_render_process_host.h
+++ b/content/public/test/mock_render_process_host.h
@@ -133,7 +133,7 @@
   void BindInterface(const std::string& interface_name,
                      mojo::ScopedMessagePipeHandle interface_pipe) override;
   const service_manager::Identity& GetChildIdentity() override;
-  std::unique_ptr<base::SharedPersistentMemoryAllocator> TakeMetricsAllocator()
+  std::unique_ptr<base::PersistentMemoryAllocator> TakeMetricsAllocator()
       override;
   const base::TimeTicks& GetInitTimeForNavigationMetrics() override;
   bool IsProcessBackgrounded() override;
diff --git a/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc b/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
index 1dc4927..57f11a0 100644
--- a/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
+++ b/content/renderer/media/webrtc/rtc_video_decoder_adapter.cc
@@ -226,7 +226,6 @@
   DVLOG(2) << __func__;
   DCHECK_CALLED_ON_VALID_THREAD(decoding_thread_checker_);
 
-#if defined(OS_WIN)
   // Hardware VP9 decoders don't handle more than one spatial layer. Fall back
   // to software decoding. See https://crbug.com/webrtc/9304.
   if (codec_specific_info &&
@@ -235,7 +234,6 @@
       codec_specific_info->codecSpecific.VP9.num_spatial_layers > 1) {
     return WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
   }
-#endif  // defined(OS_WIN)
 
   if (missing_frames || !input_image._completeFrame) {
     DVLOG(2) << "Missing or incomplete frames";
diff --git a/content/renderer/navigation_state.cc b/content/renderer/navigation_state.cc
index b7635f9d..7a1e009 100644
--- a/content/renderer/navigation_state.cc
+++ b/content/renderer/navigation_state.cc
@@ -15,6 +15,7 @@
 
 NavigationState::~NavigationState() {
   RunCommitNavigationCallback(blink::mojom::CommitResult::Aborted);
+  navigation_client_.reset();
 }
 
 // static
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index f3a505f..d357cd6 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1629,17 +1629,13 @@
     bool is_opener_navigation,
     const blink::WebURLRequest& request,
     const WebSecurityOrigin& current_origin) {
-  if (!is_opener_navigation)
-    return NavigationDownloadPolicy::kAllow;
-  bool gesture = request.HasUserGesture();
-  bool cross_origin = !request.RequestorOrigin().CanAccess(current_origin);
-  if (!gesture && cross_origin)
-    return NavigationDownloadPolicy::kAllowOpenerCrossOriginNoGesture;
-  if (!gesture)
-    return NavigationDownloadPolicy::kAllowOpenerNoGesture;
-  if (cross_origin)
-    return NavigationDownloadPolicy::kAllowOpenerCrossOrigin;
-  return NavigationDownloadPolicy::kAllowOpener;
+  // Disallow downloads on an opener if the requestor is cross origin.
+  // See crbug.com/632514.
+  if (is_opener_navigation &&
+      !request.RequestorOrigin().CanAccess(current_origin)) {
+    return NavigationDownloadPolicy::kDisallowOpenerCrossOrigin;
+  }
+  return NavigationDownloadPolicy::kAllow;
 }
 
 blink::WebURL RenderFrameImpl::OverrideFlashEmbedWithHTML(
@@ -3587,7 +3583,11 @@
   if (!ShouldDisplayErrorPageForFailedLoad(error_code, common_params.url)) {
     // The browser expects this frame to be loading an error page. Inform it
     // that the load stopped.
-    std::move(callback).Run(blink::mojom::CommitResult::Aborted);
+    if (callback) {
+      std::move(callback).Run(blink::mojom::CommitResult::Aborted);
+    } else {
+      navigation_client_impl_.reset();
+    }
     Send(new FrameHostMsg_DidStopLoading(routing_id_));
     browser_side_navigation_pending_ = false;
     browser_side_navigation_pending_url_ = GURL();
@@ -3605,10 +3605,15 @@
       // either, as the frame has already been populated with something
       // unrelated to this navigation failure. In that case, just send a stop
       // IPC to the browser to unwind its state, and leave the frame as-is.
-      std::move(callback).Run(blink::mojom::CommitResult::Aborted);
+      if (callback) {
+        std::move(callback).Run(blink::mojom::CommitResult::Aborted);
+      } else {
+        navigation_client_impl_.reset();
+      }
       Send(new FrameHostMsg_DidStopLoading(routing_id_));
     } else {
-      std::move(callback).Run(blink::mojom::CommitResult::Ok);
+      if (callback)
+        std::move(callback).Run(blink::mojom::CommitResult::Ok);
     }
     browser_side_navigation_pending_ = false;
     browser_side_navigation_pending_url_ = GURL();
@@ -3669,7 +3674,7 @@
     navigation_params->frame_load_type = WebFrameLoadType::kReplaceCurrentItem;
   }
   navigation_params->service_worker_network_provider =
-      BuildServiceWorkerNetworkProviderForNavigation(&commit_params, nullptr);
+      ServiceWorkerNetworkProviderForFrame::CreateInvalidInstance();
   FillMiscNavigationParams(common_params, commit_params,
                            navigation_params.get());
   WebNavigationParams::FillStaticResponse(navigation_params.get(), "text/html",
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index eb842be..1ae3a32 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -74,12 +74,12 @@
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
 #include "third_party/blink/public/common/feature_policy/feature_policy.h"
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
+#include "third_party/blink/public/mojom/autoplay/autoplay.mojom.h"
 #include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom.h"
 #include "third_party/blink/public/mojom/manifest/manifest_manager.mojom.h"
 #include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
-#include "third_party/blink/public/platform/autoplay.mojom.h"
 #include "third_party/blink/public/platform/web_effective_connection_type.h"
 #include "third_party/blink/public/platform/web_focus_type.h"
 #include "third_party/blink/public/platform/web_loading_behavior_flag.h"
diff --git a/content/renderer/worker/dedicated_worker_host_factory_client.cc b/content/renderer/worker/dedicated_worker_host_factory_client.cc
index 052018e..f2526f6e 100644
--- a/content/renderer/worker/dedicated_worker_host_factory_client.cc
+++ b/content/renderer/worker/dedicated_worker_host_factory_client.cc
@@ -34,7 +34,7 @@
   blink::mojom::DedicatedWorkerHostFactoryClientPtr client_ptr;
   binding_.Bind(mojo::MakeRequest(&client_ptr));
 
-  factory_->CreateAndStartLoad(
+  factory_->CreateWorkerHostAndStartScriptLoad(
       script_url, script_origin,
       blink::mojom::BlobURLTokenPtr(blink::mojom::BlobURLTokenPtrInfo(
           std::move(blob_url_token), blink::mojom::BlobURLToken::Version_)),
@@ -46,7 +46,7 @@
   worker_->OnWorkerHostCreated(interface_provider.PassInterface().PassHandle());
 }
 
-void DedicatedWorkerHostFactoryClient::OnScriptLoaded(
+void DedicatedWorkerHostFactoryClient::OnScriptLoadStarted(
     blink::mojom::ServiceWorkerProviderInfoForWorkerPtr
         service_worker_provider_info,
     blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params,
@@ -56,12 +56,12 @@
   DCHECK(blink::features::IsPlzDedicatedWorkerEnabled());
   // TODO(nhiroki): Keep the given values for creating
   // WebWorkerFetchContextImpl.
-  worker_->OnScriptLoaded();
+  worker_->OnScriptLoadStarted();
 }
 
-void DedicatedWorkerHostFactoryClient::OnScriptLoadFailed() {
+void DedicatedWorkerHostFactoryClient::OnScriptLoadStartFailed() {
   DCHECK(blink::features::IsPlzDedicatedWorkerEnabled());
-  worker_->OnScriptLoadFailed();
+  worker_->OnScriptLoadStartFailed();
   // |this| may be destroyed at this point.
 }
 
diff --git a/content/renderer/worker/dedicated_worker_host_factory_client.h b/content/renderer/worker/dedicated_worker_host_factory_client.h
index 74330b6..a86cb38 100644
--- a/content/renderer/worker/dedicated_worker_host_factory_client.h
+++ b/content/renderer/worker/dedicated_worker_host_factory_client.h
@@ -41,14 +41,14 @@
   // Implements blink::mojom::DedicatedWorkerHostFactoryClient.
   void OnWorkerHostCreated(
       service_manager::mojom::InterfaceProviderPtr interface_provider) override;
-  void OnScriptLoaded(
+  void OnScriptLoadStarted(
       blink::mojom::ServiceWorkerProviderInfoForWorkerPtr
           service_worker_provider_info,
       blink::mojom::WorkerMainScriptLoadParamsPtr main_script_load_params,
       std::unique_ptr<blink::URLLoaderFactoryBundleInfo>
           subresource_loader_factory_bundle_info,
       blink::mojom::ControllerServiceWorkerInfoPtr controller_info) override;
-  void OnScriptLoadFailed() override;
+  void OnScriptLoadStartFailed() override;
 
   // |worker_| owns |this|.
   blink::WebDedicatedWorker* worker_;
diff --git a/content/test/data/accessibility/event/menulist-collapse-expected-win.txt b/content/test/data/accessibility/event/menulist-collapse-expected-win.txt
index b035655..d950ffe 100644
--- a/content/test/data/accessibility/event/menulist-collapse-expected-win.txt
+++ b/content/test/data/accessibility/event/menulist-collapse-expected-win.txt
@@ -1,2 +1,3 @@
+EVENT_OBJECT_SELECTIONWITHIN on role=ROLE_SYSTEM_LIST INVISIBLE SetSize=3
 EVENT_OBJECT_STATECHANGE on <option> role=ROLE_SYSTEM_LISTITEM name="Apple" INVISIBLE,FOCUSABLE,SELECTABLE PosInSet=1 SetSize=3
 EVENT_OBJECT_VALUECHANGE on <select> role=ROLE_SYSTEM_COMBOBOX FOCUSED,COLLAPSED,FOCUSABLE,HASPOPUP
diff --git a/content/test/data/accessibility/event/menulist-collapse-next-expected-auralinux.txt b/content/test/data/accessibility/event/menulist-collapse-next-expected-auralinux.txt
new file mode 100644
index 0000000..09f8aed
--- /dev/null
+++ b/content/test/data/accessibility/event/menulist-collapse-next-expected-auralinux.txt
@@ -0,0 +1,2 @@
+SELECTION-CHANGED role=ROLE_MENU name='(null)' ENABLED,SENSITIVE
+STATE-CHANGE:SELECTED:TRUE role=ROLE_MENU_ITEM name='Orange' ENABLED,FOCUSABLE,SELECTABLE,SELECTED,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/data/accessibility/event/menulist-collapse-next-expected-win.txt b/content/test/data/accessibility/event/menulist-collapse-next-expected-win.txt
index 313ded5..d3e5cdf4 100644
--- a/content/test/data/accessibility/event/menulist-collapse-next-expected-win.txt
+++ b/content/test/data/accessibility/event/menulist-collapse-next-expected-win.txt
@@ -1,4 +1,5 @@
 EVENT_OBJECT_SELECTION on <option> role=ROLE_SYSTEM_LISTITEM name="Orange" SELECTED,FOCUSABLE,SELECTABLE PosInSet=2 SetSize=3
+EVENT_OBJECT_SELECTIONWITHIN on role=ROLE_SYSTEM_LIST INVISIBLE SetSize=3
 EVENT_OBJECT_STATECHANGE on <option> role=ROLE_SYSTEM_LISTITEM name="Apple" INVISIBLE,FOCUSABLE,SELECTABLE PosInSet=1 SetSize=3
 EVENT_OBJECT_STATECHANGE on <option> role=ROLE_SYSTEM_LISTITEM name="Orange" SELECTED,FOCUSABLE,SELECTABLE PosInSet=2 SetSize=3
 EVENT_OBJECT_VALUECHANGE on <select> role=ROLE_SYSTEM_COMBOBOX value="Orange" FOCUSED,COLLAPSED,FOCUSABLE,HASPOPUP
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index 4cc3e61..dc51c77 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -15,6 +15,7 @@
 #include "content/common/frame_messages.h"
 #include "content/common/navigation_params.h"
 #include "content/common/navigation_params.mojom.h"
+#include "content/public/common/navigation_policy.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/mock_render_thread.h"
 #include "content/renderer/input/frame_input_handler_impl.h"
@@ -68,6 +69,20 @@
         std::move(document_interface_broker_request);
   }
 
+  void DidCommitProvisionalLoad(
+      std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> params,
+      mojom::DidCommitProvisionalLoadInterfaceParamsPtr interface_params)
+      override {
+    last_commit_params_ = std::move(params);
+    if (interface_params) {
+      last_interface_provider_request_ =
+          std::move(interface_params->interface_provider_request);
+      last_document_interface_broker_request_ =
+          blink::mojom::DocumentInterfaceBrokerRequest(std::move(
+              interface_params->document_interface_broker_content_request));
+    }
+  }
+
  protected:
   // mojom::FrameHost:
   void CreateNewWindow(mojom::CreateNewWindowParamsPtr,
@@ -93,20 +108,6 @@
 
   void IssueKeepAliveHandle(mojom::KeepAliveHandleRequest request) override {}
 
-  void DidCommitProvisionalLoad(
-      std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> params,
-      mojom::DidCommitProvisionalLoadInterfaceParamsPtr interface_params)
-      override {
-    last_commit_params_ = std::move(params);
-    if (interface_params) {
-      last_interface_provider_request_ =
-          std::move(interface_params->interface_provider_request);
-      last_document_interface_broker_request_ =
-          blink::mojom::DocumentInterfaceBrokerRequest(std::move(
-              interface_params->document_interface_broker_content_request));
-    }
-  }
-
   void DidCommitSameDocumentNavigation(
       std::unique_ptr<FrameHostMsg_DidCommitProvisionalLoad_Params> params)
       override {
@@ -191,13 +192,26 @@
 void TestRenderFrame::Navigate(const network::ResourceResponseHead& head,
                                const CommonNavigationParams& common_params,
                                const CommitNavigationParams& commit_params) {
-  CommitNavigation(
-      head, common_params, commit_params,
-      network::mojom::URLLoaderClientEndpointsPtr(),
-      std::make_unique<blink::URLLoaderFactoryBundleInfo>(), base::nullopt,
-      blink::mojom::ControllerServiceWorkerInfoPtr(),
-      network::mojom::URLLoaderFactoryPtr(), base::UnguessableToken::Create(),
-      CommitNavigationCallback());
+  if (!IsPerNavigationMojoInterfaceEnabled()) {
+    CommitNavigation(head, common_params, commit_params,
+                     network::mojom::URLLoaderClientEndpointsPtr(),
+                     std::make_unique<blink::URLLoaderFactoryBundleInfo>(),
+                     base::nullopt,
+                     blink::mojom::ControllerServiceWorkerInfoPtr(),
+                     network::mojom::URLLoaderFactoryPtr(),
+                     base::UnguessableToken::Create(), base::DoNothing());
+  } else {
+    BindNavigationClient(
+        mojo::MakeRequestAssociatedWithDedicatedPipe(&mock_navigation_client_));
+    CommitPerNavigationMojoInterfaceNavigation(
+        head, common_params, commit_params,
+        network::mojom::URLLoaderClientEndpointsPtr(),
+        std::make_unique<blink::URLLoaderFactoryBundleInfo>(), base::nullopt,
+        blink::mojom::ControllerServiceWorkerInfoPtr(),
+        network::mojom::URLLoaderFactoryPtr(), base::UnguessableToken::Create(),
+        base::BindOnce(&MockFrameHost::DidCommitProvisionalLoad,
+                       base::Unretained(mock_frame_host_.get())));
+  }
 }
 
 void TestRenderFrame::Navigate(const CommonNavigationParams& common_params,
@@ -210,9 +224,19 @@
     const CommitNavigationParams& commit_params,
     int error_code,
     const base::Optional<std::string>& error_page_content) {
-  CommitFailedNavigation(common_params, commit_params,
-                         false /* has_stale_copy_in_cache */, error_code,
-                         error_page_content, nullptr, base::DoNothing());
+  if (!IsPerNavigationMojoInterfaceEnabled()) {
+    CommitFailedNavigation(common_params, commit_params,
+                           false /* has_stale_copy_in_cache */, error_code,
+                           error_page_content, nullptr, base::DoNothing());
+  } else {
+    BindNavigationClient(
+        mojo::MakeRequestAssociatedWithDedicatedPipe(&mock_navigation_client_));
+    mock_navigation_client_->CommitFailedNavigation(
+        common_params, commit_params, false /* has_stale_copy_in_cache */,
+        error_code, error_page_content, nullptr,
+        base::BindOnce(&MockFrameHost::DidCommitProvisionalLoad,
+                       base::Unretained(mock_frame_host_.get())));
+  }
 }
 
 void TestRenderFrame::SwapOut(
diff --git a/content/test/test_render_frame.h b/content/test/test_render_frame.h
index c48a590..97c787c 100644
--- a/content/test/test_render_frame.h
+++ b/content/test/test_render_frame.h
@@ -85,6 +85,8 @@
   base::Optional<std::string> next_navigation_html_override_;
   mojom::FrameInputHandlerPtr frame_input_handler_;
 
+  mojom::NavigationClientAssociatedPtr mock_navigation_client_;
+
   DISALLOW_COPY_AND_ASSIGN(TestRenderFrame);
 };
 
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 4b3a1d5..d1fcd83 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -332,7 +332,9 @@
       "0136FCB13DB29FD5CD442F56E59E53B61F1DF96F",  // http://crbug.com/642141
       "46578A13607D38F1DC8E280C4F499FB0A2F9565C",  // http://crbug.com/819404
       "898FB5A39687D210766B8998BA4530B99C9E6586",  // http://crbug.com/819404
-      "82F30B65397BC3E4ADE627BBD857AB8A58210648"   // http://crbug.com/819404
+      "82F30B65397BC3E4ADE627BBD857AB8A58210648",  // http://crbug.com/819404
+      "A3E3DE9E9F16B41D4A2FAD106BD6CA76B94A0C94",  // http://crbug.com/932466
+      "B41E7F08E1179CC03CBD1F49E57CF353A40ADE07"   // http://crbug.com/932466
     ]
   },
   "mimeHandlerPrivate": {
diff --git a/ios/chrome/app/application_delegate/app_state_unittest.mm b/ios/chrome/app/application_delegate/app_state_unittest.mm
index bb7b10d..01bab65 100644
--- a/ios/chrome/app/application_delegate/app_state_unittest.mm
+++ b/ios/chrome/app/application_delegate/app_state_unittest.mm
@@ -29,13 +29,13 @@
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/device_sharing/device_sharing_manager.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/geolocation/omnibox_geolocation_config.h"
 #import "ios/chrome/browser/metrics/ios_profile_session_durations_service.h"
 #import "ios/chrome/browser/metrics/ios_profile_session_durations_service_factory.h"
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.h"
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/authentication_service_fake.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/browser_view_controller.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
diff --git a/ios/chrome/app/application_delegate/metrics_mediator.mm b/ios/chrome/app/application_delegate/metrics_mediator.mm
index 3346b06..668247c 100644
--- a/ios/chrome/app/application_delegate/metrics_mediator.mm
+++ b/ios/chrome/app/application_delegate/metrics_mediator.mm
@@ -17,11 +17,11 @@
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/metrics/first_user_action_recorder.h"
 #import "ios/chrome/browser/metrics/previous_session_info.h"
 #import "ios/chrome/browser/net/connection_type_observer_bridge.h"
 #include "ios/chrome/browser/pref_names.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/main/browser_interface_provider.h"
diff --git a/ios/chrome/app/application_delegate/user_activity_handler.mm b/ios/chrome/app/application_delegate/user_activity_handler.mm
index 5339326..2b10c86 100644
--- a/ios/chrome/app/application_delegate/user_activity_handler.mm
+++ b/ios/chrome/app/application_delegate/user_activity_handler.mm
@@ -21,8 +21,8 @@
 #include "ios/chrome/app/startup/chrome_app_startup_parameters.h"
 #include "ios/chrome/browser/app_startup_parameters.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/metrics/first_user_action_recorder.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/legacy_tab_helper.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
diff --git a/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm b/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm
index d5dd59d..6a2ef7a 100644
--- a/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm
+++ b/ios/chrome/app/application_delegate/user_activity_handler_unittest.mm
@@ -25,7 +25,7 @@
 #include "ios/chrome/browser/app_startup_parameters.h"
 #include "ios/chrome/browser/chrome_switches.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/legacy_tab_helper.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 74bd262..cacc0c0 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -75,7 +75,6 @@
 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
 #import "ios/chrome/browser/crash_report/crash_restore_helper.h"
 #include "ios/chrome/browser/download/download_directory_util.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/feature_engagement/tracker_factory.h"
 #include "ios/chrome/browser/feature_engagement/tracker_util.h"
 #include "ios/chrome/browser/file_metadata_util.h"
@@ -105,6 +104,7 @@
 #import "ios/chrome/browser/snapshots/snapshot_cache.h"
 #import "ios/chrome/browser/snapshots/snapshot_cache_factory.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/tabs/tab_model_observer.h"
@@ -1841,7 +1841,8 @@
       search_args, templateURLService->search_terms_data()));
   web::NavigationManager::WebLoadParams params(result);
   params.transition_type = ui::PAGE_TRANSITION_TYPED;
-  [self.currentBVC.dispatcher loadURLWithParams:ChromeLoadParams(params)];
+  UrlLoadingServiceFactory::GetForBrowserState([self.currentBVC browserState])
+      ->LoadUrlInCurrentTab(ChromeLoadParams(params));
 }
 
 #pragma mark - Preferences Management
diff --git a/ios/chrome/app/spotlight/spotlight_manager.mm b/ios/chrome/app/spotlight/spotlight_manager.mm
index af5e336..d376717 100644
--- a/ios/chrome/app/spotlight/spotlight_manager.mm
+++ b/ios/chrome/app/spotlight/spotlight_manager.mm
@@ -8,7 +8,7 @@
 #include "ios/chrome/app/spotlight/actions_spotlight_manager.h"
 #include "ios/chrome/app/spotlight/bookmarks_spotlight_manager.h"
 #include "ios/chrome/app/spotlight/topsites_spotlight_manager.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/app/startup/content_suggestions_scheduler_notifications.mm b/ios/chrome/app/startup/content_suggestions_scheduler_notifications.mm
index 4ded77b..7f665d5 100644
--- a/ios/chrome/app/startup/content_suggestions_scheduler_notifications.mm
+++ b/ios/chrome/app/startup/content_suggestions_scheduler_notifications.mm
@@ -6,8 +6,8 @@
 
 #include "components/ntp_snippets/content_suggestions_service.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 6547d1b..feb491f 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -50,7 +50,6 @@
     "crash_loop_detection_util.h",
     "crash_loop_detection_util.mm",
     "experimental_flags.h",
-    "experimental_flags.mm",
     "file_metadata_util.h",
     "file_metadata_util.mm",
     "install_time_util.h",
@@ -70,6 +69,8 @@
     "pref_names.cc",
     "pref_names.h",
     "procedural_block_types.h",
+    "system_flags.h",
+    "system_flags.mm",
     "tab_parenting_global_observer.cc",
     "tab_parenting_global_observer.h",
     "web_data_service_factory.cc",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index f3c948d..4637639 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -49,12 +49,12 @@
 #include "ios/chrome/browser/crash_report/crash_report_flags.h"
 #include "ios/chrome/browser/download/features.h"
 #include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/find_in_page/features.h"
 #include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
 #include "ios/chrome/browser/itunes_urls/itunes_urls_flag.h"
 #include "ios/chrome/browser/search_engines/feature_flags.h"
 #include "ios/chrome/browser/signin/feature_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/dialogs/dialog_features.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_features.h"
 #import "ios/chrome/browser/ui/infobars/infobar_feature.h"
@@ -560,7 +560,10 @@
      flags_ui::kOsIos, FEATURE_VALUE_TYPE(kBrowserContainerKeepsContentView)},
     {"web-clear-browsing-data", flag_descriptions::kWebClearBrowsingDataName,
      flag_descriptions::kWebClearBrowsingDataDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(experimental_flags::kWebClearBrowsingData)},
+     FEATURE_VALUE_TYPE(kWebClearBrowsingData)},
+    {"web-ui-scheme-handling", flag_descriptions::kWebUISchemeHandlingName,
+     flag_descriptions::kWebUISchemeHandlingDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(web::features::kWebUISchemeHandling)},
 };
 
 // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/browsing_data/BUILD.gn b/ios/chrome/browser/browsing_data/BUILD.gn
index 614c8d2..e63f5ba 100644
--- a/ios/chrome/browser/browsing_data/BUILD.gn
+++ b/ios/chrome/browser/browsing_data/BUILD.gn
@@ -34,6 +34,7 @@
   ]
   deps = [
     ":counters",
+    ":feature_flags",
     "//base",
     "//components/autofill/core/browser",
     "//components/browser_sync",
diff --git a/ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.cc b/ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.cc
index 0f4e4bf..ae1d0ec 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.cc
+++ b/ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.cc
@@ -16,8 +16,8 @@
 #include "components/prefs/pref_service.h"
 #include "components/sync/driver/sync_service.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/browsing_data/browsing_data_features.h"
 #include "ios/chrome/browser/browsing_data/cache_counter.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/history/web_history_service_factory.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
@@ -31,7 +31,7 @@
 std::unique_ptr<browsing_data::BrowsingDataCounter>
 CreateCounterForBrowserStateAndPref(ios::ChromeBrowserState* browser_state,
                                     base::StringPiece pref_name) {
-  if (!experimental_flags::IsNewClearBrowsingDataUIEnabled())
+  if (!IsNewClearBrowsingDataUIEnabled())
     return nullptr;
 
   if (pref_name == browsing_data::prefs::kDeleteBrowsingHistory) {
diff --git a/ios/chrome/browser/browsing_data/browsing_data_features.cc b/ios/chrome/browser/browsing_data/browsing_data_features.cc
index bc8c755..4b585cc 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_features.cc
+++ b/ios/chrome/browser/browsing_data/browsing_data_features.cc
@@ -6,3 +6,10 @@
 
 const base::Feature kNewClearBrowsingDataUI{"NewClearBrowsingDataUI",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kWebClearBrowsingData{"WebClearBrowsingData",
+                                          base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsNewClearBrowsingDataUIEnabled() {
+  return base::FeatureList::IsEnabled(kNewClearBrowsingDataUI);
+}
diff --git a/ios/chrome/browser/browsing_data/browsing_data_features.h b/ios/chrome/browser/browsing_data/browsing_data_features.h
index c919057..64d9bd7 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_features.h
+++ b/ios/chrome/browser/browsing_data/browsing_data_features.h
@@ -10,4 +10,11 @@
 // Feature flag to enable new Clear Browsing Data UI.
 extern const base::Feature kNewClearBrowsingDataUI;
 
+// Feature to use the clear browsing data from web instead of the one from
+// chrome.
+extern const base::Feature kWebClearBrowsingData;
+
+// Whether the new Clear Browsing Data UI is enabled.
+bool IsNewClearBrowsingDataUIEnabled();
+
 #endif  // IOS_CHROME_BROWSER_BROWSING_DATA_BROWSING_DATA_FEATURES_H_
diff --git a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
index 5011d77..fe471d0 100644
--- a/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
+++ b/ios/chrome/browser/browsing_data/browsing_data_remover_impl.mm
@@ -41,8 +41,8 @@
 #include "ios/chrome/browser/autofill/personal_data_manager_factory.h"
 #include "ios/chrome/browser/bookmarks/bookmark_remover_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
+#include "ios/chrome/browser/browsing_data/browsing_data_features.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remove_mask.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/history/web_history_service_factory.h"
 #include "ios/chrome/browser/ios_chrome_io_thread.h"
@@ -548,7 +548,7 @@
     base::Time delete_begin,
     base::Time delete_end,
     BrowsingDataRemoveMask mask) {
-  if (base::FeatureList::IsEnabled(experimental_flags::kWebClearBrowsingData)) {
+  if (base::FeatureList::IsEnabled(kWebClearBrowsingData)) {
     web::ClearBrowsingDataMask types =
         web::ClearBrowsingDataMask::kRemoveNothing;
     if (IsRemoveDataMaskSet(mask, BrowsingDataRemoveMask::REMOVE_APPCACHE)) {
diff --git a/ios/chrome/browser/experimental_flags.h b/ios/chrome/browser/experimental_flags.h
index 85c9a7a..30023005 100644
--- a/ios/chrome/browser/experimental_flags.h
+++ b/ios/chrome/browser/experimental_flags.h
@@ -1,81 +1,11 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// 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 IOS_CHROME_BROWSER_EXPERIMENTAL_FLAGS_H_
 #define IOS_CHROME_BROWSER_EXPERIMENTAL_FLAGS_H_
 
-#include <string>
-
-#include "base/feature_list.h"
-
-// This file can be empty. Its purpose is to contain the relatively short lived
-// declarations required for experimental flags.
-
-namespace experimental_flags {
-
-// Feature to load external files with WebState instead of using
-// ExternalFileController.
-extern const base::Feature kExternalFilesLoadedInWebState;
-
-// Feature to use the clear browsing data from web instead of the one from
-// chrome.
-extern const base::Feature kWebClearBrowsingData;
-
-enum GaiaEnvironment {
-  GAIA_ENVIRONMENT_PROD,
-  GAIA_ENVIRONMENT_STAGING,
-  GAIA_ENVIRONMENT_TEST,
-};
-
-enum WhatsNewPromoStatus {
-  WHATS_NEW_DEFAULT = 0,         // Not forced to enable a promo.
-  WHATS_NEW_TEST_COMMAND_TIP,    // Test Tip that runs a command.
-  WHATS_NEW_MOVE_TO_DOCK_TIP,    // Force enable Move To Dock Tip promo.
-  WHATS_NEW_PROMO_STATUS_COUNT,  // Count of Whats New Promo Statuses.
-};
-
-// Whether the First Run UI will be always be displayed.
-bool AlwaysDisplayFirstRun();
-
-GaiaEnvironment GetGaiaEnvironment();
-
-// Returns the host name for an alternative Origin Server host for use by
-// |BrandCode| startup ping. Returns empty string if there is no alternative
-// host specified.
-std::string GetOriginServerHost();
-
-// Returns the promo force enabled, as determined by the experimental flags.
-// If |WHATS_NEW_DEFAULT| is returned, no promo is force enabled.
-WhatsNewPromoStatus GetWhatsNewPromoStatus();
-
-// Whether memory debugging tools are enabled.
-bool IsMemoryDebuggingEnabled();
-
-// Whether startup crash is enabled.
-bool IsStartupCrashEnabled();
-
-// Whether the new Clear Browsing Data UI is enabled.
-bool IsNewClearBrowsingDataUIEnabled();
-
-// Whether the 3rd party keyboard omnibox workaround is enabled.
-bool IsThirdPartyKeyboardWorkaroundEnabled();
-
-// Whether the Bookmarks UI Reboot is enabled.
-// TODO (crbug.com/884719): Remove all use of this flag.
-bool IsBookmarksUIRebootEnabled();
-
-// Whether the Infobar UI Reboot is enabled.
-bool IsInfobarUIRebootEnabled();
-
-// Whether the application group sandbox must be cleared before starting.
-// Calling this method will reset the flag to false, so the sandbox is cleared
-// only once.
-bool MustClearApplicationGroupSandbox();
-
-// Whether password generation is enabled.
-bool IsAutomaticPasswordGenerationEnabled();
-
-}  // namespace experimental_flags
+// This file is only temporary.
+#include "ios/chrome/browser/system_flags.h"
 
 #endif  // IOS_CHROME_BROWSER_EXPERIMENTAL_FLAGS_H_
diff --git a/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm b/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
index 682b046..4882a98 100644
--- a/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
+++ b/ios/chrome/browser/feature_engagement/feature_engagement_egtest.mm
@@ -14,8 +14,8 @@
 #include "components/feature_engagement/public/tracker.h"
 #include "components/feature_engagement/test/test_tracker.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/feature_engagement/tracker_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
 #import "ios/chrome/browser/ui/tab_grid/tab_grid_egtest_util.h"
 #import "ios/chrome/browser/ui/table_view/table_view_navigation_controller_constants.h"
@@ -343,7 +343,8 @@
 
 // Verifies that the New Tab Tip does not appear if all conditions are met,
 // but the NTP is open.
-- (void)testNewTabTipPromoDoesNotAppearOnNTP {
+// TODO(crbug.com/934248) The test is flaky.
+- (void)DISABLED_testNewTabTipPromoDoesNotAppearOnNTP {
   base::test::ScopedFeatureList scoped_feature_list;
 
   EnableNewTabTipTriggering(scoped_feature_list);
@@ -368,7 +369,8 @@
 
 // Verifies that the bottom toolbar tip is displayed when the phone is in split
 // toolbar mode.
-- (void)testBottomToolbarAppear {
+// TODO(crbug.com/934248) The test is flaky.
+- (void)DISABLED_testBottomToolbarAppear {
   if (!IsUIRefreshPhase1Enabled())
     return;
 
@@ -434,7 +436,8 @@
 
 // Verifies that the LongPress tip is displayed only after the Bottom Toolbar
 // tip is presented.
-- (void)testLongPressTipAppearAfterBottomToolbar {
+// TODO(crbug.com/934248) The test is flaky.
+- (void)DISABLED_testLongPressTipAppearAfterBottomToolbar {
   if (!IsUIRefreshPhase1Enabled())
     return;
 
diff --git a/ios/chrome/browser/infobars/BUILD.gn b/ios/chrome/browser/infobars/BUILD.gn
index b77cd31..9508d9e 100644
--- a/ios/chrome/browser/infobars/BUILD.gn
+++ b/ios/chrome/browser/infobars/BUILD.gn
@@ -25,6 +25,7 @@
     "//base",
     "//components/translate/core/browser",
     "//ios/chrome/browser",
+    "//ios/chrome/browser/ui/infobars:feature_flags",
     "//ios/chrome/browser/ui/infobars:infobars_ui",
     "//ios/chrome/browser/ui/infobars/coordinators",
     "//ios/web",
diff --git a/ios/chrome/browser/infobars/infobar_container_ios.h b/ios/chrome/browser/infobars/infobar_container_ios.h
index eb8f570e..6170a119 100644
--- a/ios/chrome/browser/infobars/infobar_container_ios.h
+++ b/ios/chrome/browser/infobars/infobar_container_ios.h
@@ -13,11 +13,14 @@
 
 @protocol InfobarContainerConsumer;
 
-// IOS infobar container specialization, managing infobars visibility so
-// that only the front most one is visible at any time.
+// IOS infobar container specialization, managing infobars visibility and
+// presentation via the InfobarContainerConsumer protocol.|legacyConsumer| is
+// used to support the legacy InfobarPresentation concurrently with the new one
+// that uses |consumer|.
 class InfoBarContainerIOS : public infobars::InfoBarContainer {
  public:
-  InfoBarContainerIOS(id<InfobarContainerConsumer> consumer);
+  InfoBarContainerIOS(id<InfobarContainerConsumer> consumer,
+                      id<InfobarContainerConsumer> legacyConsumer);
   ~InfoBarContainerIOS() override;
 
  protected:
@@ -28,6 +31,7 @@
 
  private:
   id<InfobarContainerConsumer> consumer_;
+  id<InfobarContainerConsumer> legacyConsumer_;
 
   DISALLOW_COPY_AND_ASSIGN(InfoBarContainerIOS);
 };
diff --git a/ios/chrome/browser/infobars/infobar_container_ios.mm b/ios/chrome/browser/infobars/infobar_container_ios.mm
index 2c1e66f..98b0ed3 100644
--- a/ios/chrome/browser/infobars/infobar_container_ios.mm
+++ b/ios/chrome/browser/infobars/infobar_container_ios.mm
@@ -6,13 +6,19 @@
 
 #include "ios/chrome/browser/infobars/infobar.h"
 #import "ios/chrome/browser/ui/infobars/infobar_container_consumer.h"
+#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
+#import "ios/chrome/browser/ui/infobars/infobar_ui_delegate.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-InfoBarContainerIOS::InfoBarContainerIOS(id<InfobarContainerConsumer> consumer)
-    : InfoBarContainer(nullptr), consumer_(consumer) {}
+InfoBarContainerIOS::InfoBarContainerIOS(
+    id<InfobarContainerConsumer> consumer,
+    id<InfobarContainerConsumer> legacyConsumer)
+    : InfoBarContainer(nullptr),
+      consumer_(consumer),
+      legacyConsumer_(legacyConsumer) {}
 
 InfoBarContainerIOS::~InfoBarContainerIOS() {
   RemoveAllInfoBarsForDestruction();
@@ -21,8 +27,16 @@
 void InfoBarContainerIOS::PlatformSpecificAddInfoBar(infobars::InfoBar* infobar,
                                                      size_t position) {
   InfoBarIOS* infobar_ios = static_cast<InfoBarIOS*>(infobar);
-  [consumer_ addInfoBarWithDelegate:infobar_ios->InfobarUIDelegate()
-                           position:position];
+  id<InfobarUIDelegate> delegate = infobar_ios->InfobarUIDelegate();
+
+  if ([delegate isPresented]) {
+    // Only InfobarUIReboot Infobars should be presented using the non legacy
+    // consumer.
+    DCHECK(IsInfobarUIRebootEnabled());
+    [consumer_ addInfoBarWithDelegate:delegate position:position];
+  } else {
+    [legacyConsumer_ addInfoBarWithDelegate:delegate position:position];
+  }
 }
 
 void InfoBarContainerIOS::PlatformSpecificRemoveInfoBar(
@@ -34,4 +48,5 @@
 void InfoBarContainerIOS::PlatformSpecificInfoBarStateChanged(
     bool is_animating) {
   [consumer_ setUserInteractionEnabled:!is_animating];
+  [legacyConsumer_ setUserInteractionEnabled:!is_animating];
 }
diff --git a/ios/chrome/browser/infobars/infobar_controller.mm b/ios/chrome/browser/infobars/infobar_controller.mm
index 75997be..8dce1c8 100644
--- a/ios/chrome/browser/infobars/infobar_controller.mm
+++ b/ios/chrome/browser/infobars/infobar_controller.mm
@@ -21,6 +21,7 @@
 @synthesize view = _view;
 @synthesize delegate = _delegate;
 @synthesize infoBarDelegate = _infoBarDelegate;
+@synthesize presented = _presented;
 
 #pragma mark - Public
 
@@ -29,6 +30,7 @@
   self = [super init];
   if (self) {
     _infoBarDelegate = infoBarDelegate;
+    _presented = NO;
     _view = [self infobarView];
   }
   return self;
diff --git a/ios/chrome/browser/infobars/infobar_utils.mm b/ios/chrome/browser/infobars/infobar_utils.mm
index ca41c6e..bce0258 100644
--- a/ios/chrome/browser/infobars/infobar_utils.mm
+++ b/ios/chrome/browser/infobars/infobar_utils.mm
@@ -8,10 +8,10 @@
 #include <utility>
 
 #include "components/infobars/core/confirm_infobar_delegate.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/infobars/confirm_infobar_controller.h"
 #include "ios/chrome/browser/infobars/infobar.h"
 #import "ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.h"
+#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -19,7 +19,7 @@
 
 std::unique_ptr<infobars::InfoBar> CreateConfirmInfoBar(
     std::unique_ptr<ConfirmInfoBarDelegate> delegate) {
-  if (experimental_flags::IsInfobarUIRebootEnabled()) {
+  if (IsInfobarUIRebootEnabled()) {
     // TODO(crbug.com/927064): Coordinators shouldn't be created at this level,
     // we should probably send only the delegate and have the presenting
     // Coordinator create the right Coordinator using that delegate.
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index 3d5e45e..96f7593 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -430,6 +430,11 @@
     "When enabled, text in web pages will respect the user's Dynamic Type "
     "setting.";
 
+const char kWebUISchemeHandlingName[] = "WKWebView is handling the WebUI pages";
+const char kWebUISchemeHandlingDescription[] =
+    "When enabled, the page with a WebUI scheme are directly loaded by the "
+    "WKWebView by using setURLSchemeHandler:forURLScheme: API.";
+
 const char kWKHTTPSystemCookieStoreName[] = "Use WKHTTPSystemCookieStore.";
 const char kWKHTTPSystemCookieStoreDescription[] =
     "Use WKHTTPCookieStore backed store for main context URL requests.";
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index 2f2a0aa..bf5b300 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -358,6 +358,11 @@
 extern const char kWebPageTextAccessibilityName[];
 extern const char kWebPageTextAccessibilityDescription[];
 
+// Title and description for the flag to have the WKWebView handling the WebUI
+// pages.
+extern const char kWebUISchemeHandlingName[];
+extern const char kWebUISchemeHandlingDescription[];
+
 // Title and description for the flag to enable WKHTTPSystemCookieStore usage
 // for main context URL requests.
 extern const char kWKHTTPSystemCookieStoreName[];
diff --git a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
index 3b3f48d..cffc482 100644
--- a/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
+++ b/ios/chrome/browser/metrics/tab_usage_recorder_egtest.mm
@@ -127,7 +127,8 @@
 }
 
 // Tests that the recorder actual recorde tab state.
-- (void)testTabSwitchRecorder {
+// TODO(crbug.com/934228) The test is flaky.
+- (void)DISABLED_testTabSwitchRecorder {
   web::test::SetUpFileBasedHttpServer();
   chrome_test_util::HistogramTester histogramTester;
   ResetTabUsageRecorder();
@@ -238,7 +239,8 @@
 
 // Tests that tabs reloaded on cold start are reported as
 // EVICTED_DUE_TO_COLD_START.
-- (void)testColdLaunchReloadCount {
+// TODO(crbug.com/934228) The test is disabled due to flakiness.
+- (void)DISABLED_testColdLaunchReloadCount {
   web::test::SetUpFileBasedHttpServer();
   chrome_test_util::HistogramTester histogramTester;
   ResetTabUsageRecorder();
@@ -287,7 +289,8 @@
 }
 
 // Tests that tabs reloads after backgrounding and eviction.
-- (void)testBackgroundingReloadCount {
+// TODO(crbug.com/934228) The test is flaky.
+- (void)DISABLED_testBackgroundingReloadCount {
   web::test::SetUpFileBasedHttpServer();
   chrome_test_util::HistogramTester histogramTester;
   ResetTabUsageRecorder();
@@ -330,7 +333,8 @@
 
 // Verify correct recording of metrics when the reloading of an evicted tab
 // succeeds.
-- (void)testEvictedTabReloadSuccess {
+// TODO(crbug.com/934228) The test is flaky.
+- (void)DISABLED_testEvictedTabReloadSuccess {
   web::test::SetUpFileBasedHttpServer();
   chrome_test_util::HistogramTester histogramTester;
   FailureBlock failureBlock = ^(NSString* error) {
diff --git a/ios/chrome/browser/passwords/BUILD.gn b/ios/chrome/browser/passwords/BUILD.gn
index 3ab1867..815cf48 100644
--- a/ios/chrome/browser/passwords/BUILD.gn
+++ b/ios/chrome/browser/passwords/BUILD.gn
@@ -77,6 +77,7 @@
     "//ios/chrome/browser/ui/alert_coordinator",
     "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/elements",
+    "//ios/chrome/browser/ui/infobars:feature_flags",
     "//ios/chrome/browser/ui/infobars:infobars_ui",
     "//ios/chrome/browser/ui/infobars/coordinators",
     "//ios/chrome/browser/web",
diff --git a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
index a06bb167..78b0fd9 100644
--- a/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_password_manager_client.mm
@@ -22,11 +22,11 @@
 #include "components/translate/core/browser/translate_manager.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
 #include "ios/chrome/browser/passwords/password_manager_internals_service_factory.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/browser/translate/chrome_ios_translate_client.h"
 #include "net/cert/cert_status_flags.h"
 #include "services/metrics/public/cpp/ukm_recorder.h"
diff --git a/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm b/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm
index 899a5e2..299f4d0 100644
--- a/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.mm
@@ -13,10 +13,10 @@
 #include "components/password_manager/core/browser/password_form_metrics_recorder.h"
 #include "components/password_manager/core/browser/password_manager_constants.h"
 #include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/infobars/infobar.h"
 #import "ios/chrome/browser/passwords/ios_password_infobar_controller.h"
 #import "ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.h"
+#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -38,7 +38,7 @@
       is_sync_user, std::move(form_to_save)));
   delegate->set_dispatcher(dispatcher);
 
-  if (experimental_flags::IsInfobarUIRebootEnabled()) {
+  if (IsInfobarUIRebootEnabled()) {
     InfobarPasswordCoordinator* coordinator =
         [[InfobarPasswordCoordinator alloc]
             initWithInfoBarDelegate:delegate.get()];
diff --git a/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm b/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm
index 8f0a696..fce000c6 100644
--- a/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm
+++ b/ios/chrome/browser/passwords/ios_chrome_update_password_infobar_delegate.mm
@@ -15,10 +15,10 @@
 #include "components/password_manager/core/browser/password_form_metrics_recorder.h"
 #include "components/password_manager/core/browser/password_manager_constants.h"
 #include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/infobars/infobar.h"
 #import "ios/chrome/browser/passwords/update_password_infobar_controller.h"
 #import "ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.h"
+#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -41,7 +41,7 @@
       is_sync_user, std::move(form_manager)));
   delegate->set_dispatcher(dispatcher);
 
-  if (experimental_flags::IsInfobarUIRebootEnabled()) {
+  if (IsInfobarUIRebootEnabled()) {
     InfobarPasswordCoordinator* coordinator =
         [[InfobarPasswordCoordinator alloc]
             initWithInfoBarDelegate:delegate.get()];
diff --git a/ios/chrome/browser/passwords/password_controller.mm b/ios/chrome/browser/passwords/password_controller.mm
index fc61776..662c178 100644
--- a/ios/chrome/browser/passwords/password_controller.mm
+++ b/ios/chrome/browser/passwords/password_controller.mm
@@ -42,7 +42,6 @@
 #include "components/strings/grit/components_strings.h"
 #include "components/sync/driver/sync_service.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
 #import "ios/chrome/browser/metrics/ukm_url_recorder.h"
 #include "ios/chrome/browser/passwords/credential_manager.h"
@@ -220,7 +219,7 @@
     _passwordManager.reset(new PasswordManager(_passwordManagerClient.get()));
     _passwordManagerDriver.reset(new IOSChromePasswordManagerDriver(self));
 
-    if (experimental_flags::IsAutomaticPasswordGenerationEnabled() &&
+    if (features::IsAutomaticPasswordGenerationEnabled() &&
         !_passwordManagerClient->IsIncognito()) {
       _passwordGenerationManager.reset(new PasswordGenerationManager(
           _passwordManagerClient.get(), _passwordManagerDriver.get()));
@@ -676,7 +675,7 @@
 - (BOOL)canGeneratePasswordForForm:(NSString*)formName
                    fieldIdentifier:(NSString*)fieldIdentifier
                          fieldType:(NSString*)fieldType {
-  if (!experimental_flags::IsAutomaticPasswordGenerationEnabled())
+  if (!features::IsAutomaticPasswordGenerationEnabled())
     return NO;
   if (![fieldType isEqualToString:@"password"])
     return NO;
diff --git a/ios/chrome/browser/passwords/password_manager_features.cc b/ios/chrome/browser/passwords/password_manager_features.cc
index c24b2487..ac3a77c 100644
--- a/ios/chrome/browser/passwords/password_manager_features.cc
+++ b/ios/chrome/browser/passwords/password_manager_features.cc
@@ -12,4 +12,8 @@
 const base::Feature kPasswordGeneration{"PasswordGeneration",
                                         base::FEATURE_DISABLED_BY_DEFAULT};
 
+bool IsAutomaticPasswordGenerationEnabled() {
+  return base::FeatureList::IsEnabled(features::kPasswordGeneration);
+}
+
 }  // namespace features
diff --git a/ios/chrome/browser/passwords/password_manager_features.h b/ios/chrome/browser/passwords/password_manager_features.h
index 64cab87..d439d6f 100644
--- a/ios/chrome/browser/passwords/password_manager_features.h
+++ b/ios/chrome/browser/passwords/password_manager_features.h
@@ -15,6 +15,9 @@
 // Used to control the state of the iOS password generation feature.
 extern const base::Feature kPasswordGeneration;
 
+// Whether password generation is enabled.
+bool IsAutomaticPasswordGenerationEnabled();
+
 }  // namespace features
 
 #endif  // IOS_CHROME_BROWSER_PASSWORDS_PASSWORD_MANAGER_FEATURES_H_
diff --git a/ios/chrome/browser/reading_list/reading_list_model_factory.cc b/ios/chrome/browser/reading_list/reading_list_model_factory.cc
index bdc3b522..1f9c444 100644
--- a/ios/chrome/browser/reading_list/reading_list_model_factory.cc
+++ b/ios/chrome/browser/reading_list/reading_list_model_factory.cc
@@ -20,8 +20,8 @@
 #include "components/sync/model_impl/client_tag_based_model_type_processor.h"
 #include "ios/chrome/browser/browser_state/browser_state_otr_helper.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/sync/model_type_store_service_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/common/channel_info.h"
 #include "ios/web/public/web_thread.h"
 
diff --git a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc
index b4433f8..7ee2a1c 100644
--- a/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc
+++ b/ios/chrome/browser/search_engines/ui_thread_search_terms_data.cc
@@ -11,9 +11,9 @@
 #include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/version_info/version_info.h"
 #include "ios/chrome/browser/application_context.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/google/google_brand.h"
 #include "ios/chrome/browser/google/google_url_tracker_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/common/channel_info.h"
 #include "ios/web/public/web_thread.h"
 #include "net/base/escape.h"
diff --git a/ios/chrome/browser/share_extension/share_extension_item_receiver.mm b/ios/chrome/browser/share_extension/share_extension_item_receiver.mm
index 99ce9f4..cd06e32 100644
--- a/ios/chrome/browser/share_extension/share_extension_item_receiver.mm
+++ b/ios/chrome/browser/share_extension/share_extension_item_receiver.mm
@@ -19,7 +19,7 @@
 #include "components/bookmarks/browser/bookmark_model.h"
 #include "components/reading_list/core/reading_list_model.h"
 #include "components/reading_list/core/reading_list_model_observer.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/common/app_group/app_group_constants.h"
 #include "ios/web/public/web_task_traits.h"
 #include "ios/web/public/web_thread.h"
diff --git a/ios/chrome/browser/signin/authentication_service.mm b/ios/chrome/browser/signin/authentication_service.mm
index a817f1c..f0ad357 100644
--- a/ios/chrome/browser/signin/authentication_service.mm
+++ b/ios/chrome/browser/signin/authentication_service.mm
@@ -20,12 +20,12 @@
 #include "components/sync/driver/sync_user_settings.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/pref_names.h"
 #import "ios/chrome/browser/signin/authentication_service_delegate.h"
 #include "ios/chrome/browser/signin/constants.h"
 #include "ios/chrome/browser/signin/signin_util.h"
 #include "ios/chrome/browser/sync/sync_setup_service.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
 #include "ios/public/provider/chrome/browser/signin/chrome_identity_service.h"
diff --git a/ios/chrome/browser/signin/authentication_service_unittest.mm b/ios/chrome/browser/signin/authentication_service_unittest.mm
index 501b0b8..52a4b5c 100644
--- a/ios/chrome/browser/signin/authentication_service_unittest.mm
+++ b/ios/chrome/browser/signin/authentication_service_unittest.mm
@@ -17,7 +17,6 @@
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state_manager.h"
 #include "ios/chrome/browser/content_settings/cookie_settings_factory.h"
 #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/prefs/browser_prefs.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
@@ -31,6 +30,7 @@
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service_mock.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/test/ios_chrome_scoped_testing_chrome_browser_state_manager.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/signin/chrome_identity.h"
diff --git a/ios/chrome/browser/system_flags.h b/ios/chrome/browser/system_flags.h
new file mode 100644
index 0000000..ac7dc6c
--- /dev/null
+++ b/ios/chrome/browser/system_flags.h
@@ -0,0 +1,65 @@
+// 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 IOS_CHROME_BROWSER_SYSTEM_FLAGS_H_
+#define IOS_CHROME_BROWSER_SYSTEM_FLAGS_H_
+
+#include <string>
+
+#include "base/feature_list.h"
+
+// This file can be empty. Its purpose is to contain the flags living in the
+// System Settings, used for testing/debugging. No base::Feature (or check for
+// them) should be added.
+
+namespace experimental_flags {
+
+// Feature to load external files with WebState instead of using
+// ExternalFileController.
+extern const base::Feature kExternalFilesLoadedInWebState;
+
+enum GaiaEnvironment {
+  GAIA_ENVIRONMENT_PROD,
+  GAIA_ENVIRONMENT_STAGING,
+  GAIA_ENVIRONMENT_TEST,
+};
+
+enum WhatsNewPromoStatus {
+  WHATS_NEW_DEFAULT = 0,         // Not forced to enable a promo.
+  WHATS_NEW_TEST_COMMAND_TIP,    // Test Tip that runs a command.
+  WHATS_NEW_MOVE_TO_DOCK_TIP,    // Force enable Move To Dock Tip promo.
+  WHATS_NEW_PROMO_STATUS_COUNT,  // Count of Whats New Promo Statuses.
+};
+
+// Whether the First Run UI will be always be displayed.
+bool AlwaysDisplayFirstRun();
+
+GaiaEnvironment GetGaiaEnvironment();
+
+// Returns the host name for an alternative Origin Server host for use by
+// |BrandCode| startup ping. Returns empty string if there is no alternative
+// host specified.
+std::string GetOriginServerHost();
+
+// Returns the promo force enabled, as determined by the experimental flags.
+// If |WHATS_NEW_DEFAULT| is returned, no promo is force enabled.
+WhatsNewPromoStatus GetWhatsNewPromoStatus();
+
+// Whether memory debugging tools are enabled.
+bool IsMemoryDebuggingEnabled();
+
+// Whether startup crash is enabled.
+bool IsStartupCrashEnabled();
+
+// Whether the 3rd party keyboard omnibox workaround is enabled.
+bool IsThirdPartyKeyboardWorkaroundEnabled();
+
+// Whether the application group sandbox must be cleared before starting.
+// Calling this method will reset the flag to false, so the sandbox is cleared
+// only once.
+bool MustClearApplicationGroupSandbox();
+
+}  // namespace experimental_flags
+
+#endif  // IOS_CHROME_BROWSER_SYSTEM_FLAGS_H_
diff --git a/ios/chrome/browser/experimental_flags.mm b/ios/chrome/browser/system_flags.mm
similarity index 89%
rename from ios/chrome/browser/experimental_flags.mm
rename to ios/chrome/browser/system_flags.mm
index b2731f3..1fd0c0c 100644
--- a/ios/chrome/browser/experimental_flags.mm
+++ b/ios/chrome/browser/system_flags.mm
@@ -5,7 +5,7 @@
 // This file can be empty. Its purpose is to contain the relatively short lived
 // definitions required for experimental flags.
 
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 
 #import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>
@@ -50,9 +50,6 @@
 const base::Feature kExternalFilesLoadedInWebState{
     "ExternalFilesLoadedInWebState", base::FEATURE_ENABLED_BY_DEFAULT};
 
-const base::Feature kWebClearBrowsingData{"WebClearBrowsingData",
-                                          base::FEATURE_DISABLED_BY_DEFAULT};
-
 bool AlwaysDisplayFirstRun() {
   return
       [[NSUserDefaults standardUserDefaults] boolForKey:kFirstRunForceEnabled];
@@ -111,10 +108,6 @@
   return value;
 }
 
-bool IsNewClearBrowsingDataUIEnabled() {
-  return base::FeatureList::IsEnabled(kNewClearBrowsingDataUI);
-}
-
 bool IsThirdPartyKeyboardWorkaroundEnabled() {
   // Check if the experimental flag is forced on or off.
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
@@ -129,16 +122,4 @@
   return base::FeatureList::IsEnabled(kEnableThirdPartyKeyboardWorkaround);
 }
 
-bool IsBookmarksUIRebootEnabled() {
-  return true;
-}
-
-bool IsInfobarUIRebootEnabled() {
-  return base::FeatureList::IsEnabled(kInfobarUIReboot);
-}
-
-bool IsAutomaticPasswordGenerationEnabled() {
-  return base::FeatureList::IsEnabled(features::kPasswordGeneration);
-}
-
 }  // namespace experimental_flags
diff --git a/ios/chrome/browser/tabs/tab.mm b/ios/chrome/browser/tabs/tab.mm
index d7cceb09..d2ca42e 100644
--- a/ios/chrome/browser/tabs/tab.mm
+++ b/ios/chrome/browser/tabs/tab.mm
@@ -42,7 +42,6 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/download/download_manager_tab_helper.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/find_in_page/find_in_page_controller.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/history/history_tab_helper.h"
@@ -55,6 +54,7 @@
 #import "ios/chrome/browser/snapshots/snapshot_cache.h"
 #import "ios/chrome/browser/snapshots/snapshot_cache_factory.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/legacy_tab_helper.h"
 #import "ios/chrome/browser/tabs/tab_dialog_delegate.h"
 #import "ios/chrome/browser/tabs/tab_helper_util.h"
diff --git a/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
index 482b19aa..ae31600 100644
--- a/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
+++ b/ios/chrome/browser/ui/authentication/authentication_flow_performer.mm
@@ -18,13 +18,13 @@
 #include "components/strings/grit/components_strings.h"
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/signin/authentication_service.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/constants.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
 #import "ios/chrome/browser/ui/authentication/authentication_ui_util.h"
 #import "ios/chrome/browser/ui/commands/browsing_data_commands.h"
diff --git a/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm b/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm
index ec91bdd..5f4462e 100644
--- a/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm
+++ b/ios/chrome/browser/ui/autofill/manual_fill/password_mediator.mm
@@ -10,7 +10,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/password_manager/core/browser/password_store.h"
 #import "ios/chrome/browser/autofill/manual_fill/passwords_fetcher.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/passwords/password_manager_features.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/action_cell.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/credential.h"
 #import "ios/chrome/browser/ui/autofill/manual_fill/credential_password_form.h"
@@ -210,7 +210,7 @@
         [[NSMutableArray alloc] init];
     __weak __typeof(self) weakSelf = self;
 
-    if (experimental_flags::IsAutomaticPasswordGenerationEnabled() &&
+    if (features::IsAutomaticPasswordGenerationEnabled() &&
         [self.contentDelegate canUserInjectInPasswordField:YES
                                              requiresHTTPS:YES]) {
       NSString* generatePasswordTitleString =
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
index 37fcfac..0ebb504 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_edit_view_controller.mm
@@ -18,7 +18,7 @@
 #include "components/url_formatter/url_fixer.h"
 #include "ios/chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/experimental_flags.h"
+#import "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_folder_view_controller.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_mediator.h"
 #import "ios/chrome/browser/ui/bookmarks/bookmark_model_bridge_observer.h"
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
index 90a0cef..09295859 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios.mm
@@ -19,7 +19,7 @@
 #include "components/query_parser/query_parser.h"
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/bookmarks/bookmarks_utils.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/browser/ui/bookmarks/undo_manager_wrapper.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios_unittest.mm b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios_unittest.mm
index 868d51e..f9082f1 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios_unittest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_utils_ios_unittest.mm
@@ -11,7 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "components/bookmarks/browser/bookmark_model.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/browser/ui/bookmarks/bookmark_ios_unittest.h"
 #include "testing/gtest_mac.h"
 
diff --git a/ios/chrome/browser/ui/browser_view_controller.h b/ios/chrome/browser/ui/browser_view_controller.h
index 36ae15a..77803d9 100644
--- a/ios/chrome/browser/ui/browser_view_controller.h
+++ b/ios/chrome/browser/ui/browser_view_controller.h
@@ -11,7 +11,6 @@
 #import "ios/chrome/browser/ui/page_info/requirements/page_info_presentation.h"
 #import "ios/chrome/browser/ui/settings/sync/utils/sync_presenter.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_coordinator_delegate.h"
-#import "ios/chrome/browser/ui/url_loader.h"
 #import "ios/public/provider/chrome/browser/voice/logo_animation_controller.h"
 
 @protocol ApplicationCommands;
@@ -65,8 +64,7 @@
                                   PopupMenuCommands,
                                   FakeboxFocuser,
                                   SnackbarCommands,
-                                  ToolbarCommands,
-                                  UrlLoader>
+                                  ToolbarCommands>
     dispatcher;
 
 // The top-level browser container view.
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index b3c0072..87aec94 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -36,7 +36,6 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/download/download_manager_tab_helper.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/feature_engagement/tracker_util.h"
 #import "ios/chrome/browser/find_in_page/find_tab_helper.h"
 #include "ios/chrome/browser/first_run/first_run.h"
@@ -63,6 +62,7 @@
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
 #import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper.h"
 #import "ios/chrome/browser/ssl/captive_portal_detector_tab_helper_delegate.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/legacy_tab_helper.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_dialog_delegate.h"
@@ -774,8 +774,6 @@
     _dialogPresenter = [[DialogPresenter alloc] initWithDelegate:self
                                         presentingViewController:self];
     self.commandDispatcher = commandDispatcher;
-    [self.commandDispatcher startDispatchingToTarget:self
-                                         forProtocol:@protocol(UrlLoader)];
     [self.commandDispatcher
         startDispatchingToTarget:self
                      forProtocol:@protocol(BrowserCommands)];
@@ -847,11 +845,11 @@
       PopupMenuCommands,
       FakeboxFocuser,
       SnackbarCommands,
-      ToolbarCommands,
-      UrlLoader>)dispatcher {
-  return static_cast<id<ApplicationCommands, BrowserCommands, OmniboxFocuser,
-                        PopupMenuCommands, FakeboxFocuser, SnackbarCommands,
-                        ToolbarCommands, UrlLoader>>(self.commandDispatcher);
+      ToolbarCommands>)dispatcher {
+  return static_cast<
+      id<ApplicationCommands, BrowserCommands, OmniboxFocuser,
+         PopupMenuCommands, FakeboxFocuser, SnackbarCommands, ToolbarCommands>>(
+      self.commandDispatcher);
 }
 
 - (UIView*)contentArea {
@@ -2276,9 +2274,9 @@
   // Place the toolbar controller above the infobar container and adds the
   // layout guides.
   if (initialLayout) {
-    UIView* bottomView = IsIPadIdiom()
-                             ? _fakeStatusBarView
-                             : [self.infobarContainerCoordinator view];
+    UIView* bottomView =
+        IsIPadIdiom() ? _fakeStatusBarView
+                      : [self.infobarContainerCoordinator legacyContainerView];
     [[self view]
         insertSubview:self.primaryToolbarCoordinator.viewController.view
          aboveSubview:bottomView];
@@ -3002,7 +3000,7 @@
     DCHECK(self.infobarContainerCoordinator);
     if ([self.infobarContainerCoordinator
             isInfobarPresentingForWebState:self.currentWebState]) {
-      return [self.infobarContainerCoordinator view];
+      return [self.infobarContainerCoordinator legacyContainerView];
     }
   }
   return nil;
@@ -4031,24 +4029,6 @@
   return _mainContentUIUpdater.state;
 }
 
-#pragma mark - UrlLoader (Public)
-
-- (void)loadURLWithParams:(const ChromeLoadParams&)chromeParams {
-  // TODO(crbug.com/907527): call UrlLoadingService directly where we call
-  // this method.
-  UrlLoadingService* urlLoadingService =
-      UrlLoadingServiceFactory::GetForBrowserState(self.browserState);
-  urlLoadingService->LoadUrlInCurrentTab(chromeParams);
-}
-
-- (void)webPageOrderedOpen:(OpenNewTabCommand*)command {
-  // TODO(crbug.com/907527): call UrlLoadingService directly where we call
-  // this method.
-  UrlLoadingService* urlLoadingService =
-      UrlLoadingServiceFactory::GetForBrowserState(self.browserState);
-  urlLoadingService->OpenUrlInNewTab(command);
-}
-
 #pragma mark - ToolbarCoordinatorDelegate (Public)
 
 - (void)locationBarDidBecomeFirstResponder {
@@ -4651,12 +4631,12 @@
 - (void)updateAccessoryViewsForSideSwipeWithVisibility:(BOOL)visible {
   if (visible) {
     [self updateToolbar];
-    [[self.infobarContainerCoordinator view] setHidden:NO];
+    [self.infobarContainerCoordinator hideContainer:NO];
   } else {
     // Hide UI accessories such as find bar and first visit overlays
     // for welcome page.
     [self hideFindBarWithAnimation:NO];
-    [[self.infobarContainerCoordinator view] setHidden:YES];
+    [self.infobarContainerCoordinator hideContainer:YES];
   }
 }
 
@@ -4674,7 +4654,7 @@
   BOOL seenInfoBarContainer = NO;
   BOOL seenContentArea = NO;
   for (UIView* view in views.subviews) {
-    if (view == [self.infobarContainerCoordinator view])
+    if (view == [self.infobarContainerCoordinator legacyContainerView])
       seenInfoBarContainer = YES;
     else if (view == self.contentArea)
       seenContentArea = YES;
diff --git a/ios/chrome/browser/ui/content_suggestions/BUILD.gn b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
index c7b8227..489a034 100644
--- a/ios/chrome/browser/ui/content_suggestions/BUILD.gn
+++ b/ios/chrome/browser/ui/content_suggestions/BUILD.gn
@@ -67,6 +67,7 @@
     "//ios/chrome/browser/ui/settings/utils:utils",
     "//ios/chrome/browser/ui/toolbar/public",
     "//ios/chrome/browser/ui/util",
+    "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/common/app_group",
     "//ios/chrome/common/favicon",
@@ -202,6 +203,7 @@
     "//ios/chrome/browser/ui/content_suggestions/cells:cells_ui",
     "//ios/chrome/browser/ui/content_suggestions/identifier",
     "//ios/chrome/browser/ui/toolbar/test",
+    "//ios/chrome/browser/url_loading",
     "//ios/chrome/browser/web_state_list",
     "//ios/chrome/browser/web_state_list:test_support",
     "//ios/chrome/test/base",
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.h
index b11c746..6eae01b 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.h
@@ -19,7 +19,6 @@
 @protocol OmniboxFocuser;
 @protocol FakeboxFocuser;
 @protocol SnackbarCommands;
-@protocol UrlLoader;
 class WebStateList;
 
 // Coordinator to manage the Suggestions UI via a
@@ -35,8 +34,7 @@
                               BrowserCommands,
                               OmniboxFocuser,
                               FakeboxFocuser,
-                              SnackbarCommands,
-                              UrlLoader>
+                              SnackbarCommands>
     dispatcher;
 // Whether the Suggestions UI is displayed. If this is true, start is a no-op.
 @property(nonatomic, readonly) BOOL visible;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
index a4b9aac..cff198a 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_coordinator.mm
@@ -36,6 +36,8 @@
 #import "ios/chrome/browser/ui/overscroll_actions/overscroll_actions_controller.h"
 #import "ios/chrome/browser/ui/settings/utils/pref_backed_boolean.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/browser/url_loading/url_loading_service.h"
+#import "ios/chrome/browser/url_loading/url_loading_service_factory.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/voice/voice_search_provider.h"
@@ -112,12 +114,17 @@
     ntp_home::RecordNTPImpression(ntp_home::LOCAL_SUGGESTIONS);
   }
 
+  UrlLoadingService* urlLoadingService =
+      UrlLoadingServiceFactory::GetForBrowserState(_browserState);
+
   self.NTPMediator = [[NTPHomeMediator alloc]
       initWithWebStateList:self.webStateList
         templateURLService:ios::TemplateURLServiceFactory::GetForBrowserState(
                                self.browserState)
+         urlLoadingService:urlLoadingService
                 logoVendor:ios::GetChromeBrowserProvider()->CreateLogoVendor(
-                               self.browserState, self.dispatcher)];
+                               self.browserState,
+                               urlLoadingService->GetUrlLoader())];
 
   BOOL voiceSearchEnabled = ios::GetChromeBrowserProvider()
                                 ->GetVoiceSearchProvider()
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h
index cf85ec3..85a6ab2 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.h
@@ -22,7 +22,6 @@
 @protocol OmniboxFocuser;
 @class PrimaryToolbarViewController;
 class ReadingListModel;
-@protocol UrlLoader;
 
 // Controller for the header containing the logo and the fake omnibox, handling
 // the interactions between the header and the collection, and the rest of the
@@ -42,12 +41,9 @@
 - (instancetype)initWithCoder:(NSCoder*)aDecoder NS_UNAVAILABLE;
 - (instancetype)init NS_UNAVAILABLE;
 
-@property(nonatomic, weak) id<ApplicationCommands,
-                              BrowserCommands,
-                              OmniboxFocuser,
-                              FakeboxFocuser,
-                              UrlLoader>
-    dispatcher;
+@property(nonatomic, weak)
+    id<ApplicationCommands, BrowserCommands, OmniboxFocuser, FakeboxFocuser>
+        dispatcher;
 @property(nonatomic, weak) id<ContentSuggestionsHeaderViewControllerDelegate>
     delegate;
 @property(nonatomic, weak) id<ContentSuggestionsCommands> commandHandler;
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
index c9729ba..e5da47e 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -24,7 +24,6 @@
 #import "ios/chrome/browser/ui/toolbar/public/fakebox_focuser.h"
 #import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_utils.h"
-#import "ios/chrome/browser/ui/url_loader.h"
 #import "ios/chrome/browser/ui/util/named_guide.h"
 #include "ios/chrome/browser/ui/util/ui_util.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
index bb668f9..41b8ef7 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_egtest.mm
@@ -18,12 +18,12 @@
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_switches.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/notification_promo.h"
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.h"
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
 #include "ios/chrome/browser/search_engines/template_url_service_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_whats_new_item.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_view_controller.h"
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h
index da0d99f4..03dad63 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.h
@@ -27,7 +27,7 @@
 @protocol OmniboxFocuser;
 class TemplateURLService;
 @protocol SnackbarCommands;
-@protocol UrlLoader;
+class UrlLoadingService;
 class WebStateList;
 
 // Mediator for the NTP Home panel, handling the interactions with the
@@ -38,20 +38,18 @@
                ContentSuggestionsHeaderViewControllerDelegate>
 
 - (nullable instancetype)
-initWithWebStateList:(nonnull WebStateList*)webStateList
-  templateURLService:(nonnull TemplateURLService*)templateURLService
-          logoVendor:(nonnull id<LogoVendor>)logoVendor
+    initWithWebStateList:(nonnull WebStateList*)webStateList
+      templateURLService:(nonnull TemplateURLService*)templateURLService
+       urlLoadingService:(nonnull UrlLoadingService*)urlLoadingService
+              logoVendor:(nonnull id<LogoVendor>)logoVendor
     NS_DESIGNATED_INITIALIZER;
 
 - (nullable instancetype)init NS_UNAVAILABLE;
 
 // Dispatcher.
-@property(nonatomic, weak, nullable) id<ApplicationCommands,
-                                        BrowserCommands,
-                                        OmniboxFocuser,
-                                        SnackbarCommands,
-                                        UrlLoader>
-    dispatcher;
+@property(nonatomic, weak, nullable)
+    id<ApplicationCommands, BrowserCommands, OmniboxFocuser, SnackbarCommands>
+        dispatcher;
 // Suggestions service used to get the suggestions.
 @property(nonatomic, assign, nonnull)
     ntp_snippets::ContentSuggestionsService* suggestionsService;
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
index ca47ea3..8df284b7 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator.mm
@@ -17,6 +17,7 @@
 #import "ios/chrome/browser/ntp/new_tab_page_tab_helper.h"
 #import "ios/chrome/browser/search_engines/search_engine_observer_bridge.h"
 #import "ios/chrome/browser/ui/alert_coordinator/alert_coordinator.h"
+#import "ios/chrome/browser/ui/chrome_load_params.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
@@ -39,8 +40,8 @@
 #import "ios/chrome/browser/ui/ntp/notification_promo_whats_new.h"
 #import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
-#import "ios/chrome/browser/ui/url_loader.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
+#import "ios/chrome/browser/url_loading/url_loading_service.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
 #import "ios/chrome/common/favicon/favicon_attributes.h"
@@ -73,6 +74,8 @@
   std::unique_ptr<WebStateListObserverBridge> _webStateListObserver;
   // Listen for default search engine changes.
   std::unique_ptr<SearchEngineObserverBridge> _searchEngineObserver;
+  // Used to load URLs.
+  UrlLoadingService* _urlLoadingService;
 }
 
 @property(nonatomic, strong) AlertCoordinator* alertCoordinator;
@@ -104,6 +107,7 @@
 
 - (instancetype)initWithWebStateList:(WebStateList*)webStateList
                   templateURLService:(TemplateURLService*)templateURLService
+                   urlLoadingService:(UrlLoadingService*)urlLoadingService
                           logoVendor:(id<LogoVendor>)logoVendor {
   self = [super init];
   if (self) {
@@ -111,6 +115,7 @@
     _webStateListObserver = std::make_unique<WebStateListObserverBridge>(self);
     _webStateList->AddObserver(_webStateListObserver.get());
     _templateURLService = templateURLService;
+    _urlLoadingService = urlLoadingService;
     // Listen for default search engine changes.
     _searchEngineObserver = std::make_unique<SearchEngineObserverBridge>(
         self, self.templateURLService);
@@ -232,7 +237,7 @@
                     web::ReferrerPolicyDefault);
   params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
   ChromeLoadParams chromeParams(params);
-  [self.dispatcher loadURLWithParams:chromeParams];
+  _urlLoadingService->LoadUrlInCurrentTab(chromeParams);
   [self.NTPMetrics recordAction:new_tab_page_uma::ACTION_OPENED_SUGGESTION];
 }
 
@@ -276,7 +281,7 @@
   web::NavigationManager::WebLoadParams params(mostVisitedItem.URL);
   params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
   ChromeLoadParams chromeParams(params);
-  [self.dispatcher loadURLWithParams:chromeParams];
+  _urlLoadingService->LoadUrlInCurrentTab(chromeParams);
 }
 
 - (void)displayContextMenuForSuggestion:(CollectionViewItem*)item
@@ -343,7 +348,7 @@
                                    inIncognito:NO
                                   inBackground:NO
                                       appendTo:kCurrentTab];
-    [self.dispatcher webPageOrderedOpen:command];
+    _urlLoadingService->OpenUrlInNewTab(command);
     return;
   }
 
@@ -364,7 +369,7 @@
     return;
   GURL URL(kNTPHelpURL);
   ChromeLoadParams params(URL);
-  [self.dispatcher loadURLWithParams:params];
+  _urlLoadingService->LoadUrlInCurrentTab(params);
   [self.NTPMetrics recordAction:new_tab_page_uma::ACTION_OPENED_LEARN_MORE];
 }
 
@@ -551,7 +556,7 @@
     // prevent staying stuck.
     [self.dispatcher cancelOmniboxEdit];
   }
-  [self.dispatcher webPageOrderedOpen:command];
+  _urlLoadingService->OpenUrlInNewTab(command);
 }
 
 // Logs a histogram due to a Most Visited item being opened.
diff --git a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator_unittest.mm b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator_unittest.mm
index 5f4df7e..acd5c68 100644
--- a/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator_unittest.mm
+++ b/ios/chrome/browser/ui/content_suggestions/ntp_home_mediator_unittest.mm
@@ -20,7 +20,8 @@
 #import "ios/chrome/browser/ui/content_suggestions/ntp_home_consumer.h"
 #import "ios/chrome/browser/ui/location_bar_notification_names.h"
 #import "ios/chrome/browser/ui/toolbar/test/toolbar_test_navigation_manager.h"
-#import "ios/chrome/browser/ui/url_loader.h"
+#include "ios/chrome/browser/url_loading/test_url_loading_service.h"
+#include "ios/chrome/browser/url_loading/url_loading_service_factory.h"
 #include "ios/chrome/browser/web_state_list/fake_web_state_list_delegate.h"
 #include "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/chrome/browser/web_state_list/web_state_list_observer_bridge.h"
@@ -36,8 +37,7 @@
 #error "This file requires ARC support."
 #endif
 
-@protocol
-    NTPHomeMediatorDispatcher<BrowserCommands, SnackbarCommands, UrlLoader>
+@protocol NTPHomeMediatorDispatcher <BrowserCommands, SnackbarCommands>
 @end
 
 namespace {
@@ -54,6 +54,9 @@
     test_cbs_builder.AddTestingFactory(
         IOSChromeContentSuggestionsServiceFactory::GetInstance(),
         IOSChromeContentSuggestionsServiceFactory::GetDefaultFactory());
+    test_cbs_builder.AddTestingFactory(
+        UrlLoadingServiceFactory::GetInstance(),
+        UrlLoadingServiceFactory::GetDefaultFactory());
     chrome_browser_state_ = test_cbs_builder.Build();
 
     std::unique_ptr<ToolbarTestNavigationManager> navigation_manager =
@@ -67,10 +70,14 @@
     dispatcher_ = OCMProtocolMock(@protocol(NTPHomeMediatorDispatcher));
     suggestions_view_controller_ =
         OCMClassMock([ContentSuggestionsViewController class]);
+    url_loader_ =
+        (TestUrlLoadingService*)UrlLoadingServiceFactory::GetForBrowserState(
+            chrome_browser_state_.get());
     mediator_ = [[NTPHomeMediator alloc]
         initWithWebStateList:web_state_list_.get()
           templateURLService:ios::TemplateURLServiceFactory::GetForBrowserState(
                                  chrome_browser_state_.get())
+           urlLoadingService:url_loader_
                   logoVendor:logo_vendor_];
     mediator_.suggestionsService =
         IOSChromeContentSuggestionsServiceFactory::GetForBrowserState(
@@ -113,6 +120,7 @@
   ToolbarTestNavigationManager* navigation_manager_;
   std::unique_ptr<WebStateList> web_state_list_;
   FakeWebStateListDelegate web_state_list_delegate_;
+  TestUrlLoadingService* url_loader_;
 
  private:
   std::unique_ptr<web::TestWebState> test_web_state_;
@@ -240,7 +248,7 @@
   EXPECT_OCMOCK_VERIFY(dispatcher_);
 }
 
-// Tests that the command is sent to the dispatcher when opening a suggestion.
+// Tests that the command is sent to the loader when opening a suggestion.
 TEST_F(NTPHomeMediatorTest, TestOpenPage) {
   // Setup.
   [mediator_ setUp];
@@ -253,20 +261,18 @@
   id model = OCMClassMock([CollectionViewModel class]);
   OCMStub([suggestions_view_controller_ collectionViewModel]).andReturn(model);
   OCMStub([model itemAtIndexPath:indexPath]).andReturn(item);
-  web::NavigationManager::WebLoadParams params(url);
-  params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
-  ChromeLoadParams chromeParams(params);
-  OCMExpect(
-      [[dispatcher_ ignoringNonObjectArgs] loadURLWithParams:chromeParams]);
 
   // Action.
   [mediator_ openPageForItemAtIndexPath:indexPath];
 
   // Test.
-  EXPECT_OCMOCK_VERIFY(dispatcher_);
+  EXPECT_EQ(url, url_loader_->last_web_params.url);
+  EXPECT_TRUE(ui::PageTransitionCoreTypeIs(
+      ui::PAGE_TRANSITION_AUTO_BOOKMARK,
+      url_loader_->last_web_params.transition_type));
 }
 
-// Tests that the command is sent to the dispatcher when opening a most visited.
+// Tests that the command is sent to the loader when opening a most visited.
 TEST_F(NTPHomeMediatorTest, TestOpenMostVisited) {
   // Setup.
   [mediator_ setUp];
@@ -274,15 +280,13 @@
   ContentSuggestionsMostVisitedItem* item =
       [[ContentSuggestionsMostVisitedItem alloc] initWithType:0];
   item.URL = url;
-  web::NavigationManager::WebLoadParams params(url);
-  params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
-  ChromeLoadParams chromeParams(params);
-  OCMExpect(
-      [[dispatcher_ ignoringNonObjectArgs] loadURLWithParams:chromeParams]);
 
   // Action.
   [mediator_ openMostVisitedItem:item atIndex:0];
 
   // Test.
-  EXPECT_OCMOCK_VERIFY(dispatcher_);
+  EXPECT_EQ(url, url_loader_->last_web_params.url);
+  EXPECT_TRUE(ui::PageTransitionCoreTypeIs(
+      ui::PAGE_TRANSITION_AUTO_BOOKMARK,
+      url_loader_->last_web_params.transition_type));
 }
diff --git a/ios/chrome/browser/ui/infobars/BUILD.gn b/ios/chrome/browser/ui/infobars/BUILD.gn
index 5f16e17..24181eb 100644
--- a/ios/chrome/browser/ui/infobars/BUILD.gn
+++ b/ios/chrome/browser/ui/infobars/BUILD.gn
@@ -11,6 +11,7 @@
     "infobar_container_mediator.mm",
   ]
   deps = [
+    ":feature_flags",
     ":infobars_ui",
     ":public",
     "//base",
diff --git a/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm b/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm
index 2daf7d0..221c3ad 100644
--- a/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm
+++ b/ios/chrome/browser/ui/infobars/coordinators/infobar_confirm_coordinator.mm
@@ -28,6 +28,8 @@
 @synthesize bannerViewController = _bannerViewController;
 // Property defined in InfobarUIDelegate.
 @synthesize delegate = _delegate;
+// Property defined in InfobarUIDelegate.
+@synthesize presented = _presented;
 // Property defined in InfobarCoordinating.
 @synthesize started = _started;
 
@@ -36,6 +38,7 @@
   self = [super initWithBaseViewController:nil browserState:nil];
   if (self) {
     _confirmInfobarDelegate = confirmInfoBarDelegate;
+    _presented = YES;
   }
   return self;
 }
diff --git a/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm b/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm
index 649bf918..42aa710 100644
--- a/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm
+++ b/ios/chrome/browser/ui/infobars/coordinators/infobar_password_coordinator.mm
@@ -29,6 +29,8 @@
 @synthesize bannerViewController = _bannerViewController;
 // Property defined in InfobarUIDelegate.
 @synthesize delegate = _delegate;
+// Property defined in InfobarUIDelegate.
+@synthesize presented = _presented;
 // Property defined in InfobarCoordinating.
 @synthesize started = _started;
 
diff --git a/ios/chrome/browser/ui/infobars/infobar_container_coordinator.h b/ios/chrome/browser/ui/infobars/infobar_container_coordinator.h
index cd5258c..8a35e33 100644
--- a/ios/chrome/browser/ui/infobars/infobar_container_coordinator.h
+++ b/ios/chrome/browser/ui/infobars/infobar_container_coordinator.h
@@ -37,8 +37,11 @@
 - (instancetype)initWithBaseViewController:(UIViewController*)viewController
                                    browser:(Browser*)browser NS_UNAVAILABLE;
 
-// The InfobarContainer View.
-- (UIView*)view;
+// Sets the visibility of the container to |hidden|.
+- (void)hideContainer:(BOOL)hidden;
+
+// The InfobarContainer Legacy View.
+- (UIView*)legacyContainerView;
 
 // Updates the InfobarContainer according to the positioner information.
 - (void)updateInfobarContainer;
diff --git a/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm b/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm
index 8fd8d72..9eb605f 100644
--- a/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm
+++ b/ios/chrome/browser/ui/infobars/infobar_container_coordinator.mm
@@ -7,7 +7,6 @@
 #include <memory>
 
 #import "base/mac/foundation_util.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/infobars/infobar_manager_impl.h"
 #import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/fullscreen/fullscreen_controller_factory.h"
@@ -15,6 +14,7 @@
 #import "ios/chrome/browser/ui/infobars/infobar_container_consumer.h"
 #include "ios/chrome/browser/ui/infobars/infobar_container_mediator.h"
 #include "ios/chrome/browser/ui/infobars/infobar_container_view_controller.h"
+#import "ios/chrome/browser/ui/infobars/infobar_feature.h"
 #import "ios/chrome/browser/ui/infobars/infobar_positioner.h"
 #include "ios/chrome/browser/ui/infobars/legacy_infobar_container_view_controller.h"
 #import "ios/chrome/browser/ui/infobars/presentation/infobar_banner_animator.h"
@@ -34,7 +34,11 @@
 @property(nonatomic, assign) TabModel* tabModel;
 
 // UIViewController that contains Infobars.
-@property(nonatomic, strong) UIViewController* containerViewController;
+@property(nonatomic, strong)
+    InfobarContainerViewController* containerViewController;
+// UIViewController that contains legacy Infobars.
+@property(nonatomic, strong)
+    LegacyInfobarContainerViewController* legacyContainerViewController;
 // The mediator for this Coordinator.
 @property(nonatomic, strong) InfobarContainerMediator* mediator;
 
@@ -58,34 +62,32 @@
   DCHECK(self.positioner);
   DCHECK(self.dispatcher);
 
-  // Create and setup the ViewController, and initialize the mediator.
-  if (experimental_flags::IsInfobarUIRebootEnabled()) {
-    InfobarContainerViewController* container =
-        [[InfobarContainerViewController alloc] init];
-    self.containerViewController = container;
-    self.mediator =
-        [[InfobarContainerMediator alloc] initWithConsumer:self
-                                              browserState:self.browserState
-                                                  tabModel:self.tabModel];
-  } else {
-    LegacyInfobarContainerViewController* legacyContainer =
-        [[LegacyInfobarContainerViewController alloc]
-            initWithFullscreenController:
-                FullscreenControllerFactory::GetInstance()->GetForBrowserState(
-                    self.browserState)];
-    [self.baseViewController addChildViewController:legacyContainer];
-    // TODO(crbug.com/892376): We shouldn't modify the BaseVC hierarchy, BVC
-    // needs to handle this.
-    [self.baseViewController.view insertSubview:legacyContainer.view
-                                   aboveSubview:self.positioner.parentView];
-    [legacyContainer didMoveToParentViewController:self.baseViewController];
-    legacyContainer.positioner = self.positioner;
-    self.containerViewController = legacyContainer;
-    self.mediator =
-        [[InfobarContainerMediator alloc] initWithConsumer:legacyContainer
-                                              browserState:self.browserState
-                                                  tabModel:self.tabModel];
-  }
+  // Creates the InfobarContainerVC.
+  InfobarContainerViewController* container =
+      [[InfobarContainerViewController alloc] init];
+  self.containerViewController = container;
+
+  // Creates the LegacyInfobarContainerVC.
+  LegacyInfobarContainerViewController* legacyContainer =
+      [[LegacyInfobarContainerViewController alloc]
+          initWithFullscreenController:
+              FullscreenControllerFactory::GetInstance()->GetForBrowserState(
+                  self.browserState)];
+  [self.baseViewController addChildViewController:legacyContainer];
+  // TODO(crbug.com/892376): Shouldn't modify the BaseVC hierarchy, BVC
+  // needs to handle this.
+  [self.baseViewController.view insertSubview:legacyContainer.view
+                                 aboveSubview:self.positioner.parentView];
+  [legacyContainer didMoveToParentViewController:self.baseViewController];
+  legacyContainer.positioner = self.positioner;
+  self.legacyContainerViewController = legacyContainer;
+
+  // Creates the mediator using both consumers.
+  self.mediator = [[InfobarContainerMediator alloc]
+      initWithConsumer:self
+        legacyConsumer:self.legacyContainerViewController
+          browserState:self.browserState
+              tabModel:self.tabModel];
 
   self.mediator.syncPresenter = self.syncPresenter;
   self.mediator.signinPresenter = self;
@@ -101,19 +103,19 @@
 
 #pragma mark - Public Interface
 
-- (UIView*)view {
-  return self.containerViewController.view;
+- (void)hideContainer:(BOOL)hidden {
+  [self.legacyContainerViewController.view setHidden:hidden];
+  [self.containerViewController.view setHidden:hidden];
+}
+
+- (UIView*)legacyContainerView {
+  return self.legacyContainerViewController.view;
 }
 
 - (void)updateInfobarContainer {
-  // TODO(crbug.com/927064): No need to update the non legacy version since
+  // TODO(crbug.com/927064): No need to update the non legacy container since
   // updateLayoutAnimated is NO-OP.
-  if (!experimental_flags::IsInfobarUIRebootEnabled()) {
-    LegacyInfobarContainerViewController* legacyContainer =
-        base::mac::ObjCCastStrict<LegacyInfobarContainerViewController>(
-            self.containerViewController);
-    [legacyContainer updateLayoutAnimated:NO];
-  }
+  [self.legacyContainerViewController updateLayoutAnimated:NO];
 }
 
 - (BOOL)isInfobarPresentingForWebState:(web::WebState*)webState {
@@ -129,7 +131,7 @@
 
 - (void)addInfoBarWithDelegate:(id<InfobarUIDelegate>)infoBarDelegate
                       position:(NSInteger)position {
-  DCHECK(experimental_flags::IsInfobarUIRebootEnabled());
+  DCHECK(IsInfobarUIRebootEnabled());
   ChromeCoordinator<InfobarCoordinating>* infobarCoordinator =
       static_cast<ChromeCoordinator<InfobarCoordinating>*>(infoBarDelegate);
 
@@ -153,12 +155,11 @@
 }
 
 - (void)setUserInteractionEnabled:(BOOL)enabled {
-  DCHECK(experimental_flags::IsInfobarUIRebootEnabled());
-  [self.view setUserInteractionEnabled:enabled];
+  [self.containerViewController.view setUserInteractionEnabled:enabled];
 }
 
 - (void)updateLayoutAnimated:(BOOL)animated {
-  DCHECK(experimental_flags::IsInfobarUIRebootEnabled());
+  DCHECK(IsInfobarUIRebootEnabled());
   // TODO(crbug.com/927064): NO-OP - This shouldn't be needed in the new UI
   // since we use autolayout for the contained Infobars.
 }
diff --git a/ios/chrome/browser/ui/infobars/infobar_container_mediator.h b/ios/chrome/browser/ui/infobars/infobar_container_mediator.h
index 7902015..1b14c09 100644
--- a/ios/chrome/browser/ui/infobars/infobar_container_mediator.h
+++ b/ios/chrome/browser/ui/infobars/infobar_container_mediator.h
@@ -21,8 +21,10 @@
 @interface InfobarContainerMediator : NSObject<UpgradeCenterClient>
 
 // Designated initializer. None of the parameters are retained.
-// TODO(crbug.com/927064): BrowserState shouldn't be passed to the mediator.
+// TODO(crbug.com/927064): BrowserState shouldn't be passed to the mediator, the
+// legacy consumer won't be needed once legacyInfobars are no longer supported.
 - (instancetype)initWithConsumer:(id<InfobarContainerConsumer>)consumer
+                  legacyConsumer:(id<InfobarContainerConsumer>)legacyConsumer
                     browserState:(ios::ChromeBrowserState*)browserState
                         tabModel:(TabModel*)tabModel NS_DESIGNATED_INITIALIZER;
 ;
diff --git a/ios/chrome/browser/ui/infobars/infobar_container_mediator.mm b/ios/chrome/browser/ui/infobars/infobar_container_mediator.mm
index 4c4c90d..3d1dce2 100644
--- a/ios/chrome/browser/ui/infobars/infobar_container_mediator.mm
+++ b/ios/chrome/browser/ui/infobars/infobar_container_mediator.mm
@@ -35,8 +35,6 @@
 @property(nonatomic, assign, readonly) ios::ChromeBrowserState* browserState;
 // The mediator's TabModel.
 @property(nonatomic, weak, readonly) TabModel* tabModel;
-// The mediator's consumer.
-@property(nonatomic, weak) id<InfobarContainerConsumer> consumer;
 // The WebStateList that this mediator listens for any changes on its Webstates.
 @property(nonatomic, assign) WebStateList* webStateList;
 
@@ -47,16 +45,16 @@
 #pragma mark - Public Interface
 
 - (instancetype)initWithConsumer:(id<InfobarContainerConsumer>)consumer
+                  legacyConsumer:(id<InfobarContainerConsumer>)legacyConsumer
                     browserState:(ios::ChromeBrowserState*)browserState
                         tabModel:(TabModel*)tabModel {
   self = [super init];
   if (self) {
     _browserState = browserState;
-    _consumer = consumer;
     _tabModel = tabModel;
     _webStateList = _tabModel.webStateList;
 
-    _infoBarContainer.reset(new InfoBarContainerIOS(_consumer));
+    _infoBarContainer.reset(new InfoBarContainerIOS(consumer, legacyConsumer));
     infobars::InfoBarManager* infoBarManager = nullptr;
     if (_tabModel.currentTab) {
       DCHECK(_tabModel.currentTab.webState);
diff --git a/ios/chrome/browser/ui/infobars/infobar_feature.h b/ios/chrome/browser/ui/infobars/infobar_feature.h
index de68e02..fa69a56 100644
--- a/ios/chrome/browser/ui/infobars/infobar_feature.h
+++ b/ios/chrome/browser/ui/infobars/infobar_feature.h
@@ -10,4 +10,7 @@
 // Feature to choose whether to use the new Infobar design, or the legacy one.
 extern const base::Feature kInfobarUIReboot;
 
+// Whether the Infobar UI Reboot is enabled.
+bool IsInfobarUIRebootEnabled();
+
 #endif  // IOS_CHROME_BROWSER_UI_INFOBARS_INFOBAR_FEATURE_H_
diff --git a/ios/chrome/browser/ui/infobars/infobar_feature.mm b/ios/chrome/browser/ui/infobars/infobar_feature.mm
index 6116381..f7fb903 100644
--- a/ios/chrome/browser/ui/infobars/infobar_feature.mm
+++ b/ios/chrome/browser/ui/infobars/infobar_feature.mm
@@ -10,3 +10,7 @@
 
 const base::Feature kInfobarUIReboot{"InfobarUIReboot",
                                      base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool IsInfobarUIRebootEnabled() {
+  return base::FeatureList::IsEnabled(kInfobarUIReboot);
+}
diff --git a/ios/chrome/browser/ui/infobars/infobar_ui_delegate.h b/ios/chrome/browser/ui/infobars/infobar_ui_delegate.h
index 1833c88..dede13d 100644
--- a/ios/chrome/browser/ui/infobars/infobar_ui_delegate.h
+++ b/ios/chrome/browser/ui/infobars/infobar_ui_delegate.h
@@ -24,6 +24,9 @@
 // The InfobarControllerDelegate.
 @property(nonatomic, assign) InfoBarControllerDelegate* delegate;
 
+// YES if the container should modally present the Infobar.
+@property(nonatomic, assign, getter=isPresented) BOOL presented;
+
 @optional
 // The Infobar UIView.
 // TODO(crbug.com/927064): Only used in the Legacy implementation.
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.h b/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
index 5d8918e..65a906a 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.h
@@ -26,7 +26,6 @@
 @protocol FakeboxFocuser;
 @protocol SnackbarCommands;
 @class TabModel;
-@protocol UrlLoader;
 
 // A controller for the New Tab Page user interface. Supports content
 // suggestions and incognito, each with its own controller.
@@ -59,8 +58,7 @@
                              BrowserCommands,
                              OmniboxFocuser,
                              FakeboxFocuser,
-                             SnackbarCommands,
-                             UrlLoader>)dispatcher
+                             SnackbarCommands>)dispatcher
            safeAreaInset:(UIEdgeInsets)safeAreaInset;
 
 // Animates the NTP fakebox to the focused position and focuses the real
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
index 26ec6f0..a9d730b 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_controller.mm
@@ -64,8 +64,7 @@
                               BrowserCommands,
                               OmniboxFocuser,
                               FakeboxFocuser,
-                              SnackbarCommands,
-                              UrlLoader>
+                              SnackbarCommands>
     dispatcher;
 
 // Coordinator for the ContentSuggestions.
@@ -97,8 +96,7 @@
                              BrowserCommands,
                              OmniboxFocuser,
                              FakeboxFocuser,
-                             SnackbarCommands,
-                             UrlLoader>)dispatcher
+                             SnackbarCommands>)dispatcher
            safeAreaInset:(UIEdgeInsets)safeAreaInset {
   self = [super initWithNibName:nil url:url];
   if (self) {
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h
index 6de8eeb..511de37 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator.h
@@ -16,7 +16,6 @@
 @protocol OmniboxFocuser;
 @protocol FakeboxFocuser;
 @protocol SnackbarCommands;
-@protocol UrlLoader;
 @protocol NewTabPageControllerDelegate;
 
 // Coordinator handling the NTP.
@@ -47,8 +46,7 @@
                               BrowserCommands,
                               OmniboxFocuser,
                               FakeboxFocuser,
-                              SnackbarCommands,
-                              UrlLoader>
+                              SnackbarCommands>
     dispatcher;
 
 // Returns |YES| if the coordinator is started.
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator_unittest.mm b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator_unittest.mm
index 8d1d756..1d4b129 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_coordinator_unittest.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_coordinator_unittest.mm
@@ -28,12 +28,11 @@
 #error "This file requires ARC support."
 #endif
 
-@protocol NewTabPageTabDispatcher<ApplicationCommands,
-                                  BrowserCommands,
-                                  OmniboxFocuser,
-                                  FakeboxFocuser,
-                                  SnackbarCommands,
-                                  UrlLoader>
+@protocol NewTabPageTabDispatcher <ApplicationCommands,
+                                   BrowserCommands,
+                                   OmniboxFocuser,
+                                   FakeboxFocuser,
+                                   SnackbarCommands>
 @end
 
 // Test fixture for testing NewTabPageCoordinator class.
diff --git a/ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm b/ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm
index 54757be..e2cdaec 100644
--- a/ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm
+++ b/ios/chrome/browser/ui/ntp/notification_promo_whats_new.mm
@@ -19,9 +19,9 @@
 #include "base/values.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/prefs/pref_service.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/notification_promo.h"
 #include "ios/chrome/browser/pref_names.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
index 334064a..f98d90a 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -16,7 +16,7 @@
 #include "components/omnibox/browser/autocomplete_input.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/autocomplete/autocomplete_scheme_classifier_impl.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_util.h"
 #import "ios/chrome/browser/ui/toolbar/public/features.h"
 #import "ios/chrome/browser/ui/toolbar/public/toolbar_constants.h"
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
index 2faa79a..e234819 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_coordinator.mm
@@ -102,7 +102,7 @@
         initWithBaseViewController:self.popupViewController
                       browserState:self.browserState];
     self.shortcutsCoordinator.dispatcher =
-        (id<ApplicationCommands, BrowserCommands, UrlLoader,
+        (id<ApplicationCommands, BrowserCommands,
             OmniboxFocuser>)(self.dispatcher);
     [self.shortcutsCoordinator start];
     self.popupViewController.shortcutsViewController =
diff --git a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm
index 2de7495..89298d3 100644
--- a/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_ios.mm
@@ -17,7 +17,7 @@
 #include "components/omnibox/browser/omnibox_popup_model.h"
 #include "components/open_from_clipboard/clipboard_recent_content.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#import "ios/chrome/browser/experimental_flags.h"
+#import "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_util.h"
 #import "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_mediator.h"
 #include "ios/chrome/browser/ui/omnibox/popup/omnibox_popup_view_suggestions_delegate.h"
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/BUILD.gn b/ios/chrome/browser/ui/omnibox/popup/shortcuts/BUILD.gn
index 24d6d4e..1c45ca1 100644
--- a/ios/chrome/browser/ui/omnibox/popup/shortcuts/BUILD.gn
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/BUILD.gn
@@ -23,6 +23,7 @@
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/ntp_tile_views",
     "//ios/chrome/browser/ui/ntp_tile_views:constants",
+    "//ios/chrome/browser/url_loading",
     "//ios/chrome/common/favicon",
     "//ios/chrome/common/ui_util",
   ]
@@ -50,6 +51,7 @@
     "//ios/chrome/browser/ui/coordinators:chrome_coordinators",
     "//ios/chrome/browser/ui/favicon",
     "//ios/chrome/browser/ui/toolbar/public",
+    "//ios/chrome/browser/url_loading",
     "//ios/web/public",
   ]
 }
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.h b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.h
index 8bab048..7e4a26f 100644
--- a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.h
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.h
@@ -9,7 +9,6 @@
 
 @protocol ApplicationCommands;
 @protocol BrowserCommands;
-@protocol UrlLoader;
 @protocol OmniboxFocuser;
 
 // The coordinator for the shortcuts.
@@ -20,7 +19,7 @@
 @property(nonatomic, strong, readonly) UIViewController* viewController;
 
 @property(nonatomic, weak)
-    id<ApplicationCommands, BrowserCommands, UrlLoader, OmniboxFocuser>
+    id<ApplicationCommands, BrowserCommands, OmniboxFocuser>
         dispatcher;
 @end
 
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.mm b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.mm
index 8b0a69e..83bd14c 100644
--- a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_coordinator.mm
@@ -11,6 +11,8 @@
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
 #import "ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.h"
 #import "ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_view_controller.h"
+#import "ios/chrome/browser/url_loading/url_loading_service.h"
+#import "ios/chrome/browser/url_loading/url_loading_service_factory.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -37,12 +39,15 @@
       IOSMostVisitedSitesFactory::NewForBrowserState(self.browserState);
   ReadingListModel* readingListModel =
       ReadingListModelFactory::GetForBrowserState(self.browserState);
+  UrlLoadingService* loadingService =
+      UrlLoadingServiceFactory::GetForBrowserState(self.browserState);
 
   self.mediator = [[ShortcutsMediator alloc]
       initWithLargeIconService:largeIconService
                 largeIconCache:cache
                mostVisitedSite:std::move(mostVisitedSites)
-              readingListModel:readingListModel];
+              readingListModel:readingListModel
+                loadingService:loadingService];
 
   ShortcutsViewController* shortcutsViewController =
       [[ShortcutsViewController alloc] init];
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.h b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.h
index b40cb48..ee00a10 100644
--- a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.h
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.h
@@ -18,28 +18,29 @@
 }
 class LargeIconCache;
 class ReadingListModel;
+class UrlLoadingService;
 
 @protocol ApplicationCommands;
 @protocol BrowserCommands;
 @protocol OmniboxFocuser;
 @protocol ShortcutsConsumer;
-@protocol UrlLoader;
 
 // Coordinator for the Omnibox Popup Shortcuts.
 @interface ShortcutsMediator : NSObject<ShortcutsViewControllerDelegate>
 
 - (instancetype)
-initWithLargeIconService:(favicon::LargeIconService*)largeIconService
-          largeIconCache:(LargeIconCache*)largeIconCache
-         mostVisitedSite:
-             (std::unique_ptr<ntp_tiles::MostVisitedSites>)mostVisitedSites
-        readingListModel:(ReadingListModel*)readingListModel;
+    initWithLargeIconService:(favicon::LargeIconService*)largeIconService
+              largeIconCache:(LargeIconCache*)largeIconCache
+             mostVisitedSite:
+                 (std::unique_ptr<ntp_tiles::MostVisitedSites>)mostVisitedSites
+            readingListModel:(ReadingListModel*)readingListModel
+              loadingService:(UrlLoadingService*)loadingService;
 
 // The consumer for the data fetched by this mediator.
 @property(nonatomic, weak) id<ShortcutsConsumer> consumer;
 // Dispatcher.
 @property(nonatomic, weak)
-    id<ApplicationCommands, BrowserCommands, UrlLoader, OmniboxFocuser>
+    id<ApplicationCommands, BrowserCommands, OmniboxFocuser>
         dispatcher;
 @end
 
diff --git a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.mm b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.mm
index 7d69eedd..cfb6084 100644
--- a/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.mm
+++ b/ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_mediator.mm
@@ -15,6 +15,7 @@
 #import "ios/chrome/browser/ui/omnibox/popup/shortcuts/shortcuts_consumer.h"
 #import "ios/chrome/browser/ui/toolbar/public/omnibox_focuser.h"
 #import "ios/chrome/browser/ui/url_loader.h"
+#import "ios/chrome/browser/url_loading/url_loading_service.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
 
@@ -50,14 +51,16 @@
   // ShortcutsMediator observes the reading list model to get the reading list
   // badge.
   std::unique_ptr<ReadingListModelBridge> _readingListModelBridge;
+  UrlLoadingService* _loadingService;
 }
 
 - (instancetype)
-initWithLargeIconService:(favicon::LargeIconService*)largeIconService
-          largeIconCache:(LargeIconCache*)largeIconCache
-         mostVisitedSite:
-             (std::unique_ptr<ntp_tiles::MostVisitedSites>)mostVisitedSites
-        readingListModel:(ReadingListModel*)readingListModel {
+    initWithLargeIconService:(favicon::LargeIconService*)largeIconService
+              largeIconCache:(LargeIconCache*)largeIconCache
+             mostVisitedSite:
+                 (std::unique_ptr<ntp_tiles::MostVisitedSites>)mostVisitedSites
+            readingListModel:(ReadingListModel*)readingListModel
+              loadingService:(UrlLoadingService*)loadingService {
   self = [super init];
   if (self) {
     _faviconAttributesProvider = [[FaviconAttributesProvider alloc]
@@ -74,6 +77,8 @@
 
     _readingListModelBridge =
         std::make_unique<ReadingListModelBridge>(self, readingListModel);
+
+    _loadingService = loadingService;
   }
   return self;
 }
@@ -106,7 +111,7 @@
   params.transition_type = ui::PAGE_TRANSITION_AUTO_BOOKMARK;
   ChromeLoadParams chromeParams(params);
   [self.dispatcher cancelOmniboxEdit];
-  [self.dispatcher loadURLWithParams:chromeParams];
+  _loadingService->LoadUrlInCurrentTab(chromeParams);
 }
 
 - (void)openBookmarks {
diff --git a/ios/chrome/browser/ui/reading_list/empty_reading_list_message_util.mm b/ios/chrome/browser/ui/reading_list/empty_reading_list_message_util.mm
index 7f863e0..429f581b 100644
--- a/ios/chrome/browser/ui/reading_list/empty_reading_list_message_util.mm
+++ b/ios/chrome/browser/ui/reading_list/empty_reading_list_message_util.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/ui/reading_list/empty_reading_list_message_util.h"
 
 #include "base/logging.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/browser/ui/util/rtl_geometry.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
diff --git a/ios/chrome/browser/ui/reading_list/offline_page_native_content.h b/ios/chrome/browser/ui/reading_list/offline_page_native_content.h
index c722208..b14e46c 100644
--- a/ios/chrome/browser/ui/reading_list/offline_page_native_content.h
+++ b/ios/chrome/browser/ui/reading_list/offline_page_native_content.h
@@ -14,8 +14,6 @@
 class WebState;
 }
 
-@protocol UrlLoader;
-
 // A |StaticHtmlNativeContent| that displays offline pages located in the
 // application data folder that have been distilled by DOMdistiller.
 @interface OfflinePageNativeContent : StaticHtmlNativeContent
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
index f3f855b..1029b85 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_egtest.mm
@@ -14,8 +14,8 @@
 #include "base/strings/utf_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #include "components/reading_list/core/reading_list_model.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/reading_list/reading_list_model_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/commands/reading_list_add_command.h"
 #import "ios/chrome/browser/ui/popup_menu/popup_menu_constants.h"
 #import "ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.h"
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/BUILD.gn b/ios/chrome/browser/ui/settings/clear_browsing_data/BUILD.gn
index 4c1499b..5f8b42a 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/BUILD.gn
@@ -27,6 +27,7 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browsing_data",
+    "//ios/chrome/browser/browsing_data:feature_flags",
     "//ios/chrome/browser/feature_engagement",
     "//ios/chrome/browser/history",
     "//ios/chrome/browser/signin",
@@ -74,6 +75,7 @@
     "//ios/chrome/browser",
     "//ios/chrome/browser/browser_state:test_support",
     "//ios/chrome/browser/browsing_data:counters",
+    "//ios/chrome/browser/browsing_data:feature_flags",
     "//ios/chrome/browser/prefs:browser_prefs",
     "//ios/chrome/browser/signin:test_support",
     "//ios/chrome/browser/sync",
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller.mm
index c62c473..529cbea 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller.mm
@@ -17,12 +17,12 @@
 #include "components/strings/grit/components_strings.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.h"
+#include "ios/chrome/browser/browsing_data/browsing_data_features.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remove_mask.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remover.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remover_factory.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remover_observer.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/ui/alert_coordinator/action_sheet_coordinator.h"
 #import "ios/chrome/browser/ui/collection_view/cells/MDCCollectionViewCell+Chrome.h"
 #import "ios/chrome/browser/ui/collection_view/collection_view_model.h"
@@ -141,7 +141,7 @@
     self.collectionViewAccessibilityIdentifier =
         kClearBrowsingDataCollectionViewAccessibilityIdentifier;
 
-    if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+    if (IsNewClearBrowsingDataUIEnabled()) {
       __weak ClearBrowsingDataCollectionViewController* weakSelf = self;
       observer_ = std::make_unique<BrowsingDataRemoverObserverWrapper>(
           ^(BrowsingDataRemoveMask mask) {
@@ -307,14 +307,14 @@
         clearDataItem.accessoryType = MDCCollectionViewCellAccessoryCheckmark;
         _browserState->GetPrefs()->SetBoolean(clearDataItem.prefName, true);
         if (itemType == ItemTypeDataTypeCookiesSiteData &&
-            experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+            IsNewClearBrowsingDataUIEnabled()) {
           [self updateCounter:itemType
                    detailText:l10n_util::GetNSString(IDS_DEL_COOKIES_COUNTER)];
         }
       } else {
         clearDataItem.accessoryType = MDCCollectionViewCellAccessoryNone;
         _browserState->GetPrefs()->SetBoolean(clearDataItem.prefName, false);
-        if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+        if (IsNewClearBrowsingDataUIEnabled()) {
           [self updateCounter:itemType detailText:@""];
         }
       }
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller_unittest.mm
index 678852da..9c6631c 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_collection_view_controller_unittest.mm
@@ -18,8 +18,8 @@
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#include "ios/chrome/browser/browsing_data/browsing_data_features.h"
 #include "ios/chrome/browser/browsing_data/cache_counter.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/prefs/browser_prefs.h"
 #include "ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.h"
@@ -120,7 +120,7 @@
   CheckController();
 
   int section_offset = 0;
-  if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+  if (IsNewClearBrowsingDataUIEnabled()) {
     section_offset = 1;
   }
 
@@ -155,7 +155,7 @@
   CheckController();
 
   int section_offset = 0;
-  if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+  if (IsNewClearBrowsingDataUIEnabled()) {
     EXPECT_EQ(5, NumberOfSections());
     EXPECT_EQ(1, NumberOfItemsInSection(0));
     section_offset = 1;
@@ -194,7 +194,7 @@
   CheckController();
 
   int section_offset = 0;
-  if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+  if (IsNewClearBrowsingDataUIEnabled()) {
     section_offset = 1;
   }
 
@@ -211,8 +211,7 @@
   CheckController();
   PrefService* prefs = browser_state_->GetPrefs();
 
-  const int section_offset =
-      experimental_flags::IsNewClearBrowsingDataUIEnabled() ? 1 : 0;
+  const int section_offset = IsNewClearBrowsingDataUIEnabled() ? 1 : 0;
 
   SelectItem(kDeleteBrowsingHistoryItem, 0 + section_offset);
   EXPECT_FALSE(prefs->GetBoolean(browsing_data::prefs::kDeleteBrowsingHistory));
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
index 312f137c..bad7ba2 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager.mm
@@ -20,9 +20,9 @@
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_counter_wrapper.h"
+#include "ios/chrome/browser/browsing_data/browsing_data_features.h"
 #include "ios/chrome/browser/browsing_data/browsing_data_remove_mask.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/feature_engagement/tracker_factory.h"
 #include "ios/chrome/browser/history/web_history_service_factory.h"
 #include "ios/chrome/browser/signin/identity_manager_factory.h"
@@ -100,7 +100,7 @@
     _listType = listType;
 
     _timePeriod = browsing_data::TimePeriod::ALL_TIME;
-    if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+    if (IsNewClearBrowsingDataUIEnabled()) {
       constexpr int maxValue =
           static_cast<int>(browsing_data::TimePeriod::TIME_PERIOD_LAST);
       const int prefValue = browserState->GetPrefs()->GetInteger(
@@ -119,7 +119,7 @@
 - (void)loadModel:(ListModel*)model {
   // Time range section.
   // Only implementing new UI for kListTypeCollectionView.
-  if (experimental_flags::IsNewClearBrowsingDataUIEnabled() &&
+  if (IsNewClearBrowsingDataUIEnabled() &&
       self.listType == ClearBrowsingDataListType::kListTypeCollectionView) {
     [model addSectionWithIdentifier:SectionIdentifierTimeRange];
     [model addItem:[self timeRangeItem]
@@ -355,7 +355,7 @@
                           prefName:(const char*)prefName {
   PrefService* prefs = self.browserState->GetPrefs();
   std::unique_ptr<BrowsingDataCounterWrapper> counter;
-  if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+  if (IsNewClearBrowsingDataUIEnabled()) {
     __weak ClearBrowsingDataManager* weakSelf = self;
     counter = BrowsingDataCounterWrapper::CreateCounterWrapper(
         prefName, self.browserState, prefs,
@@ -386,7 +386,7 @@
     // Because there is no counter for cookies, an explanatory text is
     // displayed.
     if (itemType == ItemTypeDataTypeCookiesSiteData &&
-        experimental_flags::IsNewClearBrowsingDataUIEnabled() &&
+        IsNewClearBrowsingDataUIEnabled() &&
         prefs->GetBoolean(browsing_data::prefs::kDeleteCookies)) {
       collectionClearDataItem.detailText =
           l10n_util::GetNSString(IDS_DEL_COOKIES_COUNTER);
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm
index cdb7a60..70e8ab5 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_manager_unittest.mm
@@ -12,8 +12,8 @@
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
+#include "ios/chrome/browser/browsing_data/browsing_data_features.h"
 #include "ios/chrome/browser/browsing_data/cache_counter.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/prefs/browser_prefs.h"
 #include "ios/chrome/browser/signin/identity_test_environment_chrome_browser_state_adaptor.h"
@@ -88,7 +88,7 @@
   [manager_ loadModel:model_];
 
   int section_offset = 0;
-  if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+  if (IsNewClearBrowsingDataUIEnabled()) {
     EXPECT_EQ(4, [model_ numberOfSections]);
     EXPECT_EQ(1, [model_ numberOfItemsInSection:0]);
     section_offset = 1;
@@ -112,7 +112,7 @@
   [manager_ loadModel:model_];
 
   int section_offset = 0;
-  if (experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+  if (IsNewClearBrowsingDataUIEnabled()) {
     EXPECT_EQ(5, [model_ numberOfSections]);
     EXPECT_EQ(1, [model_ numberOfItemsInSection:0]);
     section_offset = 1;
@@ -162,7 +162,7 @@
 
   // If the new UI is not enabled then the pref value for the time period
   // is ignored and the time period defaults to ALL_TIME.
-  if (!experimental_flags::IsNewClearBrowsingDataUIEnabled()) {
+  if (!IsNewClearBrowsingDataUIEnabled()) {
     return;
   }
   PrefService* prefs = browser_state_->GetPrefs();
diff --git a/ios/chrome/browser/ui/settings/google_services/BUILD.gn b/ios/chrome/browser/ui/settings/google_services/BUILD.gn
index d582c30..2bd5a4a 100644
--- a/ios/chrome/browser/ui/settings/google_services/BUILD.gn
+++ b/ios/chrome/browser/ui/settings/google_services/BUILD.gn
@@ -30,6 +30,7 @@
     "manage_sync_settings_view_controller_model_delegate.h",
   ]
   deps = [
+    "resources:google_services_sync_error",
     "//base",
     "//components/metrics",
     "//components/prefs",
diff --git a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
index 4813e1b..2e7165e 100644
--- a/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
+++ b/ios/chrome/browser/ui/settings/google_services/accounts_table_egtest.mm
@@ -13,12 +13,12 @@
 #include "components/sync/engine/sync_encryption_handler.h"
 #include "components/sync/protocol/proto_value_conversions.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory.h"
 #include "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #import "ios/chrome/browser/signin/authentication_service_factory.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/authentication/cells/account_control_item.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
diff --git a/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm b/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm
index 35a89b8..1f187f5 100644
--- a/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm
+++ b/ios/chrome/browser/ui/settings/google_services/google_services_settings_mediator.mm
@@ -70,6 +70,8 @@
   BetterSearchAndBrowsingItemType,
 };
 
+NSString* kGoogleServicesSyncErrorImage = @"google_services_sync_error";
+
 }  // namespace
 
 @interface GoogleServicesSettingsMediator () <
@@ -517,15 +519,7 @@
   syncErrorItem.text = GetNSString(IDS_IOS_SYNC_ERROR_TITLE);
   syncErrorItem.detailText =
       GetSyncErrorDescriptionForSyncSetupService(self.syncSetupService);
-  {
-    // TODO(crbug.com/889470): Needs asset for the sync error.
-    CGSize size = CGSizeMake(40, 40);
-    UIGraphicsBeginImageContextWithOptions(size, YES, 0);
-    [[UIColor grayColor] setFill];
-    UIRectFill(CGRectMake(0, 0, size.width, size.height));
-    syncErrorItem.image = UIGraphicsGetImageFromCurrentImageContext();
-    UIGraphicsEndImageContext();
-  }
+  syncErrorItem.image = [UIImage imageNamed:kGoogleServicesSyncErrorImage];
   return syncErrorItem;
 }
 
diff --git a/ios/chrome/browser/ui/settings/google_services/resources/BUILD.gn b/ios/chrome/browser/ui/settings/google_services/resources/BUILD.gn
new file mode 100644
index 0000000..a20471a
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/google_services/resources/BUILD.gn
@@ -0,0 +1,13 @@
+# 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.
+
+import("//build/config/ios/asset_catalog.gni")
+
+imageset("google_services_sync_error") {
+  sources = [
+    "google_services_sync_error.imageset/Contents.json",
+    "google_services_sync_error.imageset/google_services_sync_error@2x.png",
+    "google_services_sync_error.imageset/google_services_sync_error@3x.png",
+  ]
+}
diff --git a/ios/chrome/browser/ui/settings/google_services/resources/google_services_sync_error.imageset/Contents.json b/ios/chrome/browser/ui/settings/google_services/resources/google_services_sync_error.imageset/Contents.json
new file mode 100644
index 0000000..b338421
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/google_services/resources/google_services_sync_error.imageset/Contents.json
@@ -0,0 +1,18 @@
+{
+    "images": [
+        {
+            "idiom": "universal",
+            "scale": "2x",
+            "filename": "google_services_sync_error@2x.png"
+        },
+        {
+            "idiom": "universal",
+            "scale": "3x",
+            "filename": "google_services_sync_error@3x.png"
+        }
+    ],
+    "info": {
+        "version": 1,
+        "author": "xcode"
+    }
+}
diff --git a/ios/chrome/browser/ui/settings/google_services/resources/google_services_sync_error.imageset/google_services_sync_error@2x.png b/ios/chrome/browser/ui/settings/google_services/resources/google_services_sync_error.imageset/google_services_sync_error@2x.png
new file mode 100644
index 0000000..e1c54bf
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/google_services/resources/google_services_sync_error.imageset/google_services_sync_error@2x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/settings/google_services/resources/google_services_sync_error.imageset/google_services_sync_error@3x.png b/ios/chrome/browser/ui/settings/google_services/resources/google_services_sync_error.imageset/google_services_sync_error@3x.png
new file mode 100644
index 0000000..67b1bbe
--- /dev/null
+++ b/ios/chrome/browser/ui/settings/google_services/resources/google_services_sync_error.imageset/google_services_sync_error@3x.png
Binary files differ
diff --git a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
index 8c53971..46a1962 100644
--- a/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/password/passwords_table_view_controller.mm
@@ -27,9 +27,9 @@
 #include "components/url_formatter/url_formatter.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
 #import "ios/chrome/browser/passwords/save_passwords_consumer.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_cells_constants.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_switch_cell.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_switch_item.h"
diff --git a/ios/chrome/browser/ui/settings/privacy_table_view_controller.mm b/ios/chrome/browser/ui/settings/privacy_table_view_controller.mm
index 2350241..111226f 100644
--- a/ios/chrome/browser/ui/settings/privacy_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/privacy_table_view_controller.mm
@@ -20,8 +20,8 @@
 #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"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/pref_names.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_cells_constants.h"
 #import "ios/chrome/browser/ui/settings/cells/settings_detail_item.h"
diff --git a/ios/chrome/browser/ui/settings/privacy_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/privacy_table_view_controller_unittest.mm
index 84a1ed9..c336976 100644
--- a/ios/chrome/browser/ui/settings/privacy_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/privacy_table_view_controller_unittest.mm
@@ -16,9 +16,9 @@
 #include "components/sync_preferences/pref_service_syncable.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/pref_names.h"
 #include "ios/chrome/browser/prefs/browser_prefs.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/table_view/chrome_table_view_controller_test.h"
 #include "ios/chrome/grit/ios_chromium_strings.h"
 #include "ios/chrome/grit/ios_strings.h"
diff --git a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
index 08d7989..7a8b3f6 100644
--- a/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_table_view_controller.mm
@@ -22,7 +22,6 @@
 #include "components/unified_consent/feature.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/ios_chrome_flag_descriptions.h"
 #include "ios/chrome/browser/passwords/ios_chrome_password_store_factory.h"
 #include "ios/chrome/browser/pref_names.h"
@@ -34,6 +33,7 @@
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
 #import "ios/chrome/browser/sync/sync_observer_bridge.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view_consumer.h"
 #import "ios/chrome/browser/ui/authentication/cells/table_view_account_item.h"
 #import "ios/chrome/browser/ui/authentication/cells/table_view_signin_promo_item.h"
diff --git a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.mm b/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.mm
index d21dbe1..4c135746 100644
--- a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller.mm
@@ -18,7 +18,6 @@
 #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"
-#include "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/signin/authentication_service.h"
 #include "ios/chrome/browser/signin/authentication_service_factory.h"
 #import "ios/chrome/browser/signin/chrome_identity_service_observer_bridge.h"
@@ -26,6 +25,7 @@
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/authentication/authentication_flow.h"
 #import "ios/chrome/browser/ui/authentication/cells/table_view_account_item.h"
 #import "ios/chrome/browser/ui/authentication/resized_avatar_cache.h"
diff --git a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller_unittest.mm
index 0bf49e8..eb53348 100644
--- a/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/sync/sync_settings_table_view_controller_unittest.mm
@@ -19,13 +19,13 @@
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #include "ios/chrome/browser/prefs/browser_prefs.h"
 #include "ios/chrome/browser/sync/ios_chrome_profile_sync_test_util.h"
 #include "ios/chrome/browser/sync/profile_sync_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service.h"
 #include "ios/chrome/browser/sync/sync_setup_service_factory.h"
 #include "ios/chrome/browser/sync/sync_setup_service_mock.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/settings/cells/sync_switch_item.h"
 #import "ios/chrome/browser/ui/settings/sync/utils/sync_util.h"
 #import "ios/chrome/browser/ui/table_view/cells/table_view_image_item.h"
diff --git a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
index 74603e8..258a898 100644
--- a/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
+++ b/ios/chrome/browser/ui/signin_interaction/signin_interaction_controller_egtest.mm
@@ -8,7 +8,7 @@
 #include "base/strings/sys_string_conversions.h"
 #import "base/test/ios/wait_util.h"
 #include "base/test/scoped_feature_list.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/authentication/cells/signin_promo_view.h"
 #import "ios/chrome/browser/ui/authentication/signin_earl_grey_ui.h"
 #import "ios/chrome/browser/ui/authentication/signin_earlgrey_utils.h"
diff --git a/ios/chrome/browser/ui/static_content/static_html_view_controller.h b/ios/chrome/browser/ui/static_content/static_html_view_controller.h
index 8d9c6f91..1aae923 100644
--- a/ios/chrome/browser/ui/static_content/static_html_view_controller.h
+++ b/ios/chrome/browser/ui/static_content/static_html_view_controller.h
@@ -15,7 +15,6 @@
 
 namespace web {
 class BrowserState;
-struct Referrer;
 }
 
 // Callback for the HtmlGenerator protocol.
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm
index 87be67c..8a45471 100644
--- a/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm
+++ b/ios/chrome/browser/ui/tab_grid/tab_grid_mediator.mm
@@ -14,11 +14,11 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/chrome_url_util.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/snapshots/snapshot_cache.h"
 #import "ios/chrome/browser/snapshots/snapshot_cache_factory.h"
 #import "ios/chrome/browser/snapshots/snapshot_cache_observer.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/tabs/tab_title_util.h"
 #import "ios/chrome/browser/ui/tab_grid/grid/grid_consumer.h"
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
index 7434e42..f97ebf8a 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_controller.mm
@@ -19,8 +19,8 @@
 #include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h"
 #import "ios/chrome/browser/drag_and_drop/drop_and_navigate_delegate.h"
 #import "ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/snapshots/snapshot_tab_helper.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/legacy_tab_helper.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
diff --git a/ios/chrome/browser/ui/tabs/tab_strip_egtest.mm b/ios/chrome/browser/ui/tabs/tab_strip_egtest.mm
index 00d94c8..20266db 100644
--- a/ios/chrome/browser/ui/tabs/tab_strip_egtest.mm
+++ b/ios/chrome/browser/ui/tabs/tab_strip_egtest.mm
@@ -5,7 +5,7 @@
 #import <EarlGrey/EarlGrey.h>
 #import <XCTest/XCTest.h>
 
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/tab_title_util.h"
 #import "ios/chrome/browser/ui/tabs/tab_view.h"
 #import "ios/chrome/browser/ui/util/uikit_ui_util.h"
diff --git a/ios/chrome/browser/ui/tabs/tab_view.mm b/ios/chrome/browser/ui/tabs/tab_view.mm
index 3ae798b..99110798 100644
--- a/ios/chrome/browser/ui/tabs/tab_view.mm
+++ b/ios/chrome/browser/ui/tabs/tab_view.mm
@@ -12,7 +12,7 @@
 #include "ios/chrome/browser/drag_and_drop/drag_and_drop_flag.h"
 #include "ios/chrome/browser/drag_and_drop/drop_and_navigate_delegate.h"
 #include "ios/chrome/browser/drag_and_drop/drop_and_navigate_interaction.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/image_util/image_util.h"
 #include "ios/chrome/browser/ui/util/rtl_geometry.h"
diff --git a/ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_keyboard_accessory_view.mm b/ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_keyboard_accessory_view.mm
index e007b79..ddff7b7 100644
--- a/ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_keyboard_accessory_view.mm
+++ b/ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_keyboard_accessory_view.mm
@@ -5,7 +5,7 @@
 #import "ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_keyboard_accessory_view.h"
 
 #include "base/mac/foundation_util.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views.h"
 #import "ios/chrome/browser/ui/toolbar/keyboard_assist/toolbar_assistive_keyboard_views_utils.h"
 #include "ios/chrome/browser/ui/util/rtl_geometry.h"
diff --git a/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.h b/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.h
index dd5344d..a29ef88 100644
--- a/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.h
+++ b/ios/chrome/browser/ui/toolbar/primary_toolbar_coordinator.h
@@ -9,7 +9,6 @@
 #import "ios/chrome/browser/ui/toolbar/public/primary_toolbar_coordinator.h"
 
 @protocol ToolbarCoordinatorDelegate;
-@protocol UrlLoader;
 
 // Coordinator for the primary part, the one containing the omnibox, of the
 // adaptive toolbar.
diff --git a/ios/chrome/browser/ui/util/uikit_ui_util.mm b/ios/chrome/browser/ui/util/uikit_ui_util.mm
index 3b78abc..96d1b1b 100644
--- a/ios/chrome/browser/ui/util/uikit_ui_util.mm
+++ b/ios/chrome/browser/ui/util/uikit_ui_util.mm
@@ -16,7 +16,7 @@
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #include "base/numerics/math_constants.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/browser/ui/ui_feature_flags.h"
 #include "ios/chrome/browser/ui/util/dynamic_type_util.h"
 #include "ios/chrome/browser/ui/util/rtl_geometry.h"
diff --git a/ios/chrome/browser/ui/webui/chrome_web_ui_ios_controller_factory.mm b/ios/chrome/browser/ui/webui/chrome_web_ui_ios_controller_factory.mm
index 9deec54..7bc8aaf 100644
--- a/ios/chrome/browser/ui/webui/chrome_web_ui_ios_controller_factory.mm
+++ b/ios/chrome/browser/ui/webui/chrome_web_ui_ios_controller_factory.mm
@@ -7,7 +7,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #include "ios/chrome/browser/ui/webui/about_ui.h"
 #include "ios/chrome/browser/ui/webui/crashes_ui.h"
 #include "ios/chrome/browser/ui/webui/flags_ui.h"
diff --git a/ios/chrome/browser/ui/webui/web_ui_egtest.mm b/ios/chrome/browser/ui/webui/web_ui_egtest.mm
index 2422bdc..0924539 100644
--- a/ios/chrome/browser/ui/webui/web_ui_egtest.mm
+++ b/ios/chrome/browser/ui/webui/web_ui_egtest.mm
@@ -10,7 +10,7 @@
 #import "base/test/ios/wait_util.h"
 #include "components/version_info/version_info.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.h"
 #include "ios/chrome/test/app/navigation_test_util.h"
 #import "ios/chrome/test/app/web_view_interaction_test_util.h"
diff --git a/ios/chrome/test/app/tab_test_util.mm b/ios/chrome/test/app/tab_test_util.mm
index 7b93790..2b85888 100644
--- a/ios/chrome/test/app/tab_test_util.mm
+++ b/ios/chrome/test/app/tab_test_util.mm
@@ -10,8 +10,8 @@
 #import "base/test/ios/wait_util.h"
 #import "ios/chrome/app/main_controller_private.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/experimental_flags.h"
 #import "ios/chrome/browser/metrics/tab_usage_recorder.h"
+#include "ios/chrome/browser/system_flags.h"
 #import "ios/chrome/browser/tabs/tab.h"
 #import "ios/chrome/browser/tabs/tab_model.h"
 #import "ios/chrome/browser/ui/browser_view_controller.h"
diff --git a/ios/testing/earl_grey/BUILD.gn b/ios/testing/earl_grey/BUILD.gn
index 875b994..86694a5 100644
--- a/ios/testing/earl_grey/BUILD.gn
+++ b/ios/testing/earl_grey/BUILD.gn
@@ -8,6 +8,7 @@
 }
 
 source_set("earl_grey_support") {
+  defines = [ "CHROME_EARL_GREY_1" ]
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
 
@@ -22,13 +23,12 @@
     "matchers.mm",
   ]
 
-  defines = [ "CHROME_EARL_GREY_1" ]
-
   public_configs = [ ":earl_grey_support_config" ]
   configs += [ ":earl_grey_support_config" ]
 }
 
 source_set("eg_app_support+eg2") {
+  defines = [ "CHROME_EARL_GREY_2" ]
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
 
@@ -38,13 +38,19 @@
   ]
 
   sources = [
-    "disabled_test_macros.h",
     "matchers.h",
     "matchers.mm",
   ]
 
-  defines = [ "CHROME_EARL_GREY_2" ]
-
   public_configs = [ ":earl_grey_support_config" ]
   configs += [ ":earl_grey_support_config" ]
 }
+
+source_set("eg_test_support+eg2") {
+  configs += [ "//build/config/compiler:enable_arc" ]
+  testonly = true
+
+  sources = [
+    "disabled_test_macros.h",
+  ]
+}
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 47a7bd7..bbadf5a 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -550,6 +550,7 @@
   sources = [
     "webui/crw_web_ui_manager_unittest.mm",
     "webui/crw_web_ui_page_builder_unittest.mm",
+    "webui/crw_web_ui_scheme_handler_unittest.mm",
     "webui/mojo_facade_unittest.mm",
     "webui/url_fetcher_block_adapter_unittest.mm",
   ]
diff --git a/ios/web/features.mm b/ios/web/features.mm
index 78b2936..87ea3f2 100644
--- a/ios/web/features.mm
+++ b/ios/web/features.mm
@@ -33,5 +33,16 @@
 
 const base::Feature kBlockUniversalLinksInOffTheRecordMode{
     "BlockUniversalLinksInOffTheRecord", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kWebUISchemeHandling{"WebUISchemeHandling",
+                                         base::FEATURE_DISABLED_BY_DEFAULT};
+
+bool WebUISchemeHandlingEnabled() {
+  if (@available(iOS 11, *)) {
+    return base::FeatureList::IsEnabled(web::features::kWebUISchemeHandling);
+  }
+  return false;
+}
+
 }  // namespace features
 }  // namespace web
diff --git a/ios/web/public/features.h b/ios/web/public/features.h
index 1a5ab17..555a3c8 100644
--- a/ios/web/public/features.h
+++ b/ios/web/public/features.h
@@ -40,6 +40,13 @@
 // and the user is browsing in off the record mode.
 extern const base::Feature kBlockUniversalLinksInOffTheRecordMode;
 
+// Used to have the WebUI schemes being handled by the WKWebView directly.
+extern const base::Feature kWebUISchemeHandling;
+
+// Whether the WebUI scheme handling in the WKWebView is enabled and can be
+// used.
+bool WebUISchemeHandlingEnabled();
+
 }  // namespace features
 }  // namespace web
 
diff --git a/ios/web/shell/test/BUILD.gn b/ios/web/shell/test/BUILD.gn
index 71b437e..22beafa 100644
--- a/ios/web/shell/test/BUILD.gn
+++ b/ios/web/shell/test/BUILD.gn
@@ -55,6 +55,7 @@
 }
 
 source_set("earl_grey_test_support") {
+  defines = [ "CHROME_EARL_GREY_1" ]
   testonly = true
 
   deps = [
@@ -96,7 +97,7 @@
 }
 
 bundle_data("bundle") {
-  visibility = [ ":ios_web_shell_egtests" ]
+  visibility = [ ":*" ]
   sources = [
     "http_server_files/basic_navigation_test.html",
     "http_server_files/tall_page.html",
@@ -115,8 +116,26 @@
   testonly = true
 }
 
-group("eg_test_support+eg2") {
+source_set("eg_test_support+eg2") {
+  defines = [ "CHROME_EARL_GREY_2" ]
+  configs += [
+    "//build/config/compiler:enable_arc",
+    "//build/config/ios:xctest_config",
+  ]
   testonly = true
+
+  sources = [
+    "earl_grey/web_shell_test_case.h",
+    "earl_grey/web_shell_test_case.mm",
+  ]
+
+  include_dirs = [ "//ios/third_party/edo/src" ]
+
+  deps = [
+    "//ios/testing/earl_grey:eg_test_support+eg2",
+    "//ios/third_party/earl_grey2:test_lib",
+    "//ios/web/public/test/http_server",
+  ]
 }
 
 source_set("eg_tests+eg2") {
@@ -127,7 +146,7 @@
   testonly = true
 
   sources = [
-    "web_shell_egtest.mm",
+    "web_shell_sample_egtest.mm",
   ]
 
   include_dirs = [ "//ios/third_party/edo/src" ]
@@ -159,4 +178,6 @@
     # Test support libraries.
     ":eg_tests+eg2",
   ]
+
+  bundle_deps = [ ":bundle" ]
 }
diff --git a/ios/web/shell/test/earl_grey/web_shell_test_case.mm b/ios/web/shell/test/earl_grey/web_shell_test_case.mm
index aec1601..bf79531 100644
--- a/ios/web/shell/test/earl_grey/web_shell_test_case.mm
+++ b/ios/web/shell/test/earl_grey/web_shell_test_case.mm
@@ -4,11 +4,16 @@
 
 #import "ios/web/shell/test/earl_grey/web_shell_test_case.h"
 
-#import <EarlGrey/EarlGrey.h>
-
 #import "ios/web/public/test/http_server/http_server.h"
-#import "ios/web/shell/test/earl_grey/shell_matchers.h"
-#include "testing/coverage_util_ios.h"
+
+#if defined(CHROME_EARL_GREY_1)
+#import <EarlGrey/EarlGrey.h>           // nogncheck
+#include "testing/coverage_util_ios.h"  // nogncheck
+#endif
+
+#if defined(CHROME_EARL_GREY_2)
+#import "ios/third_party/earl_grey2/src/TestLib/EarlGreyImpl/EarlGrey.h"  // nogncheck
+#endif
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -18,6 +23,7 @@
 
 @implementation WebShellTestCase
 
+#if defined(CHROME_EARL_GREY_1)
 // Overrides |testInvocations| to skip all tests if a system alert view is
 // shown, since this isn't a case a user would encounter (i.e. they would
 // dismiss the alert first).
@@ -35,13 +41,16 @@
   }
   return [super testInvocations];
 }
+#endif
 
 // Set up called once for the class.
 + (void)setUp {
   [super setUp];
   HttpServer::GetSharedInstance().StartOrDie();
 
+#if defined(CHROME_EARL_GREY_1)
   coverage_util::ConfigureCoverageReportPath();
+#endif
 }
 
 // Tear down called once for the class.
diff --git a/ios/web/shell/test/web_shell_egtest.mm b/ios/web/shell/test/web_shell_sample_egtest.mm
similarity index 65%
rename from ios/web/shell/test/web_shell_egtest.mm
rename to ios/web/shell/test/web_shell_sample_egtest.mm
index 6b29000..b0cbdac 100644
--- a/ios/web/shell/test/web_shell_egtest.mm
+++ b/ios/web/shell/test/web_shell_sample_egtest.mm
@@ -6,25 +6,28 @@
 #import <XCTest/XCTest.h>
 
 #import "ios/third_party/earl_grey2/src/TestLib/EarlGreyImpl/EarlGrey.h"
+#import "ios/web/shell/test/earl_grey/web_shell_test_case.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
 #endif
 
-// WebShellTestCase will temporarily hold EG2 versions of web shell tests, until
-// the EG2 tests are running on the bots and the EG1 versions can be deleted.
-@interface WebShellTestCase : XCTestCase
+// WebShellSampleTestCase will temporarily hold EG2 versions of web shell tests,
+// until the EG2 tests are running on the bots and the EG1 versions can be
+// deleted.
+@interface WebShellSampleTestCase : WebShellTestCase
 @end
 
-@implementation WebShellTestCase
+@implementation WebShellSampleTestCase
 
 - (void)setUp {
-  [super setUp];
   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
     XCUIApplication* application = [[XCUIApplication alloc] init];
     [application launch];
   });
+
+  [super setUp];
 }
 
 @end
diff --git a/ios/web/web_state/ui/BUILD.gn b/ios/web/web_state/ui/BUILD.gn
index f2ea56e..8cf2503 100644
--- a/ios/web/web_state/ui/BUILD.gn
+++ b/ios/web/web_state/ui/BUILD.gn
@@ -131,6 +131,7 @@
     "//ios/web/public",
     "//ios/web/web_state/js",
     "//ios/web/web_state/js:script_util",
+    "//ios/web/webui",
   ]
 
   sources = [
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index 7b9af50..d4d1485 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -2066,7 +2066,8 @@
     [self loadCurrentURLInNativeViewWithRendererInitiatedNavigation:
               rendererInitiated];
   } else if (web::GetWebClient()->IsSlimNavigationManagerEnabled() &&
-             isCurrentURLAppSpecific && _webStateImpl->HasWebUI()) {
+             isCurrentURLAppSpecific && _webStateImpl->HasWebUI() &&
+             !web::features::WebUISchemeHandlingEnabled()) {
     [self loadPlaceholderInWebViewForURL:currentURL
                        rendererInitiated:rendererInitiated
                               forContext:nullptr];
@@ -3356,7 +3357,7 @@
   // |HasWebUI| will return false.
   _webStateImpl->CreateWebUI(URL);
   bool isWebUIURL = _webStateImpl->HasWebUI();
-  if (isWebUIURL) {
+  if (isWebUIURL && !web::features::WebUISchemeHandlingEnabled()) {
     _webUIManager = [[CRWWebUIManager alloc] initWithWebState:_webStateImpl];
   }
 }
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider.h b/ios/web/web_state/ui/wk_web_view_configuration_provider.h
index 664acc9..82a8eb1 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider.h
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/supports_user_data.h"
 
+@class CRWWebUISchemeHandler;
 @class CRWWKScriptMessageRouter;
 @class WKWebViewConfiguration;
 
@@ -50,6 +51,7 @@
   explicit WKWebViewConfigurationProvider(BrowserState* browser_state);
   WKWebViewConfigurationProvider() = delete;
 
+  CRWWebUISchemeHandler* scheme_handler_ = nil;
   WKWebViewConfiguration* configuration_;
   CRWWKScriptMessageRouter* router_;
   BrowserState* browser_state_;
diff --git a/ios/web/web_state/ui/wk_web_view_configuration_provider.mm b/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
index 9661502..3fa8e65 100644
--- a/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
+++ b/ios/web/web_state/ui/wk_web_view_configuration_provider.mm
@@ -7,12 +7,16 @@
 #import <Foundation/Foundation.h>
 #import <WebKit/WebKit.h>
 
+#include "base/ios/ios_util.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
+#include "base/strings/sys_string_conversions.h"
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/features.h"
+#include "ios/web/public/web_client.h"
 #import "ios/web/web_state/js/page_script_util.h"
 #import "ios/web/web_state/ui/crw_wk_script_message_router.h"
+#import "ios/web/webui/crw_web_ui_scheme_handler.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -21,6 +25,7 @@
 namespace web {
 
 namespace {
+
 // A key used to associate a WKWebViewConfigurationProvider with a BrowserState.
 const char kWKWebViewConfigProviderKeyName[] = "wk_web_view_config_provider";
 
@@ -105,7 +110,26 @@
                           browser_state_)];
     [[configuration_ userContentController]
         addUserScript:InternalGetDocumentEndScriptForAllFrames(browser_state_)];
+
+    if (@available(iOS 11, *)) {
+      if (features::WebUISchemeHandlingEnabled()) {
+        if (!scheme_handler_) {
+          scoped_refptr<network::SharedURLLoaderFactory> shared_loader_factory =
+              browser_state_->GetSharedURLLoaderFactory();
+          scheme_handler_ = [[CRWWebUISchemeHandler alloc]
+              initWithURLLoaderFactory:shared_loader_factory];
+        }
+        WebClient::Schemes schemes;
+        GetWebClient()->AddAdditionalSchemes(&schemes);
+        GetWebClient()->GetAdditionalWebUISchemes(&(schemes.standard_schemes));
+        for (std::string scheme : schemes.standard_schemes) {
+          [configuration_ setURLSchemeHandler:scheme_handler_
+                                 forURLScheme:base::SysUTF8ToNSString(scheme)];
+        }
+      }
+    }
   }
+
   // This is a shallow copy to prevent callers from changing the internals of
   // configuration.
   return [configuration_ copy];
diff --git a/ios/web/webui/BUILD.gn b/ios/web/webui/BUILD.gn
index b7e0602..9947ca2 100644
--- a/ios/web/webui/BUILD.gn
+++ b/ios/web/webui/BUILD.gn
@@ -23,6 +23,8 @@
     "crw_web_ui_manager.mm",
     "crw_web_ui_page_builder.h",
     "crw_web_ui_page_builder.mm",
+    "crw_web_ui_scheme_handler.h",
+    "crw_web_ui_scheme_handler.mm",
     "mojo_facade.h",
     "mojo_facade.mm",
     "shared_resources_data_source_ios.h",
diff --git a/ios/web/webui/crw_web_ui_scheme_handler.h b/ios/web/webui/crw_web_ui_scheme_handler.h
new file mode 100644
index 0000000..09a7bad
--- /dev/null
+++ b/ios/web/webui/crw_web_ui_scheme_handler.h
@@ -0,0 +1,27 @@
+// 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 IOS_WEB_WEBUI_CRW_WEB_UI_SCHEME_HANDLER_H_
+#define IOS_WEB_WEBUI_CRW_WEB_UI_SCHEME_HANDLER_H_
+
+#import <WebKit/WebKit.h>
+
+#include "base/memory/scoped_refptr.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+
+// This class allows the handle the pages associated with a WebUI URL, using the
+// custom scheme handling of the WKWebView.
+API_AVAILABLE(ios(11.0))
+@interface CRWWebUISchemeHandler : NSObject <WKURLSchemeHandler>
+
+// Initializes the handler with the |URLLoaderFactory| used to load the URLs.
+- (instancetype)initWithURLLoaderFactory:
+    (scoped_refptr<network::SharedURLLoaderFactory>)URLLoaderFactory
+    NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+#endif  // IOS_WEB_WEBUI_CRW_WEB_UI_SCHEME_HANDLER_H_
diff --git a/ios/web/webui/crw_web_ui_scheme_handler.mm b/ios/web/webui/crw_web_ui_scheme_handler.mm
new file mode 100644
index 0000000..0fae559
--- /dev/null
+++ b/ios/web/webui/crw_web_ui_scheme_handler.mm
@@ -0,0 +1,90 @@
+// 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.
+
+#import "ios/web/webui/crw_web_ui_scheme_handler.h"
+
+#include <map>
+
+#import "ios/web/webui/url_fetcher_block_adapter.h"
+#import "net/base/mac/url_conversions.h"
+#include "url/gurl.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation CRWWebUISchemeHandler {
+  scoped_refptr<network::SharedURLLoaderFactory> _URLLoaderFactory;
+
+  // Set of live WebUI fetchers for retrieving data.
+  API_AVAILABLE(ios(11.0))
+  std::map<id<WKURLSchemeTask>, std::unique_ptr<web::URLFetcherBlockAdapter>>
+      _map;
+}
+
+- (instancetype)initWithURLLoaderFactory:
+    (scoped_refptr<network::SharedURLLoaderFactory>)URLLoaderFactory {
+  self = [super init];
+  if (self) {
+    _URLLoaderFactory = URLLoaderFactory;
+  }
+  return self;
+}
+
+- (void)webView:(WKWebView*)webView
+    startURLSchemeTask:(id<WKURLSchemeTask>)urlSchemeTask
+    API_AVAILABLE(ios(11.0)) {
+  GURL URL = net::GURLWithNSURL(urlSchemeTask.request.URL);
+  __weak CRWWebUISchemeHandler* weakSelf = self;
+  std::unique_ptr<web::URLFetcherBlockAdapter> adapter =
+      std::make_unique<web::URLFetcherBlockAdapter>(
+          URL, _URLLoaderFactory,
+          ^(NSData* data, web::URLFetcherBlockAdapter* fetcher) {
+            CRWWebUISchemeHandler* strongSelf = weakSelf;
+            if (!strongSelf ||
+                strongSelf.map->find(urlSchemeTask) == strongSelf.map->end()) {
+              return;
+            }
+            NSURLResponse* response =
+                [[NSURLResponse alloc] initWithURL:urlSchemeTask.request.URL
+                                          MIMEType:@"text/html"
+                             expectedContentLength:0
+                                  textEncodingName:nil];
+            [urlSchemeTask didReceiveResponse:response];
+            [urlSchemeTask didReceiveData:data];
+            [urlSchemeTask didFinish];
+            [weakSelf removeFetcher:fetcher];
+          });
+  _map.insert(std::make_pair(urlSchemeTask, std::move(adapter)));
+  _map.find(urlSchemeTask)->second->Start();
+}
+
+- (void)webView:(WKWebView*)webView
+    stopURLSchemeTask:(id<WKURLSchemeTask>)urlSchemeTask
+    API_AVAILABLE(ios(11.0)) {
+  auto result = _map.find(urlSchemeTask);
+  if (result != _map.end()) {
+    _map.erase(result);
+  }
+}
+
+#pragma mark - Private
+
+// Returns a pointer to the |_map| ivar for strongSelf.
+- (std::map<id<WKURLSchemeTask>, std::unique_ptr<web::URLFetcherBlockAdapter>>*)
+    map API_AVAILABLE(ios(11.0)) {
+  return &_map;
+}
+
+// Removes |fetcher| from map of active fetchers.
+- (void)removeFetcher:(web::URLFetcherBlockAdapter*)fetcher
+    API_AVAILABLE(ios(11.0)) {
+  _map.erase(std::find_if(
+      _map.begin(), _map.end(),
+      [fetcher](const std::pair<const id<WKURLSchemeTask>,
+                                std::unique_ptr<web::URLFetcherBlockAdapter>>&
+                    entry) { return entry.second.get() == fetcher; }));
+}
+
+@end
diff --git a/ios/web/