diff --git a/DEPS b/DEPS
index a1978bc..6b9624e 100644
--- a/DEPS
+++ b/DEPS
@@ -200,11 +200,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '95b5fb9213d745aa8dd435044ca771554f2a3794',
+  'skia_revision': '65fb101861aba547ebc04b39a6147aa3982d4e5f',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'db1a5e72db56e0241356c2b824f50770d62dec90',
+  'v8_revision': '4ff956a829fefd66af0deeb9bb091fda4389fa21',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -212,11 +212,11 @@
   # 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': 'abcabb474bf1c25eea48d7dca14bcafde737eba7',
+  'angle_revision': 'c2a74cbb8ee1b1076c6e28f6aae2e8f8de283f28',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
-  'swiftshader_revision': '88e698a4f3e35f509ac80d9ffed8a4e0bbe3a85a',
+  'swiftshader_revision': '43bb60e1fa119d80b449c6550dd2b72328b101b9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
@@ -323,7 +323,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.
-  'shaderc_revision': '46ea32f58c63aabc794ba69c219d0d920212b620',
+  'shaderc_revision': '6216d098d8abe3ccda8781016c4f69372c48afb9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -563,7 +563,7 @@
   },
 
   'src/ios/third_party/material_components_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'a539853e3ca9603dfc10f9e6680114970a295879',
+      'url': Var('chromium_git') + '/external/github.com/material-components/material-components-ios.git' + '@' + 'a4d2f5ac0acfe1af18eefc7df9349c1547f1b4ce',
       'condition': 'checkout_ios',
   },
 
@@ -747,7 +747,7 @@
       'packages': [
           {
                'package': 'chromium/third_party/android_tools_bundletool',
-               'version': 'FIj7ed-law2zMv41QhjEXabkaJ7aN2ztmE0Tv3Z_gFUC',
+               'version': 'gB66fGCdzqmQO6U6hxhoZDCGjOg-oqxhT_4uywaUw1oC',
           },
       ],
       'condition': 'checkout_android',
@@ -1274,7 +1274,7 @@
     Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + '3dd5b80bc4f172dd82925bb259cb7c82348409c5',
 
   'src/third_party/openscreen/src':
-    Var('chromium_git') + '/openscreen' + '@' + 'a63f1abf172a55dde56701209770e1deb3fc52b1',
+    Var('chromium_git') + '/openscreen' + '@' + 'b5ac6d34a14cc938258a938ebe3604a93776f7fa',
 
   'src/third_party/openxr/src': {
     'url': Var('chromium_git') + '/external/github.com/KhronosGroup/OpenXR-SDK' + '@' + '97cfe495bb7a3853266b646d1c79e169387f9c7a',
@@ -1369,7 +1369,7 @@
       'packages': [
           {
               'package': 'fuchsia/third_party/aemu/linux-amd64',
-              'version': '5OY8JrY59_SN8JDYYSYG1f0O_RxD33PtPWz_jpCPEkEC'
+              'version': 'qDJOg4W2RuPZ92H6d33I9kLLWjqfYuMr_gFsPRodSQAC'
           },
       ],
       'condition': 'host_os == "linux" and checkout_fuchsia',
@@ -1538,7 +1538,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '1a111c2adcb4898655aacaca018d6e275172760b',
 
   'src/third_party/webgpu-cts/src':
-    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + '7518ac184c13bc1d7d68309d03234c834682428e',
+    Var('chromium_git') + '/external/github.com/gpuweb/cts.git' + '@' + 'a8196844ac6228fea3560b82d29e01fed2fbf13a',
 
   'src/third_party/blink/web_tests/wpt_internal/webgpu/third_party/glslang_js': {
     'packages': [
@@ -1623,7 +1623,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@047f4d3302282c0c9b2ecaf3acbd697c97457e17',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@60b0ce5c4a445cc2fa83866f55671e8ca4ba70ce',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/state_serializer.cc b/android_webview/browser/state_serializer.cc
index a2445d42..f776e9e 100644
--- a/android_webview/browser/state_serializer.cc
+++ b/android_webview/browser/state_serializer.cc
@@ -99,8 +99,7 @@
 
   // |web_contents| takes ownership of these entries after this call.
   content::NavigationController& controller = web_contents->GetController();
-  controller.Restore(selected_entry,
-                     content::RestoreType::LAST_SESSION_EXITED_CLEANLY,
+  controller.Restore(selected_entry, content::RestoreType::LAST_SESSION,
                      &entries);
   DCHECK_EQ(0u, entries.size());
   controller.LoadIfNecessary();
diff --git a/ash/accessibility/accessibility_controller_impl.cc b/ash/accessibility/accessibility_controller_impl.cc
index d0d8fcf9..4496afe 100644
--- a/ash/accessibility/accessibility_controller_impl.cc
+++ b/ash/accessibility/accessibility_controller_impl.cc
@@ -1847,6 +1847,10 @@
       suspend);
 }
 
+void AccessibilityControllerImpl::EnableChromeVoxVolumeSlideGesture() {
+  enable_chromevox_volume_slide_gesture_ = true;
+}
+
 void AccessibilityControllerImpl::UpdateFeatureFromPref(FeatureType feature) {
   bool enabled = features_[feature]->enabled();
 
diff --git a/ash/accessibility/accessibility_controller_impl.h b/ash/accessibility/accessibility_controller_impl.h
index 4998aee..51d4643a 100644
--- a/ash/accessibility/accessibility_controller_impl.h
+++ b/ash/accessibility/accessibility_controller_impl.h
@@ -372,6 +372,7 @@
       const std::string& path) override;
   void DisablePolicyRecommendationRestorerForTesting() override;
   void SuspendSwitchAccessKeyHandling(bool suspend) override;
+  void EnableChromeVoxVolumeSlideGesture() override;
 
   // SessionObserver:
   void OnSigninScreenPrefServiceInitialized(PrefService* prefs) override;
@@ -388,6 +389,10 @@
     return select_to_speak_bubble_controller_.get();
   }
 
+  bool enable_chromevox_volume_slide_gesture() {
+    return enable_chromevox_volume_slide_gesture_;
+  }
+
  private:
   // Populate |features_| with the feature of the correct type.
   void CreateAccessibilityFeatures();
@@ -478,11 +483,15 @@
   // Used to force the backlights off to darken the screen.
   std::unique_ptr<ScopedBacklightsForcedOff> scoped_backlights_forced_off_;
 
+  // True if ChromeVox should enable its volume slide gesture.
+  bool enable_chromevox_volume_slide_gesture_ = true;
+
   base::ObserverList<AccessibilityObserver> observers_;
 
   // The pref service of the currently active user or the signin profile before
   // user logs in. Can be null in ash_unittests.
   PrefService* active_user_prefs_ = nullptr;
+
   // This has to be the first one to be destroyed so we don't get updates about
   // any prefs during destruction.
   std::unique_ptr<PrefChangeRegistrar> pref_change_registrar_;
diff --git a/ash/accessibility/touch_exploration_controller.cc b/ash/accessibility/touch_exploration_controller.cc
index 187cf64..e00f5d3 100644
--- a/ash/accessibility/touch_exploration_controller.cc
+++ b/ash/accessibility/touch_exploration_controller.cc
@@ -8,9 +8,12 @@
 #include <string>
 #include <utility>
 
+#include "ash/accessibility/accessibility_controller_impl.h"
 #include "ash/accessibility/touch_accessibility_enabler.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/shell.h"
 #include "ash/wm/container_finder.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
@@ -323,8 +326,7 @@
               << gesture_detector_config_.minimum_swipe_velocity;
     }
     // Change to slide gesture if the slide occurred at the right edge.
-    int edge = FindEdgesWithinInset(event.location(), kMaxDistanceFromEdge);
-    if (edge & RIGHT_EDGE && edge != BOTTOM_RIGHT_CORNER) {
+    if (ShouldEnableVolumeSlideGesture(event)) {
       SET_STATE(SLIDE_GESTURE);
       return InSlideGesture(event, continuation);
     }
@@ -1212,4 +1214,16 @@
   return container->id() == kShellWindowId_ArcVirtualKeyboardContainer;
 }
 
+bool TouchExplorationController::ShouldEnableVolumeSlideGesture(
+    const ui::TouchEvent& event) {
+  // Can be nullptr in unit tests.
+  int edge = FindEdgesWithinInset(event.location(), kMaxDistanceFromEdge);
+  return edge & RIGHT_EDGE && edge != BOTTOM_RIGHT_CORNER &&
+         (!Shell::HasInstance() ||
+          Shell::Get()->tablet_mode_controller()->InTabletMode() ||
+          Shell::Get()
+              ->accessibility_controller()
+              ->enable_chromevox_volume_slide_gesture());
+}
+
 }  // namespace ash
diff --git a/ash/accessibility/touch_exploration_controller.h b/ash/accessibility/touch_exploration_controller.h
index ff753d0..e2f4fba5 100644
--- a/ash/accessibility/touch_exploration_controller.h
+++ b/ash/accessibility/touch_exploration_controller.h
@@ -329,6 +329,9 @@
   // Returns true if the touch event is targeted to Arc virtual keyboard.
   bool IsTargetedToArcVirtualKeyboard(const gfx::Point& location_in_host);
 
+  // Whether the right side of the screen should serve as a volume control.
+  bool ShouldEnableVolumeSlideGesture(const ui::TouchEvent& event);
+
   enum State {
     // No fingers are down and no events are pending.
     NO_FINGERS_DOWN,
diff --git a/ash/app_list/model/app_list_item.h b/ash/app_list/model/app_list_item.h
index a65c958..acc9aeb 100644
--- a/ash/app_list/model/app_list_item.h
+++ b/ash/app_list/model/app_list_item.h
@@ -14,6 +14,7 @@
 
 #include "ash/app_list/model/app_list_model_export.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
+#include "ash/public/cpp/shelf_types.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "components/sync/model/string_ordinal.h"
@@ -90,6 +91,12 @@
     UpdateNotificationBadge(has_badge);
   }
 
+  AppStatus app_status() const { return metadata_->app_status; }
+
+  void UpdateAppStatusForTesting(AppStatus app_status) {
+    metadata_->app_status = app_status;
+  }
+
  protected:
   // Subclasses also have mutable access to the metadata ptr.
   AppListItemMetadata* metadata() { return metadata_.get(); }
diff --git a/ash/app_list/views/app_list_item_view.cc b/ash/app_list/views/app_list_item_view.cc
index 6b9319f..0476922 100644
--- a/ash/app_list/views/app_list_item_view.cc
+++ b/ash/app_list/views/app_list_item_view.cc
@@ -18,6 +18,7 @@
 #include "ash/public/cpp/app_list/app_list_config.h"
 #include "ash/public/cpp/app_list/app_list_switches.h"
 #include "ash/public/cpp/app_list/app_list_types.h"
+#include "ash/strings/grit/ash_strings.h"
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
@@ -577,6 +578,30 @@
   Layout();
 }
 
+void AppListItemView::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+  if (!item_weak_)
+    return;
+
+  DCHECK(node_data);
+  Button::GetAccessibleNodeData(node_data);
+
+  auto app_status = item_weak_->app_status();
+  switch (app_status) {
+    case AppStatus::kBlocked:
+      node_data->SetDescription(
+          ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
+              IDS_APP_LIST_BLOCKED_APP));
+      break;
+    case AppStatus::kPaused:
+      node_data->SetDescription(
+          ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
+              IDS_APP_LIST_PAUSED_APP));
+      break;
+    default:
+      break;
+  }
+}
+
 void AppListItemView::OnContextMenuModelReceived(
     const gfx::Point& point,
     ui::MenuSourceType source_type,
diff --git a/ash/app_list/views/app_list_item_view.h b/ash/app_list/views/app_list_item_view.h
index d142a83..663f6ee 100644
--- a/ash/app_list/views/app_list_item_view.h
+++ b/ash/app_list/views/app_list_item_view.h
@@ -60,6 +60,8 @@
   void SetItemName(const base::string16& display_name,
                    const base::string16& full_name);
 
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
+
   void CancelContextMenu();
 
   void OnDragEnded();
diff --git a/ash/ash_strings.grd b/ash/ash_strings.grd
index ea83bb3..720920a 100644
--- a/ash/ash_strings.grd
+++ b/ash/ash_strings.grd
@@ -3195,10 +3195,16 @@
         Search
       </message>
 
-      <message name="IDS_SHELF_ITEM_HAS_BLOCK_BADGE" desc="Accessibility announcement notifying users that the currently focused shelf app is blocked.">
+      <message name="IDS_APP_LIST_BLOCKED_APP" desc="The spoken feedback text when a focused app is blocked.">
         Blocked
       </message>
-      <message name="IDS_SHELF_ITEM_HAS_PAUSE_BADGE" desc="Accessibility announcement notifying users that the currently focused shelf app is paused.">
+      <message name="IDS_APP_LIST_PAUSED_APP" desc="The spoken feedback text when a focused app is paused.">
+        Paused
+      </message>
+      <message name="IDS_SHELF_ITEM_BLOCKED_APP" desc="Accessibility announcement notifying users that the currently focused shelf app is blocked.">
+        Blocked
+      </message>
+      <message name="IDS_SHELF_ITEM_PAUSED_APP" desc="Accessibility announcement notifying users that the currently focused shelf app is paused.">
         Paused
       </message>
       <message name="IDS_APP_ACCESSIBILITY_BLOCKED_INSTALLED_APP_ANNOUNCEMENT" desc="Accessibility text to specify a search result is a blocked installed app.">
diff --git a/ash/ash_strings_grd/IDS_APP_LIST_BLOCKED_APP.png.sha1 b/ash/ash_strings_grd/IDS_APP_LIST_BLOCKED_APP.png.sha1
new file mode 100644
index 0000000..8322487
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_APP_LIST_BLOCKED_APP.png.sha1
@@ -0,0 +1 @@
+d81f468bc91e75d841d791b51a3f0ac12799d019
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_APP_LIST_PAUSED_APP.png.sha1 b/ash/ash_strings_grd/IDS_APP_LIST_PAUSED_APP.png.sha1
new file mode 100644
index 0000000..3e5f9770
--- /dev/null
+++ b/ash/ash_strings_grd/IDS_APP_LIST_PAUSED_APP.png.sha1
@@ -0,0 +1 @@
+8634443aef2b53a8fb50b6cdeaed58339989bdea
\ No newline at end of file
diff --git a/ash/ash_strings_grd/IDS_SHELF_ITEM_HAS_BLOCK_BADGE.png.sha1 b/ash/ash_strings_grd/IDS_SHELF_ITEM_BLOCKED_APP.png.sha1
similarity index 100%
rename from ash/ash_strings_grd/IDS_SHELF_ITEM_HAS_BLOCK_BADGE.png.sha1
rename to ash/ash_strings_grd/IDS_SHELF_ITEM_BLOCKED_APP.png.sha1
diff --git a/ash/ash_strings_grd/IDS_SHELF_ITEM_HAS_PAUSE_BADGE.png.sha1 b/ash/ash_strings_grd/IDS_SHELF_ITEM_PAUSED_APP.png.sha1
similarity index 100%
rename from ash/ash_strings_grd/IDS_SHELF_ITEM_HAS_PAUSE_BADGE.png.sha1
rename to ash/ash_strings_grd/IDS_SHELF_ITEM_PAUSED_APP.png.sha1
diff --git a/ash/public/cpp/accessibility_controller.h b/ash/public/cpp/accessibility_controller.h
index 2a1a987..c9ebcc66 100644
--- a/ash/public/cpp/accessibility_controller.h
+++ b/ash/public/cpp/accessibility_controller.h
@@ -138,6 +138,9 @@
   // Suspends (or resumes) key handling for Switch Access.
   virtual void SuspendSwitchAccessKeyHandling(bool suspend) {}
 
+  // Enables ChromeVox's volume slide gesture.
+  virtual void EnableChromeVoxVolumeSlideGesture() {}
+
  protected:
   AccessibilityController();
   virtual ~AccessibilityController();
diff --git a/ash/public/cpp/app_list/app_list_types.h b/ash/public/cpp/app_list/app_list_types.h
index 50acd00..f98dbb7 100644
--- a/ash/public/cpp/app_list/app_list_types.h
+++ b/ash/public/cpp/app_list/app_list_types.h
@@ -10,6 +10,7 @@
 
 #include "ash/public/cpp/app_list/app_list_metrics.h"
 #include "ash/public/cpp/ash_public_export.h"
+#include "ash/public/cpp/shelf_types.h"
 #include "base/optional.h"
 #include "base/strings/string16.h"
 #include "components/sync/model/string_ordinal.h"
@@ -64,6 +65,9 @@
   std::string name;        // Corresponding app/folder's name of the item.
   std::string short_name;  // Corresponding app's short name of the item. Empty
                            // if the app doesn't have one or it's a folder.
+
+  AppStatus app_status = AppStatus::kReady;  // App status.
+
   std::string folder_id;   // Id of folder where the item resides.
   syncer::StringOrdinal position;  // Position of the item.
   bool is_folder = false;          // Whether this item is a folder.
diff --git a/ash/public/cpp/ash_features.cc b/ash/public/cpp/ash_features.cc
index d18d866..1e449be4 100644
--- a/ash/public/cpp/ash_features.cc
+++ b/ash/public/cpp/ash_features.cc
@@ -45,7 +45,7 @@
     "DragToSnapInClamshellMode", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kEnhancedDeskAnimations{"EnhancedDeskAnimations",
-                                            base::FEATURE_DISABLED_BY_DEFAULT};
+                                            base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kFullRestore{"FullRestore",
                                  base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/ash/services/recording/recording_service.cc b/ash/services/recording/recording_service.cc
index e92da981..d7b96dc 100644
--- a/ash/services/recording/recording_service.cc
+++ b/ash/services/recording/recording_service.cc
@@ -255,8 +255,7 @@
   media::VideoEncoder::Options video_encoder_options;
   video_encoder_options.bitrate = CalculateVpxEncoderBitrate(capture_size);
   video_encoder_options.framerate = kMaxFrameRate;
-  video_encoder_options.width = capture_size.width();
-  video_encoder_options.height = capture_size.height();
+  video_encoder_options.frame_size = capture_size;
   // This value, expressed as a number of frames, forces the encoder to code
   // a keyframe if one has not been coded in the last keyframe_interval frames.
   video_encoder_options.keyframe_interval = 100;
diff --git a/ash/shelf/shelf_app_button.cc b/ash/shelf/shelf_app_button.cc
index b24e2af..c0b045e 100644
--- a/ash/shelf/shelf_app_button.cc
+++ b/ash/shelf/shelf_app_button.cc
@@ -551,12 +551,12 @@
     case AppStatus::kBlocked:
       node_data->SetDescription(
           ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
-              IDS_SHELF_ITEM_HAS_BLOCK_BADGE));
+              IDS_SHELF_ITEM_BLOCKED_APP));
       break;
     case AppStatus::kPaused:
       node_data->SetDescription(
           ui::ResourceBundle::GetSharedInstance().GetLocalizedString(
-              IDS_SHELF_ITEM_HAS_PAUSE_BADGE));
+              IDS_SHELF_ITEM_PAUSED_APP));
       break;
     default:
       break;
diff --git a/ash/wm/desks/desk_animation_base.cc b/ash/wm/desks/desk_animation_base.cc
index b0ba911..f99eb82 100644
--- a/ash/wm/desks/desk_animation_base.cc
+++ b/ash/wm/desks/desk_animation_base.cc
@@ -33,7 +33,10 @@
   for (auto& observer : controller_->observers_)
     observer.OnDeskSwitchAnimationLaunching();
 
-  throughput_tracker_.Start(GetReportCallback());
+  // The throughput tracker measures the animation when the user lifts their
+  // fingers off the trackpad, which is done in EndSwipeAnimation.
+  if (!is_continuous_gesture_animation_)
+    throughput_tracker_.Start(GetReportCallback());
 
   // This step makes sure that the containers of the target desk are shown at
   // the beginning of the animation (but not actually visible to the user yet,
diff --git a/ash/wm/desks/desk_animation_impl.cc b/ash/wm/desks/desk_animation_impl.cc
index dc02657..75d82655a 100644
--- a/ash/wm/desks/desk_animation_impl.cc
+++ b/ash/wm/desks/desk_animation_impl.cc
@@ -83,6 +83,11 @@
   if (source != switch_source_)
     return false;
 
+  // Do not log any EndSwipeAnimation smoothness metrics if the animation has
+  // been canceled midway by an Replace call.
+  if (is_continuous_gesture_animation_)
+    throughput_tracker_.Cancel();
+
   // If any of the animators are still taking either screenshot, do not replace
   // the animation.
   for (const auto& animator : desk_switch_animators_) {
@@ -135,10 +140,6 @@
   if (!is_continuous_gesture_animation_)
     return false;
 
-  // Do not log any EndSwipeAnimation smoothness metrics if the animation has
-  // been canceled midway by an UpdateSwipeAnimation call.
-  throughput_tracker_.Cancel();
-
   presentation_time_recorder_->RequestNext();
 
   // List of animators that need a screenshot. It should be either empty or
diff --git a/ash/wm/desks/root_window_desk_switch_animator.cc b/ash/wm/desks/root_window_desk_switch_animator.cc
index 74dc82c..10083d7 100644
--- a/ash/wm/desks/root_window_desk_switch_animator.cc
+++ b/ash/wm/desks/root_window_desk_switch_animator.cc
@@ -459,6 +459,11 @@
 
   ending_desk_screenshot_taken_ = true;
   OnScreenshotLayerCreated();
+
+  // On ending screenshot may delete |this|.
+  if (on_ending_screenshot_taken_callback_for_testing_)
+    std::move(on_ending_screenshot_taken_callback_for_testing_).Run();
+
   delegate_->OnEndingDeskScreenshotTaken();
 }
 
diff --git a/ash/wm/desks/root_window_desk_switch_animator.h b/ash/wm/desks/root_window_desk_switch_animator.h
index 45b574f1..9bb431ba 100644
--- a/ash/wm/desks/root_window_desk_switch_animator.h
+++ b/ash/wm/desks/root_window_desk_switch_animator.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "ash/ash_export.h"
+#include "base/callback.h"
 #include "base/memory/weak_ptr.h"
 #include "ui/compositor/layer_animation_observer.h"
 
@@ -376,6 +377,10 @@
   // cases we do not want to notify our delegate that the animation is finished.
   bool setting_new_transform_ = false;
 
+  // Callback that is run after the ending screenshot is taken for testing
+  // purposes.
+  base::OnceClosure on_ending_screenshot_taken_callback_for_testing_;
+
   base::WeakPtrFactory<RootWindowDeskSwitchAnimator> weak_ptr_factory_{this};
 };
 
diff --git a/ash/wm/desks/root_window_desk_switch_animator_test_api.cc b/ash/wm/desks/root_window_desk_switch_animator_test_api.cc
index f93cb65..0ed4be83 100644
--- a/ash/wm/desks/root_window_desk_switch_animator_test_api.cc
+++ b/ash/wm/desks/root_window_desk_switch_animator_test_api.cc
@@ -40,4 +40,10 @@
   return animator_->ending_desk_index_;
 }
 
+void RootWindowDeskSwitchAnimatorTestApi::SetOnEndingScreenshotTakenCallback(
+    base::OnceClosure callback) {
+  animator_->on_ending_screenshot_taken_callback_for_testing_ =
+      std::move(callback);
+}
+
 }  // namespace ash
diff --git a/ash/wm/desks/root_window_desk_switch_animator_test_api.h b/ash/wm/desks/root_window_desk_switch_animator_test_api.h
index ad1cf76..8221151 100644
--- a/ash/wm/desks/root_window_desk_switch_animator_test_api.h
+++ b/ash/wm/desks/root_window_desk_switch_animator_test_api.h
@@ -5,6 +5,8 @@
 #ifndef ASH_WM_DESKS_ROOT_WINDOW_DESK_SWITCH_ANIMATOR_TEST_API_H_
 #define ASH_WM_DESKS_ROOT_WINDOW_DESK_SWITCH_ANIMATOR_TEST_API_H_
 
+#include "base/callback.h"
+
 namespace ui {
 class Layer;
 }
@@ -31,6 +33,8 @@
 
   int GetEndingDeskIndex() const;
 
+  void SetOnEndingScreenshotTakenCallback(base::OnceClosure callback);
+
  private:
   RootWindowDeskSwitchAnimator* const animator_;
 };
diff --git a/ash/wm/gestures/wm_gesture_handler.cc b/ash/wm/gestures/wm_gesture_handler.cc
index 3c25ddd3..84d998c 100644
--- a/ash/wm/gestures/wm_gesture_handler.cc
+++ b/ash/wm/gestures/wm_gesture_handler.cc
@@ -108,10 +108,6 @@
   return false;
 }
 
-// The amount the fingers must move in a direction before a continuous gesture
-// animation is started. This is to minimize accidental scrolls.
-constexpr int kContinuousGestureMoveThresholdDp = 10;
-
 // Handles vertical 3-finger scroll gesture by entering overview on scrolling
 // up, and exiting it on scrolling down. If entering overview and window cycle
 // list is open, close the window cycle list.
@@ -284,7 +280,7 @@
 
   if (is_enhanced_desk_animations_ && finger_count == 4) {
     DCHECK(!moved);
-    // Horizon gesture may be flipped.
+    // Horizontal gesture may be flipped.
     const float offset_x = GetOffset(-delta_x);
     const float scroll_x = GetOffset(scroll_data_->scroll_x);
     auto* desks_controller = DesksController::Get();
diff --git a/ash/wm/gestures/wm_gesture_handler.h b/ash/wm/gestures/wm_gesture_handler.h
index 655ad142..2e4287d 100644
--- a/ash/wm/gestures/wm_gesture_handler.h
+++ b/ash/wm/gestures/wm_gesture_handler.h
@@ -39,6 +39,11 @@
   static constexpr float kVerticalThresholdDp = 300.f;
   static constexpr float kHorizontalThresholdDp = 330.f;
 
+  // The amount in trackpad units the fingers must move in a direction before a
+  // continuous gesture animation is started. This is to minimize accidental
+  // scrolls.
+  static constexpr int kContinuousGestureMoveThresholdDp = 10;
+
   WmGestureHandler();
   WmGestureHandler(const WmGestureHandler&) = delete;
   WmGestureHandler& operator=(const WmGestureHandler&) = delete;
diff --git a/ash/wm/gestures/wm_gesture_handler_unittest.cc b/ash/wm/gestures/wm_gesture_handler_unittest.cc
index 83a2290..4bf8c91 100644
--- a/ash/wm/gestures/wm_gesture_handler_unittest.cc
+++ b/ash/wm/gestures/wm_gesture_handler_unittest.cc
@@ -10,9 +10,11 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/desks/desk.h"
+#include "ash/wm/desks/desk_animation_base.h"
 #include "ash/wm/desks/desks_controller.h"
 #include "ash/wm/desks/desks_histogram_enums.h"
 #include "ash/wm/desks/desks_test_util.h"
+#include "ash/wm/desks/root_window_desk_switch_animator_test_api.h"
 #include "ash/wm/overview/overview_controller.h"
 #include "ash/wm/overview/overview_test_util.h"
 #include "ash/wm/window_cycle_controller.h"
@@ -21,6 +23,8 @@
 #include "base/test/scoped_feature_list.h"
 #include "components/prefs/pref_service.h"
 #include "ui/aura/window.h"
+#include "ui/compositor/scoped_animation_duration_scale_mode.h"
+#include "ui/events/base_event_utils.h"
 #include "ui/events/test/event_generator.h"
 #include "ui/message_center/message_center.h"
 #include "ui/views/widget/widget.h"
@@ -81,6 +85,8 @@
 class WmGestureHandlerTest : public AshTestBase {
  public:
   WmGestureHandlerTest() = default;
+  WmGestureHandlerTest(const WmGestureHandlerTest&) = delete;
+  WmGestureHandlerTest& operator=(const WmGestureHandlerTest&) = delete;
   ~WmGestureHandlerTest() override = default;
 
   void Scroll(float x_offset, float y_offset, int fingers) {
@@ -90,6 +96,67 @@
   }
 
   void ScrollToSwitchDesks(bool scroll_left) {
+    if (features::IsEnhancedDeskAnimations()) {
+      // Scrolling to switch desks with enhanced desk animations is a bit tricky
+      // because it involves multiple async operations.
+      ui::ScopedAnimationDurationScaleMode test_duration_mode(
+          ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
+
+      // Start off with a fling cancel (touchpad start) to start the touchpad
+      // swipe sequence.
+      base::TimeTicks timestamp = ui::EventTimeForNow();
+      ui::ScrollEvent fling_cancel(ui::ET_SCROLL_FLING_CANCEL, gfx::Point(),
+                                   timestamp, 0, 0, 0, 0, 0,
+                                   kNumFingersForDesksSwitch);
+      auto* event_generator = GetEventGenerator();
+      event_generator->Dispatch(&fling_cancel);
+
+      // Continue with a large enough scroll to start the desk switch animation.
+      // The animation does not start on fling cancel since there is no finger
+      // data in production code.
+      const base::TimeDelta step_delay = base::TimeDelta::FromMilliseconds(5);
+      timestamp += step_delay;
+      const int direction = scroll_left ? -1 : 1;
+      const int initial_move_x =
+          (WmGestureHandler::kContinuousGestureMoveThresholdDp + 5) * direction;
+      ui::ScrollEvent initial_move(ui::ET_SCROLL, gfx::Point(), timestamp, 0,
+                                   initial_move_x, 0, initial_move_x, 0,
+                                   kNumFingersForDesksSwitch);
+      event_generator->Dispatch(&initial_move);
+
+      // Wait until the animations ending screenshot has been taken. Otherwise,
+      // we will just stay at the initial desk if no screenshot has been taken.
+      auto* animation = DesksController::Get()->animation();
+      DCHECK(animation);
+      auto* desk_switch_animator =
+          animation->GetFirstDeskSwitchAnimatorForTesting();
+      base::RunLoop run_loop;
+      RootWindowDeskSwitchAnimatorTestApi(desk_switch_animator)
+          .SetOnEndingScreenshotTakenCallback(run_loop.QuitClosure());
+      run_loop.Run();
+
+      // Send some more move events, enough to shift to the next desk.
+      const int steps = 100;
+      const float x_offset =
+          direction * WmGestureHandler::kHorizontalThresholdDp;
+      float dx = x_offset / steps;
+      for (int i = 0; i < steps; ++i) {
+        timestamp += step_delay;
+        ui::ScrollEvent move(ui::ET_SCROLL, gfx::Point(), timestamp, 0, dx, 0,
+                             dx, 0, kNumFingersForDesksSwitch);
+        event_generator->Dispatch(&move);
+      }
+
+      // End the swipe and wait for the animation to finish.
+      ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, gfx::Point(),
+                                  timestamp, 0, x_offset, 0, x_offset, 0,
+                                  kNumFingersForDesksSwitch);
+      DeskSwitchAnimationWaiter animation_finished_waiter;
+      event_generator->Dispatch(&fling_start);
+      animation_finished_waiter.Wait();
+      return;
+    }
+
     DeskSwitchAnimationWaiter waiter;
     const float x_offset =
         (scroll_left ? -1 : 1) * WmGestureHandler::kHorizontalThresholdDp;
@@ -102,9 +169,6 @@
     for (int i = 0; i < num_of_times; i++)
       generator->MoveMouseWheel(delta_x, delta_y);
   }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(WmGestureHandlerTest);
 };
 
 // Tests a three fingers upwards scroll gesture to enter and a scroll down to
@@ -226,8 +290,6 @@
   EXPECT_TRUE(InOverviewSession());
 }
 
-// The tests that verifies Virtual Desks gestures will be parameterized
-// separately to run only when Virtual Desks and its gestures are enabled.
 using DesksGestureHandlerTest = WmGestureHandlerTest;
 
 // Tests that a four-finger horizontal scroll will switch desks as expected.
@@ -279,6 +341,11 @@
 
 // Tests that a large scroll only moves to the next desk.
 TEST_F(DesksGestureHandlerTest, NoDoubleDeskChange) {
+  // Enhanced desk animations supports switching multiple desks with large
+  // enough scrolls.
+  if (features::IsEnhancedDeskAnimations())
+    return;
+
   auto* desk_controller = DesksController::Get();
   desk_controller->NewDesk(DesksCreationRemovalSource::kButton);
   desk_controller->NewDesk(DesksCreationRemovalSource::kButton);
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 09f25d1..f638c9c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -3867,6 +3867,7 @@
     ]
 
     sources = [
+      "test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java",
       "test/android/javatests/src/org/chromium/base/test/BaseChromiumAndroidJUnitRunner.java",
       "test/android/javatests/src/org/chromium/base/test/BaseChromiumRunnerCommon.java",
       "test/android/javatests/src/org/chromium/base/test/BaseJUnit4ClassRunner.java",
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java
new file mode 100644
index 0000000..af570fb
--- /dev/null
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseActivityTestRule.java
@@ -0,0 +1,94 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.base.test;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.support.test.runner.lifecycle.Stage;
+import android.text.TextUtils;
+
+import androidx.annotation.NonNull;
+
+import org.junit.Assert;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import org.chromium.base.ContextUtils;
+import org.chromium.base.Log;
+import org.chromium.base.test.util.ApplicationTestUtils;
+
+/**
+ * A replacement for ActivityTestRule, designed for use in Chromium. This implementation supports
+ * launching the target activity through a launcher or redirect from another Activity.
+ *
+ * @param <T> The type of Activity this Rule will use.
+ */
+public class BaseActivityTestRule<T extends Activity> implements TestRule {
+    private static final String TAG = "BaseActivityTestRule";
+
+    private final Class<T> mActivityClass;
+    private boolean mFinishActivity = true;
+    private T mActivity;
+
+    /**
+     * @param activityClass The Class of the Activity the TestRule will use.
+     */
+    public BaseActivityTestRule(Class<T> activityClass) {
+        mActivityClass = activityClass;
+    }
+
+    @Override
+    public Statement apply(final Statement base, final Description desc) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                base.evaluate();
+                if (mFinishActivity && mActivity != null) {
+                    ApplicationTestUtils.finishActivity(mActivity);
+                }
+            }
+        };
+    }
+
+    /**
+     * @param finishActivity Whether to finish the Activity between tests. This is only meaningful
+     *     in the context of {@link Batch} tests. Non-batched tests will always finish Activities
+     *     between tests.
+     */
+    public void setFinishActivity(boolean finishActivity) {
+        mFinishActivity = finishActivity;
+    }
+
+    /**
+     * @return The activity under test.
+     */
+    public T getActivity() {
+        return mActivity;
+    }
+
+    /**
+     * Set the Activity to be used by this TestRule.
+     */
+    public void setActivity(T activity) {
+        mActivity = activity;
+    }
+
+    /**
+     * Launches the Activity under test using the provided intent.
+     */
+    public void launchActivity(@NonNull Intent startIntent) {
+        String packageName = ContextUtils.getApplicationContext().getPackageName();
+        Assert.assertTrue(TextUtils.equals(startIntent.getPackage(), packageName)
+                || TextUtils.equals(startIntent.getComponent().getPackageName(), packageName));
+
+        startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        Log.d(TAG, String.format("Launching activity %s", mActivityClass.getName()));
+
+        mActivity = ApplicationTestUtils.waitForActivityWithClass(mActivityClass, Stage.CREATED,
+                () -> ContextUtils.getApplicationContext().startActivity(startIntent));
+    }
+}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/util/ApplicationTestUtils.java b/base/test/android/javatests/src/org/chromium/base/test/util/ApplicationTestUtils.java
index 799c803..bd174282 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/util/ApplicationTestUtils.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/util/ApplicationTestUtils.java
@@ -26,9 +26,16 @@
 
     /** Waits until the given activity transitions to the given state. */
     public static void waitForActivityState(Activity activity, Stage stage) {
-        CriteriaHelper.pollUiThread(() -> {
-            return sMonitor.getLifecycleStageOf(activity) == stage;
-        }, ScalableTimeout.scaleTimeout(10000), CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+        waitForActivityState(null, activity, stage);
+    }
+
+    /** Waits until the given activity transitions to the given state. */
+    public static void waitForActivityState(String failureReason, Activity activity, Stage stage) {
+        CriteriaHelper.pollUiThread(
+                ()
+                        -> { return sMonitor.getLifecycleStageOf(activity) == stage; },
+                failureReason, ScalableTimeout.scaleTimeout(10000),
+                CriteriaHelper.DEFAULT_POLLING_INTERVAL);
     }
 
     /** Finishes the given activity and waits for its onDestroy() to be called. */
@@ -38,7 +45,9 @@
                 activity.finish();
             }
         });
-        waitForActivityState(activity, Stage.DESTROYED);
+        waitForActivityState(
+                "Failed to finish the Activity. Did you start a second Activity and not finish it?",
+                activity, Stage.DESTROYED);
     }
 
     /**
@@ -48,11 +57,25 @@
      * @return The newly created Activity.
      */
     public static <T extends Activity> T recreateActivity(T activity) {
-        final Class<?> activityClass = activity.getClass();
+        return waitForActivityWithClass(
+                activity.getClass(), Stage.RESUMED, () -> activity.recreate());
+    }
+
+    /**
+     * Waits for an activity of the specified class to reach the specified Activity {@link Stage},
+     * triggered by running the provided trigger.
+     *
+     * @param activityClass The class type to wait for.
+     * @param state The Activity {@link Stage} to wait for an activity of the right class type to
+     * reach.
+     * @param trigger The Runnable that will trigger the state change to wait for.
+     */
+    public static <T extends Activity> T waitForActivityWithClass(
+            Class<? extends Activity> activityClass, Stage stage, Runnable trigger) {
         final CallbackHelper activityCallback = new CallbackHelper();
         final AtomicReference<T> activityRef = new AtomicReference<>();
-        ActivityLifecycleCallback stateListener = (Activity newActivity, Stage stage) -> {
-            if (stage == Stage.RESUMED) {
+        ActivityLifecycleCallback stateListener = (Activity newActivity, Stage newStage) -> {
+            if (newStage == stage) {
                 if (!activityClass.isAssignableFrom(newActivity.getClass())) return;
 
                 activityRef.set((T) newActivity);
@@ -62,8 +85,8 @@
         sMonitor.addLifecycleCallback(stateListener);
 
         try {
-            ThreadUtils.runOnUiThreadBlocking(() -> activity.recreate());
-            activityCallback.waitForCallback("Activity did not start as expected", 0);
+            ThreadUtils.runOnUiThreadBlocking(() -> trigger.run());
+            activityCallback.waitForCallback("No Activity reached target state.", 0);
             T createdActivity = activityRef.get();
             Assert.assertNotNull("Activity reference is null.", createdActivity);
             return createdActivity;
diff --git a/build/android/BUILD.gn b/build/android/BUILD.gn
index e7e3d5c..01500199 100644
--- a/build/android/BUILD.gn
+++ b/build/android/BUILD.gn
@@ -68,7 +68,7 @@
       "//tools/android/md5sum",
     ]
     data = [
-      "//third_party/android_build_tools/bundletool/bundletool-all-1.4.0.jar",
+      "//third_party/android_build_tools/bundletool/bundletool-all-1.2.0.jar",
     ]
   }
 }
diff --git a/build/android/devil_chromium.json b/build/android/devil_chromium.json
index 0bfcfd84..10b0740c 100644
--- a/build/android/devil_chromium.json
+++ b/build/android/devil_chromium.json
@@ -111,7 +111,7 @@
       "file_info": {
         "default": {
           "local_paths": [
-            "../../third_party/android_build_tools/bundletool/bundletool-all-1.4.0.jar"
+            "../../third_party/android_build_tools/bundletool/bundletool-all-1.2.0.jar"
           ]
         }
       }
diff --git a/build/android/gyp/bundletool.py b/build/android/gyp/bundletool.py
index 695d3cd..003e3bf 100755
--- a/build/android/gyp/bundletool.py
+++ b/build/android/gyp/bundletool.py
@@ -19,7 +19,7 @@
     __file__, '..', '..', '..', '..', 'third_party', 'android_build_tools',
     'bundletool'))
 
-BUNDLETOOL_VERSION = '1.4.0'
+BUNDLETOOL_VERSION = '1.2.0'
 
 BUNDLETOOL_JAR_PATH = os.path.join(
     BUNDLETOOL_DIR, 'bundletool-all-%s.jar' % BUNDLETOOL_VERSION)
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1
index 6f947bd..e6083fd 100644
--- a/build/fuchsia/linux.sdk.sha1
+++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@
-0.20201123.1.1
+0.20201123.2.1
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1
index 6f947bd..e6083fd 100644
--- a/build/fuchsia/mac.sdk.sha1
+++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@
-0.20201123.1.1
+0.20201123.2.1
diff --git a/build/toolchain/concurrent_links.gni b/build/toolchain/concurrent_links.gni
index 538007c..c3fa3ce 100644
--- a/build/toolchain/concurrent_links.gni
+++ b/build/toolchain/concurrent_links.gni
@@ -36,7 +36,7 @@
     } else {
       _args += [ "--mem_per_link_gb=10" ]
     }
-  } else if (use_sanitizer_coverage || use_fuzzing_engine) {
+  } else if (use_clang_coverage || use_sanitizer_coverage || use_fuzzing_engine) {
     # Sanitizer coverage instrumentation increases linker memory consumption
     # significantly.
     _args = [ "--mem_per_link_gb=16" ]
diff --git a/cc/debug/layer_tree_debug_state.cc b/cc/debug/layer_tree_debug_state.cc
index eed1d44..26ca00e 100644
--- a/cc/debug/layer_tree_debug_state.cc
+++ b/cc/debug/layer_tree_debug_state.cc
@@ -23,7 +23,8 @@
 }
 
 bool LayerTreeDebugState::ShouldCreateHudLayer() const {
-  return show_fps_counter || ShowDebugRects() || show_web_vital_metrics;
+  return show_fps_counter || ShowDebugRects() || show_web_vital_metrics ||
+         show_smoothness_metrics;
 }
 
 bool LayerTreeDebugState::ShowDebugRects() const {
@@ -40,7 +41,7 @@
 }
 
 bool LayerTreeDebugState::ShouldDrawHudInfo() const {
-  return show_fps_counter || show_web_vital_metrics;
+  return show_fps_counter || show_web_vital_metrics || show_smoothness_metrics;
 }
 
 bool LayerTreeDebugState::Equal(const LayerTreeDebugState& a,
diff --git a/cc/debug/layer_tree_debug_state.h b/cc/debug/layer_tree_debug_state.h
index 798173e..853fe06 100644
--- a/cc/debug/layer_tree_debug_state.h
+++ b/cc/debug/layer_tree_debug_state.h
@@ -53,6 +53,7 @@
   // This is part of the feature to show performance metrics on HUD. This
   // particular flag is set only in Blink.
   bool show_web_vital_metrics = false;
+  bool show_smoothness_metrics = false;
 
   void SetRecordRenderingStats(bool enabled);
   bool RecordRenderingStats() const;
diff --git a/cc/layers/heads_up_display_layer.cc b/cc/layers/heads_up_display_layer.cc
index 01639af0..8fc104c 100644
--- a/cc/layers/heads_up_display_layer.cc
+++ b/cc/layers/heads_up_display_layer.cc
@@ -39,13 +39,19 @@
 
   gfx::Size bounds;
 
+  // If the HUD is not displaying full-viewport rects (e.g., it is showing the
+  // Frame Rendering Stats), use a fixed size.
+  constexpr int kDefaultHUDSize = 256;
+  bounds.SetSize(kDefaultHUDSize, kDefaultHUDSize);
+
   if (layer_tree_host()->GetDebugState().ShowDebugRects()) {
     bounds = device_viewport_in_layout_pixels;
-  } else {
-    // If the HUD is not displaying full-viewport rects (e.g., it is showing the
-    // Frame Rendering Stats), use a fixed size.
-    constexpr int kDefaultHUDSize = 256;
-    bounds.SetSize(kDefaultHUDSize, kDefaultHUDSize);
+  } else if (layer_tree_host()->GetDebugState().show_web_vital_metrics ||
+             layer_tree_host()->GetDebugState().show_smoothness_metrics) {
+    // If the HUD is used to display performance metrics (which is on the right
+    // hand side_, make sure the bounds has the correct width, with a fixed
+    // height.
+    bounds.set_width(device_viewport_in_layout_pixels.width());
   }
 
   SetBounds(bounds);
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 2a4acbb..e74b44d 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -603,9 +603,18 @@
                              std::max<SkScalar>(area.width(), 150));
   }
 
+  SkRect metrics_area = SkRect::MakeXYWH(
+      std::max<SkScalar>(0, bounds().width() - 150), 0, 150, 0);
   if (debug_state.show_web_vital_metrics) {
-    area = DrawWebVitalMetrics(canvas, 0, area.bottom(),
-                               std::max<SkScalar>(area.width(), 150));
+    metrics_area =
+        DrawWebVitalMetrics(canvas, metrics_area.left(), metrics_area.bottom(),
+                            std::max<SkScalar>(metrics_area.width(), 150));
+  }
+
+  if (debug_state.show_smoothness_metrics) {
+    metrics_area = DrawSmoothnessMetrics(
+        canvas, metrics_area.left(), metrics_area.bottom(),
+        std::max<SkScalar>(metrics_area.width(), 150));
   }
 
   canvas->restore();
@@ -1045,45 +1054,94 @@
   }
 }
 
+int HeadsUpDisplayLayerImpl::DrawSingleMetric(
+    PaintCanvas* canvas,
+    int left,
+    int right,
+    int top,
+    std::string name,
+    const WebVitalMetrics::MetricsInfo& info,
+    double value) const {
+  std::string value_str = "-";
+  SkColor metrics_color = DebugColors::HUDTitleColor();
+  if (value >= 0.f) {
+    value_str = ToStringTwoDecimalPrecision(value) + info.UnitToString();
+    if (value < info.green_threshold)
+      metrics_color = SK_ColorGREEN;
+    else if (value < info.yellow_threshold)
+      metrics_color = SK_ColorYELLOW;
+    else
+      metrics_color = SK_ColorRED;
+  }
+  const int kPadding = 4;
+  const int kTitleFontHeight = 13;
+  const int kFontHeight = 12;
+
+  PaintFlags flags;
+  flags.setColor(DebugColors::HUDTitleColor());
+  DrawText(canvas, flags, name, TextAlign::kLeft, kTitleFontHeight,
+           left + kPadding, top);
+  flags.setColor(metrics_color);
+  DrawText(canvas, flags, value_str, TextAlign::kRight, kFontHeight,
+           right - kPadding, top + kFontHeight + kPadding);
+
+  return top + 2 * kFontHeight + 2 * kPadding;
+}
+
 SkRect HeadsUpDisplayLayerImpl::DrawWebVitalMetrics(PaintCanvas* canvas,
-                                                    int right,
+                                                    int left,
                                                     int top,
                                                     int width) const {
-  std::string largest_contentful_paint = "-";
-  SkColor largest_contentful_paint_color = DebugColors::HUDTitleColor();
-  if (web_vital_metrics_) {
-    if (web_vital_metrics_->largest_contentful_paint.has_value()) {
-      double time = web_vital_metrics_->largest_contentful_paint->InSecondsF();
-      largest_contentful_paint = ToStringTwoDecimalPrecision(time) + " s";
-      if (time < 2.5f)
-        largest_contentful_paint_color = SK_ColorGREEN;
-      else if (time < 4.f)
-        largest_contentful_paint_color = SK_ColorYELLOW;
-      else
-        largest_contentful_paint_color = SK_ColorRED;
-    }
-  }
-  std::string first_input_delay = "-";
-  SkColor first_input_delay_color = DebugColors::HUDTitleColor();
-  if (web_vital_metrics_) {
-    if (web_vital_metrics_->first_input_delay.has_value()) {
-      double delay = web_vital_metrics_->first_input_delay->InMillisecondsF();
-      first_input_delay = ToStringTwoDecimalPrecision(delay) + " ms";
-      if (delay < 100.f)
-        first_input_delay_color = SK_ColorGREEN;
-      else if (delay < 300.f)
-        first_input_delay_color = SK_ColorYELLOW;
-      else
-        first_input_delay_color = SK_ColorRED;
-    }
-  }
+  const int kPadding = 4;
+  const int kTitleFontHeight = 13;
+  const int kFontHeight = 12;
+
+  const int height = 3 * kTitleFontHeight + 3 * kFontHeight + 7 * kPadding;
+  const SkRect area = SkRect::MakeXYWH(left, top, width, height);
+
+  PaintFlags flags;
+  DrawGraphBackground(canvas, &flags, area);
+
+  int current_top = top + kFontHeight + kPadding;
+  double lcp_value = -1;
+  if (web_vital_metrics_ &&
+      web_vital_metrics_->largest_contentful_paint.has_value())
+    lcp_value = web_vital_metrics_->largest_contentful_paint->InSecondsF();
+  current_top = DrawSingleMetric(canvas, left, left + width, current_top,
+                                 "Largest contentful paint",
+                                 WebVitalMetrics::lcp_info, lcp_value);
+
+  double fid_value = -1;
+  if (web_vital_metrics_ && web_vital_metrics_->first_input_delay.has_value())
+    fid_value = web_vital_metrics_->first_input_delay->InMillisecondsF();
+  current_top = DrawSingleMetric(canvas, left, left + width, current_top,
+                                 "First input delay", WebVitalMetrics::fid_info,
+                                 fid_value);
+
+  current_top = DrawSingleMetric(
+      canvas, left, left + width, current_top, "Cumulative layout shift",
+      WebVitalMetrics::cls_info,
+      web_vital_metrics_ ? web_vital_metrics_->layout_shift : -1);
+
+  return area;
+}
+
+SkRect HeadsUpDisplayLayerImpl::DrawSmoothnessMetrics(PaintCanvas* canvas,
+                                                      int left,
+                                                      int top,
+                                                      int width) const {
+  std::string avg_smoothness = "-";
+  double smoothness_data = layer_tree_impl()
+                               ->dropped_frame_counter()
+                               ->GetMostRecentAverageSmoothness();
+  if (smoothness_data >= 0.f)
+    avg_smoothness = ToStringTwoDecimalPrecision(smoothness_data) + " %";
 
   const int kPadding = 4;
   const int kTitleFontHeight = 13;
   const int kFontHeight = 12;
 
-  const int height = 2 * kTitleFontHeight + 2 * kFontHeight + 5 * kPadding;
-  const int left = 0;
+  const int height = kTitleFontHeight + kFontHeight + 3 * kPadding;
   const SkRect area = SkRect::MakeXYWH(left, top, width, height);
 
   PaintFlags flags;
@@ -1092,22 +1150,10 @@
   SkPoint metrics_pos = SkPoint::Make(left + width - kPadding,
                                       top + 2 * kFontHeight + 2 * kPadding);
   flags.setColor(DebugColors::HUDTitleColor());
-  DrawText(canvas, flags, "Largest contentful paint", TextAlign::kLeft,
+  DrawText(canvas, flags, "Average Dropped Frame:", TextAlign::kLeft,
            kTitleFontHeight, left + kPadding, top + kFontHeight + kPadding);
-  flags.setColor(largest_contentful_paint_color);
-  DrawText(canvas, flags, largest_contentful_paint, TextAlign::kRight,
-           kFontHeight, metrics_pos);
-
-  metrics_pos = SkPoint::Make(left + width - kPadding,
-                              top + 4 * kFontHeight + 4 * kPadding);
-  flags.setColor(DebugColors::HUDTitleColor());
-  DrawText(canvas, flags, "First input delay:", TextAlign::kLeft,
-           kTitleFontHeight, left + kPadding,
-           top + 3 * kFontHeight + 3 * kPadding);
-  flags.setColor(first_input_delay_color);
-  DrawText(canvas, flags, first_input_delay, TextAlign::kRight, kFontHeight,
+  DrawText(canvas, flags, avg_smoothness, TextAlign::kRight, kFontHeight,
            metrics_pos);
-
   return area;
 }
 
diff --git a/cc/layers/heads_up_display_layer_impl.h b/cc/layers/heads_up_display_layer_impl.h
index c98b60199..de7f166 100644
--- a/cc/layers/heads_up_display_layer_impl.h
+++ b/cc/layers/heads_up_display_layer_impl.h
@@ -129,11 +129,27 @@
   void DrawDebugRects(PaintCanvas* canvas,
                       DebugRectHistory* debug_rect_history);
 
+  // This function draws a single web vital metric. If the metrics doesn't have
+  // a valid value, the value is set to -1. This function returns the height
+  // of the current draw so it can be used to calculate the top of the next
+  // draw.
+  int DrawSingleMetric(PaintCanvas* canvas,
+                       int left,
+                       int right,
+                       int top,
+                       std::string name,
+                       const WebVitalMetrics::MetricsInfo& info,
+                       double value) const;
   SkRect DrawWebVitalMetrics(PaintCanvas* canvas,
-                             int right,
+                             int left,
                              int top,
                              int width) const;
 
+  SkRect DrawSmoothnessMetrics(PaintCanvas* canvas,
+                               int left,
+                               int top,
+                               int width) const;
+
   ResourcePool::InUsePoolResource in_flight_resource_;
   std::unique_ptr<ResourcePool> pool_;
   viz::DrawQuad* current_quad_ = nullptr;
diff --git a/cc/layers/heads_up_display_unittest.cc b/cc/layers/heads_up_display_unittest.cc
index 9587f04..204a88e 100644
--- a/cc/layers/heads_up_display_unittest.cc
+++ b/cc/layers/heads_up_display_unittest.cc
@@ -106,8 +106,11 @@
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
 
   void DidCommit() override {
+    // The metrics should be shown on the right, so the width of the HUD layer
+    // should be the saem as the root layer bounds.
     ASSERT_TRUE(layer_tree_host()->hud_layer());
-    EXPECT_EQ(gfx::Size(256, 256), layer_tree_host()->hud_layer()->bounds());
+    EXPECT_EQ(gfx::Size(layer_tree_host()->root_layer()->bounds().width(), 256),
+              layer_tree_host()->hud_layer()->bounds());
     EndTest();
   }
 };
diff --git a/cc/metrics/dropped_frame_counter.cc b/cc/metrics/dropped_frame_counter.cc
index 99daca0f..4d1ac25 100644
--- a/cc/metrics/dropped_frame_counter.cc
+++ b/cc/metrics/dropped_frame_counter.cc
@@ -89,6 +89,13 @@
   }
 }
 
+double DroppedFrameCounter::GetMostRecentAverageSmoothness() const {
+  if (ukm_smoothness_data_)
+    return ukm_smoothness_data_->data.avg_smoothness;
+
+  return -1.f;
+}
+
 void DroppedFrameCounter::SetUkmSmoothnessDestination(
     UkmSmoothnessDataShared* smoothness_data) {
   ukm_smoothness_data_ = smoothness_data;
diff --git a/cc/metrics/dropped_frame_counter.h b/cc/metrics/dropped_frame_counter.h
index 1fa5e318..8054c12 100644
--- a/cc/metrics/dropped_frame_counter.h
+++ b/cc/metrics/dropped_frame_counter.h
@@ -41,6 +41,8 @@
 
   uint32_t GetAverageThroughput() const;
 
+  double GetMostRecentAverageSmoothness() const;
+
   typedef base::RingBuffer<FrameState, 180> RingBufferType;
   RingBufferType::Iterator begin() const { return ring_buffer_.Begin(); }
   RingBufferType::Iterator end() const { return ring_buffer_.End(); }
diff --git a/cc/metrics/web_vital_metrics.cc b/cc/metrics/web_vital_metrics.cc
index d27f6b3..cbc86a7 100644
--- a/cc/metrics/web_vital_metrics.cc
+++ b/cc/metrics/web_vital_metrics.cc
@@ -6,6 +6,10 @@
 
 namespace cc {
 
+constexpr WebVitalMetrics::MetricsInfo WebVitalMetrics::lcp_info;
+constexpr WebVitalMetrics::MetricsInfo WebVitalMetrics::fid_info;
+constexpr WebVitalMetrics::MetricsInfo WebVitalMetrics::cls_info;
+
 WebVitalMetrics::WebVitalMetrics() = default;
 
 WebVitalMetrics::WebVitalMetrics(const WebVitalMetrics& other) = default;
@@ -17,6 +21,9 @@
   if (first_input_delay.has_value())
     return true;
 
+  if (layout_shift > 0.f)
+    return true;
+
   return false;
 }
 
diff --git a/cc/metrics/web_vital_metrics.h b/cc/metrics/web_vital_metrics.h
index f8383b69..d61143b 100644
--- a/cc/metrics/web_vital_metrics.h
+++ b/cc/metrics/web_vital_metrics.h
@@ -5,6 +5,8 @@
 #ifndef CC_METRICS_WEB_VITAL_METRICS_H_
 #define CC_METRICS_WEB_VITAL_METRICS_H_
 
+#include <string>
+
 #include "base/time/time.h"
 #include "cc/cc_export.h"
 
@@ -14,11 +16,36 @@
 struct CC_EXPORT WebVitalMetrics {
   base::Optional<base::TimeDelta> largest_contentful_paint;
   base::Optional<base::TimeDelta> first_input_delay;
+  double layout_shift = 0.f;
 
   WebVitalMetrics();
   WebVitalMetrics(const WebVitalMetrics& other);
 
   bool HasValue() const;
+
+  struct MetricsInfo {
+    double green_threshold;
+    double yellow_threshold;
+    enum Unit { kSecond, kMillisecond, kScore };
+    Unit unit;
+    std::string UnitToString() const {
+      switch (unit) {
+        case Unit::kSecond:
+          return " s";
+        case Unit::kMillisecond:
+          return " ms";
+        case Unit::kScore:
+        default:
+          return "";
+      }
+    }
+  };
+  static constexpr MetricsInfo lcp_info = {
+      2.5f, 4.f, WebVitalMetrics::MetricsInfo::Unit::kSecond};
+  static constexpr MetricsInfo fid_info = {
+      100, 300, WebVitalMetrics::MetricsInfo::Unit::kMillisecond};
+  static constexpr MetricsInfo cls_info = {
+      0.1f, 0.25f, WebVitalMetrics::MetricsInfo::Unit::kScore};
 };
 
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 6ffb53a..307064ee9 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -1893,4 +1893,10 @@
   proxy_->SetEnableFrameRateThrottling(enable_frame_rate_throttling);
 }
 
+void LayerTreeHost::SetDelegatedInkMetadata(
+    std::unique_ptr<viz::DelegatedInkMetadata> metadata) {
+  delegated_ink_metadata_ = std::move(metadata);
+  SetNeedsCommit();
+}
+
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index ea6852e..574439f 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -712,9 +712,7 @@
   }
 
   void SetDelegatedInkMetadata(
-      std::unique_ptr<viz::DelegatedInkMetadata> metadata) {
-    delegated_ink_metadata_ = std::move(metadata);
-  }
+      std::unique_ptr<viz::DelegatedInkMetadata> metadata);
   viz::DelegatedInkMetadata* DelegatedInkMetadataForTesting() {
     return delegated_ink_metadata_.get();
   }
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index a9bbcad3..7ccb1b2e 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -158,6 +158,7 @@
         ":visual_elements_resources",
         "//base",
         "//build:branding_buildflags",
+        "//build:chromeos_buildflags",
         "//chrome/app/version_assembly:chrome_exe_manifest",
         "//chrome/browser:active_use_util",
         "//chrome/browser:chrome_process_finder",
diff --git a/chrome/VERSION b/chrome/VERSION
index 953d035..d4f2fbbb 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=89
 MINOR=0
-BUILD=4335
+BUILD=4336
 PATCH=0
diff --git a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java
index 80b4009..2717c72 100644
--- a/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java
+++ b/chrome/android/features/autofill_assistant/javatests/src/org/chromium/chrome/browser/autofill_assistant/AssistantOnboardingCoordinatorTest.java
@@ -23,10 +23,9 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.verify;
 
-import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntil;
 import static org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiTestUtil.waitUntilViewMatchesCondition;
 
-import android.app.Activity;
+import android.support.test.runner.lifecycle.Stage;
 import android.text.Spanned;
 import android.text.style.ClickableSpan;
 import android.view.View;
@@ -43,10 +42,10 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
-import org.chromium.base.ActivityState;
-import org.chromium.base.ApplicationStatus;
 import org.chromium.base.Callback;
+import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.chrome.autofill_assistant.R;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.autofill_assistant.overlay.AssistantOverlayCoordinator;
@@ -57,7 +56,6 @@
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
-import org.chromium.chrome.test.util.ChromeTabUtils;
 import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
 import org.chromium.components.browser_ui.widget.scrim.ScrimCoordinator;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
@@ -295,8 +293,11 @@
                                     spannedMessage.getSpanEnd(spans[0]))
                             .toString());
         });
-        spans[0].onClick(termsMessage);
-        waitUntil(() -> getOpenedUrlSpec().equals(expectedTermsUrl));
+        CustomTabActivity activity = ApplicationTestUtils.waitForActivityWithClass(
+                CustomTabActivity.class, Stage.RESUMED, () -> spans[0].onClick(termsMessage));
+        CriteriaHelper.pollUiThread(
+                () -> activity.getActivityTab().getUrlString().equals(expectedTermsUrl));
+        activity.finish();
     }
 
     @Test
@@ -356,12 +357,13 @@
                             .toString()
                             .replaceAll("\\s+", " "));
         });
-        spans[0].onClick(termsMessage);
-        waitUntil(()
-                          -> getOpenedUrlSpec().equals(
-                                  mActivity.getResources()
-                                          .getText(R.string.autofill_assistant_google_terms_url)
-                                          .toString()));
+        CustomTabActivity activity = ApplicationTestUtils.waitForActivityWithClass(
+                CustomTabActivity.class, Stage.RESUMED, () -> spans[0].onClick(termsMessage));
+        String url = mActivity.getResources()
+                             .getText(R.string.autofill_assistant_google_terms_url)
+                             .toString();
+        CriteriaHelper.pollUiThread(() -> activity.getActivityTab().getUrlString().equals(url));
+        activity.finish();
     }
 
     /** Trigger onboarding and wait until it is fully displayed. */
@@ -370,21 +372,4 @@
         TestThreadUtils.runOnUiThreadBlocking(() -> coordinator.show(callback));
         waitUntilViewMatchesCondition(withId(R.id.button_init_ok), isCompletelyDisplayed());
     }
-
-    // Get the newly opened Activity (through CustomTabActivity.showInfoPage) that happens on
-    // terms click. Return the URL of the current tab on that activity.
-    private String getOpenedUrlSpec() {
-        for (Activity runningActivity : ApplicationStatus.getRunningActivities()) {
-            if (runningActivity instanceof CustomTabActivity
-                    && ApplicationStatus.getStateForActivity(runningActivity)
-                            == ActivityState.RESUMED) {
-                return ChromeTabUtils
-                        .getUrlOnUiThread(((CustomTabActivity) runningActivity)
-                                                  .getTabModelSelector()
-                                                  .getCurrentTab())
-                        .getSpec();
-            }
-        }
-        return "";
-    }
 }
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
index 149d2f59..a512350 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceCoordinator.java
@@ -97,7 +97,7 @@
     public StartSurfaceCoordinator(ChromeActivity activity, ScrimCoordinator scrimCoordinator,
             BottomSheetController sheetController,
             OneshotSupplierImpl<StartSurface> startSurfaceOneshotSupplier,
-            Supplier<Tab> parentTabSupplier) {
+            Supplier<Tab> parentTabSupplier, boolean hadWarmStart) {
         mActivity = activity;
         mScrimCoordinator = scrimCoordinator;
         mSurfaceMode = computeSurfaceMode();
@@ -126,7 +126,7 @@
                 mSurfaceMode, mActivity, mActivity.getBrowserControlsManager(),
                 this::isActivityFinishingOrDestroyed, excludeMVTiles,
                 StartSurfaceConfiguration.START_SURFACE_SHOW_STACK_TAB_SWITCHER.getValue(),
-                startSurfaceOneshotSupplier);
+                startSurfaceOneshotSupplier, hadWarmStart);
 
         // Show feed loading image.
         if (mStartSurfaceMediator.shouldShowFeedPlaceholder()) {
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
index ad747cc..5291383 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceDelegate.java
@@ -33,8 +33,8 @@
     public static StartSurface createStartSurface(ChromeActivity activity,
             ScrimCoordinator scrimCoordinator, BottomSheetController sheetController,
             OneshotSupplierImpl<StartSurface> startSurfaceOneshotSupplier,
-            Supplier<Tab> parentTabSupplier) {
+            Supplier<Tab> parentTabSupplier, boolean hadWarmStart) {
         return new StartSurfaceCoordinator(activity, scrimCoordinator, sheetController,
-                startSurfaceOneshotSupplier, parentTabSupplier);
+                startSurfaceOneshotSupplier, parentTabSupplier, hadWarmStart);
     }
 }
\ No newline at end of file
diff --git a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
index 8b839b5..58be031 100644
--- a/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
+++ b/chrome/android/features/start_surface/internal/java/src/org/chromium/chrome/features/start_surface/StartSurfaceMediator.java
@@ -166,6 +166,7 @@
      */
     @Nullable
     private Boolean mFeedVisibilityInSharedPreferenceOnStartUp;
+    private boolean mHadWarmStart;
 
     StartSurfaceMediator(TabSwitcher.Controller controller, TabModelSelector tabModelSelector,
             @Nullable PropertyModel propertyModel,
@@ -173,7 +174,8 @@
             @SurfaceMode int surfaceMode, Context context,
             BrowserControlsStateProvider browserControlsStateProvider,
             ActivityStateChecker activityStateChecker, boolean excludeMVTiles,
-            boolean showStackTabSwitcher, OneshotSupplier<StartSurface> startSurfaceSupplier) {
+            boolean showStackTabSwitcher, OneshotSupplier<StartSurface> startSurfaceSupplier,
+            boolean hadWarmStart) {
         mController = controller;
         mTabModelSelector = tabModelSelector;
         mPropertyModel = propertyModel;
@@ -185,6 +187,7 @@
         mExcludeMVTiles = excludeMVTiles;
         mShowStackTabSwitcher = showStackTabSwitcher;
         mStartSurfaceSupplier = startSurfaceSupplier;
+        mHadWarmStart = hadWarmStart;
 
         if (mPropertyModel != null) {
             assert mSurfaceMode == SurfaceMode.SINGLE_PANE || mSurfaceMode == SurfaceMode.TWO_PANES
@@ -752,7 +755,7 @@
 
         return mSurfaceMode == SurfaceMode.SINGLE_PANE
                 && CachedFeatureFlags.isEnabled(ChromeFeatureList.INSTANT_START)
-                && StartSurfaceConfiguration.getFeedArticlesVisibility();
+                && StartSurfaceConfiguration.getFeedArticlesVisibility() && !mHadWarmStart;
     }
 
     /** This interface builds the feed surface coordinator when showing if needed. */
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
index e507266..a3ae2c4 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/InstantStartTest.java
@@ -65,6 +65,7 @@
 import org.chromium.base.test.util.DisableIf;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.Restriction;
+import org.chromium.base.test.util.ScalableTimeout;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.compositor.layouts.Layout;
 import org.chromium.chrome.browser.compositor.layouts.LayoutManagerChromePhone;
@@ -172,7 +173,7 @@
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(Intent.CATEGORY_LAUNCHER);
         mActivityTestRule.prepareUrlIntent(intent, null);
-        mActivityTestRule.startActivityCompletely(intent);
+        mActivityTestRule.launchActivity(intent);
     }
 
     public static Bitmap createThumbnailBitmapAndWriteToFile(int tabId) {
@@ -271,7 +272,8 @@
         TestThreadUtils.runOnUiThreadBlocking(
                 () -> mActivityTestRule.getActivity().startDelayedNativeInitializationForTests());
         CriteriaHelper.pollUiThread(
-                mActivityTestRule.getActivity().getTabModelSelector()::isTabStateInitialized);
+                mActivityTestRule.getActivity().getTabModelSelector()::isTabStateInitialized,
+                ScalableTimeout.scaleTimeout(10000L), CriteriaHelper.DEFAULT_POLLING_INTERVAL);
         Assert.assertTrue(LibraryLoader.getInstance().isInitialized());
     }
 
@@ -568,6 +570,7 @@
             RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(i);
             if (viewHolder != null) {
                 ImageView thumbnail = viewHolder.itemView.findViewById(R.id.tab_thumbnail);
+                if (!(thumbnail.getDrawable() instanceof BitmapDrawable)) return false;
                 BitmapDrawable drawable = (BitmapDrawable) thumbnail.getDrawable();
                 Bitmap bitmap = drawable.getBitmap();
                 if (bitmap == null) return false;
@@ -775,12 +778,15 @@
             "force-fieldtrials=Study/Group",
             IMMEDIATE_RETURN_PARAMS + "/start_surface_variation/single"})
     @ParameterAnnotations.UseMethodParameter(FeedParams.class)
-    public void testFeedLoading(boolean isFeedV2) {
+    public void testFeedPlaceholderFromColdStart(boolean isFeedV2) {
         // clang-format on
         setFeedVersion(isFeedV2);
         startMainActivityFromLauncher();
         Assert.assertFalse(mActivityTestRule.getActivity().isTablet());
         Assert.assertTrue(CachedFeatureFlags.isEnabled(ChromeFeatureList.INSTANT_START));
+
+        // Feed placeholder should be shown from cold start with Instant Start on.
+        StartSurfaceCoordinator startSurfaceCoordinator = getStartSurfaceFromUIThread();
         onView(withId(R.id.placeholders_layout)).check(matches(isDisplayed()));
         Assert.assertFalse(LibraryLoader.getInstance().isInitialized());
 
@@ -788,6 +794,10 @@
         // Feed background should be non-transparent finally.
         ViewUtils.onViewWaiting(
                 AllOf.allOf(withId(R.id.feed_stream_recycler_view), matchesBackgroundAlpha(255)));
+
+        // TODO(spdonghao): Add a test for Feed placeholder from warm start. It's tested in
+        // StartSurfaceMediatorUnitTest#feedPlaceholderFromWarmStart currently because warm start is
+        // hard to simulate here.
     }
 
     @Test
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java
index 19a30c7..260b84d6 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceNoTabsTest.java
@@ -91,7 +91,7 @@
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.addCategory(Intent.CATEGORY_LAUNCHER);
         mActivityTestRule.prepareUrlIntent(intent, null);
-        mActivityTestRule.startActivityCompletely(intent);
+        mActivityTestRule.launchActivity(intent);
     }
 
     @Before
diff --git a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
index 863eac0..91f7d94 100644
--- a/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
+++ b/chrome/android/features/start_surface/internal/javatests/src/org/chromium/chrome/features/start_surface/StartSurfaceTest.java
@@ -812,7 +812,7 @@
     @CommandLineFlags.Add({BASE_PARAMS + "/single/exclude_mv_tiles/true"
             + "/show_last_active_tab_only/true/show_stack_tab_switcher/true"})
     public void
-    testShow_SingleAsHomepageV2_FromResumeShowStart() throws ExecutionException {
+    testShow_SingleAsHomepageV2_FromResumeShowStart() throws Exception {
         // clang-format on
         if (!mImmediateReturn) return;
 
@@ -832,7 +832,7 @@
         pressHome();
 
         // Simulates pressing Chrome's icon and launching Chrome from warm start.
-        startMainActivityFromLauncher();
+        mActivityTestRule.resumeMainActivityFromLauncher();
 
         CriteriaHelper.pollUiThread(
                 () -> cta.getLayoutManager() != null && cta.getLayoutManager().overviewVisible());
diff --git a/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java b/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
index 444168d5..b8a1505b 100644
--- a/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
+++ b/chrome/android/features/start_surface/internal/junit/src/org/chromium/chrome/features/start_surface/StartSurfaceMediatorUnitTest.java
@@ -7,6 +7,7 @@
 import static org.hamcrest.CoreMatchers.equalTo;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -20,6 +21,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import static org.chromium.chrome.browser.flags.ChromeFeatureList.INSTANT_START;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_FAKE_SEARCH_BOX_VISIBLE;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_INCOGNITO;
 import static org.chromium.chrome.browser.tasks.TasksSurfaceProperties.IS_INCOGNITO_DESCRIPTION_INITIALIZED;
@@ -63,6 +65,7 @@
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.chrome.browser.browser_controls.BrowserControlsStateProvider;
 import org.chromium.chrome.browser.feed.FeedSurfaceCoordinator;
+import org.chromium.chrome.browser.flags.CachedFeatureFlags;
 import org.chromium.chrome.browser.night_mode.NightModeStateProvider;
 import org.chromium.chrome.browser.ntp.FakeboxDelegate;
 import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener;
@@ -444,7 +447,8 @@
         doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
 
         StartSurfaceMediator mediator =
-                createStartSurfaceMediator(SurfaceMode.SINGLE_PANE, true, false);
+                createStartSurfaceMediator(SurfaceMode.SINGLE_PANE, /* excludeMVTiles= */ true,
+                        /* showStackTabSwitcher= */ false, /* hadWarmStart= */ false);
         verify(mMainTabGridController)
                 .addOverviewModeObserver(mOverviewModeObserverCaptor.capture());
 
@@ -855,7 +859,8 @@
         doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
 
         StartSurfaceMediator mediator =
-                createStartSurfaceMediator(SurfaceMode.SINGLE_PANE, true, true);
+                createStartSurfaceMediator(SurfaceMode.SINGLE_PANE, /* excludeMVTiles= */ true,
+                        /* showStackTabSwitcher= */ true, /* hadWarmStart= */ false);
         assertThat(mediator.getStartSurfaceState(), equalTo(StartSurfaceState.NOT_SHOWN));
 
         doReturn(2).when(mNormalTabModel).getCount();
@@ -1369,7 +1374,8 @@
         doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
 
         StartSurfaceMediator mediator =
-                createStartSurfaceMediator(SurfaceMode.SINGLE_PANE, true, true);
+                createStartSurfaceMediator(SurfaceMode.SINGLE_PANE, /* excludeMVTiles= */ true,
+                        /* showStackTabSwitcher= */ true, /* hadWarmStart= */ false);
         mediator.setOverviewState(StartSurfaceState.SHOWING_HOMEPAGE);
         mediator.showOverview(false);
         verify(mTabModelSelector).addObserver(mTabModelSelectorObserverCaptor.capture());
@@ -1682,8 +1688,9 @@
         doReturn(mVoiceRecognitionHandler).when(mFakeBoxDelegate).getVoiceRecognitionHandler();
         doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
 
-        StartSurfaceMediator mediator =
-                createStartSurfaceMediatorWithoutInit(SurfaceMode.SINGLE_PANE, false, false);
+        StartSurfaceMediator mediator = createStartSurfaceMediatorWithoutInit(
+                SurfaceMode.SINGLE_PANE, /* excludeMVTiles= */ false,
+                /* showStackTabSwitcher= */ false, /* hadWarmStart= */ false);
         verify(mMainTabGridController)
                 .addOverviewModeObserver(mOverviewModeObserverCaptor.capture());
 
@@ -1713,12 +1720,14 @@
         int tabSwitcherTitleTopMargin =
                 resources.getDimensionPixelSize(R.dimen.tab_switcher_title_top_margin);
 
-        createStartSurfaceMediatorWithoutInit(SurfaceMode.OMNIBOX_ONLY, false, false);
+        createStartSurfaceMediatorWithoutInit(SurfaceMode.OMNIBOX_ONLY, /* excludeMVTiles= */ false,
+                /* showStackTabSwitcher= */ false, /* hadWarmStart= */ false);
         assertThat(mPropertyModel.get(TASKS_SURFACE_BODY_TOP_MARGIN), equalTo(0));
         assertThat(mPropertyModel.get(MV_TILES_CONTAINER_TOP_MARGIN), equalTo(0));
         assertThat(mPropertyModel.get(TAB_SWITCHER_TITLE_TOP_MARGIN), equalTo(0));
 
-        createStartSurfaceMediatorWithoutInit(SurfaceMode.SINGLE_PANE, false, false);
+        createStartSurfaceMediatorWithoutInit(SurfaceMode.SINGLE_PANE, /* excludeMVTiles= */ false,
+                /* showStackTabSwitcher= */ false, /* hadWarmStart= */ false);
         assertThat(mPropertyModel.get(TASKS_SURFACE_BODY_TOP_MARGIN),
                 equalTo(tasksSurfaceBodyTopMargin));
         assertThat(mPropertyModel.get(MV_TILES_CONTAINER_TOP_MARGIN),
@@ -1727,15 +1736,42 @@
                 equalTo(tabSwitcherTitleTopMargin));
     }
 
-    private StartSurfaceMediator createStartSurfaceMediator(
-            @SurfaceMode int mode, boolean excludeMVTiles) {
-        return createStartSurfaceMediator(mode, excludeMVTiles, false);
+    @Test
+    public void feedPlaceholderFromWarmStart() {
+        doReturn(false).when(mTabModelSelector).isIncognitoSelected();
+        doReturn(mVoiceRecognitionHandler).when(mFakeBoxDelegate).getVoiceRecognitionHandler();
+        doReturn(true).when(mVoiceRecognitionHandler).isVoiceSearchEnabled();
+
+        CachedFeatureFlags.setForTesting(INSTANT_START, true);
+        StartSurfaceMediator mediator =
+                createStartSurfaceMediator(SurfaceMode.SINGLE_PANE, /* excludeMVTiles= */ false,
+                        /* showStackTabSwitcher= */ false, /* hadWarmStart= */ true);
+        assertFalse(mediator.shouldShowFeedPlaceholder());
+
+        mediator.setOverviewState(StartSurfaceState.SHOWING_HOMEPAGE);
+        mPropertyModel.set(IS_EXPLORE_SURFACE_VISIBLE, true);
+        when(mFeedSurfaceCreator.createFeedSurfaceCoordinator(anyBoolean(), anyBoolean()))
+                .thenReturn(mFeedSurfaceCoordinator);
+        mediator.showOverview(false);
+        assertThat(mediator.getStartSurfaceState(), equalTo(StartSurfaceState.SHOWN_HOMEPAGE));
+
+        FeedSurfaceCoordinator feedSurfaceCoordinator =
+                mPropertyModel.get(FEED_SURFACE_COORDINATOR);
+        assertThat(feedSurfaceCoordinator, equalTo(mFeedSurfaceCoordinator));
+
+        assertFalse(feedSurfaceCoordinator.isPlaceholderShown());
     }
 
     private StartSurfaceMediator createStartSurfaceMediator(
-            @SurfaceMode int mode, boolean excludeMVTiles, boolean showStackTabSwitcher) {
-        StartSurfaceMediator mediator =
-                createStartSurfaceMediatorWithoutInit(mode, excludeMVTiles, showStackTabSwitcher);
+            @SurfaceMode int mode, boolean excludeMVTiles) {
+        return createStartSurfaceMediator(
+                mode, excludeMVTiles, /* showStackTabSwitcher= */ false, /* hadWarmStart= */ false);
+    }
+
+    private StartSurfaceMediator createStartSurfaceMediator(@SurfaceMode int mode,
+            boolean excludeMVTiles, boolean showStackTabSwitcher, boolean hadWarmStart) {
+        StartSurfaceMediator mediator = createStartSurfaceMediatorWithoutInit(
+                mode, excludeMVTiles, showStackTabSwitcher, hadWarmStart);
         mediator.initWithNative(mFakeBoxDelegate,
                 (mode == SurfaceMode.SINGLE_PANE || mode == SurfaceMode.TWO_PANES)
                         ? mFeedSurfaceCreator
@@ -1744,13 +1780,14 @@
         return mediator;
     }
 
-    private StartSurfaceMediator createStartSurfaceMediatorWithoutInit(
-            @SurfaceMode int mode, boolean excludeMVTiles, boolean showStackTabSwitcher) {
+    private StartSurfaceMediator createStartSurfaceMediatorWithoutInit(@SurfaceMode int mode,
+            boolean excludeMVTiles, boolean showStackTabSwitcher, boolean hadWarmStart) {
         StartSurfaceMediator mediator = new StartSurfaceMediator(mMainTabGridController,
                 mTabModelSelector, mode == SurfaceMode.NO_START_SURFACE ? null : mPropertyModel,
                 mode == SurfaceMode.SINGLE_PANE ? mSecondaryTasksSurfaceInitializer : null, mode,
                 ContextUtils.getApplicationContext(), mBrowserControlsStateProvider,
-                mActivityStateChecker, excludeMVTiles, showStackTabSwitcher, mStartSurfaceSupplier);
+                mActivityStateChecker, excludeMVTiles, showStackTabSwitcher, mStartSurfaceSupplier,
+                hadWarmStart);
         return mediator;
     }
 }
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java
index d95d2f2..639157d 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegate.java
@@ -120,12 +120,14 @@
      * @param sheetController A {@link BottomSheetController} to show content in the bottom sheet.
      * @param parentTabSupplier A {@link Supplier} to provide parent tab for
      *         StartSurface.
+     * @param hadWarmStart Whether the activity had a warm start because the native library was
+     *         already fully loaded and initialized
      * @return the {@link StartSurface}
      */
     StartSurface createStartSurface(ChromeActivity activity, ScrimCoordinator scrimCoordinator,
             BottomSheetController sheetController,
             OneshotSupplierImpl<StartSurface> startSurfaceOneshotSupplier,
-            Supplier<Tab> parentTabSupplier);
+            Supplier<Tab> parentTabSupplier, boolean hadWarmStart);
 
     /**
      * Create a {@link TabGroupModelFilter} for the given {@link TabModel}.
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java
index 2f6cbee..e8f96f4c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementDelegateImpl.java
@@ -101,9 +101,9 @@
     public StartSurface createStartSurface(ChromeActivity activity,
             ScrimCoordinator scrimCoordinator, BottomSheetController sheetController,
             OneshotSupplierImpl<StartSurface> startSurfaceOneshotSupplier,
-            Supplier<Tab> parentTabSupplier) {
+            Supplier<Tab> parentTabSupplier, boolean hadWarmStart) {
         return StartSurfaceDelegate.createStartSurface(activity, scrimCoordinator, sheetController,
-                startSurfaceOneshotSupplier, parentTabSupplier);
+                startSurfaceOneshotSupplier, parentTabSupplier, hadWarmStart);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index 3ff9001..07ee1f46 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -570,7 +570,7 @@
                     StartSurface startSurface = tabManagementDelegate.createStartSurface(this,
                             mRootUiCoordinator.getScrimCoordinator(),
                             mRootUiCoordinator.getBottomSheetController(), mStartSurfaceSupplier,
-                            mStartSurfaceParentTabSupplier);
+                            mStartSurfaceParentTabSupplier, hadWarmStart());
                 }
             }
             mLayoutManager = new LayoutManagerChromePhone(compositorViewHolder, mContentContainer,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java b/chrome/android/java/src/org/chromium/chrome/browser/app/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java
index 6b74e356..243642d0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/tab_activity_glue/ActivityTabWebContentsDelegateAndroid.java
@@ -98,7 +98,7 @@
     }
 
     @Override
-    protected int getDisplayMode() {
+    public int getDisplayMode() {
         return WebDisplayMode.BROWSER;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java
index e5d315b..92b7d31 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/app/video_tutorials/NewTabPageVideoIPHManager.java
@@ -117,8 +117,8 @@
         String summaryCardImageUrl = ChromeFeatureList.getFieldTrialParamByFeature(
                 ChromeFeatureList.VIDEO_TUTORIALS, VARIATION_SUMMARY_CARD_POSTER_URL);
         Tutorial summary = new Tutorial(FeatureType.SUMMARY,
-                mContext.getString(R.string.video_tutorials_card_all_videos), null,
-                summaryCardImageUrl, null, null, 0);
+                mContext.getString(R.string.video_tutorials_card_all_videos), null, null,
+                summaryCardImageUrl, summaryCardImageUrl, null, null, 0);
         tutorials.add(summary);
     }
 
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 3821ce3..2a794a2 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
@@ -316,7 +316,7 @@
         }
 
         @Override
-        protected @WebDisplayMode int getDisplayMode() {
+        public @WebDisplayMode int getDisplayMode() {
             return mDisplayMode;
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
index ffdf0de..444b4510 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarCoordinator.java
@@ -21,6 +21,7 @@
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.Destroyable;
 import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
+import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.ntp.FakeboxDelegate;
 import org.chromium.chrome.browser.omnibox.status.StatusCoordinator;
 import org.chromium.chrome.browser.omnibox.status.StatusView;
@@ -116,8 +117,11 @@
         View urlBar = mLocationBarLayout.findViewById(R.id.url_bar);
         OneshotSupplierImpl<AssistantVoiceSearchService> assistantVoiceSearchSupplier =
                 new OneshotSupplierImpl();
-        mLocationBarMediator = new LocationBarMediator(
-                mLocationBarLayout, locationBarDataProvider, assistantVoiceSearchSupplier);
+        // TODO(crbug.com/1151513): Inject LocaleManager instance to LocationBarCoordinator instead
+        // of using the singleton.
+        mLocationBarMediator = new LocationBarMediator(mLocationBarLayout, locationBarDataProvider,
+                assistantVoiceSearchSupplier, overrideUrlLoadingDelegate,
+                LocaleManager.getInstance());
         mUrlCoordinator = new UrlBarCoordinator((UrlBar) urlBar, windowDelegate, actionModeCallback,
                 mCallbackController.makeCancelable(mLocationBarMediator::onUrlFocusChange),
                 mLocationBarMediator);
@@ -143,8 +147,7 @@
         mLocationBarLayout.addUrlFocusChangeListener(mAutocompleteCoordinator);
         mLocationBarLayout.initialize(mAutocompleteCoordinator, mUrlCoordinator, mStatusCoordinator,
                 locationBarDataProvider, profileObservableSupplier, windowDelegate, windowAndroid,
-                overrideUrlLoadingDelegate, mLocationBarMediator.getVoiceRecognitionHandler(),
-                assistantVoiceSearchSupplier);
+                mLocationBarMediator.getVoiceRecognitionHandler(), assistantVoiceSearchSupplier);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
index 41f8b688..224be0d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarLayout.java
@@ -42,9 +42,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.WindowDelegate;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
-import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.native_page.NativePageFactory;
-import org.chromium.chrome.browser.ntp.NewTabPageUma;
 import org.chromium.chrome.browser.omnibox.UrlBar.ScrollType;
 import org.chromium.chrome.browser.omnibox.UrlBarCoordinator.SelectionState;
 import org.chromium.chrome.browser.omnibox.geo.GeolocationHeader;
@@ -65,15 +63,11 @@
 import org.chromium.components.search_engines.TemplateUrl;
 import org.chromium.components.search_engines.TemplateUrlService;
 import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
-import org.chromium.content_public.browser.LoadUrlParams;
-import org.chromium.content_public.common.ResourceRequestBody;
 import org.chromium.ui.KeyboardVisibilityDelegate;
-import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.util.ColorUtils;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -129,7 +123,6 @@
     private Callback<Profile> mProfileSupplierObserver;
     private CallbackController mCallbackController = new CallbackController();
     private TemplateUrlServiceObserver mTemplateUrlObserver;
-    private OverrideUrlLoadingDelegate mOverrideUrlLoadingDelegate;
 
     /**
      * Class to handle input from a hardware keyboard when the focus is on the URL bar. In
@@ -276,7 +269,6 @@
             @NonNull LocationBarDataProvider locationBarDataProvider,
             @NonNull ObservableSupplier<Profile> profileSupplier,
             @NonNull WindowDelegate windowDelegate, @NonNull WindowAndroid windowAndroid,
-            @NonNull OverrideUrlLoadingDelegate overrideUrlLoadingDelegate,
             @NonNull VoiceRecognitionHandler voiceRecognitionHandler,
             @NonNull OneshotSupplier<AssistantVoiceSearchService> assistantVoiceSearchSupplier) {
         mAutocompleteCoordinator = autocompleteCoordinator;
@@ -285,7 +277,6 @@
         mWindowDelegate = windowDelegate;
         mWindowAndroid = windowAndroid;
         mLocationBarDataProvider = locationBarDataProvider;
-        mOverrideUrlLoadingDelegate = overrideUrlLoadingDelegate;
         mVoiceRecognitionHandler = voiceRecognitionHandler;
         mAssistantVoiceSearchServiceSupplier = assistantVoiceSearchSupplier;
 
@@ -442,18 +433,6 @@
         // When we restore tabs, we focus the selected tab so the URL of the page shows.
     }
 
-    public void performSearchQuery(String query, List<String> searchParams) {
-        if (TextUtils.isEmpty(query)) return;
-
-        String queryUrl = TemplateUrlServiceFactory.get().getUrlForSearchQuery(query, searchParams);
-
-        if (!TextUtils.isEmpty(queryUrl)) {
-            loadUrl(queryUrl, PageTransition.GENERATED, 0);
-        } else {
-            setSearchQuery(query);
-        }
-    }
-
     /**
      * Sets the query string in the omnibox (ensuring the URL bar has focus and triggering
      * autocomplete for the specified query) as if the user typed it.
@@ -506,7 +485,6 @@
         setUrlBarFocus(false, null, OmniboxFocusReason.UNFOCUS);
         // Revert the URL to match the current page.
         setUrl(mLocationBarDataProvider.getCurrentUrl());
-        focusCurrentTab();
     }
 
     public void gestureDetected(boolean isLongPress) {
@@ -711,78 +689,6 @@
         updateButtonVisibility();
     }
 
-    /* package */ void loadUrlFromVoice(String url) {
-        loadUrl(url, PageTransition.TYPED, 0);
-    }
-
-    /**
-     * Load the url given with the given transition. Exposed for child classes to overwrite as
-     * necessary.
-     */
-    /* package */ void loadUrl(String url, @PageTransition int transition, long inputStart) {
-        loadUrlWithPostData(url, transition, inputStart, null, null);
-    }
-
-    protected void loadUrlWithPostData(String url, @PageTransition int transition, long inputStart,
-            @Nullable String postDataType, @Nullable byte[] postData) {
-        Tab currentTab = getCurrentTab();
-
-        // The code of the rest of this class ensures that this can't be called until the native
-        // side is initialized
-        assert mNativeInitialized : "Loading URL before native side initialized";
-
-        // TODO(crbug.com/1085812): Should be taking a full loaded LoadUrlParams.
-        if (mOverrideUrlLoadingDelegate.willHandleLoadUrlWithPostData(url, transition, postDataType,
-                    postData, mLocationBarDataProvider.isIncognito())) {
-            return;
-        }
-
-        if (currentTab != null
-                && (currentTab.isNativePage()
-                        || UrlUtilities.isNTPUrl(currentTab.getUrlString()))) {
-            NewTabPageUma.recordOmniboxNavigation(url, transition);
-            // Passing in an empty string should not do anything unless the user is at the NTP.
-            // Since the NTP has no url, pressing enter while clicking on the URL bar should refresh
-            // the page as it does when you click and press enter on any other site.
-            if (url.isEmpty()) url = currentTab.getUrlString();
-        }
-
-        // Loads the |url| in a new tab or the current ContentView and gives focus to the
-        // ContentView.
-        if (currentTab != null && !url.isEmpty()) {
-            LoadUrlParams loadUrlParams = new LoadUrlParams(url);
-            loadUrlParams.setVerbatimHeaders(GeolocationHeader.getGeoHeader(url, currentTab));
-            loadUrlParams.setTransitionType(transition | PageTransition.FROM_ADDRESS_BAR);
-            if (inputStart != 0) {
-                loadUrlParams.setInputStartTimestamp(inputStart);
-            }
-
-            if (!TextUtils.isEmpty(postDataType)) {
-                StringBuilder headers = new StringBuilder();
-                String prevHeader = loadUrlParams.getVerbatimHeaders();
-                if (prevHeader != null && !prevHeader.isEmpty()) {
-                    headers.append(prevHeader);
-                    headers.append("\r\n");
-                }
-                loadUrlParams.setExtraHeaders(new HashMap<String, String>() {
-                    { put("Content-Type", postDataType); }
-                });
-                headers.append(loadUrlParams.getExtraHttpRequestHeadersString());
-                loadUrlParams.setVerbatimHeaders(headers.toString());
-            }
-
-            if (postData != null && postData.length != 0) {
-                loadUrlParams.setPostData(ResourceRequestBody.createFromBytes(postData));
-            }
-
-            currentTab.loadUrl(loadUrlParams);
-            RecordUserAction.record("MobileOmniboxUse");
-        }
-        LocaleManager.getInstance().recordLocaleBasedSearchMetrics(false, url, transition);
-
-        focusCurrentTab();
-    }
-
     /**
      * @param focusable Whether the url bar should be focusable.
      */
@@ -859,14 +765,6 @@
                 SearchEngineLogoUtils.shouldShowSearchEngineLogo(profile.isOffTheRecord()));
     }
 
-    /** Focuses the current page. */
-    private void focusCurrentTab() {
-        if (mLocationBarDataProvider.hasTab()) {
-            View view = getCurrentTab().getView();
-            if (view != null) view.requestFocus();
-        }
-    }
-
     /**
      * @return Whether the URL focus change is taking place, e.g. a focus animation is running on
      *         a phone device.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
index 18887f6..2ef28a57 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarMediator.java
@@ -5,24 +5,35 @@
 package org.chromium.chrome.browser.omnibox;
 
 import android.content.Context;
+import android.text.TextUtils;
 import android.view.View;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.chrome.browser.AppHooks;
 import org.chromium.chrome.browser.gsa.GSAState;
+import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.ntp.FakeboxDelegate;
+import org.chromium.chrome.browser.ntp.NewTabPageUma;
 import org.chromium.chrome.browser.omnibox.UrlBar.UrlBarDelegate;
+import org.chromium.chrome.browser.omnibox.geo.GeolocationHeader;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteCoordinator;
 import org.chromium.chrome.browser.omnibox.suggestions.AutocompleteDelegate;
 import org.chromium.chrome.browser.omnibox.voice.AssistantVoiceSearchService;
 import org.chromium.chrome.browser.omnibox.voice.VoiceRecognitionHandler;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.components.embedder_support.util.UrlUtilities;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.content_public.common.ResourceRequestBody;
+import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
 
+import java.util.HashMap;
 import java.util.List;
 
 /**
@@ -33,19 +44,29 @@
                                      AutocompleteDelegate, FakeboxDelegate,
                                      VoiceRecognitionHandler.Delegate,
                                      AssistantVoiceSearchService.Observer, UrlBarDelegate {
+    private final OverrideUrlLoadingDelegate mOverrideUrlLoadingDelegate;
+    private final LocaleManager mLocaleManager;
+
     private LocationBarLayout mLocationBarLayout;
     private VoiceRecognitionHandler mVoiceRecognitionHandler;
     private LocationBarDataProvider mLocationBarDataProvider;
     private AssistantVoiceSearchService mAssistantVoiceSearchService;
     private OneshotSupplierImpl<AssistantVoiceSearchService> mAssistantVoiceSearchSupplier;
+    private boolean mNativeInitialized;
 
     /*package */ LocationBarMediator(@NonNull LocationBarLayout locationBarLayout,
             @NonNull LocationBarDataProvider locationBarDataProvider,
-            @NonNull OneshotSupplierImpl<AssistantVoiceSearchService>
-                    assistantVoiceSearchSupplier) {
+            @NonNull OneshotSupplierImpl<AssistantVoiceSearchService> assistantVoiceSearchSupplier,
+            @NonNull OverrideUrlLoadingDelegate overrideUrlLoadingDelegate,
+            @NonNull LocaleManager localeManager) {
         mLocationBarLayout = locationBarLayout;
+        mOverrideUrlLoadingDelegate = overrideUrlLoadingDelegate;
+        mLocaleManager = localeManager;
+        mNativeInitialized = false;
+
         mLocationBarDataProvider = locationBarDataProvider;
         mLocationBarDataProvider.addObserver(this);
+
         mAssistantVoiceSearchSupplier = assistantVoiceSearchSupplier;
         mVoiceRecognitionHandler = new VoiceRecognitionHandler(this, mAssistantVoiceSearchSupplier);
     }
@@ -55,6 +76,7 @@
     }
 
     /*package */ void onFinishNativeInitialization() {
+        mNativeInitialized = true;
         Context context = mLocationBarLayout.getContext();
         mAssistantVoiceSearchService = new AssistantVoiceSearchService(context,
                 AppHooks.get().getExternalAuthUtils(), TemplateUrlServiceFactory.get(),
@@ -77,6 +99,16 @@
         mLocationBarLayout.setVoiceRecognitionHandlerForTesting(voiceRecognitionHandler);
     }
 
+    // Private methods
+
+    private void focusCurrentTab() {
+        assert mLocationBarDataProvider != null;
+        if (mLocationBarDataProvider.hasTab()) {
+            View view = mLocationBarDataProvider.getTab().getView();
+            if (view != null) view.requestFocus();
+        }
+    }
+
     // LocationBarData.Observer implementation
 
     @Override
@@ -165,7 +197,15 @@
 
     @Override
     public void performSearchQuery(String query, List<String> searchParams) {
-        mLocationBarLayout.performSearchQuery(query, searchParams);
+        if (TextUtils.isEmpty(query)) return;
+
+        String queryUrl = TemplateUrlServiceFactory.get().getUrlForSearchQuery(query, searchParams);
+
+        if (!TextUtils.isEmpty(queryUrl)) {
+            loadUrl(queryUrl, PageTransition.GENERATED, 0);
+        } else {
+            mLocationBarLayout.setSearchQuery(query);
+        }
     }
 
     @Override
@@ -216,14 +256,70 @@
     }
 
     @Override
-    public void loadUrl(String url, int transition, long inputStart) {
-        mLocationBarLayout.loadUrl(url, transition, inputStart);
+    public void loadUrl(String url, @PageTransition int transition, long inputStart) {
+        loadUrlWithPostData(url, transition, inputStart, null, null);
     }
 
     @Override
     public void loadUrlWithPostData(
             String url, int transition, long inputStart, String postDataType, byte[] postData) {
-        mLocationBarLayout.loadUrlWithPostData(url, transition, inputStart, postDataType, postData);
+        assert mLocationBarDataProvider != null;
+        Tab currentTab = mLocationBarDataProvider.getTab();
+
+        // The code of the rest of this class ensures that this can't be called until the native
+        // side is initialized
+        assert mNativeInitialized : "Loading URL before native side initialized";
+
+        // TODO(crbug.com/1085812): Should be taking a full loaded LoadUrlParams.
+        if (mOverrideUrlLoadingDelegate.willHandleLoadUrlWithPostData(url, transition, postDataType,
+                    postData, mLocationBarDataProvider.isIncognito())) {
+            return;
+        }
+
+        if (currentTab != null
+                && (currentTab.isNativePage()
+                        || UrlUtilities.isNTPUrl(currentTab.getUrlString()))) {
+            NewTabPageUma.recordOmniboxNavigation(url, transition);
+            // Passing in an empty string should not do anything unless the user is at the NTP.
+            // Since the NTP has no url, pressing enter while clicking on the URL bar should refresh
+            // the page as it does when you click and press enter on any other site.
+            if (url.isEmpty()) url = currentTab.getUrlString();
+        }
+
+        // Loads the |url| in a new tab or the current ContentView and gives focus to the
+        // ContentView.
+        if (currentTab != null && !url.isEmpty()) {
+            LoadUrlParams loadUrlParams = new LoadUrlParams(url);
+            loadUrlParams.setVerbatimHeaders(GeolocationHeader.getGeoHeader(url, currentTab));
+            loadUrlParams.setTransitionType(transition | PageTransition.FROM_ADDRESS_BAR);
+            if (inputStart != 0) {
+                loadUrlParams.setInputStartTimestamp(inputStart);
+            }
+
+            if (!TextUtils.isEmpty(postDataType)) {
+                StringBuilder headers = new StringBuilder();
+                String prevHeader = loadUrlParams.getVerbatimHeaders();
+                if (prevHeader != null && !prevHeader.isEmpty()) {
+                    headers.append(prevHeader);
+                    headers.append("\r\n");
+                }
+                loadUrlParams.setExtraHeaders(new HashMap<String, String>() {
+                    { put("Content-Type", postDataType); }
+                });
+                headers.append(loadUrlParams.getExtraHttpRequestHeadersString());
+                loadUrlParams.setVerbatimHeaders(headers.toString());
+            }
+
+            if (postData != null && postData.length != 0) {
+                loadUrlParams.setPostData(ResourceRequestBody.createFromBytes(postData));
+            }
+
+            currentTab.loadUrl(loadUrlParams);
+            RecordUserAction.record("MobileOmniboxUse");
+        }
+        mLocaleManager.recordLocaleBasedSearchMetrics(false, url, transition);
+
+        focusCurrentTab();
     }
 
     @Override
@@ -262,7 +358,7 @@
 
     @Override
     public void loadUrlFromVoice(String url) {
-        mLocationBarLayout.loadUrlFromVoice(url);
+        loadUrl(url, PageTransition.TYPED, 0);
     }
 
     @Override
@@ -312,6 +408,7 @@
     @Override
     public void backKeyPressed() {
         mLocationBarLayout.backKeyPressed();
+        focusCurrentTab();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
index a251949..a07d5c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/LocationBarTablet.java
@@ -122,12 +122,11 @@
             @NonNull LocationBarDataProvider locationBarDataProvider,
             @NonNull ObservableSupplier<Profile> profileSupplier,
             @NonNull WindowDelegate windowDelegate, @NonNull WindowAndroid windowAndroid,
-            @NonNull OverrideUrlLoadingDelegate overrideUrlLoadingDelegate,
             @NonNull VoiceRecognitionHandler voiceRecognitionHandler,
             @NonNull OneshotSupplier<AssistantVoiceSearchService> assistantVoiceSearchSupplier) {
         super.initialize(autocompleteCoordinator, urlCoordinator, statusCoordinator,
                 locationBarDataProvider, profileSupplier, windowDelegate, windowAndroid,
-                overrideUrlLoadingDelegate, voiceRecognitionHandler, assistantVoiceSearchSupplier);
+                voiceRecognitionHandler, assistantVoiceSearchSupplier);
         mStatusCoordinator.setShowIconsWhenUrlFocused(true);
         if (SearchEngineLogoUtils.shouldShowSearchEngineLogo(
                     mLocationBarDataProvider.isIncognito())) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
index 175f4f57..1f38b8a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivity.java
@@ -107,6 +107,7 @@
 
     /** Input submitted before before the native library was loaded. */
     private String mQueuedUrl;
+    private @PageTransition int mQueuedTransition;
     private String mQueuedPostDataType;
     private byte[] mQueuedPostData;
 
@@ -176,7 +177,10 @@
                 /*shareDelegateSupplier=*/null, /*incognitoStateProvider=*/null,
                 getLifecycleDispatcher(), /*overrideUrlLoadingDelegate=*/
                 (String url, @PageTransition int transition, String postDataType, byte[] postData,
-                        boolean incognito) -> false);
+                        boolean incognito) -> {
+                    loadUrl(url, transition, postDataType, postData);
+                    return true;
+                });
 
         // Kick off everything needed for the user to type into the box.
         beginQuery();
@@ -202,7 +206,7 @@
             public TabWebContentsDelegateAndroid createWebContentsDelegate(Tab tab) {
                 return new TabWebContentsDelegateAndroid() {
                     @Override
-                    protected int getDisplayMode() {
+                    public int getDisplayMode() {
                         return WebDisplayMode.BROWSER;
                     }
 
@@ -292,7 +296,9 @@
         assert !mIsActivityUsable
                 : "finishDeferredInitialization() incorrectly called multiple times";
         mIsActivityUsable = true;
-        if (mQueuedUrl != null) loadUrl(mQueuedUrl, mQueuedPostDataType, mQueuedPostData);
+        if (mQueuedUrl != null) {
+            loadUrl(mQueuedUrl, mQueuedTransition, mQueuedPostDataType, mQueuedPostData);
+        }
 
         // TODO(tedchoc): Warmup triggers the CustomTab layout to be inflated, but this widget
         //                will navigate to Tabbed mode.  Investigate whether this can inflate
@@ -345,11 +351,12 @@
         return true;
     }
 
-    @Override
-    public void loadUrl(String url, @Nullable String postDataType, @Nullable byte[] postData) {
+    /* package */ void loadUrl(String url, @PageTransition int transition,
+            @Nullable String postDataType, @Nullable byte[] postData) {
         // Wait until native has loaded.
         if (!mIsActivityUsable) {
             mQueuedUrl = url;
+            mQueuedTransition = transition;
             mQueuedPostDataType = postDataType;
             mQueuedPostData = postData;
             return;
@@ -363,6 +370,7 @@
                         .makeCustomAnimation(this, android.R.anim.fade_in, android.R.anim.fade_out)
                         .toBundle());
         RecordUserAction.record("SearchWidget.SearchMade");
+        LocaleManager.getInstance().recordLocaleBasedSearchMetrics(true, url, transition);
         finish();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
index 1edb1fb..f66e95aa 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/searchwidget/SearchActivityLocationBarLayout.java
@@ -21,7 +21,6 @@
 import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.omnibox.LocationBarDataProvider;
 import org.chromium.chrome.browser.omnibox.LocationBarLayout;
-import org.chromium.chrome.browser.omnibox.OverrideUrlLoadingDelegate;
 import org.chromium.chrome.browser.omnibox.UrlBar;
 import org.chromium.chrome.browser.omnibox.UrlBarCoordinator;
 import org.chromium.chrome.browser.omnibox.UrlBarCoordinator.SelectionState;
@@ -38,9 +37,6 @@
 public class SearchActivityLocationBarLayout extends LocationBarLayout {
     /** Delegates calls out to the containing Activity. */
     public static interface Delegate {
-        /** Load a URL in the associated tab. */
-        void loadUrl(String url, @Nullable String postDataType, @Nullable byte[] postData);
-
         /** The user hit the back button. */
         void backKeyPressed();
     }
@@ -69,14 +65,12 @@
             @NonNull LocationBarDataProvider locationBarDataProvider,
             @NonNull ObservableSupplier<Profile> profileSupplier,
             @NonNull WindowDelegate windowDelegate, @NonNull WindowAndroid windowAndroid,
-            @NonNull OverrideUrlLoadingDelegate overrideUrlLoadingDelegate,
             @NonNull VoiceRecognitionHandler voiceRecognitionHandler,
             @NonNull OneshotSupplier<AssistantVoiceSearchService>
                     assistantVoiceSearchServiceSupplier) {
         super.initialize(autocompleteCoordinator, urlCoordinator, statusCoordinator,
                 locationBarDataProvider, profileSupplier, windowDelegate, windowAndroid,
-                overrideUrlLoadingDelegate, voiceRecognitionHandler,
-                assistantVoiceSearchServiceSupplier);
+                voiceRecognitionHandler, assistantVoiceSearchServiceSupplier);
         setUrlBarFocusable(true);
         mPendingSearchPromoDecision = LocaleManager.getInstance().needToCheckForSearchEnginePromo();
         getAutocompleteCoordinator().setShouldPreventOmniboxAutocomplete(
@@ -84,13 +78,6 @@
     }
 
     @Override
-    protected void loadUrlWithPostData(String url, int transition, long inputStart,
-            @Nullable String postDataType, @Nullable byte[] postData) {
-        mDelegate.loadUrl(url, postDataType, postData);
-        LocaleManager.getInstance().recordLocaleBasedSearchMetrics(true, url, transition);
-    }
-
-    @Override
     public void backKeyPressed() {
         mDelegate.backKeyPressed();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java
index f6bec45..3bad967 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroidImpl.java
@@ -87,9 +87,8 @@
         findMatchRectsDetails.rects[index] = rect;
     }
 
-    @CalledByNative
     @Override
-    protected int getDisplayMode() {
+    public int getDisplayMode() {
         return mDelegate.getDisplayMode();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
index 2d53db6..55cc509 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -130,10 +130,10 @@
 
     @Override
     public boolean hasTab() {
-        // TODO(dtrainor, tedchoc): Remove the isInitialized() check when we no longer wait for
-        // TAB_CLOSED events to remove this tab.  Otherwise there is a chance we use this tab after
-        // {@link ChromeTab#destroy()} is called.
-        return mTab != null && mTab.isInitialized();
+        // TODO(https://crbug.com/1147131): Remove the isInitialized() and isDestroyed checks when
+        // we no longer wait for TAB_CLOSED events to remove this tab.  Otherwise there is a chance
+        // we use this tab after {@link Tab#destroy()} is called.
+        return mTab != null && mTab.isInitialized() && !mTab.isDestroyed();
     }
 
     @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java
index 279eb8d3..d2e0260 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/CopylessPasteTest.java
@@ -15,7 +15,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
@@ -72,7 +71,6 @@
     @After
     public void tearDown() throws Exception {
         AppIndexingUtil.setCallbackForTesting(null);
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
     }
 
     private static class CopylessHelper extends CallbackHelper {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java
index cee2800..723653c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/MainActivityWithURLTest.java
@@ -8,13 +8,11 @@
 
 import androidx.test.filters.SmallTest;
 
-import org.junit.After;
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Feature;
@@ -36,11 +34,6 @@
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
-    @After
-    public void tearDown() throws Exception {
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
-    }
-
     /**
      * Verify launch the activity with URL.
      */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java
index 2d586b71..8640a48 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoDismissTest.java
@@ -11,8 +11,11 @@
 import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
 import static androidx.test.espresso.matcher.ViewMatchers.withId;
 
+import static org.hamcrest.CoreMatchers.allOf;
 import static org.junit.Assert.assertEquals;
 
+import static org.chromium.chrome.test.util.ViewUtils.onViewWaiting;
+
 import android.support.test.InstrumentationRegistry;
 
 import androidx.test.filters.MediumTest;
@@ -81,7 +84,7 @@
     @MediumTest
     public void testPromoNotShownAfterBeingDismissed() {
         mBookmarkTestRule.showBookmarkManager(mSyncTestRule.getActivity());
-        onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
+        onViewWaiting(allOf(withId(R.id.signin_promo_view_container), isDisplayed()));
         onView(withId(R.id.signin_promo_close_button)).perform(click());
         onView(withId(R.id.signin_promo_view_container)).check(doesNotExist());
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
index 645fad0..733c40d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java
@@ -204,8 +204,9 @@
     }
 
     @After
-    public void tearDown() {
+    public void tearDown() throws Exception {
         if (mTestServer != null) mTestServer.stopAndDestroyServer();
+        if (mBookmarkActivity != null) ApplicationTestUtils.finishActivity(mBookmarkActivity);
     }
 
     @AfterClass
@@ -283,7 +284,7 @@
         // Click the star button again to launch the edit activity.
         MenuUtils.invokeCustomMenuActionSync(InstrumentationRegistry.getInstrumentation(),
                 mActivityTestRule.getActivity(), R.id.bookmark_this_page_id);
-        waitForEditActivity();
+        waitForEditActivity().finish();
     }
 
     @Test
@@ -314,8 +315,9 @@
             currentSnackbar.getController().onAction(null);
         });
 
-        waitForEditActivity();
+        BookmarkEditActivity activity = waitForEditActivity();
         SnackbarManager.setDurationForTesting(0);
+        activity.finish();
     }
 
     @Test
@@ -1731,12 +1733,13 @@
         RecyclerViewTestUtils.waitForStableRecyclerView(mItemsContainer);
     }
 
-    private void waitForEditActivity() {
+    private BookmarkEditActivity waitForEditActivity() {
         CriteriaHelper.pollUiThread(() -> {
             Criteria.checkThat(ApplicationStatus.getLastTrackedFocusedActivity(),
                     IsInstanceOf.instanceOf(BookmarkEditActivity.class));
         });
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        return (BookmarkEditActivity) ApplicationStatus.getLastTrackedFocusedActivity();
     }
 
     private ChromeTabbedActivity waitForTabbedActivity() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java
index 6fc157e..c6d9b533 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/browsing_data/ClearBrowsingDataFragmentBasicTest.java
@@ -17,6 +17,7 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
@@ -44,14 +45,18 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class ClearBrowsingDataFragmentBasicTest {
-    @Rule
     public final ChromeTabbedActivityTestRule mActivityTestRule =
             new ChromeTabbedActivityTestRule();
-    @Rule
     public final SettingsActivityTestRule<ClearBrowsingDataFragmentBasic>
             mSettingsActivityTestRule =
                     new SettingsActivityTestRule<>(ClearBrowsingDataFragmentBasic.class);
 
+    // SettingsActivity has to be finished before the outer CTA can be finished or trying to finish
+    // CTA won't work.
+    @Rule
+    public final RuleChain mRuleChain =
+            RuleChain.outerRule(mActivityTestRule).around(mSettingsActivityTestRule);
+
     @Rule
     public final AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
index 8101eec..96b2323a 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -707,7 +707,7 @@
         IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW);
         filter.addDataScheme(Uri.parse(mTestServer.getURL("/")).getScheme());
         final ActivityMonitor monitor =
-                InstrumentationRegistry.getInstrumentation().addMonitor(filter, null, false);
+                InstrumentationRegistry.getInstrumentation().addMonitor(filter, null, true);
         openAppMenuAndAssertMenuShown();
         PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, () -> {
             MenuItem item =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java
index ff48c21..e832ecf 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java
@@ -4,29 +4,20 @@
 
 package org.chromium.chrome.browser.customtabs;
 
-import android.app.Activity;
 import android.content.Intent;
-import android.support.test.InstrumentationRegistry;
 
-import org.hamcrest.Matchers;
+import androidx.annotation.NonNull;
+
 import org.junit.Assert;
 
-import org.chromium.base.ApplicationStatus;
 import org.chromium.base.FeatureList;
-import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.base.test.util.Criteria;
-import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.ScalableTimeout;
-import org.chromium.chrome.browser.DeferredStartupHandler;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
-import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabTestUtils;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 
 import java.util.Collections;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
 
 /**
  * Custom ActivityTestRule for all instrumentation tests that require a {@link CustomTabActivity}.
@@ -54,29 +45,13 @@
     }
 
     @Override
-    public void startActivityCompletely(Intent intent) {
+    public void launchActivity(@NonNull Intent intent) {
         if (!FeatureList.hasTestFeatures()) {
             FeatureList.setTestFeatures(
                     Collections.singletonMap(ChromeFeatureList.SHARE_BY_DEFAULT_IN_CCT, true));
         }
         putCustomTabIdInIntent(intent);
-        int currentIntentId = getCustomTabIdFromIntent(intent);
-
-        Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
-        Assert.assertNotNull("Main activity did not start", activity);
-        CriteriaHelper.pollUiThread(() -> {
-            for (Activity runningActivity : ApplicationStatus.getRunningActivities()) {
-                if (runningActivity instanceof CustomTabActivity) {
-                    CustomTabActivity customTabActivity = (CustomTabActivity) runningActivity;
-                    final int customTabIdInActivity =
-                            getCustomTabIdFromIntent(customTabActivity.getIntent());
-                    if (currentIntentId != customTabIdInActivity) continue;
-                    setActivity(customTabActivity);
-                    return true;
-                }
-            }
-            return false;
-        });
+        super.launchActivity(intent);
     }
 
     /**
@@ -84,33 +59,8 @@
      * initialized.
      */
     public void startCustomTabActivityWithIntent(Intent intent) {
-        DeferredStartupHandler.setExpectingActivityStartupForTesting();
         startActivityCompletely(intent);
-        waitForActivityNativeInitializationComplete();
-        CriteriaHelper.pollUiThread(() -> {
-            Criteria.checkThat(getActivity().getActivityTab(), Matchers.notNullValue());
-        });
         final Tab tab = getActivity().getActivityTab();
-        final CallbackHelper pageLoadFinishedHelper = new CallbackHelper();
-        tab.addObserver(new EmptyTabObserver() {
-            @Override
-            public void onLoadStopped(Tab tab, boolean toDifferentDocument) {
-                pageLoadFinishedHelper.notifyCalled();
-            }
-        });
-        try {
-            if (tab.isLoading()) {
-                pageLoadFinishedHelper.waitForCallback(
-                        0, 1, LONG_TIMEOUT_MS, TimeUnit.MILLISECONDS);
-            }
-        } catch (TimeoutException e) {
-            Assert.fail();
-        }
-        Assert.assertTrue("Deferred startup never completed",
-                DeferredStartupHandler.waitForDeferredStartupCompleteForTesting(
-                        STARTUP_TIMEOUT_MS));
-        Assert.assertNotNull(tab);
-        Assert.assertNotNull(tab.getView());
         Assert.assertTrue(TabTestUtils.isCustomTab(tab));
     }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java
index 576b546..1216b15 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabFromChromeExternalNavigationTest.java
@@ -111,8 +111,7 @@
     @Test
     @Feature("CustomTabFromChrome")
     @LargeTest
-    public void
-    testIntentWithRedirectToApp() {
+    public void testIntentWithRedirectToApp() {
         final String redirectUrl = "https://maps.google.com/maps?q=1600+amphitheatre+parkway";
         final String initialUrl =
                 mServerRule.getServer().getURL("/chrome/test/data/android/redirect/js_redirect.html"
@@ -123,7 +122,7 @@
                         + Base64.encodeToString(
                                 ApiCompatibilityUtils.getBytesUtf8(redirectUrl), Base64.URL_SAFE));
 
-        mActivityRule.startActivityCompletely(getCustomTabFromChromeIntent(initialUrl, true));
+        mActivityRule.launchActivity(getCustomTabFromChromeIntent(initialUrl, true));
         mActivityRule.waitForActivityNativeInitializationComplete();
 
         final AtomicReference<InterceptNavigationDelegateImpl> navigationDelegate =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java
index 0899713..af9727f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/display_cutout/DisplayCutoutTest.java
@@ -9,12 +9,10 @@
 
 import androidx.test.filters.LargeTest;
 
-import org.junit.After;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.MinAndroidSdkLevel;
@@ -37,11 +35,6 @@
     public DisplayCutoutTestRule mTestRule =
             new DisplayCutoutTestRule<ChromeActivity>(ChromeActivity.class);
 
-    @After
-    public void tearDown() throws Exception {
-        ApplicationTestUtils.finishActivity(mTestRule.getActivity());
-    }
-
     /**
      * Test that no safe area is applied when we have viewport fit auto
      */
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
index c505f0f..ed52c68d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
@@ -13,6 +13,7 @@
 import android.net.Uri;
 import android.os.SystemClock;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.lifecycle.Stage;
 import android.text.TextUtils;
 import android.util.Base64;
 
@@ -28,10 +29,14 @@
 import org.junit.runner.RunWith;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.ContextUtils;
+import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.ScalableTimeout;
+import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
@@ -424,24 +429,36 @@
 
     @Test
     @SmallTest
-    public void testRedirectionFromIntent() {
-        // Test cold-start.
+    public void testRedirectionFromIntentCold() throws Exception {
+        Context context = ContextUtils.getApplicationContext();
         Intent intent = new Intent(Intent.ACTION_VIEW,
                 Uri.parse(mTestServer.getURL(NAVIGATION_FROM_JAVA_REDIRECTION_PAGE)));
-        Context targetContext = InstrumentationRegistry.getTargetContext();
-        intent.setClassName(targetContext, ChromeLauncherActivity.class.getName());
+        intent.setClassName(context, ChromeLauncherActivity.class.getName());
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
+
+        ChromeTabbedActivity activity = ApplicationTestUtils.waitForActivityWithClass(
+                ChromeTabbedActivity.class, Stage.CREATED, () -> context.startActivity(intent));
+        mActivityTestRule.setActivity(activity);
+
+        CriteriaHelper.pollUiThread(() -> {
+            Criteria.checkThat(mActivityMonitor.getHits(), Matchers.is(1));
+        }, ScalableTimeout.scaleTimeout(10000L), CriteriaHelper.DEFAULT_POLLING_INTERVAL);
+        ApplicationTestUtils.waitForActivityState(activity, Stage.STOPPED);
+    }
+
+    @Test
+    @SmallTest
+    public void testRedirectionFromIntentWarm() throws Exception {
+        Context context = ContextUtils.getApplicationContext();
+        mActivityTestRule.startMainActivityOnBlankPage();
+        Intent intent = new Intent(Intent.ACTION_VIEW,
+                Uri.parse(mTestServer.getURL(NAVIGATION_FROM_JAVA_REDIRECTION_PAGE)));
+        intent.setClassName(context, ChromeLauncherActivity.class.getName());
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
 
         CriteriaHelper.pollUiThread(
                 () -> Criteria.checkThat(mActivityMonitor.getHits(), Matchers.is(1)));
-
-        // Test warm start.
-        mActivityTestRule.startMainActivityOnBlankPage();
-        targetContext.startActivity(intent);
-
-        CriteriaHelper.pollUiThread(
-                () -> Criteria.checkThat(mActivityMonitor.getHits(), Matchers.is(2)));
     }
 
     @Test
@@ -489,7 +506,6 @@
         String originalUrl = mTestServer.getURL(NAVIGATION_TO_FILE_SCHEME_FROM_INTENT_URI);
         loadUrlAndWaitForIntentUrl(originalUrl, true, false, false, null, false, "null_scheme");
     }
-
     @Test
     @LargeTest
     public void testIntentURIWithEmptySchemeDoesNothing() throws TimeoutException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java
index 7934a16..3579486 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/HomepagePolicyIntegrationTest.java
@@ -16,6 +16,7 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
 import org.chromium.base.ActivityState;
@@ -64,12 +65,16 @@
 
     private EmbeddedTestServer mTestServer;
 
-    @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
-    @Rule
     public SettingsActivityTestRule<HomepageSettings> mSettingsActivityTestRule =
             new SettingsActivityTestRule<>(HomepageSettings.class);
 
+    // SettingsActivity has to be finished before the outer CTA can be finished or trying to finish
+    // CTA won't work.
+    @Rule
+    public final RuleChain mRuleChain =
+            RuleChain.outerRule(mActivityTestRule).around(mSettingsActivityTestRule);
+
     @Rule
     public HomepageTestRule mHomepageTestRule = new HomepageTestRule();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsFragmentTest.java
index 703521dd..a273db8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/homepage/settings/HomepageSettingsFragmentTest.java
@@ -14,6 +14,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UserActionTester;
@@ -104,9 +105,8 @@
         Assert.assertNotNull("Custom URI radio button is null.", mCustomUriRadioButton);
     }
 
-    private void finishSettingsActivity() {
-        mTestRule.getActivity().finish();
-        mTestRule.waitTillActivityIsDestroyed();
+    private void finishSettingsActivity() throws Exception {
+        ApplicationTestUtils.finishActivity(mTestRule.getActivity());
     }
 
     @Test
@@ -394,7 +394,7 @@
     @Test
     @SmallTest
     @Feature({"Homepage"})
-    public void testCheckRadioButtons() {
+    public void testCheckRadioButtons() throws Exception {
         mHomepageTestRule.useCustomizedHomepageForTest(TEST_URL_FOO);
         launchSettingsActivity();
         LocationChangedCounter counter = new LocationChangedCounter();
@@ -446,7 +446,7 @@
     @Test
     @SmallTest
     @Feature({"Homepage"})
-    public void testChangeCustomized() {
+    public void testChangeCustomized() throws Exception {
         mHomepageTestRule.useChromeNTPForTest();
         launchSettingsActivity();
         LocationChangedCounter actionCounter = new LocationChangedCounter();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java
index 5c0af74..98254843 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/metrics/StartupLoadingMetricsTest.java
@@ -218,7 +218,7 @@
             // mSlowPage will hang for 2 seconds before sending a response. It should be enough to
             // put Chrome in background before the page is committed.
             mTabbedActivityTestRule.prepareUrlIntent(intent, mSlowPage);
-            mTabbedActivityTestRule.startActivityCompletely(intent);
+            mTabbedActivityTestRule.launchActivity(intent);
 
             // Put Chrome in background before the page is committed.
             ChromeApplicationTestUtils.fireHomeScreenIntent(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java
index cdbf6b55..8c2cbab 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/offlinepages/indicator/OfflineIndicatorControllerTest.java
@@ -250,6 +250,7 @@
 
         // Offline indicator should not be shown.
         checkOfflineIndicatorVisibility(downloadActivity, false);
+        downloadActivity.finish();
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchConsentUiTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchConsentUiTest.java
index 4485b232..012b466 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchConsentUiTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/voice/AssistantVoiceSearchConsentUiTest.java
@@ -13,6 +13,8 @@
 
 import static org.chromium.chrome.browser.preferences.ChromePreferenceKeys.ASSISTANT_VOICE_SEARCH_ENABLED;
 
+import android.support.test.runner.lifecycle.Stage;
+
 import androidx.test.filters.MediumTest;
 
 import org.junit.After;
@@ -26,6 +28,7 @@
 import org.mockito.junit.MockitoRule;
 
 import org.chromium.base.Callback;
+import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
@@ -33,6 +36,7 @@
 import org.chromium.chrome.browser.ChromeTabbedActivity;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
+import org.chromium.chrome.browser.settings.SettingsActivity;
 import org.chromium.chrome.browser.settings.SettingsLauncherImpl;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
@@ -130,16 +134,19 @@
     public void testDialogInteractivity_LearnMoreButton() {
         showConsentUi();
 
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            ClickUtils.clickButton(mAssistantVoiceSearchConsentUi.getContentView().findViewById(
-                    R.id.avs_consent_ui_learn_more));
-            mBottomSheetTestSupport.endAllAnimations();
-        });
+        SettingsActivity activity = ApplicationTestUtils.waitForActivityWithClass(
+                SettingsActivity.class, Stage.RESUMED, () -> {
+                    ClickUtils.clickButton(
+                            mAssistantVoiceSearchConsentUi.getContentView().findViewById(
+                                    R.id.avs_consent_ui_learn_more));
+                    mBottomSheetTestSupport.endAllAnimations();
+                });
 
         onView(withText(mActivityTestRule.getActivity().getResources().getString(
                        R.string.avs_setting_category_title)))
                 .check(matches(isDisplayed()));
         Mockito.verify(mCallback, Mockito.times(0)).onResult(/* meaningless value */ true);
+        activity.finish();
     }
 
     @Test
@@ -156,4 +163,4 @@
         });
         Mockito.verify(mCallback, Mockito.timeout(1000)).onResult(false);
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
index a7fd8a3..bc91ea83 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/page_info/PageInfoViewTest.java
@@ -105,7 +105,7 @@
 
     private void loadUrlAndOpenPageInfo(String url) {
         mActivityTestRule.loadUrl(url);
-        onView(withId(R.id.location_bar_status_icon)).perform(click());
+        onViewWaiting(allOf(withId(R.id.location_bar_status_icon), isDisplayed())).perform(click());
     }
 
     private View getPageInfoView() {
@@ -184,8 +184,6 @@
         // Choose a fixed, "random" port to create stable screenshots.
         mTestServerRule.setServerPort(424242);
         mTestServerRule.setServerUsesHttps(true);
-
-        mActivityTestRule.startMainActivityOnBlankPage();
     }
 
     @After
@@ -209,6 +207,7 @@
     @Feature({"RenderTest"})
     @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowOnInsecureHttpWebsite() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         mTestServerRule.setServerUsesHttps(false);
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
         mRenderTestRule.render(getPageInfoView(), "PageInfo_HttpWebsite");
@@ -222,6 +221,7 @@
     @Feature({"RenderTest"})
     @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowOnSecureWebsite() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
         mRenderTestRule.render(getPageInfoView(), "PageInfo_SecureWebsite");
     }
@@ -235,6 +235,7 @@
     @DisabledTest(message = "https://crbug.com/1133770")
     @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowOnExpiredCertificateWebsite() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         mTestServerRule.setCertificateType(ServerCertificate.CERT_EXPIRED);
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
         mRenderTestRule.render(getPageInfoView(), "PageInfo_ExpiredCertWebsite");
@@ -248,6 +249,7 @@
     @Feature({"RenderTest"})
     @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testChromePage() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         loadUrlAndOpenPageInfo("chrome://version/");
         mRenderTestRule.render(getPageInfoView(), "PageInfo_InternalSite");
     }
@@ -261,6 +263,7 @@
     @Feature({"RenderTest"})
     @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowWithPermissions() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         mIsSystemLocationSettingEnabled = false;
         addSomePermissions(mTestServerRule.getServer().getURL("/"));
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
@@ -275,6 +278,7 @@
     @Feature({"RenderTest"})
     @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowWithCookieBlocking() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         setThirdPartyCookieBlocking(CookieControlsMode.BLOCK_THIRD_PARTY);
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
         mRenderTestRule.render(getPageInfoView(), "PageInfo_CookieBlocking");
@@ -288,6 +292,7 @@
     @Feature({"RenderTest"})
     @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowWithPermissionsAndCookieBlocking() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         addSomePermissions(mTestServerRule.getServer().getURL("/"));
         setThirdPartyCookieBlocking(CookieControlsMode.BLOCK_THIRD_PARTY);
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
@@ -302,6 +307,7 @@
     @Feature({"RenderTest"})
     @Features.DisableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowWithDefaultSettingPermissions() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         addDefaultSettingPermissions(mTestServerRule.getServer().getURL("/"));
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
         mRenderTestRule.render(getPageInfoView(), "PageInfo_DefaultSettingPermissions");
@@ -315,6 +321,7 @@
     @Feature({"RenderTest"})
     @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowOnSecureWebsiteV2() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
         mRenderTestRule.render(getPageInfoView(), "PageInfo_SecureWebsiteV2");
     }
@@ -343,6 +350,7 @@
     @Feature({"RenderTest"})
     @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowConnectionInfoSubpage() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
         onView(withId(R.id.page_info_connection_row)).perform(click());
         mRenderTestRule.render(getPageInfoView(), "PageInfo_ConnectionInfoSubpage");
@@ -356,6 +364,7 @@
     @Feature({"RenderTest"})
     @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowPermissionsSubpage() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         addSomePermissions(mTestServerRule.getServer().getURL("/"));
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
         onView(withId(R.id.page_info_permissions_row)).perform(click());
@@ -370,6 +379,7 @@
     @Feature({"RenderTest"})
     @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testShowCookiesSubpage() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         setThirdPartyCookieBlocking(CookieControlsMode.BLOCK_THIRD_PARTY);
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
         onView(withId(R.id.page_info_cookies_row)).perform(click());
@@ -384,6 +394,7 @@
     @MediumTest
     @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testNoPermissionsSubpage() throws IOException {
+        mActivityTestRule.startMainActivityOnBlankPage();
         loadUrlAndOpenPageInfo(mTestServerRule.getServer().getURL(sSimpleHtml));
         View dialog = (View) getPageInfoView().getParent();
         onView(withId(R.id.page_info_permissions_row))
@@ -398,6 +409,7 @@
     @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     @FlakyTest(message = "https://crbug.com/1147236")
     public void testClearCookiesOnSubpage() throws Exception {
+        mActivityTestRule.startMainActivityOnBlankPage();
         mActivityTestRule.loadUrl(mTestServerRule.getServer().getURL(sSiteDataHtml));
         // Create cookies.
         expectHasCookies(false);
@@ -423,6 +435,7 @@
     @MediumTest
     @Features.EnableFeatures(PageInfoFeatureList.PAGE_INFO_V2)
     public void testResetPermissionsOnSubpage() throws Exception {
+        mActivityTestRule.startMainActivityOnBlankPage();
         mActivityTestRule.loadUrl(mTestServerRule.getServer().getURL(sSiteDataHtml));
         String url = mTestServerRule.getServer().getURL("/");
         // Create permissions.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
index 3b5375ab2..2c90ae80 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/payments/PaymentRequestTestRule.java
@@ -1245,6 +1245,7 @@
         @Override
         public void create(PaymentAppFactoryDelegate delegate) {
             Runnable createApp = () -> {
+                if (delegate.getParams().hasClosed()) return;
                 boolean canMakePayment =
                         delegate.getParams().getMethodData().containsKey(mAppMethodName);
                 delegate.onCanMakePaymentCalculated(canMakePayment);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
index aa1888d..947221f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/MainSettingsFragmentTest.java
@@ -15,6 +15,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.app.Activity;
+import android.support.test.InstrumentationRegistry;
 import android.text.TextUtils;
 import android.view.View;
 
@@ -101,7 +102,7 @@
     private final SyncTestRule mSyncTestRule = new SyncTestRule();
 
     private final SettingsActivityTestRule<MainSettings> mSettingsActivityTestRule =
-            new SettingsActivityTestRule<>(MainSettings.class, true);
+            new SettingsActivityTestRule<>(MainSettings.class);
 
     // SettingsActivity needs to be initialized and destroyed with the mock
     // signin environment setup in SyncTestRule
@@ -133,6 +134,7 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
+        InstrumentationRegistry.getInstrumentation().setInTouchMode(true);
         PasswordCheckFactory.setPasswordCheckForTesting(mPasswordCheck);
         SigninActivityLauncherImpl.setLauncherForTest(mMockSigninActivityLauncherImpl);
         DeveloperSettings.setIsEnabledForTests(true);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java
index 516bc1db0..67834235 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/signin/AccountPickerBottomSheetRenderTest.java
@@ -22,7 +22,6 @@
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.test.filters.MediumTest;
 
-import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
@@ -34,7 +33,6 @@
 import org.chromium.base.Callback;
 import org.chromium.base.test.params.ParameterAnnotations;
 import org.chromium.base.test.params.ParameterizedRunner;
-import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.Batch;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
@@ -120,11 +118,6 @@
         mActivityTestRule.startMainActivityOnBlankPage();
     }
 
-    @After
-    public void tearDown() throws Exception {
-        ApplicationTestUtils.finishActivity(mActivityTestRule.getActivity());
-    }
-
     @AfterClass
     public static void tearDownAfterActivityDestroyed() {
         ChromeNightModeTestUtils.tearDownNightModeAfterChromeActivityDestroyed();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java
index 16095c4..5383798 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/site_settings/ManageSpaceActivityTest.java
@@ -100,7 +100,7 @@
     @Test
     @SmallTest
     public void testLaunchActivity() {
-        startManageSpaceActivity();
+        startManageSpaceActivity().finish();
     }
 
     @Test
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
index b42cd0d..d0a1c47 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
@@ -18,6 +18,7 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
@@ -40,14 +41,18 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class AccountManagementFragmentTest {
-    @Rule
     public final SettingsActivityTestRule<AccountManagementFragment> mSettingsActivityTestRule =
             new SettingsActivityTestRule<>(AccountManagementFragment.class);
 
-    @Rule
     public final ChromeTabbedActivityTestRule mActivityTestRule =
             new ChromeTabbedActivityTestRule();
 
+    // SettingsActivity has to be finished before the outer CTA can be finished or trying to finish
+    // CTA won't work.
+    @Rule
+    public final RuleChain mRuleChain =
+            RuleChain.outerRule(mActivityTestRule).around(mSettingsActivityTestRule);
+
     @Rule
     public final AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule();
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java
index dc9d76a..9b38421 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/GoogleServicesSettingsTest.java
@@ -16,6 +16,7 @@
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
 import org.chromium.base.test.util.CommandLineFlags;
@@ -51,13 +52,17 @@
     @Rule
     public final AccountManagerTestRule mAccountManagerTestRule = new AccountManagerTestRule();
 
-    @Rule
     public final ChromeTabbedActivityTestRule mActivityTestRule =
             new ChromeTabbedActivityTestRule();
 
-    @Rule
     public final SettingsActivityTestRule<GoogleServicesSettings> mSettingsActivityTestRule =
-            new SettingsActivityTestRule<>(GoogleServicesSettings.class, true);
+            new SettingsActivityTestRule<>(GoogleServicesSettings.class);
+
+    // SettingsActivity has to be finished before the outer CTA can be finished or trying to finish
+    // CTA won't work.
+    @Rule
+    public final RuleChain mRuleChain =
+            RuleChain.outerRule(mActivityTestRule).around(mSettingsActivityTestRule);
 
     @Before
     public void setUp() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
index 9c90fe6..2acd095 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/ManageSyncSettingsTest.java
@@ -90,7 +90,7 @@
     private final SyncTestRule mSyncTestRule = new SyncTestRule();
 
     private final SettingsActivityTestRule<ManageSyncSettings> mSettingsActivityTestRule =
-            new SettingsActivityTestRule<>(ManageSyncSettings.class, true);
+            new SettingsActivityTestRule<>(ManageSyncSettings.class);
 
     // SettingsActivity needs to be initialized and destroyed with the mock
     // signin environment setup in SyncTestRule
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java
index 76da0b0..559a75f 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncErrorCardPreferenceTest.java
@@ -62,7 +62,7 @@
 
     @Rule
     public final SettingsActivityTestRule<ManageSyncSettings> mSettingsActivityTestRule =
-            new SettingsActivityTestRule<>(ManageSyncSettings.class, true);
+            new SettingsActivityTestRule<>(ManageSyncSettings.class);
 
     @Rule
     public final ChromeRenderTestRule mRenderTestRule =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
index cfd5d948..458cdfa 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/SyncTestRule.java
@@ -4,6 +4,12 @@
 
 package org.chromium.chrome.browser.sync;
 
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -13,6 +19,7 @@
 
 import androidx.annotation.Nullable;
 import androidx.preference.TwoStatePreference;
+import androidx.test.espresso.contrib.RecyclerViewActions;
 
 import org.junit.Assert;
 import org.junit.runner.Description;
@@ -31,6 +38,7 @@
 import org.chromium.chrome.test.util.browser.signin.AccountManagerTestRule;
 import org.chromium.chrome.test.util.browser.signin.SigninTestUtil;
 import org.chromium.chrome.test.util.browser.sync.SyncTestUtil;
+import org.chromium.components.browser_ui.widget.R;
 import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.sync.ModelType;
 import org.chromium.components.sync.protocol.AutofillWalletSpecifics;
@@ -410,12 +418,9 @@
 
     // UI interaction convenience methods.
     public void togglePreference(final TwoStatePreference pref) {
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            boolean newValue = !pref.isChecked();
-            pref.getOnPreferenceChangeListener().onPreferenceChange(pref, newValue);
-            pref.setChecked(newValue);
-        });
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+        onView(withId(R.id.recycler_view))
+                .perform(RecyclerViewActions.actionOnItem(
+                        hasDescendant(withText(pref.getTitle().toString())), click()));
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageFactoryTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageFactoryTest.java
index 2611d9a5..c715a63 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageFactoryTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/state/LevelDBPersistedTabDataStorageFactoryTest.java
@@ -64,9 +64,11 @@
         LevelDBPersistedTabDataStorage.setSkipNativeAssertionsForTesting(true);
     }
 
+    @UiThreadTest
     @SmallTest
     @Test
     public void testFactoryMethod() {
+        Profile realProfile = Profile.getLastUsedRegularProfile();
         LevelDBPersistedTabDataStorageFactory factory = new LevelDBPersistedTabDataStorageFactory();
         Profile.setLastUsedProfileForTesting(mProfile1);
         LevelDBPersistedTabDataStorage profile1Storage = factory.create();
@@ -76,6 +78,8 @@
         LevelDBPersistedTabDataStorage profile1StorageAgain = factory.create();
         Assert.assertEquals(profile1Storage, profile1StorageAgain);
         Assert.assertNotEquals(profile1Storage, profile2Storage);
+        // Restore the original profile so the Activity can shut down correctly.
+        Profile.setLastUsedProfileForTesting(realProfile);
     }
 
     @UiThreadTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java
index 12907e88..cf1a94e0 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tasks/ReturnToChromeTest.java
@@ -597,7 +597,7 @@
         intent.addCategory(Intent.CATEGORY_LAUNCHER);
         mActivityTestRule.prepareUrlIntent(intent, url);
         Assert.assertFalse(mInflated.get());
-        mActivityTestRule.startActivityCompletely(intent);
+        mActivityTestRule.launchActivity(intent);
         if (mUseInstantStart) {
             CriteriaHelper.pollUiThread(mInflated::get);
         } else {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
index 33af8329..fc5fc02 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappNavigationTest.java
@@ -263,7 +263,7 @@
         IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW);
         filter.addDataScheme("https");
         final ActivityMonitor monitor =
-                InstrumentationRegistry.getInstrumentation().addMonitor(filter, null, false);
+                InstrumentationRegistry.getInstrumentation().addMonitor(filter, null, true);
 
         RevampedContextMenuUtils.selectContextMenuItem(InstrumentationRegistry.getInstrumentation(),
                 null /* activity to check for focus after click */,
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java
index 267fa5c..5622c9d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/omnibox/LocationBarMediatorTest.java
@@ -4,10 +4,13 @@
 
 package org.chromium.chrome.browser.omnibox;
 
+import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNull;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.notNull;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
@@ -17,24 +20,38 @@
 import org.junit.Test;
 import org.junit.rules.TestRule;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 import org.robolectric.annotation.Config;
 
+import org.chromium.base.BuildConfig;
 import org.chromium.base.supplier.OneshotSupplierImpl;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.locale.LocaleManager;
 import org.chromium.chrome.browser.omnibox.voice.AssistantVoiceSearchService;
+import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.profiles.ProfileJni;
 import org.chromium.chrome.browser.search_engines.TemplateUrlServiceFactory;
+import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.components.search_engines.TemplateUrlService;
+import org.chromium.content_public.browser.LoadUrlParams;
+import org.chromium.ui.base.PageTransition;
 
 /** Unit tests for LocationBarMediator. */
 @RunWith(BaseRobolectricTestRunner.class)
 @Config(manifest = Config.NONE)
 @Features.EnableFeatures(ChromeFeatureList.OMNIBOX_ASSISTANT_VOICE_SEARCH)
 public class LocationBarMediatorTest {
+    private static final String TEST_URL = "http://testurl.com";
+
+    @Rule
+    public JniMocker mJniMocker = new JniMocker();
     @Rule
     public MockitoRule mMockitoRule = MockitoJUnit.rule();
     @Rule
@@ -50,6 +67,16 @@
     private LocationBarDataProvider mLocationBarDataProvider;
     @Mock
     private OneshotSupplierImpl<AssistantVoiceSearchService> mAssistantVoiceSearchSupplier;
+    @Mock
+    private OverrideUrlLoadingDelegate mOverrideUrlLoadingDelegate;
+    @Mock
+    private LocaleManager mLocaleManager;
+    @Mock
+    private Profile.Natives mProfileNativesJniMock;
+    @Mock
+    private Tab mTab;
+    @Captor
+    private ArgumentCaptor<LoadUrlParams> mLoadUrlParamsCaptor;
 
     private LocationBarMediator mMediator;
 
@@ -57,8 +84,9 @@
     public void setUp() {
         doReturn(mContext).when(mLocationBarLayout).getContext();
         TemplateUrlServiceFactory.setInstanceForTesting(mTemplateUrlService);
-        mMediator = new LocationBarMediator(
-                mLocationBarLayout, mLocationBarDataProvider, mAssistantVoiceSearchSupplier);
+        mJniMocker.mock(ProfileJni.TEST_HOOKS, mProfileNativesJniMock);
+        mMediator = new LocationBarMediator(mLocationBarLayout, mLocationBarDataProvider,
+                mAssistantVoiceSearchSupplier, mOverrideUrlLoadingDelegate, mLocaleManager);
     }
 
     @Test
@@ -86,4 +114,44 @@
         mMediator.onNtpStartedLoading();
         verify(mLocationBarLayout).onNtpStartedLoading();
     }
+
+    @Test
+    public void testLoadUrl() {
+        mMediator.onFinishNativeInitialization();
+
+        doReturn(mTab).when(mLocationBarDataProvider).getTab();
+        mMediator.loadUrl(TEST_URL, PageTransition.TYPED, 0);
+
+        verify(mTab).loadUrl(mLoadUrlParamsCaptor.capture());
+        assertEquals(TEST_URL, mLoadUrlParamsCaptor.getValue().getUrl());
+        assertEquals(PageTransition.TYPED | PageTransition.FROM_ADDRESS_BAR,
+                mLoadUrlParamsCaptor.getValue().getTransitionType());
+    }
+
+    @Test
+    public void testLoadUrl_NativeNotInitialized() {
+        if (BuildConfig.DCHECK_IS_ON) {
+            // clang-format off
+            try {
+                mMediator.loadUrl(TEST_URL, PageTransition.TYPED, 0);
+                throw new Error("Expected an assert to be triggered.");
+            } catch (AssertionError e) {}
+            // clang-format on
+        }
+    }
+
+    @Test
+    public void testLoadUrl_OverrideLoadingDelegate() {
+        mMediator.onFinishNativeInitialization();
+
+        doReturn(mTab).when(mLocationBarDataProvider).getTab();
+        doReturn(true)
+                .when(mOverrideUrlLoadingDelegate)
+                .willHandleLoadUrlWithPostData(TEST_URL, PageTransition.TYPED, null, null, false);
+        mMediator.loadUrl(TEST_URL, PageTransition.TYPED, 0);
+
+        verify(mOverrideUrlLoadingDelegate)
+                .willHandleLoadUrlWithPostData(TEST_URL, PageTransition.TYPED, null, null, false);
+        verify(mTab, times(0)).loadUrl(any());
+    }
 }
diff --git a/chrome/android/profiles/newest.txt b/chrome/android/profiles/newest.txt
index 166ce7e..b30874b 100644
--- a/chrome/android/profiles/newest.txt
+++ b/chrome/android/profiles/newest.txt
@@ -1 +1 @@
-chromeos-chrome-amd64-89.0.4328.0_rc-r1-merged.afdo.bz2
+chromeos-chrome-amd64-89.0.4334.0_rc-r1-merged.afdo.bz2
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 726a3e3..84f6f83 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -1535,9 +1535,12 @@
   </message>
 
   <!-- Reset Settings Page -->
-  <message name="IDS_SETTINGS_RESET" desc="Title for an item in the 'Reset and clean up' section of Chrome Settings. If the user clicks this option, browser settings will be returned to their default values, after a confirmation by the user." meaning="Chrome Cleanup feature. Try to use the same translation for 'Reset' in 'Reset and cleanup' string.">
+  <message name="IDS_SETTINGS_RESET_PROMPT_TITLE" desc="Title for a prompt that gives an explanation of what would be resetted by 'Reset and clean up' section of Chrome Settings. " meaning="Chrome Cleanup feature. Try to use the same translation for 'Reset' in 'Reset and cleanup' string.">
     Reset settings?
   </message>
+  <message name="IDS_SETTINGS_RESET" desc="Title for an item in the 'Reset and clean up' section of Chrome Settings. If the user clicks this option, browser settings will be returned to their default values, after a confirmation by the user." meaning="Chrome Cleanup feature. Try to use the same translation for 'Reset' in 'Reset and cleanup' string.">
+    Reset settings
+  </message>
   <message name="IDS_SETTINGS_RESET_SETTINGS_TRIGGER" desc="The label describing the 'reset profile setting' feature">
     Restore settings to their original defaults
   </message>
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_RESET.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_RESET.png.sha1
index d787cc99..1574cbc 100644
--- a/chrome/app/settings_strings_grdp/IDS_SETTINGS_RESET.png.sha1
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_RESET.png.sha1
@@ -1 +1 @@
-eaa08b5f937a899c93112f574f2e76eb7ac97f40
\ No newline at end of file
+ca06b8e88edebb0c6160161864edcf0d7c1247c6
\ No newline at end of file
diff --git a/chrome/app/settings_strings_grdp/IDS_SETTINGS_RESET_PROMPT_TITLE.png.sha1 b/chrome/app/settings_strings_grdp/IDS_SETTINGS_RESET_PROMPT_TITLE.png.sha1
new file mode 100644
index 0000000..1574cbc
--- /dev/null
+++ b/chrome/app/settings_strings_grdp/IDS_SETTINGS_RESET_PROMPT_TITLE.png.sha1
@@ -0,0 +1 @@
+ca06b8e88edebb0c6160161864edcf0d7c1247c6
\ No newline at end of file
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.cc b/chrome/browser/android/tab_web_contents_delegate_android.cc
index f854a3a9..f09b10b 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.cc
+++ b/chrome/browser/android/tab_web_contents_delegate_android.cc
@@ -220,18 +220,6 @@
   return false;
 }
 
-blink::mojom::DisplayMode TabWebContentsDelegateAndroid::GetDisplayMode(
-    const WebContents* web_contents) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-
-  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
-  if (obj.is_null())
-    return blink::mojom::DisplayMode::kUndefined;
-
-  return static_cast<blink::mojom::DisplayMode>(
-      Java_TabWebContentsDelegateAndroidImpl_getDisplayMode(env, obj));
-}
-
 void TabWebContentsDelegateAndroid::FindReply(
     WebContents* web_contents,
     int request_id,
diff --git a/chrome/browser/android/tab_web_contents_delegate_android.h b/chrome/browser/android/tab_web_contents_delegate_android.h
index 84fd2e6..11b47c936 100644
--- a/chrome/browser/android/tab_web_contents_delegate_android.h
+++ b/chrome/browser/android/tab_web_contents_delegate_android.h
@@ -53,8 +53,6 @@
                        base::OnceClosure on_confirm,
                        base::OnceClosure on_cancel) override;
   bool ShouldFocusLocationBarByDefault(content::WebContents* source) override;
-  blink::mojom::DisplayMode GetDisplayMode(
-      const content::WebContents* web_contents) override;
   void FindReply(content::WebContents* web_contents,
                  int request_id,
                  int number_of_matches,
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 535ba8d0..83d1172 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -60,6 +60,7 @@
 #include "chrome/browser/component_updater/registration.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/first_run/first_run.h"
+#include "chrome/browser/language/url_language_histogram_factory.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/lifetime/browser_shutdown.h"
 #include "chrome/browser/media/router/chrome_media_router_factory.h"
@@ -1533,6 +1534,11 @@
       profile_->GetPrefs()->GetString(language::prefs::kAcceptLanguages));
   language_usage_metrics::LanguageUsageMetrics::RecordApplicationLanguage(
       browser_process_->GetApplicationLocale());
+// On ChromeOS results in a crash. https://crbug.com/1151558
+#if !defined(OS_CHROMEOS)
+  language_usage_metrics::LanguageUsageMetrics::RecordPageLanguages(
+      *UrlLanguageHistogramFactory::GetForBrowserContext(profile_));
+#endif  // defined(OS_CHROMEOS)
 
 // On mobile, need for clean shutdown arises only when the application comes
 // to foreground (i.e. MetricsService::OnAppEnterForeground is called).
diff --git a/chrome/browser/chrome_browser_main_win.h b/chrome/browser/chrome_browser_main_win.h
index 56063150..a69e78c2 100644
--- a/chrome/browser/chrome_browser_main_win.h
+++ b/chrome/browser/chrome_browser_main_win.h
@@ -9,7 +9,6 @@
 
 #include <memory>
 
-#include "base/files/file_path_watcher.h"
 #include "chrome/browser/chrome_browser_main.h"
 
 class ModuleWatcher;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 02d1670..0246f53 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -75,6 +75,7 @@
     "//base",
     "//base/util/timer",
     "//build:branding_buildflags",
+    "//build:chromeos_buildflags",
     "//chrome/app:command_ids",
     "//chrome/app/vector_icons",
     "//chrome/browser:browser_process",
@@ -1192,6 +1193,8 @@
     "eol_notification.h",
     "events/event_rewriter_delegate_impl.cc",
     "events/event_rewriter_delegate_impl.h",
+    "exo/chrome_file_helper.cc",
+    "exo/chrome_file_helper.h",
     "extensions/active_tab_permission_granter_delegate_chromeos.cc",
     "extensions/active_tab_permission_granter_delegate_chromeos.h",
     "extensions/default_app_order.cc",
@@ -1420,6 +1423,10 @@
     "first_run/help_app_first_run_field_trial.h",
     "full_restore/full_restore_prefs.cc",
     "full_restore/full_restore_prefs.h",
+    "full_restore/full_restore_service.cc",
+    "full_restore/full_restore_service.h",
+    "full_restore/full_restore_service_factory.cc",
+    "full_restore/full_restore_service_factory.h",
     "guest_os/guest_os_external_protocol_handler.cc",
     "guest_os/guest_os_external_protocol_handler.h",
     "guest_os/guest_os_pref_names.cc",
@@ -3441,6 +3448,7 @@
     "drive/file_system_util_unittest.cc",
     "eol_notification_unittest.cc",
     "events/event_rewriter_unittest.cc",
+    "exo/chrome_file_helper_unittest.cc",
     "extensions/active_tab_permission_granter_delegate_chromeos_unittest.cc",
     "extensions/default_app_order_unittest.cc",
     "extensions/device_local_account_external_policy_loader_unittest.cc",
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 6cd87fc..a57289d 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -42,6 +42,7 @@
 #include "chrome/browser/chromeos/accessibility/select_to_speak_event_handler_delegate.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
+#include "chrome/browser/chromeos/policy/enrollment_requisition_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -1415,6 +1416,11 @@
       media_session::mojom::EnforcementMode::kNone);
 
   InitializeFocusRings(extension_id);
+
+  // Force volume slide gesture to be on for Chromebox for Meetings provisioned
+  // devices.
+  if (policy::EnrollmentRequisitionManager::IsRemoraRequisition())
+    ash::AccessibilityController::Get()->EnableChromeVoxVolumeSlideGesture();
 }
 
 void AccessibilityManager::PostUnloadChromeVox() {
diff --git a/chrome/browser/chromeos/accessibility/spoken_feedback_app_list_browsertest.cc b/chrome/browser/chromeos/accessibility/spoken_feedback_app_list_browsertest.cc
index d9b6f5b..34d025a 100644
--- a/chrome/browser/chromeos/accessibility/spoken_feedback_app_list_browsertest.cc
+++ b/chrome/browser/chromeos/accessibility/spoken_feedback_app_list_browsertest.cc
@@ -206,6 +206,76 @@
   sm_.Replay();
 }
 
+// Checks that when a paused app list item is focused, an announcement 'Paused'
+// is made.
+IN_PROC_BROWSER_TEST_P(TabletModeSpokenFeedbackAppListTest,
+                       AppListItemPausedAppAnnounced) {
+  PopulateApps(1);
+  ash::Shell::Get()
+      ->app_list_controller()
+      ->GetModel()
+      ->FindItem("Item 0")
+      ->UpdateAppStatusForTesting(ash::AppStatus::kPaused);
+
+  EnableChromeVox();
+
+  sm_.Call(
+      [this]() { EXPECT_TRUE(PerformAcceleratorAction(ash::FOCUS_SHELF)); });
+  sm_.ExpectSpeech("Shelf");
+  // Press space on the launcher button in shelf, this opens peeking
+  // launcher.
+  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_SPACE); });
+  sm_.ExpectSpeech("Launcher, partial view");
+  // Move focus to expand all apps button.
+  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_UP); });
+  sm_.ExpectSpeech("Expand to all apps");
+  // Press space on expand arrow to go to fullscreen launcher.
+  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_SPACE); });
+  sm_.ExpectSpeech("Launcher, all apps");
+
+  // Move focus to 1st app;
+  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_RIGHT); });
+
+  // Check that the announcmenet for items with a pause badge occurs.
+  sm_.ExpectSpeech("Paused");
+  sm_.Replay();
+}
+
+// Checks that when a blocked app list item is focused, an announcement
+// 'Blocked' is made.
+IN_PROC_BROWSER_TEST_P(TabletModeSpokenFeedbackAppListTest,
+                       AppListItemBlockedAppAnnounced) {
+  PopulateApps(1);
+  ash::Shell::Get()
+      ->app_list_controller()
+      ->GetModel()
+      ->FindItem("Item 0")
+      ->UpdateAppStatusForTesting(ash::AppStatus::kBlocked);
+
+  EnableChromeVox();
+
+  sm_.Call(
+      [this]() { EXPECT_TRUE(PerformAcceleratorAction(ash::FOCUS_SHELF)); });
+  sm_.ExpectSpeech("Shelf");
+  // Press space on the launcher button in shelf, this opens peeking
+  // launcher.
+  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_SPACE); });
+  sm_.ExpectSpeech("Launcher, partial view");
+  // Move focus to expand all apps button.
+  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_UP); });
+  sm_.ExpectSpeech("Expand to all apps");
+  // Press space on expand arrow to go to fullscreen launcher.
+  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_SPACE); });
+  sm_.ExpectSpeech("Launcher, all apps");
+
+  // Move focus to 1st app;
+  sm_.Call([this]() { SendKeyPressWithSearch(ui::VKEY_RIGHT); });
+
+  // Check that the announcmenet for items with a block badge occurs.
+  sm_.ExpectSpeech("Blocked");
+  sm_.Replay();
+}
+
 // Checks that entering and exiting tablet mode with a browser window open does
 // not generate an accessibility event.
 IN_PROC_BROWSER_TEST_P(
diff --git a/chrome/browser/chromeos/crostini/crostini_manager.cc b/chrome/browser/chromeos/crostini/crostini_manager.cc
index e614e4c..894a7e0 100644
--- a/chrome/browser/chromeos/crostini/crostini_manager.cc
+++ b/chrome/browser/chromeos/crostini/crostini_manager.cc
@@ -659,7 +659,7 @@
 bool CrostiniManager::is_dev_kvm_present_ = true;
 
 void CrostiniManager::UpdateVmState(std::string vm_name, VmState vm_state) {
-  auto vm_info = running_vms_.find(std::move(vm_name));
+  auto vm_info = running_vms_.find(vm_name);
   if (vm_info != running_vms_.end()) {
     vm_info->second.state = vm_state;
     return;
diff --git a/chrome/browser/chromeos/crostini/crostini_util.cc b/chrome/browser/chromeos/crostini/crostini_util.cc
index 74acc95f..fd307c4 100644
--- a/chrome/browser/chromeos/crostini/crostini_util.cc
+++ b/chrome/browser/chromeos/crostini/crostini_util.cc
@@ -210,8 +210,9 @@
                                     display_id, std::move(launch_args),
                                     std::move(callback), true, "");
   } else {
+    const auto vm_name = registration.VmName();
     guest_os::GuestOsSharePath::GetForProfile(profile)->SharePaths(
-        registration.VmName(), std::move(paths_to_share), /*persist=*/false,
+        vm_name, std::move(paths_to_share), /*persist=*/false,
         base::BindOnce(OnSharePathForLaunchApplication, profile, app_id,
                        std::move(registration), display_id,
                        std::move(launch_args), std::move(callback)));
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index 77b2b11..64628a46 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -1108,6 +1108,7 @@
     drivefs::mojom::DriveFs::LocateFilesByItemIdsCallback callback) {
   if (!IsMounted() || !GetDriveFsInterface()) {
     std::move(callback).Run({});
+    return;
   }
   GetDriveFsInterface()->LocateFilesByItemIds(item_ids, std::move(callback));
 }
diff --git a/chrome/browser/chromeos/exo/DEPS b/chrome/browser/chromeos/exo/DEPS
new file mode 100644
index 0000000..1ff90b7
--- /dev/null
+++ b/chrome/browser/chromeos/exo/DEPS
@@ -0,0 +1,8 @@
+specific_include_rules = {
+  "chrome_file_helper\.cc": [
+    "+ash/wm/window_util.h",
+  ],
+  "chrome_file_helper_unittest\.cc": [
+    "+ash/wm/window_util.h",
+  ],
+}
diff --git a/chrome/browser/chromeos/exo/OWNERS b/chrome/browser/chromeos/exo/OWNERS
new file mode 100644
index 0000000..a8103d1
--- /dev/null
+++ b/chrome/browser/chromeos/exo/OWNERS
@@ -0,0 +1,5 @@
+joelhockey@chromium.org
+oshima@chromium.org
+
+# COMPONENT: Internals>Exosphere
+# COMPONENT: UI>Shell>Containers
diff --git a/chrome/browser/chromeos/exo/README.md b/chrome/browser/chromeos/exo/README.md
new file mode 100644
index 0000000..7a3fcc9
--- /dev/null
+++ b/chrome/browser/chromeos/exo/README.md
@@ -0,0 +1,4 @@
+# chrome/browser/chromeos/exo
+
+Contains exo code with dependencies on chrome/browser/chromeos such as drag and
+drop file path conversion, and VM file sharing.
diff --git a/chrome/browser/chromeos/exo/chrome_file_helper.cc b/chrome/browser/chromeos/exo/chrome_file_helper.cc
new file mode 100644
index 0000000..e027d04
--- /dev/null
+++ b/chrome/browser/chromeos/exo/chrome_file_helper.cc
@@ -0,0 +1,360 @@
+// Copyright 2020 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/exo/chrome_file_helper.h"
+
+#include <string>
+#include <vector>
+
+#include "ash/wm/window_util.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/strings/escape.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
+#include "chrome/browser/chromeos/file_manager/app_id.h"
+#include "chrome/browser/chromeos/file_manager/fileapi_util.h"
+#include "chrome/browser/chromeos/file_manager/path_util.h"
+#include "chrome/browser/chromeos/guest_os/guest_os_share_path.h"
+#include "chrome/browser/chromeos/plugin_vm/plugin_vm_files.h"
+#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/user_manager/user_manager.h"
+#include "content/public/common/drop_data.h"
+#include "storage/browser/file_system/external_mount_points.h"
+#include "storage/browser/file_system/file_system_context.h"
+#include "storage/browser/file_system/file_system_url.h"
+#include "ui/aura/window.h"
+#include "ui/base/dragdrop/file_info/file_info.h"
+#include "url/gurl.h"
+
+namespace chromeos {
+
+namespace {
+
+constexpr char kMimeTypeArcUriList[] = "application/x-arc-uri-list";
+constexpr char kMimeTypeTextUriList[] = "text/uri-list";
+constexpr char kFileSchemePrefix[] = "file:";
+constexpr char kUriListSeparator[] = "\r\n";
+constexpr char kVmFileScheme[] = "vmfile";
+
+// We are using our own GetPrimaryProfile() rather than
+// ProfileManager::GetPrimaryUserProfile() to help unittest.
+Profile* GetPrimaryProfile() {
+  if (!user_manager::UserManager::IsInitialized())
+    return nullptr;
+  const auto* primary_user = user_manager::UserManager::Get()->GetPrimaryUser();
+  if (!primary_user)
+    return nullptr;
+  return chromeos::ProfileHelper::Get()->GetProfileByUser(primary_user);
+}
+
+// We implement our own URLToPath() and PathToURL() rather than use
+// net::FileUrlToFilePath() or net::FilePathToFileURL() since //net code does
+// not support Windows network paths such as //ChromeOS/MyFiles on OS_CHROMEOS.
+bool URLToPath(const base::StringPiece& url, std::string* path) {
+  if (!base::StartsWith(url, kFileSchemePrefix, base::CompareCase::SENSITIVE))
+    return false;
+
+  // Skip slashes after 'file:' if needed:
+  //  file://host/path => //host/path
+  //  file:///path     => /path
+  int path_start = sizeof(kFileSchemePrefix) - 1;
+  if (url.size() > path_start + 2 && url[path_start] == '/' &&
+      url[path_start + 1] == '/' && url[path_start + 2] == '/') {
+    path_start += 2;
+  }
+
+  *path = base::UnescapeBinaryURLComponent(url.substr(path_start));
+  return true;
+}
+
+std::string PathToURL(const std::string& path) {
+  std::string url;
+  url.reserve(sizeof(kFileSchemePrefix) + 3 + (3 * path.size()));
+  url += kFileSchemePrefix;
+
+  // Add slashes after 'file:' if needed:
+  //  //host/path    => file://host/path
+  //  /absolute/path => file:///absolute/path
+  //  relative/path  => file:///relative/path
+  if (path.size() > 1 && path[0] == '/' && path[1] == '/') {
+    // Do nothing.
+  } else if (path.size() > 0 && path[0] == '/') {
+    url += "//";
+  } else {
+    url += "///";
+  }
+
+  // Escape special characters `%;#?\ `
+  for (auto c : path) {
+    if (c == '%' || c == ';' || c == '#' || c == '?' || c == '\\' || c <= ' ') {
+      static const char kHexChars[] = "0123456789ABCDEF";
+      url += '%';
+      url += kHexChars[(c >> 4) & 0xf];
+      url += kHexChars[c & 0xf];
+    } else {
+      url += c;
+    }
+  }
+
+  return url;
+}
+
+storage::FileSystemContext* GetFileSystemContext() {
+  Profile* primary_profile = GetPrimaryProfile();
+  if (!primary_profile)
+    return nullptr;
+
+  return file_manager::util::GetFileSystemContextForExtensionId(
+      primary_profile, file_manager::kFileManagerAppId);
+}
+
+void GetFileSystemUrlsFromPickle(
+    const base::Pickle& pickle,
+    std::vector<storage::FileSystemURL>* file_system_urls) {
+  storage::FileSystemContext* file_system_context = GetFileSystemContext();
+  if (!file_system_context)
+    return;
+
+  std::vector<content::DropData::FileSystemFileInfo> file_system_files;
+  if (!content::DropData::FileSystemFileInfo::ReadFileSystemFilesFromPickle(
+          pickle, &file_system_files))
+    return;
+
+  for (const auto& file_system_file : file_system_files) {
+    const storage::FileSystemURL file_system_url =
+        file_system_context->CrackURL(file_system_file.url);
+    if (file_system_url.is_valid())
+      file_system_urls->push_back(file_system_url);
+  }
+}
+
+void SendArcUrls(exo::FileHelper::SendDataCallback callback,
+                 const std::vector<GURL>& urls) {
+  std::vector<std::string> lines;
+  for (const GURL& url : urls) {
+    if (!url.is_valid())
+      continue;
+    lines.emplace_back(url.spec());
+  }
+  // Arc requires UTF16 for data.
+  base::string16 data =
+      base::UTF8ToUTF16(base::JoinString(lines, kUriListSeparator));
+  std::move(callback).Run(base::RefCountedString16::TakeString(&data));
+}
+
+void SendAfterShare(exo::FileHelper::SendDataCallback callback,
+                    scoped_refptr<base::RefCountedMemory> data,
+                    bool success,
+                    const std::string& failure_reason) {
+  if (!success)
+    LOG(ERROR) << "Error sharing paths for drag and drop: " << failure_reason;
+
+  // Still send the data, even if sharing failed.
+  std::move(callback).Run(data);
+}
+
+struct FileInfo {
+  base::FilePath path;
+  storage::FileSystemURL url;
+};
+
+void ShareAndSend(aura::Window* target,
+                  std::vector<FileInfo> files,
+                  exo::FileHelper::SendDataCallback callback) {
+  Profile* primary_profile = GetPrimaryProfile();
+  aura::Window* toplevel = target->GetToplevelWindow();
+  bool is_crostini = crostini::IsCrostiniWindow(toplevel);
+  bool is_plugin_vm = plugin_vm::IsPluginVmAppWindow(toplevel);
+
+  base::FilePath vm_mount;
+  std::string vm_name;
+  if (is_crostini) {
+    vm_mount = crostini::ContainerChromeOSBaseDirectory();
+    vm_name = crostini::kCrostiniDefaultVmName;
+  } else if (is_plugin_vm) {
+    vm_mount = plugin_vm::ChromeOSBaseDirectory();
+    vm_name = plugin_vm::kPluginVmName;
+  }
+
+  const std::string vm_prefix =
+      base::StrCat({kVmFileScheme, ":", vm_name, ":"});
+  std::vector<std::string> lines_to_send;
+  auto* share_path = guest_os::GuestOsSharePath::GetForProfile(primary_profile);
+  std::vector<base::FilePath> paths_to_share;
+
+  for (auto& info : files) {
+    base::FilePath path_to_send = info.path;
+    if (is_crostini || is_plugin_vm) {
+      // Check if it is a path inside the VM: 'vmfile:<vm_name>:'.
+      if (base::StartsWith(info.path.value(), vm_prefix,
+                           base::CompareCase::SENSITIVE)) {
+        path_to_send =
+            base::FilePath(info.path.value().substr(vm_prefix.size()));
+      } else if (file_manager::util::ConvertFileSystemURLToPathInsideVM(
+                     primary_profile, info.url, vm_mount,
+                     /*map_crostini_home=*/is_crostini, &path_to_send)) {
+        // Convert to path inside the VM and check if the path needs sharing.
+        if (!share_path->IsPathShared(vm_name, info.path))
+          paths_to_share.emplace_back(info.path);
+      } else {
+        LOG(WARNING) << "Could not convert path " << info.path;
+        continue;
+      }
+    }
+    lines_to_send.emplace_back(PathToURL(path_to_send.value()));
+  }
+
+  std::string joined = base::JoinString(lines_to_send, kUriListSeparator);
+  auto data = base::RefCountedString::TakeString(&joined);
+  if (!paths_to_share.empty()) {
+    share_path->SharePaths(
+        vm_name, std::move(paths_to_share),
+        /*persist=*/false,
+        base::BindOnce(&SendAfterShare, std::move(callback), std::move(data)));
+  } else {
+    std::move(callback).Run(std::move(data));
+  }
+}
+
+}  // namespace
+
+ChromeFileHelper::ChromeFileHelper() = default;
+
+ChromeFileHelper::~ChromeFileHelper() = default;
+
+std::vector<ui::FileInfo> ChromeFileHelper::GetFilenames(
+    aura::Window* source,
+    const std::vector<uint8_t>& data) const {
+  Profile* primary_profile = GetPrimaryProfile();
+  aura::Window* toplevel = source->GetToplevelWindow();
+  bool is_crostini = crostini::IsCrostiniWindow(toplevel);
+  bool is_plugin_vm = plugin_vm::IsPluginVmAppWindow(toplevel);
+
+  base::FilePath vm_mount;
+  std::string vm_name;
+  if (is_crostini) {
+    vm_mount = crostini::ContainerChromeOSBaseDirectory();
+    vm_name = crostini::kCrostiniDefaultVmName;
+  } else if (is_plugin_vm) {
+    vm_mount = plugin_vm::ChromeOSBaseDirectory();
+    vm_name = plugin_vm::kPluginVmName;
+  }
+
+  std::string lines(data.begin(), data.end());
+  std::vector<ui::FileInfo> filenames;
+
+  base::FilePath path;
+  storage::FileSystemURL url;
+  for (const base::StringPiece& line :
+       base::SplitStringPiece(lines, kUriListSeparator, base::TRIM_WHITESPACE,
+                              base::SPLIT_WANT_NONEMPTY)) {
+    if (line.empty() || line[0] == '#')
+      continue;
+    std::string path_str;
+    if (!URLToPath(line, &path_str)) {
+      LOG(WARNING) << "Invalid drop file path: " << line;
+      continue;
+    }
+    path = base::FilePath(path_str);
+
+    // Convert the VM path to a path in the host if possible (in homedir or
+    // /mnt/chromeos for crostini; in //ChromeOS for Plugin VM), otherwise
+    // prefix with 'vmfile:<vm_name>:' to avoid VMs spoofing host paths.
+    // E.g. crostini /etc/mime.types => vmfile:termina:/etc/mime.types.
+    if (is_crostini || is_plugin_vm) {
+      if (file_manager::util::ConvertPathInsideVMToFileSystemURL(
+              primary_profile, path, vm_mount,
+              /*map_crostini_home=*/is_crostini, &url)) {
+        path = url.path();
+      } else {
+        path = base::FilePath(
+            base::StrCat({kVmFileScheme, ":", vm_name, ":", path.value()}));
+      }
+    }
+    filenames.emplace_back(ui::FileInfo(path, base::FilePath()));
+  }
+  return filenames;
+}
+
+std::string ChromeFileHelper::GetMimeTypeForUriList(
+    aura::Window* target) const {
+  return ash::window_util::IsArcWindow(target->GetToplevelWindow())
+             ? kMimeTypeArcUriList
+             : kMimeTypeTextUriList;
+}
+
+void ChromeFileHelper::SendFileInfo(aura::Window* target,
+                                    const std::vector<ui::FileInfo>& files,
+                                    SendDataCallback callback) const {
+  // ARC converts to ArcUrl and uses utf-16.
+  if (ash::window_util::IsArcWindow(target->GetToplevelWindow())) {
+    std::vector<std::string> lines;
+    GURL url;
+    for (const auto& info : files) {
+      if (file_manager::util::ConvertPathToArcUrl(info.path, &url))
+        lines.emplace_back(url.spec());
+    }
+    base::string16 data =
+        base::UTF8ToUTF16(base::JoinString(lines, kUriListSeparator));
+    std::move(callback).Run(base::RefCountedString16::TakeString(&data));
+    return;
+  }
+
+  storage::ExternalMountPoints* mount_points =
+      storage::ExternalMountPoints::GetSystemInstance();
+  base::FilePath virtual_path;
+  std::vector<FileInfo> list;
+
+  for (const auto& info : files) {
+    // Convert absolute host path to FileSystemURL if possible.
+    storage::FileSystemURL url;
+    if (mount_points->GetVirtualPath(info.path, &virtual_path)) {
+      url = mount_points->CreateCrackedFileSystemURL(
+          url::Origin(), storage::kFileSystemTypeExternal, virtual_path);
+    }
+    list.push_back({info.path, std::move(url)});
+  }
+
+  ShareAndSend(target, std::move(list), std::move(callback));
+}
+
+bool ChromeFileHelper::HasUrlsInPickle(const base::Pickle& pickle) const {
+  std::vector<storage::FileSystemURL> file_system_urls;
+  GetFileSystemUrlsFromPickle(pickle, &file_system_urls);
+  return !file_system_urls.empty();
+}
+
+void ChromeFileHelper::SendPickle(aura::Window* target,
+                                  const base::Pickle& pickle,
+                                  SendDataCallback callback) {
+  std::vector<storage::FileSystemURL> file_system_urls;
+  GetFileSystemUrlsFromPickle(pickle, &file_system_urls);
+
+  // ARC FileSystemURLs are converted to Content URLs.
+  if (ash::window_util::IsArcWindow(target->GetToplevelWindow())) {
+    if (file_system_urls.empty()) {
+      std::move(callback).Run(nullptr);
+      return;
+    }
+    file_manager::util::ConvertToContentUrls(
+        file_system_urls, base::BindOnce(&SendArcUrls, std::move(callback)));
+    return;
+  }
+
+  std::vector<FileInfo> list;
+  for (const auto& url : file_system_urls)
+    list.push_back({url.path(), url});
+
+  ShareAndSend(target, std::move(list), std::move(callback));
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/exo/chrome_file_helper.h b/chrome/browser/chromeos/exo/chrome_file_helper.h
new file mode 100644
index 0000000..a26e296
--- /dev/null
+++ b/chrome/browser/chromeos/exo/chrome_file_helper.h
@@ -0,0 +1,35 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_EXO_CHROME_FILE_HELPER_H_
+#define CHROME_BROWSER_CHROMEOS_EXO_CHROME_FILE_HELPER_H_
+
+#include "components/exo/file_helper.h"
+
+namespace chromeos {
+
+class ChromeFileHelper : public exo::FileHelper {
+ public:
+  ChromeFileHelper();
+  ChromeFileHelper(const ChromeFileHelper&) = delete;
+  ChromeFileHelper& operator=(const ChromeFileHelper&) = delete;
+  ~ChromeFileHelper() override;
+
+  // FileHelper:
+  std::vector<ui::FileInfo> GetFilenames(
+      aura::Window* source,
+      const std::vector<uint8_t>& data) const override;
+  std::string GetMimeTypeForUriList(aura::Window* target) const override;
+  void SendFileInfo(aura::Window* target,
+                    const std::vector<ui::FileInfo>& files,
+                    SendDataCallback callback) const override;
+  bool HasUrlsInPickle(const base::Pickle& pickle) const override;
+  void SendPickle(aura::Window* target,
+                  const base::Pickle& pickle,
+                  SendDataCallback callback) override;
+};
+
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_EXO_CHROME_FILE_HELPER_H_
diff --git a/chrome/browser/chromeos/exo/chrome_file_helper_unittest.cc b/chrome/browser/chromeos/exo/chrome_file_helper_unittest.cc
new file mode 100644
index 0000000..eb34429c
--- /dev/null
+++ b/chrome/browser/chromeos/exo/chrome_file_helper_unittest.cc
@@ -0,0 +1,341 @@
+// Copyright 2020 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/exo/chrome_file_helper.h"
+
+#include "ash/public/cpp/app_types.h"
+#include "ash/wm/window_util.h"
+#include "base/memory/ref_counted_memory.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/pickle.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "chrome/browser/chromeos/crostini/crostini_manager.h"
+#include "chrome/browser/chromeos/crostini/crostini_test_helper.h"
+#include "chrome/browser/chromeos/crostini/crostini_util.h"
+#include "chrome/browser/chromeos/file_manager/path_util.h"
+#include "chrome/browser/chromeos/guest_os/guest_os_share_path.h"
+#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h"
+#include "chrome/test/base/testing_profile.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/fake_seneschal_client.h"
+#include "components/exo/shell_surface_util.h"
+#include "content/public/common/drop_data.h"
+#include "content/public/test/browser_task_environment.h"
+#include "storage/browser/file_system/external_mount_points.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/test/test_window_delegate.h"
+#include "ui/aura/test/test_windows.h"
+#include "ui/aura/window.h"
+#include "ui/base/dragdrop/file_info/file_info.h"
+#include "ui/gfx/geometry/rect.h"
+#include "url/origin.h"
+
+namespace chromeos {
+
+namespace {
+
+std::vector<uint8_t> Data(const std::string& s) {
+  return std::vector<uint8_t>(s.begin(), s.end());
+}
+
+void Capture(std::string* result, scoped_refptr<base::RefCountedMemory> data) {
+  *result = std::string(data->front_as<char>(), data->size());
+}
+
+void CaptureUTF16(std::string* result,
+                  scoped_refptr<base::RefCountedMemory> data) {
+  base::UTF16ToUTF8(data->front_as<base::char16>(), data->size() / 2, result);
+}
+
+}  // namespace
+
+class ChromeFileHelperTest : public testing::Test {
+ public:
+  void SetUp() override {
+    chromeos::DBusThreadManager::Initialize();
+    profile_ = std::make_unique<TestingProfile>();
+    test_helper_ =
+        std::make_unique<crostini::CrostiniTestHelper>(profile_.get());
+
+    // Setup CrostiniManager for testing.
+    crostini::CrostiniManager* crostini_manager =
+        crostini::CrostiniManager::GetForProfile(profile_.get());
+    crostini_manager->AddRunningVmForTesting(crostini::kCrostiniDefaultVmName);
+    crostini_manager->AddRunningContainerForTesting(
+        crostini::kCrostiniDefaultVmName,
+        crostini::ContainerInfo(crostini::kCrostiniDefaultContainerName,
+                                "testuser", "/home/testuser",
+                                "PLACEHOLDER_IP"));
+
+    // Register my files and crostini.
+    mount_points_ = storage::ExternalMountPoints::GetSystemInstance();
+    myfiles_mount_name_ =
+        file_manager::util::GetDownloadsMountPointName(profile_.get());
+    myfiles_dir_ =
+        file_manager::util::GetMyFilesFolderForProfile(profile_.get());
+    mount_points_->RegisterFileSystem(
+        myfiles_mount_name_, storage::kFileSystemTypeNativeLocal,
+        storage::FileSystemMountOption(), myfiles_dir_);
+    crostini_mount_name_ =
+        file_manager::util::GetCrostiniMountPointName(profile_.get());
+    crostini_dir_ =
+        file_manager::util::GetCrostiniMountDirectory(profile_.get());
+    mount_points_->RegisterFileSystem(
+        crostini_mount_name_, storage::kFileSystemTypeNativeLocal,
+        storage::FileSystemMountOption(), crostini_dir_);
+
+    // ChromeFileHelper always checks app type in window->GetToplevelWindow(),
+    // so we must create a parent window with delegate and app type set, but
+    // use the child window in tests.
+    // Arc:
+    arc_toplevel_ = aura::test::CreateTestWindowWithDelegate(
+        &delegate_, 0, gfx::Rect(), nullptr);
+    arc_toplevel_->SetProperty(aura::client::kAppType,
+                               static_cast<int>(ash::AppType::ARC_APP));
+    ASSERT_TRUE(ash::window_util::IsArcWindow(arc_toplevel_));
+    arc_window_ =
+        aura::test::CreateTestWindowWithBounds(gfx::Rect(), arc_toplevel_);
+    ASSERT_TRUE(
+        ash::window_util::IsArcWindow(arc_window_->GetToplevelWindow()));
+
+    // Crostini:
+    crostini_toplevel_ = aura::test::CreateTestWindowWithDelegate(
+        &delegate_, 0, gfx::Rect(), nullptr);
+    crostini_toplevel_->SetProperty(
+        aura::client::kAppType, static_cast<int>(ash::AppType::CROSTINI_APP));
+    ASSERT_TRUE(crostini::IsCrostiniWindow(crostini_toplevel_));
+    crostini_window_ =
+        aura::test::CreateTestWindowWithBounds(gfx::Rect(), crostini_toplevel_);
+    ASSERT_TRUE(
+        crostini::IsCrostiniWindow(crostini_window_->GetToplevelWindow()));
+
+    // Plugin VM:
+    plugin_vm_toplevel_ = aura::test::CreateTestWindowWithDelegate(
+        &delegate_, 0, gfx::Rect(), nullptr);
+    exo::SetShellApplicationId(plugin_vm_toplevel_,
+                               "org.chromium.plugin_vm_ui");
+    ASSERT_TRUE(plugin_vm::IsPluginVmAppWindow(plugin_vm_toplevel_));
+    plugin_vm_window_ = aura::test::CreateTestWindowWithBounds(
+        gfx::Rect(), plugin_vm_toplevel_);
+    ASSERT_TRUE(
+        plugin_vm::IsPluginVmAppWindow(plugin_vm_window_->GetToplevelWindow()));
+
+    // DBus seneschal client.
+    fake_seneschal_client_ = static_cast<chromeos::FakeSeneschalClient*>(
+        chromeos::DBusThreadManager::Get()->GetSeneschalClient());
+    ASSERT_TRUE(fake_seneschal_client_);
+  }
+
+  void TearDown() override {
+    mount_points_->RevokeAllFileSystems();
+    test_helper_.reset();
+    profile_.reset();
+    chromeos::DBusThreadManager::Shutdown();
+  }
+
+ protected:
+  Profile* profile() { return profile_.get(); }
+
+  content::BrowserTaskEnvironment task_environment_;
+  std::unique_ptr<TestingProfile> profile_;
+  std::unique_ptr<crostini::CrostiniTestHelper> test_helper_;
+
+  aura::test::TestWindowDelegate delegate_;
+  aura::Window* arc_toplevel_;
+  aura::Window* arc_window_;
+  aura::Window* crostini_toplevel_;
+  aura::Window* crostini_window_;
+  aura::Window* plugin_vm_toplevel_;
+  aura::Window* plugin_vm_window_;
+
+  storage::ExternalMountPoints* mount_points_;
+  std::string myfiles_mount_name_;
+  base::FilePath myfiles_dir_;
+  std::string crostini_mount_name_;
+  base::FilePath crostini_dir_;
+
+  chromeos::FakeSeneschalClient* fake_seneschal_client_ = nullptr;
+};
+
+TEST_F(ChromeFileHelperTest, GetFilenames) {
+  ChromeFileHelper file_helper;
+
+  // Multiple lines should be parsed.
+  // Arc should not translate paths.
+  std::vector<ui::FileInfo> files = file_helper.GetFilenames(
+      arc_window_, Data("\n\tfile:///file1\t\r\n#ignore\r\nfile:///file2\r\n"));
+  EXPECT_EQ(2, files.size());
+  EXPECT_EQ("/file1", files[0].path.value());
+  EXPECT_EQ("", files[0].display_name.value());
+  EXPECT_EQ("/file2", files[1].path.value());
+  EXPECT_EQ("", files[1].display_name.value());
+
+  // Crostini shared paths should be mapped.
+  files = file_helper.GetFilenames(crostini_window_,
+                                   Data("file:///mnt/chromeos/MyFiles/file"));
+  EXPECT_EQ(myfiles_dir_.Append("file"), files[0].path);
+
+  // Crostini homedir should be mapped.
+  files = file_helper.GetFilenames(crostini_window_,
+                                   Data("file:///home/testuser/file"));
+  EXPECT_EQ(crostini_dir_.Append("file"), files[0].path);
+
+  // Crostini internal paths should be mapped.
+  files = file_helper.GetFilenames(crostini_window_, Data("file:///etc/hosts"));
+  EXPECT_EQ("vmfile:termina:/etc/hosts", files[0].path.value());
+
+  // Plugin VM shared paths should be mapped.
+  files = file_helper.GetFilenames(plugin_vm_window_,
+                                   Data("file://ChromeOS/MyFiles/file"));
+  EXPECT_EQ(myfiles_dir_.Append("file"), files[0].path);
+
+  // Plugin VM internal paths should be mapped.
+  files = file_helper.GetFilenames(plugin_vm_window_,
+                                   Data("file:///C:/WINDOWS/notepad.exe"));
+  EXPECT_EQ("vmfile:PvmDefault:/C:/WINDOWS/notepad.exe", files[0].path.value());
+}
+
+TEST_F(ChromeFileHelperTest, GetMimeTypeForUriList) {
+  ChromeFileHelper file_helper;
+  EXPECT_EQ("application/x-arc-uri-list",
+            file_helper.GetMimeTypeForUriList(arc_window_));
+  EXPECT_EQ("text/uri-list",
+            file_helper.GetMimeTypeForUriList(crostini_window_));
+  EXPECT_EQ("text/uri-list",
+            file_helper.GetMimeTypeForUriList(plugin_vm_window_));
+}
+
+TEST_F(ChromeFileHelperTest, SendFileInfoConvertPaths) {
+  ChromeFileHelper file_helper;
+  ui::FileInfo file1(myfiles_dir_.Append("file1"), base::FilePath());
+  ui::FileInfo file2(myfiles_dir_.Append("file2"), base::FilePath());
+
+  // Arc should convert path to UTF16 URL.
+  std::string data;
+  file_helper.SendFileInfo(arc_window_, {file1},
+                           base::BindOnce(&CaptureUTF16, &data));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ(
+      "content://org.chromium.arc.volumeprovider/"
+      "0000000000000000000000000000CAFEF00D2019/file1",
+      data);
+
+  // Arc should join lines with CRLF.
+  file_helper.SendFileInfo(arc_window_, {file1, file2},
+                           base::BindOnce(&CaptureUTF16, &data));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ(
+      "content://org.chromium.arc.volumeprovider/"
+      "0000000000000000000000000000CAFEF00D2019/file1"
+      "\r\n"
+      "content://org.chromium.arc.volumeprovider/"
+      "0000000000000000000000000000CAFEF00D2019/file2",
+      data);
+
+  // Crostini should convert path to inside VM, and share the path.
+  file_helper.SendFileInfo(crostini_window_, {file1},
+                           base::BindOnce(&Capture, &data));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ("file:///mnt/chromeos/MyFiles/file1", data);
+
+  // Crostini should join lines with CRLF.
+  file_helper.SendFileInfo(crostini_window_, {file1, file2},
+                           base::BindOnce(&Capture, &data));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ(
+      "file:///mnt/chromeos/MyFiles/file1"
+      "\r\n"
+      "file:///mnt/chromeos/MyFiles/file2",
+      data);
+
+  // Plugin VM should convert path to inside VM.
+  file_helper.SendFileInfo(plugin_vm_window_, {file1},
+                           base::BindOnce(&Capture, &data));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ("file://ChromeOS/MyFiles/file1", data);
+
+  // Crostini should handle vmfile:termina:/etc/hosts.
+  file1.path = base::FilePath("vmfile:termina:/etc/hosts");
+  file_helper.SendFileInfo(crostini_window_, {file1},
+                           base::BindOnce(&Capture, &data));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ("file:///etc/hosts", data);
+
+  // Crostini should ignore vmfile:PvmDefault:C:/WINDOWS/notepad.exe.
+  file1.path = base::FilePath("vmfile:PvmDefault:C:/WINDOWS/notepad.exe");
+  file_helper.SendFileInfo(crostini_window_, {file1},
+                           base::BindOnce(&Capture, &data));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ("", data);
+
+  // Plugin VM should handle vmfile:PvmDefault:C:/WINDOWS/notepad.exe.
+  file1.path = base::FilePath("vmfile:PvmDefault:C:/WINDOWS/notepad.exe");
+  file_helper.SendFileInfo(plugin_vm_window_, {file1},
+                           base::BindOnce(&Capture, &data));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ("file:///C:/WINDOWS/notepad.exe", data);
+
+  // Crostini should handle vmfile:termina:/etc/hosts.
+  file1.path = base::FilePath("vmfile:termina:/etc/hosts");
+  file_helper.SendFileInfo(plugin_vm_window_, {file1},
+                           base::BindOnce(&Capture, &data));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ("", data);
+}
+
+TEST_F(ChromeFileHelperTest, SendFileInfoSharePaths) {
+  ChromeFileHelper file_helper;
+
+  // A path which is already shared should not be shared again.
+  base::FilePath shared_path = myfiles_dir_.Append("shared");
+  auto* guest_os_share_path =
+      guest_os::GuestOsSharePath::GetForProfile(profile());
+  guest_os_share_path->RegisterSharedPath(crostini::kCrostiniDefaultVmName,
+                                          shared_path);
+  ui::FileInfo file(shared_path, base::FilePath());
+  EXPECT_FALSE(fake_seneschal_client_->share_path_called());
+  std::string data;
+  file_helper.SendFileInfo(crostini_window_, {file},
+                           base::BindOnce(&Capture, &data));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ("file:///mnt/chromeos/MyFiles/shared", data);
+  EXPECT_FALSE(fake_seneschal_client_->share_path_called());
+
+  // A path which is not already shared should be shared.
+  file = ui::FileInfo(myfiles_dir_.Append("file"), base::FilePath());
+  file_helper.SendFileInfo(crostini_window_, {file},
+                           base::BindOnce(&Capture, &data));
+  task_environment_.RunUntilIdle();
+  EXPECT_EQ("file:///mnt/chromeos/MyFiles/file", data);
+  EXPECT_TRUE(fake_seneschal_client_->share_path_called());
+}
+
+TEST_F(ChromeFileHelperTest, HasUrlsInPickle) {
+  ChromeFileHelper file_helper;
+
+  // Pickle empty.
+  base::Pickle empty;
+  EXPECT_EQ(false, file_helper.HasUrlsInPickle(empty));
+
+  // Invalid FileInfo.url.
+  base::Pickle invalid;
+  content::DropData::FileSystemFileInfo file_info;
+  content::DropData::FileSystemFileInfo::WriteFileSystemFilesToPickle(
+      {file_info}, &invalid);
+  EXPECT_EQ(false, file_helper.HasUrlsInPickle(invalid));
+
+  // Valid FileInfo.url.
+  base::Pickle valid;
+  storage::FileSystemURL url = mount_points_->CreateExternalFileSystemURL(
+      url::Origin::Create(GURL("http://example.com")), myfiles_mount_name_,
+      base::FilePath("path"));
+  file_info.url = url.ToGURL();
+  content::DropData::FileSystemFileInfo::WriteFileSystemFilesToPickle(
+      {file_info}, &valid);
+  EXPECT_EQ(true, file_helper.HasUrlsInPickle(valid));
+}
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index 61bc783..af5c37aa 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -2234,12 +2234,13 @@
 ExtensionFunction::ResponseAction AutotestPrivateTakeScreenshotFunction::Run() {
   DVLOG(1) << "AutotestPrivateTakeScreenshotFunction";
   auto grabber = std::make_unique<ui::ScreenshotGrabber>();
+  auto* const grabber_ptr = grabber.get();
   // TODO(mash): Fix for mash, http://crbug.com/557397
   aura::Window* primary_root = ash::Shell::GetPrimaryRootWindow();
   // Pass the ScreenshotGrabber to the callback so that it stays alive for the
   // duration of the operation, it'll then get deallocated when the callback
   // completes.
-  grabber->TakeScreenshot(
+  grabber_ptr->TakeScreenshot(
       primary_root, primary_root->bounds(),
       base::BindOnce(&AutotestPrivateTakeScreenshotFunction::ScreenshotTaken,
                      this, std::move(grabber)));
@@ -2280,7 +2281,8 @@
     const int64_t display_id =
         display::Screen::GetScreen()->GetDisplayNearestWindow(window).id();
     if (display_id == target_display_id) {
-      grabber->TakeScreenshot(
+      auto* const grabber_ptr = grabber.get();
+      grabber_ptr->TakeScreenshot(
           window, window->bounds(),
           base::BindOnce(
               &AutotestPrivateTakeScreenshotForDisplayFunction::ScreenshotTaken,
diff --git a/chrome/browser/chromeos/extensions/file_manager/event_router.h b/chrome/browser/chromeos/extensions/file_manager/event_router.h
index 8eaf90b..3ef8b04 100644
--- a/chrome/browser/chromeos/extensions/file_manager/event_router.h
+++ b/chrome/browser/chromeos/extensions/file_manager/event_router.h
@@ -13,7 +13,6 @@
 #include <vector>
 
 #include "base/compiler_specific.h"
-#include "base/files/file_path_watcher.h"
 #include "base/macros.h"
 #include "base/optional.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
diff --git a/chrome/browser/chromeos/extensions/input_method_api.cc b/chrome/browser/chromeos/extensions/input_method_api.cc
index 43fe9666..c6385d5 100644
--- a/chrome/browser/chromeos/extensions/input_method_api.cc
+++ b/chrome/browser/chromeos/extensions/input_method_api.cc
@@ -570,8 +570,8 @@
   const auto parent_params = SetAutocorrectRange::Params::Create(*args_);
   const auto& params = parent_params->parameters;
   if (!engine->SetAutocorrectRange(
-          params.context_id, base::UTF8ToUTF16(params.autocorrect_string),
-          params.selection_start, params.selection_end, &error)) {
+          params.context_id,
+          gfx::Range(params.selection_start, params.selection_end), &error)) {
     auto results = std::make_unique<base::ListValue>();
     results->Append(std::make_unique<base::Value>(false));
     return RespondNow(Error(InformativeError(error, static_function_name())));
diff --git a/chrome/browser/chromeos/file_manager/filesystem_api_util.cc b/chrome/browser/chromeos/file_manager/filesystem_api_util.cc
index f3fbeff0..0c8d23f5 100644
--- a/chrome/browser/chromeos/file_manager/filesystem_api_util.cc
+++ b/chrome/browser/chromeos/file_manager/filesystem_api_util.cc
@@ -115,7 +115,8 @@
     base::OnceCallback<void(bool)> callback) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
-  file_system_context->operation_runner()->FileExists(
+  auto* const operation_runner = file_system_context->operation_runner();
+  operation_runner->FileExists(
       url, base::BindOnce(&PrepareFileAfterCheckExistOnIOThread,
                           std::move(file_system_context), url,
                           base::BindOnce(&BoolCallbackAsFileErrorCallback,
diff --git a/chrome/browser/chromeos/full_restore/full_restore_service.cc b/chrome/browser/chromeos/full_restore/full_restore_service.cc
new file mode 100644
index 0000000..f5aff1f
--- /dev/null
+++ b/chrome/browser/chromeos/full_restore/full_restore_service.cc
@@ -0,0 +1,22 @@
+// Copyright 2020 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/full_restore/full_restore_service.h"
+
+#include "chrome/browser/chromeos/full_restore/full_restore_service_factory.h"
+#include "chrome/browser/profiles/profile.h"
+
+namespace chromeos {
+namespace full_restore {
+
+FullRestoreService::FullRestoreService(Profile* profile) {
+  // TODO(crbug.com/909794):If the system crashed before reboot, show the
+  // notification notification. Otherwise, read |kRestoreAppsAndPagesPrefName|
+  // from the user pref.
+}
+
+FullRestoreService::~FullRestoreService() = default;
+
+}  // namespace full_restore
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/full_restore/full_restore_service.h b/chrome/browser/chromeos/full_restore/full_restore_service.h
new file mode 100644
index 0000000..bc98edc
--- /dev/null
+++ b/chrome/browser/chromeos/full_restore/full_restore_service.h
@@ -0,0 +1,40 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_FULL_RESTORE_FULL_RESTORE_SERVICE_H_
+#define CHROME_BROWSER_CHROMEOS_FULL_RESTORE_FULL_RESTORE_SERVICE_H_
+
+#include "components/keyed_service/core/keyed_service.h"
+
+class Profile;
+
+namespace chromeos {
+namespace full_restore {
+
+// The FullRestoreService class calls AppService and Window Management
+// interfaces to restore the app launchings and app windows.
+//
+// 1. If the system is recovered from the crash, creates the notification to let
+// the user select restore or not.
+// 2. For normal reboot, read the restore setting fromt the user pref, and based
+// on the setting to decide restore or not.
+//
+// TODO(crbug.com/909794):
+// 1. If the system crashed before reboot, show the notification notification.
+// Otherwise, read |kRestoreAppsAndPagesPrefName|
+// 2. Observe the AppRegistryCache to read the app info, and restore apps and
+// app windows.
+class FullRestoreService : public KeyedService {
+ public:
+  explicit FullRestoreService(Profile* profile);
+  ~FullRestoreService() override;
+
+  FullRestoreService(const FullRestoreService&) = delete;
+  FullRestoreService& operator=(const FullRestoreService&) = delete;
+};
+
+}  // namespace full_restore
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_FULL_RESTORE_FULL_RESTORE_SERVICE_H_
diff --git a/chrome/browser/chromeos/full_restore/full_restore_service_factory.cc b/chrome/browser/chromeos/full_restore/full_restore_service_factory.cc
new file mode 100644
index 0000000..9ea4936
--- /dev/null
+++ b/chrome/browser/chromeos/full_restore/full_restore_service_factory.cc
@@ -0,0 +1,53 @@
+// Copyright 2020 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/full_restore/full_restore_service_factory.h"
+
+#include "ash/public/cpp/ash_features.h"
+#include "chrome/browser/chromeos/full_restore/full_restore_service.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+
+namespace chromeos {
+namespace full_restore {
+
+// static
+FullRestoreServiceFactory* FullRestoreServiceFactory::GetInstance() {
+  static base::NoDestructor<FullRestoreServiceFactory> instance;
+  return instance.get();
+}
+
+// static
+FullRestoreService* FullRestoreServiceFactory::GetForBrowserContext(
+    content::BrowserContext* browser_context) {
+  if (!ash::features::IsFullRestoreEnabled())
+    return nullptr;
+
+  // No service for non-regular user profile, or ephemeral user profile.
+  Profile* profile = Profile::FromBrowserContext(browser_context);
+  if (!ProfileHelper::IsRegularProfile(profile) ||
+      ProfileHelper::IsEphemeralUserProfile(profile)) {
+    return nullptr;
+  }
+
+  return static_cast<FullRestoreService*>(
+      FullRestoreServiceFactory::GetInstance()->GetServiceForBrowserContext(
+          browser_context, true));
+}
+
+FullRestoreServiceFactory::FullRestoreServiceFactory()
+    : BrowserContextKeyedServiceFactory(
+          "FullRestoreService",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+FullRestoreServiceFactory::~FullRestoreServiceFactory() = default;
+
+KeyedService* FullRestoreServiceFactory::BuildServiceInstanceFor(
+    content::BrowserContext* context) const {
+  return new FullRestoreService(Profile::FromBrowserContext(context));
+}
+
+}  // namespace full_restore
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/full_restore/full_restore_service_factory.h b/chrome/browser/chromeos/full_restore/full_restore_service_factory.h
new file mode 100644
index 0000000..dbdb93a
--- /dev/null
+++ b/chrome/browser/chromeos/full_restore/full_restore_service_factory.h
@@ -0,0 +1,45 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_CHROMEOS_FULL_RESTORE_FULL_RESTORE_SERVICE_FACTORY_H_
+#define CHROME_BROWSER_CHROMEOS_FULL_RESTORE_FULL_RESTORE_SERVICE_FACTORY_H_
+
+#include "base/no_destructor.h"
+#include "chrome/browser/chromeos/full_restore/full_restore_service.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace content {
+class BrowserContext;
+}
+
+namespace chromeos {
+namespace full_restore {
+
+// Singleton factory that builds and owns FullRestoreService.
+class FullRestoreServiceFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  static FullRestoreServiceFactory* GetInstance();
+
+  static FullRestoreService* GetForBrowserContext(
+      content::BrowserContext* browser_context);
+
+ private:
+  friend base::NoDestructor<FullRestoreServiceFactory>;
+
+  FullRestoreServiceFactory();
+  ~FullRestoreServiceFactory() override;
+
+  FullRestoreServiceFactory(const FullRestoreServiceFactory&) = delete;
+  FullRestoreServiceFactory& operator=(const FullRestoreServiceFactory&) =
+      delete;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* context) const override;
+};
+
+}  // namespace full_restore
+}  // namespace chromeos
+
+#endif  // CHROME_BROWSER_CHROMEOS_FULL_RESTORE_FULL_RESTORE_SERVICE_FACTORY_H_
diff --git a/chrome/browser/chromeos/guest_os/guest_os_share_path.cc b/chrome/browser/chromeos/guest_os/guest_os_share_path.cc
index d8a8289..d900ede 100644
--- a/chrome/browser/chromeos/guest_os/guest_os_share_path.cc
+++ b/chrome/browser/chromeos/guest_os/guest_os_share_path.cc
@@ -470,7 +470,7 @@
           base::Owned(new ErrorCapture(paths.size(), std::move(callback))));
   for (const auto& path : paths) {
     CallSeneschalSharePath(vm_name, path, persist,
-                           base::BindOnce(barrier, std::move(path)));
+                           base::BindOnce(barrier, path));
   }
 }
 
diff --git a/chrome/browser/chromeos/input_method/autocorrect_manager.cc b/chrome/browser/chromeos/input_method/autocorrect_manager.cc
index 26dd60e..519471e 100644
--- a/chrome/browser/chromeos/input_method/autocorrect_manager.cc
+++ b/chrome/browser/chromeos/input_method/autocorrect_manager.cc
@@ -13,6 +13,7 @@
 #include "ui/base/ime/chromeos/ime_input_context_handler_interface.h"
 #include "ui/base/l10n/l10n_util.h"
 
+namespace chromeos {
 namespace {
 
 // These values are persisted to logs. Entries should not be renumbered and
@@ -21,7 +22,8 @@
 enum class AutocorrectActions {
   kWindowShown = 0,
   kUnderlined = 1,
-  kMaxValue = kUnderlined,
+  kReverted = 2,
+  kMaxValue = kReverted,
 };
 
 void LogAssistiveAutocorrectAction(AutocorrectActions action) {
@@ -29,34 +31,29 @@
                                 action);
 }
 
-}  // namespace
-
-namespace chromeos {
-
 constexpr int kKeysUntilAutocorrectWindowHides = 4;
 
+}  // namespace
+
 AutocorrectManager::AutocorrectManager(
     SuggestionHandlerInterface* suggestion_handler)
     : suggestion_handler_(suggestion_handler) {}
 
-void AutocorrectManager::MarkAutocorrectRange(const std::string& corrected_word,
-                                              const std::string& typed_word,
-                                              int start_index) {
+void AutocorrectManager::MarkAutocorrectRange(
+    gfx::Range autocorrect_range,
+    const std::string& original_text) {
   // TODO(crbug/1111135): call setAutocorrectTime() (for metrics)
   // TODO(crbug/1111135): record metric (coverage)
-  last_typed_word_ = typed_word;
-  last_corrected_word_ = corrected_word;
+  ui::IMEInputContextHandlerInterface* input_context =
+      ui::IMEBridge::Get()->GetInputContextHandler();
+  if (!input_context)
+    return;
+
+  original_text_ = original_text;
   key_presses_until_underline_hide_ = kKeysUntilAutocorrectWindowHides;
   ClearUnderline();
 
-  ui::IMEInputContextHandlerInterface* input_context =
-      ui::IMEBridge::Get()->GetInputContextHandler();
-  if (input_context) {
-    input_context->SetAutocorrectRange(base::UTF8ToUTF16(corrected_word),
-                                       start_index,
-                                       start_index + corrected_word.length());
-    LogAssistiveAutocorrectAction(AutocorrectActions::kUnderlined);
-  }
+  input_context->SetAutocorrectRange(autocorrect_range);
 }
 
 bool AutocorrectManager::OnKeyEvent(
@@ -71,7 +68,7 @@
     button.window_type = ui::ime::AssistiveWindowType::kUndoWindow;
     button.announce_string =
         l10n_util::GetStringFUTF8(IDS_SUGGESTION_AUTOCORRECT_UNDO_BUTTON,
-                                  base::UTF8ToUTF16(last_typed_word_));
+                                  base::UTF8ToUTF16(original_text_));
     suggestion_handler_->SetButtonHighlighted(context_id_, button, true,
                                               &error);
     button_highlighted = true;
@@ -94,7 +91,7 @@
   ui::IMEInputContextHandlerInterface* input_context =
       ui::IMEBridge::Get()->GetInputContextHandler();
   if (input_context) {
-    input_context->ClearAutocorrectRange();
+    input_context->SetAutocorrectRange(gfx::Range());
   }
 }
 
@@ -108,13 +105,15 @@
   if (!range.is_empty() && cursor_pos >= range.start() &&
       cursor_pos <= range.end()) {
     if (!window_visible) {
+      const std::string autocorrected_text =
+          base::UTF16ToUTF8(text.substr(range.start(), range.length()));
       chromeos::AssistiveWindowProperties properties;
       properties.type = ui::ime::AssistiveWindowType::kUndoWindow;
       properties.visible = true;
       properties.announce_string = l10n_util::GetStringFUTF8(
           IDS_SUGGESTION_AUTOCORRECT_UNDO_WINDOW_SHOWN,
-          base::UTF8ToUTF16(last_typed_word_),
-          base::UTF8ToUTF16(last_corrected_word_));
+          base::UTF8ToUTF16(original_text_),
+          base::UTF8ToUTF16(autocorrected_text));
       window_visible = true;
       button_highlighted = false;
       suggestion_handler_->SetAssistiveWindowProperties(context_id_, properties,
@@ -177,7 +176,8 @@
   input_context->CommitText(
       (base::UTF16ToUTF8(
            surrounding_text.surrounding_text.substr(0, range.start())) +
-       last_typed_word_));
+       original_text_));
+  LogAssistiveAutocorrectAction(AutocorrectActions::kReverted);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/input_method/autocorrect_manager.h b/chrome/browser/chromeos/input_method/autocorrect_manager.h
index 54ec52b..ba3c420 100644
--- a/chrome/browser/chromeos/input_method/autocorrect_manager.h
+++ b/chrome/browser/chromeos/input_method/autocorrect_manager.h
@@ -25,12 +25,10 @@
   AutocorrectManager(const AutocorrectManager&) = delete;
   AutocorrectManager& operator=(const AutocorrectManager&) = delete;
 
-  // Called by input method engine on autocorrect to initially show underline.
-  // Needs to be called after the autocorrected text (corrected_word, offset by
-  // start_index code points in SurroundingInfo) has been committed.
-  void MarkAutocorrectRange(const std::string& corrected_word,
-                            const std::string& typed_word,
-                            int start_index);
+  // Mark `autocorrect_range` with an underline. `autocorrect_range` is based on
+  // the current text contents.
+  void MarkAutocorrectRange(gfx::Range autocorrect_range,
+                            const std::string& original_text);
 
   // To hide the underline after enough keypresses, this class intercepts
   // keystrokes. Returns whether the keypress has now been handled.
@@ -53,8 +51,7 @@
   SuggestionHandlerInterface* suggestion_handler_;
   int context_id_ = 0;
   int key_presses_until_underline_hide_ = 0;
-  std::string last_typed_word_;
-  std::string last_corrected_word_;
+  std::string original_text_;
   bool window_visible = false;
   bool button_highlighted = false;
 };
diff --git a/chrome/browser/chromeos/input_method/autocorrect_manager_unittest.cc b/chrome/browser/chromeos/input_method/autocorrect_manager_unittest.cc
index 3d0ed80..ab1e72a 100644
--- a/chrome/browser/chromeos/input_method/autocorrect_manager_unittest.cc
+++ b/chrome/browser/chromeos/input_method/autocorrect_manager_unittest.cc
@@ -78,7 +78,7 @@
   MockSuggestionHandler mock_suggestion_handler;
   AutocorrectManager manager(&mock_suggestion_handler);
 
-  manager.MarkAutocorrectRange("the", "teh", /*start_index=*/0);
+  manager.MarkAutocorrectRange(gfx::Range(0, 3), "teh");
 
   EXPECT_EQ(mock_ime_input_context_handler.GetAutocorrectRange(),
             gfx::Range(0, 3));
@@ -90,7 +90,7 @@
   ui::IMEBridge::Get()->SetInputContextHandler(&mock_ime_input_context_handler);
   MockSuggestionHandler mock_suggestion_handler;
   AutocorrectManager manager(&mock_suggestion_handler);
-  manager.MarkAutocorrectRange("the", "teh", /*start_index=*/0);
+  manager.MarkAutocorrectRange(gfx::Range(0, 3), "teh");
 
   const auto key_event = CreateKeyEvent("a", "KeyA");
   EXPECT_FALSE(manager.OnKeyEvent(key_event));
@@ -110,7 +110,7 @@
   AutocorrectManager manager(&mock_suggestion_handler);
   manager.OnSurroundingTextChanged(base::ASCIIToUTF16("the "), /*cursor_pos=*/4,
                                    /*anchor_pos=*/4);
-  manager.MarkAutocorrectRange("the", "teh", /*start_index=*/0);
+  manager.MarkAutocorrectRange(gfx::Range(0, 3), "teh");
 
   AssistiveWindowProperties properties;
   properties.type = ui::ime::AssistiveWindowType::kUndoWindow;
@@ -133,7 +133,7 @@
   AutocorrectManager manager(&mock_suggestion_handler);
   manager.OnSurroundingTextChanged(base::ASCIIToUTF16("the "), /*cursor_pos=*/4,
                                    /*anchor_pos=*/4);
-  manager.MarkAutocorrectRange("the", "teh", /*start_index=*/0);
+  manager.MarkAutocorrectRange(gfx::Range(0, 3), "teh");
 
   {
     ::testing::InSequence seq;
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.cc b/chrome/browser/chromeos/input_method/input_method_engine.cc
index 6559b0e..c5ea49f 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine.cc
@@ -479,23 +479,12 @@
   return input_context->GetAutocorrectCharacterBounds();
 }
 
-bool InputMethodEngine::SetAutocorrectRange(
-    const base::string16& autocorrect_text,
-    uint32_t start,
-    uint32_t end) {
+bool InputMethodEngine::SetAutocorrectRange(const gfx::Range& range) {
   ui::IMEInputContextHandlerInterface* input_context =
       ui::IMEBridge::Get()->GetInputContextHandler();
   if (!input_context)
     return false;
-  return input_context->SetAutocorrectRange(autocorrect_text, start, end);
-}
-
-void InputMethodEngine::ClearAutocorrectRange() {
-  ui::IMEInputContextHandlerInterface* input_context =
-      ui::IMEBridge::Get()->GetInputContextHandler();
-  if (!input_context)
-    return;
-  return input_context->ClearAutocorrectRange();
+  return input_context->SetAutocorrectRange(range);
 }
 
 bool InputMethodEngine::SetSelectionRange(uint32_t start, uint32_t end) {
diff --git a/chrome/browser/chromeos/input_method/input_method_engine.h b/chrome/browser/chromeos/input_method/input_method_engine.h
index 4646c7a..ad61555 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine.h
+++ b/chrome/browser/chromeos/input_method/input_method_engine.h
@@ -175,18 +175,12 @@
   // event handler.
   bool IsValidKeyEvent(const ui::KeyEvent* ui_event) override;
 
-  // Sets a range as autocorrected to display a special dashed underline.  Start
-  // and end are code point offsets in the surroundingTextInfo which control the
-  // start and end point of the underline which is added to the text to show a
-  // word was autocorrected.
+  // Sets the autocorrect range to be `range`. The `range` is in bytes.
   // TODO(b/171924748): Improve documentation for this function all the way down
   // the stack.
-  bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                           uint32_t start,
-                           uint32_t end) override;
+  bool SetAutocorrectRange(const gfx::Range& range) override;
 
   gfx::Range GetAutocorrectRange() override;
-  void ClearAutocorrectRange() override;
 
  private:
   // InputMethodEngineBase:
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_base.cc b/chrome/browser/chromeos/input_method/input_method_engine_base.cc
index ccb5295..38fa6d5d 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_base.cc
+++ b/chrome/browser/chromeos/input_method/input_method_engine_base.cc
@@ -625,12 +625,9 @@
   return GetAutocorrectCharacterBounds();
 }
 
-bool InputMethodEngineBase::SetAutocorrectRange(
-    int context_id,
-    const base::string16& autocorrect_text,
-    int start,
-    int end,
-    std::string* error) {
+bool InputMethodEngineBase::SetAutocorrectRange(int context_id,
+                                                const gfx::Range& range,
+                                                std::string* error) {
   if (!IsActive()) {
     *error = kErrorNotActive;
     return false;
@@ -641,8 +638,7 @@
         kErrorWrongContext, context_id, context_id_);
     return false;
   }
-  return SetAutocorrectRange(autocorrect_text, static_cast<uint32_t>(start),
-                             static_cast<uint32_t>(end));
+  return SetAutocorrectRange(range);
 }
 
 bool InputMethodEngineBase::SetSelectionRange(int context_id,
diff --git a/chrome/browser/chromeos/input_method/input_method_engine_base.h b/chrome/browser/chromeos/input_method/input_method_engine_base.h
index 0d8503ed..cc19114 100644
--- a/chrome/browser/chromeos/input_method/input_method_engine_base.h
+++ b/chrome/browser/chromeos/input_method/input_method_engine_base.h
@@ -222,13 +222,9 @@
   gfx::Rect GetAutocorrectCharacterBounds(int context_id, std::string* error);
 
   bool SetAutocorrectRange(int context_id,
-                           const base::string16& autocorrect_text,
-                           int start,
-                           int end,
+                           const gfx::Range& range,
                            std::string* error);
 
-  virtual void ClearAutocorrectRange() = 0;
-
   // Set the current selection range.
   bool SetSelectionRange(int context_id,
                          int start,
@@ -302,9 +298,7 @@
 
   // Notifies the InputContextHandler that the autocorrect range should
   // be updated and the autocorrect text has updated.
-  virtual bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                                   uint32_t start,
-                                   uint32_t end) = 0;
+  virtual bool SetAutocorrectRange(const gfx::Range& range) = 0;
 
   // Notifies the InputContextHandler to change the selection range.
   virtual bool SetSelectionRange(uint32_t start, uint32_t end) = 0;
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
index 9a1477a..015e302 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.cc
@@ -1032,11 +1032,6 @@
   ime_menu_observers_.RemoveObserver(observer);
 }
 
-std::unique_ptr<InputMethodDescriptors>
-InputMethodManagerImpl::GetSupportedInputMethods() const {
-  return std::unique_ptr<InputMethodDescriptors>(new InputMethodDescriptors);
-}
-
 const InputMethodDescriptor* InputMethodManagerImpl::LookupInputMethod(
     const std::string& input_method_id,
     InputMethodManagerImpl::StateImpl* state) {
diff --git a/chrome/browser/chromeos/input_method/input_method_manager_impl.h b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
index 897291f..dca9e6d2 100644
--- a/chrome/browser/chromeos/input_method/input_method_manager_impl.h
+++ b/chrome/browser/chromeos/input_method/input_method_manager_impl.h
@@ -205,8 +205,6 @@
       InputMethodManager::CandidateWindowObserver* observer) override;
   void RemoveImeMenuObserver(
       InputMethodManager::ImeMenuObserver* observer) override;
-  std::unique_ptr<InputMethodDescriptors> GetSupportedInputMethods()
-      const override;
   void ActivateInputMethodMenuItem(const std::string& key) override;
   void ConnectInputEngineManager(
       mojo::PendingReceiver<chromeos::ime::mojom::InputEngineManager> receiver)
diff --git a/chrome/browser/chromeos/input_method/input_method_syncer.cc b/chrome/browser/chromeos/input_method/input_method_syncer.cc
index f5345d66..6ed7122 100644
--- a/chrome/browser/chromeos/input_method/input_method_syncer.cc
+++ b/chrome/browser/chromeos/input_method/input_method_syncer.cc
@@ -252,11 +252,11 @@
       pref_name == prefs::kLanguageEnabledImes) {
     input_method::InputMethodManager* manager =
         input_method::InputMethodManager::Get();
-    std::unique_ptr<input_method::InputMethodDescriptors> supported_descriptors;
+    std::unique_ptr<input_method::InputMethodDescriptors>
+        supported_descriptors =
+            std::make_unique<input_method::InputMethodDescriptors>();
 
     if (pref_name == prefs::kLanguagePreloadEngines) {
-      // Set the known input methods.
-      supported_descriptors = manager->GetSupportedInputMethods();
       // Add the available component extension IMEs.
       ComponentExtensionIMEManager* component_extension_manager =
           manager->GetComponentExtensionIMEManager();
@@ -266,7 +266,6 @@
                                     component_descriptors.begin(),
                                     component_descriptors.end());
     } else {
-      supported_descriptors.reset(new input_method::InputMethodDescriptors);
       ime_state_->GetInputMethodExtensions(supported_descriptors.get());
     }
     CheckAndResolveInputMethodIDs(*supported_descriptors, &new_token_values);
diff --git a/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc b/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc
index 7ba1f3a1..a8a056d 100644
--- a/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc
+++ b/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.cc
@@ -84,18 +84,6 @@
   ++remove_menu_observer_count_;
 }
 
-std::unique_ptr<InputMethodDescriptors>
-MockInputMethodManagerImpl::GetSupportedInputMethods() const {
-  std::unique_ptr<InputMethodDescriptors> result;
-#if _LIBCPP_STD_VER > 11
-  result = std::make_unique<InputMethodDescriptors>();
-#else
-  result.reset(new InputMethodDescriptors);
-#endif
-  result->push_back(InputMethodUtil::GetFallbackInputMethodDescriptor());
-  return result;
-}
-
 bool MockInputMethodManagerImpl::IsISOLevel5ShiftUsedByCurrentInputMethod()
     const {
   return mod3_used_;
diff --git a/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h b/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h
index de84f5e..4259f4c 100644
--- a/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h
+++ b/chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h
@@ -12,7 +12,6 @@
 #include "ui/base/ime/chromeos/fake_ime_keyboard.h"
 #include "ui/base/ime/chromeos/fake_input_method_delegate.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
-#include "ui/base/ime/chromeos/input_method_allowlist.h"
 #include "ui/base/ime/chromeos/mock_input_method_manager.h"
 
 namespace chromeos {
@@ -54,8 +53,6 @@
   void AddImeMenuObserver(ImeMenuObserver* observer) override;
   void RemoveObserver(InputMethodManager::Observer* observer) override;
   void RemoveImeMenuObserver(ImeMenuObserver* observer) override;
-  std::unique_ptr<InputMethodDescriptors> GetSupportedInputMethods()
-      const override;
   bool IsISOLevel5ShiftUsedByCurrentInputMethod() const override;
   ImeKeyboard* GetImeKeyboard() override;
   InputMethodUtil* GetInputMethodUtil() override;
diff --git a/chrome/browser/chromeos/input_method/native_input_method_engine.cc b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
index 55f16206..3196a08 100644
--- a/chrome/browser/chromeos/input_method/native_input_method_engine.cc
+++ b/chrome/browser/chromeos/input_method/native_input_method_engine.cc
@@ -113,10 +113,6 @@
   UMA_HISTOGRAM_ENUMERATION("InputMethod.Mojo.Extension.Event", event);
 }
 
-void LogLatency(const char* name, const base::TimeDelta& latency) {
-  base::UmaHistogramCustomCounts(name, latency.InMilliseconds(), 0, 1000, 50);
-}
-
 }  // namespace
 
 NativeInputMethodEngine::NativeInputMethodEngine() = default;
@@ -155,8 +151,9 @@
 void NativeInputMethodEngine::OnAutocorrect(std::string typed_word,
                                             std::string corrected_word,
                                             int start_index) {
-  autocorrect_manager_->MarkAutocorrectRange(corrected_word, typed_word,
-                                             start_index);
+  autocorrect_manager_->MarkAutocorrectRange(
+      gfx::Range(start_index, start_index + corrected_word.length()),
+      typed_word);
 }
 
 NativeInputMethodEngine::ImeObserver*
@@ -181,11 +178,8 @@
       ShouldUseFstMojoEngine(engine_id)) {
     if (!remote_manager_.is_bound()) {
       auto* ime_manager = input_method::InputMethodManager::Get();
-      const auto start = base::Time::Now();
       ime_manager->ConnectInputEngineManager(
           remote_manager_.BindNewPipeAndPassReceiver());
-      LogLatency("InputMethod.Mojo.Extension.ServiceInitLatency",
-                 base::Time::Now() - start);
       remote_manager_.set_disconnect_handler(base::BindOnce(
           &ImeObserver::OnError, base::Unretained(this), base::Time::Now()));
       LogEvent(ImeServiceEvent::kInitSuccess);
@@ -446,8 +440,6 @@
 void NativeInputMethodEngine::ImeObserver::OnConnected(base::Time start,
                                                        std::string engine_id,
                                                        bool bound) {
-  LogLatency("InputMethod.Mojo.Extension.ActivateIMELatency",
-             base::Time::Now() - start);
   LogEvent(bound ? ImeServiceEvent::kActivateImeSuccess
                  : ImeServiceEvent::kActivateImeSuccess);
 }
@@ -471,9 +463,6 @@
     base::Time start,
     ui::IMEEngineHandlerInterface::KeyEventDoneCallback callback,
     ime::mojom::KeypressResponseForRulebasedPtr response) {
-  LogLatency("InputMethod.Mojo.Extension.Rulebased.ProcessLatency",
-             base::Time::Now() - start);
-
   for (const auto& op : response->operations) {
     switch (op->method) {
       case ime::mojom::OperationMethodForRulebased::COMMIT_TEXT:
diff --git a/chrome/browser/chromeos/login/oobe_localization_browsertest.cc b/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
index 8c46461..d911671 100644
--- a/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
+++ b/chrome/browser/chromeos/login/oobe_localization_browsertest.cc
@@ -34,7 +34,6 @@
 #include "content/public/test/browser_test_utils.h"
 #include "content/public/test/test_utils.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
-#include "ui/base/ime/chromeos/input_method_allowlist.h"
 #include "ui/base/ime/chromeos/input_method_manager.h"
 #include "ui/base/ime/chromeos/input_method_util.h"
 
diff --git a/chrome/browser/chromeos/login/quick_unlock/pin_storage_cryptohome.cc b/chrome/browser/chromeos/login/quick_unlock/pin_storage_cryptohome.cc
index dd04795a7..684cb08 100644
--- a/chrome/browser/chromeos/login/quick_unlock/pin_storage_cryptohome.cc
+++ b/chrome/browser/chromeos/login/quick_unlock/pin_storage_cryptohome.cc
@@ -97,6 +97,7 @@
   if (attempt > kMaxRetryTimes) {
     LOG(ERROR) << "Could not talk to cryptohomed";
     std::move(result).Run(false);
+    return;
   }
   if (!is_available) {
     const int retry_delay_in_milliseconds = 500 * (1 << attempt);
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc
index 14f7e1b..6a06d68 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_browsertest.cc
@@ -13,7 +13,6 @@
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
 #include "base/optional.h"
-#include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
@@ -28,7 +27,6 @@
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/extensions/extension_service.h"
-#include "chrome/browser/policy/extension_force_install_mixin.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/common/chrome_constants.h"
@@ -50,7 +48,6 @@
 #include "components/policy/proto/chrome_extension_policy.pb.h"
 #include "components/policy/proto/device_management_backend.pb.h"
 #include "content/public/test/browser_test.h"
-#include "content/public/test/test_launcher.h"
 #include "crypto/rsa_private_key.h"
 #include "crypto/sha2.h"
 #include "extensions/browser/extension_registry.h"
@@ -270,21 +267,28 @@
 
 // Tests how component policy is handled for extensions installed on the sign-in
 // screen.
-class DeviceComponentPolicyBrowserTest : public DevicePolicyCrosBrowserTest {
+class SigninExtensionsDeviceCloudPolicyBrowserTest
+    : public DevicePolicyCrosBrowserTest {
  public:
   static constexpr const char* kTestExtensionId =
       "hifnmfgfdfhmoaponfpmnlpeahiomjim";
   static constexpr const char* kTestExtensionPath =
-      "extensions/signin_screen_managed_storage/extension/";
-  static constexpr const char* kTestExtensionPemPath =
-      "extensions/signin_screen_managed_storage/extension.pem";
+      "extensions/signin_screen_managed_storage/extension.crx";
+  static constexpr const char* kTestExtensionUpdateManifestPath =
+      "/extensions/signin_screen_managed_storage/update_manifest.xml";
+  static constexpr const char* kTestExtensionUpdateManifest =
+      R"(<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
+           <app appid='$1'>
+             <updatecheck codebase='http://$2/$3' version='1.0' />
+           </app>
+         </gupdate>)";
   static constexpr const char* kFakePolicyPath = "/test-policy.json";
   static constexpr const char* kFakePolicy =
       "{\"string-policy\": {\"Value\": \"value\"}}";
   static constexpr int kFakePolicyPublicKeyVersion = 1;
 
-  DeviceComponentPolicyBrowserTest() = default;
-  ~DeviceComponentPolicyBrowserTest() override = default;
+  SigninExtensionsDeviceCloudPolicyBrowserTest() = default;
+  ~SigninExtensionsDeviceCloudPolicyBrowserTest() override = default;
 
   void SetUp() override {
     ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
@@ -314,51 +318,57 @@
   void SetUpOnMainThread() override {
     DevicePolicyCrosBrowserTest::SetUpOnMainThread();
 
-    StartTestServer();
-
-    extension_result_catcher_ = std::make_unique<extensions::ResultCatcher>();
-
-    extension_force_install_mixin_.InitWithDevicePolicyCrosTestHelper(
-        chromeos::ProfileHelper::GetSigninProfile(), policy_helper());
-    ASSERT_TRUE(extension_force_install_mixin_.ForceInstallFromSourceDir(
-        base::PathService::CheckedGet(chrome::DIR_TEST_DATA)
-            .Append(kTestExtensionPath),
-        base::PathService::CheckedGet(chrome::DIR_TEST_DATA)
-            .Append(kTestExtensionPemPath),
-        ExtensionForceInstallMixin::WaitMode::kNone));
-
     BrowserPolicyConnectorChromeOS* connector =
         g_browser_process->platform_part()->browser_policy_connector_chromeos();
     connector->device_management_service()->ScheduleInitialization(0);
   }
 
-  void TearDownOnMainThread() override {
-    extension_result_catcher_.reset();
-    DevicePolicyCrosBrowserTest::TearDownOnMainThread();
-  }
-
-  extensions::ResultCatcher* extension_result_catcher() {
-    return extension_result_catcher_.get();
-  }
-
- private:
-  void StartTestServer() {
+  // |hang_component_policy_fetch| - whether requests for the component policy
+  // download should be hung indefinitely.
+  void StartTestServer(bool hang_component_policy_fetch) {
     embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
-        &DeviceComponentPolicyBrowserTest::InterceptComponentPolicy,
+        &SigninExtensionsDeviceCloudPolicyBrowserTest::InterceptComponentPolicy,
+        base::Unretained(this), hang_component_policy_fetch));
+    embedded_test_server()->RegisterRequestHandler(base::BindRepeating(
+        &SigninExtensionsDeviceCloudPolicyBrowserTest::InterceptUpdateManifest,
         base::Unretained(this)));
     embedded_test_server()->StartAcceptingConnections();
   }
 
+ private:
+  // Intercepts the request for the test extension update manifest.
+  std::unique_ptr<net::test_server::HttpResponse> InterceptUpdateManifest(
+      const net::test_server::HttpRequest& request) {
+    if (request.GetURL().path() != kTestExtensionUpdateManifestPath)
+      return nullptr;
+
+    // Create update manifest for the test extension, setting the extension URL
+    // with a test server URL pointing to the extension under the test data
+    // path.
+    std::string manifest_response = base::ReplaceStringPlaceholders(
+        kTestExtensionUpdateManifest,
+        {kTestExtensionId, embedded_test_server()->host_port_pair().ToString(),
+         kTestExtensionPath},
+        nullptr);
+
+    auto response = std::make_unique<net::test_server::BasicHttpResponse>();
+    response->set_content_type("text/xml");
+    response->set_content(manifest_response);
+    return response;
+  }
+
   // Intercepts the component policy requests.
+  // |hang| - if set, this will return a hung response, thus preventing the
+  //     policy download. Otherwise, the response will contain the test policy.
   std::unique_ptr<net::test_server::HttpResponse> InterceptComponentPolicy(
+      bool hang,
       const net::test_server::HttpRequest& request) {
     if (request.relative_url != kFakePolicyPath)
       return nullptr;
-    if (!content::IsPreTest()) {
-      // Intentionally hang the request in the non-PRE_ test.
+
+    if (hang)
       return std::make_unique<net::test_server::HungResponse>();
-    }
-    // Respond with the fake policy in the PRE_ test.
+
     auto response = std::make_unique<net::test_server::BasicHttpResponse>();
     response->set_content(kFakePolicy);
     return response;
@@ -367,19 +377,28 @@
   void SetFakeDevicePolicy() {
     device_policy()->policy_data().set_public_key_version(
         kFakePolicyPublicKeyVersion);
+
+    const GURL update_manifest_url =
+        embedded_test_server()->GetURL(kTestExtensionUpdateManifestPath);
+    const std::string policy_item_value = base::ReplaceStringPlaceholders(
+        "$1;$2", {kTestExtensionId, update_manifest_url.spec()}, nullptr);
+
+    device_policy()
+        ->payload()
+        .mutable_device_login_screen_extensions()
+        ->add_device_login_screen_extensions(policy_item_value);
+
     device_policy()->Build();
     session_manager_client()->set_device_policy(device_policy()->GetBlob());
   }
 
-  enterprise_management::ExternalPolicyData BuildTestComponentPolicyPayload()
-      const {
+  enterprise_management::ExternalPolicyData BuildTestComponentPolicyPayload() {
     ComponentCloudPolicyBuilder builder;
     MakeTestComponentPolicyBuilder(&builder);
     return builder.payload();
   }
 
-  void MakeTestComponentPolicyBuilder(
-      ComponentCloudPolicyBuilder* builder) const {
+  void MakeTestComponentPolicyBuilder(ComponentCloudPolicyBuilder* builder) {
     builder->policy_data().set_policy_type(
         dm_protocol::kChromeSigninExtensionPolicyType);
     builder->policy_data().set_settings_entity_id(kTestExtensionId);
@@ -391,10 +410,8 @@
   }
 
   chromeos::LocalPolicyTestServerMixin local_policy_mixin_{&mixin_host_};
-  ExtensionForceInstallMixin extension_force_install_mixin_{&mixin_host_};
-  std::unique_ptr<extensions::ResultCatcher> extension_result_catcher_;
 
-  DISALLOW_COPY_AND_ASSIGN(DeviceComponentPolicyBrowserTest);
+  DISALLOW_COPY_AND_ASSIGN(SigninExtensionsDeviceCloudPolicyBrowserTest);
 };
 
 }  // namespace
@@ -406,16 +423,29 @@
 //     extension installed into the sign-in profile can access the component
 //     policy downloaded during the first step.
 // PRE_ManagedStorage test handles the first step.
-IN_PROC_BROWSER_TEST_F(DeviceComponentPolicyBrowserTest, PRE_ManagedStorage) {
-  EXPECT_TRUE(extension_result_catcher()->GetNextResult());
+IN_PROC_BROWSER_TEST_F(SigninExtensionsDeviceCloudPolicyBrowserTest,
+                       PRE_ManagedStorage) {
+  // The test app will be installed via policy, at which point its
+  // background page will be loaded.
+  extensions::ResultCatcher result_catcher;
+  StartTestServer(false /*hang_component_policy_fetch*/);
+  EXPECT_TRUE(result_catcher.GetNextResult());
 }
 
 // The second step of the ManagedStorage test, which blocks component policy
 // download and verifies that a cached component policy is available to the test
 // extenion.
 // See PRE_ManagedStorage test.
-IN_PROC_BROWSER_TEST_F(DeviceComponentPolicyBrowserTest, ManagedStorage) {
-  EXPECT_TRUE(extension_result_catcher()->GetNextResult());
+IN_PROC_BROWSER_TEST_F(SigninExtensionsDeviceCloudPolicyBrowserTest,
+                       ManagedStorage) {
+  // The test app will be installed via policy, at which point its
+  // background page will be loaded. Note that the app will not be installed
+  // before the test server is started, even if the app is installed from the
+  // extension cache - the server will be pinged at least to check whether the
+  // cached app version is the latest.
+  extensions::ResultCatcher result_catcher;
+  StartTestServer(true /*hang_component_policy_fetch*/);
+  EXPECT_TRUE(result_catcher.GetNextResult());
 }
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/preferences_unittest.cc b/chrome/browser/chromeos/preferences_unittest.cc
index bd2b8b8a..237f7f32 100644
--- a/chrome/browser/chromeos/preferences_unittest.cc
+++ b/chrome/browser/chromeos/preferences_unittest.cc
@@ -38,7 +38,6 @@
 #include "content/public/test/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/chromeos/extension_ime_util.h"
-#include "ui/base/ime/chromeos/input_method_allowlist.h"
 #include "ui/base/ime/chromeos/mock_component_extension_ime_manager_delegate.h"
 #include "url/gurl.h"
 
@@ -125,11 +124,6 @@
 
   ~MyMockInputMethodManager() override {}
 
-  std::unique_ptr<InputMethodDescriptors> GetSupportedInputMethods()
-      const override {
-    return allowlist::GetSupportedInputMethods();
-  }
-
   std::string last_input_method_id_;
 
  private:
@@ -271,6 +265,34 @@
   std::vector<ComponentExtensionIME> CreateImeList() {
     std::vector<ComponentExtensionIME> ime_list;
 
+    ComponentExtensionIME ext_xkb;
+    ext_xkb.id = extension_ime_util::kXkbExtensionId;
+    ext_xkb.description = "ext_xkb_description";
+    ext_xkb.path = base::FilePath("ext_xkb_file_path");
+
+    ComponentExtensionEngine ext_xkb_engine_se;
+    ext_xkb_engine_se.engine_id = "xkb:se::swe";
+    ext_xkb_engine_se.display_name = "xkb:se::swe";
+    ext_xkb_engine_se.language_codes.push_back("sv");
+    ext_xkb_engine_se.layouts.push_back("se");
+    ext_xkb.engines.push_back(ext_xkb_engine_se);
+
+    ComponentExtensionEngine ext_xkb_engine_jp;
+    ext_xkb_engine_jp.engine_id = "xkb:jp::jpn";
+    ext_xkb_engine_jp.display_name = "xkb:jp::jpn";
+    ext_xkb_engine_jp.language_codes.push_back("ja");
+    ext_xkb_engine_jp.layouts.push_back("jp");
+    ext_xkb.engines.push_back(ext_xkb_engine_jp);
+
+    ComponentExtensionEngine ext_xkb_engine_ru;
+    ext_xkb_engine_ru.engine_id = "xkb:ru::rus";
+    ext_xkb_engine_ru.display_name = "xkb:ru::rus";
+    ext_xkb_engine_ru.language_codes.push_back("ru");
+    ext_xkb_engine_ru.layouts.push_back("ru");
+    ext_xkb.engines.push_back(ext_xkb_engine_ru);
+
+    ime_list.push_back(ext_xkb);
+
     ComponentExtensionIME ext;
     ext.id = extension_ime_util::kMozcExtensionId;
     ext.description = "ext_description";
diff --git a/chrome/browser/devtools/BUILD.gn b/chrome/browser/devtools/BUILD.gn
index 7a6188b2..cf8e2db 100644
--- a/chrome/browser/devtools/BUILD.gn
+++ b/chrome/browser/devtools/BUILD.gn
@@ -110,6 +110,7 @@
 
   if (!is_android) {
     deps += [
+      "//build:chromeos_buildflags",
       "//chrome:extra_resources",
       "//chrome:resources",
       "//chrome:strings",
diff --git a/chrome/browser/download/download_history.cc b/chrome/browser/download/download_history.cc
index 67806fc..cc8f7ad 100644
--- a/chrome/browser/download/download_history.cc
+++ b/chrome/browser/download/download_history.cc
@@ -55,6 +55,8 @@
 #include "chrome/browser/extensions/api/downloads/downloads_api.h"
 #endif
 
+using history::DownloadState;
+
 namespace {
 
 // Max data url size to be stored in history DB.
@@ -223,6 +225,52 @@
   return ShouldUpdateHistoryResult::NO_UPDATE;
 }
 
+// Counts how many times a target file path exists in |rows| and stores
+// the result into |file_path_count|.
+void CountFilePathOccurences(const std::vector<history::DownloadRow>& rows,
+                             std::map<std::string, int>* file_path_count) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (!base::FeatureList::IsEnabled(
+          download::features::kDeleteOverwrittenDownloads)) {
+    return;
+  }
+
+  for (const history::DownloadRow& row : rows) {
+    if (row.state != DownloadState::COMPLETE || row.target_path.empty())
+      continue;
+    std::string file_path = row.target_path.AsUTF8Unsafe();
+    if (file_path.empty())
+      continue;
+    ++(*file_path_count)[file_path];
+  }
+}
+
+// Checks whether a particular download row should be skipped from loading given
+// the number of times the same target file path appears in |file_path_count|.
+bool ShouldSkipLoadingDownload(const history::DownloadRow& row,
+                               std::map<std::string, int>* file_path_count) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+  if (!base::FeatureList::IsEnabled(
+          download::features::kDeleteOverwrittenDownloads)) {
+    return false;
+  }
+
+  if (row.state != DownloadState::COMPLETE && row.target_path.empty())
+    return false;
+  const std::string file_path = row.target_path.AsUTF8Unsafe();
+  if (file_path.empty())
+    return false;
+  auto iter = file_path_count->find(file_path);
+  DCHECK(iter != file_path_count->end());
+  --iter->second;
+  if (iter->second < 1)
+    return false;
+  return base::Time::Now() - row.end_time >=
+         download::GetOverwrittenDownloadDeleteTime();
+}
+
 }  // anonymous namespace
 
 DownloadHistory::HistoryAdapter::HistoryAdapter(
@@ -308,11 +356,21 @@
 }
 
 void DownloadHistory::LoadHistoryDownloads(
-    std::vector<history::DownloadRow> rows) {
+    const std::vector<history::DownloadRow>& rows) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   DCHECK(notifier_.GetManager());
 
+  std::map<std::string, int> file_name_count;
+  CountFilePathOccurences(rows, &file_name_count);
+
+  int overwritten_download_removals = 0;
   for (const history::DownloadRow& row : rows) {
+    if (ShouldSkipLoadingDownload(row, &file_name_count)) {
+      ++overwritten_download_removals;
+      ScheduleRemoveDownload(row.id);
+      continue;
+    }
+
     loading_id_ = history::ToContentDownloadId(row.id);
     download::DownloadItem::DownloadState history_download_state =
         history::ToContentDownloadState(row.state);
@@ -359,6 +417,8 @@
     DCHECK_EQ(DownloadHistoryData::PERSISTED,
               DownloadHistoryData::Get(item)->state());
   }
+  UMA_HISTOGRAM_COUNTS_1000("Download.OverwrittenDownloadRemovedFromHistory",
+                            overwritten_download_removals);
 
   // Indicate that the history db is initialized.
   notifier_.GetManager()->PostInitialization(
diff --git a/chrome/browser/download/download_history.h b/chrome/browser/download/download_history.h
index 92899fa..8607906 100644
--- a/chrome/browser/download/download_history.h
+++ b/chrome/browser/download/download_history.h
@@ -99,7 +99,7 @@
   void QueryCallback(std::vector<history::DownloadRow> rows);
 
   // Called to create all history downloads.
-  void LoadHistoryDownloads(std::vector<history::DownloadRow> rows);
+  void LoadHistoryDownloads(const std::vector<history::DownloadRow>& rows);
 
   // May add |item| to |history_|.
   void MaybeAddToHistory(download::DownloadItem* item);
diff --git a/chrome/browser/download/download_history_unittest.cc b/chrome/browser/download/download_history_unittest.cc
index a7b9f048..38f51bd8 100644
--- a/chrome/browser/download/download_history_unittest.cc
+++ b/chrome/browser/download/download_history_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/stl_util.h"
 #include "base/test/scoped_feature_list.h"
 #include "components/download/public/common/download_features.h"
+#include "components/download/public/common/download_utils.h"
 #include "components/download/public/common/mock_download_item.h"
 #include "components/history/content/browser/download_conversions.h"
 #include "components/history/core/browser/download_constants.h"
@@ -48,6 +49,24 @@
 using IdSet = DownloadHistory::IdSet;
 using StrictMockDownloadItem = testing::StrictMock<download::MockDownloadItem>;
 
+enum class LoadDownloadRowResult {
+  kCreateDownload,
+  kRemoveDownload,
+  kSkipCreation,
+};
+
+struct CreateDownloadHistoryEntry {
+  explicit CreateDownloadHistoryEntry(
+      const history::DownloadRow& row,
+      LoadDownloadRowResult result = LoadDownloadRowResult::kCreateDownload) {
+    this->row = row;
+    this->result = result;
+  }
+
+  history::DownloadRow row;
+  LoadDownloadRowResult result;
+};
+
 class FakeHistoryAdapter : public DownloadHistory::HistoryAdapter {
  public:
   FakeHistoryAdapter() : DownloadHistory::HistoryAdapter(nullptr) {}
@@ -59,7 +78,6 @@
         FROM_HERE, base::BindOnce(&FakeHistoryAdapter::QueryDownloadsDone,
                                   base::Unretained(this), std::move(callback)));
   }
-
   void QueryDownloadsDone(
       history::HistoryService::DownloadQueryCallback callback) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
@@ -210,37 +228,49 @@
     return manager_observer_;
   }
 
+  content::MockDownloadManager::CreateDownloadItemAdapter
+  GetCreateDownloadItemAdapterFromDownloadRow(const history::DownloadRow& row) {
+    return content::MockDownloadManager::CreateDownloadItemAdapter(
+        row.guid, history::ToContentDownloadId(row.id), row.current_path,
+        row.target_path, row.url_chain, row.referrer_url, row.site_url,
+        row.tab_url, row.tab_referrer_url, base::nullopt, row.mime_type,
+        row.original_mime_type, row.start_time, row.end_time, row.etag,
+        row.last_modified, row.received_bytes, row.total_bytes, std::string(),
+        history::ToContentDownloadState(row.state),
+        history::ToContentDownloadDangerType(row.danger_type),
+        history::ToContentDownloadInterruptReason(row.interrupt_reason),
+        row.opened, row.last_access_time, row.transient,
+        history::ToContentReceivedSlices(row.download_slice_info));
+  }
+
   // Creates the DownloadHistory. If |return_null_item| is true, |manager_|
   // will return nullptr on CreateDownloadItem() call,
-  void CreateDownloadHistory(std::vector<history::DownloadRow> rows,
-                             bool return_null_item = false) {
+  void CreateDownloadHistory(std::vector<CreateDownloadHistoryEntry> entries) {
     DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    EXPECT_CALL(manager(), AddObserver(_)).WillOnce(WithArg<0>(Invoke(
-        this, &DownloadHistoryTest::SetManagerObserver)));
+    EXPECT_CALL(manager(), AddObserver(_))
+        .WillOnce(
+            WithArg<0>(Invoke(this, &DownloadHistoryTest::SetManagerObserver)));
     EXPECT_CALL(manager(), RemoveObserver(_));
     download_created_index_ = 0;
-    for (size_t index = 0; index < rows.size(); ++index) {
-      const history::DownloadRow& row = rows.at(index);
-      content::MockDownloadManager::CreateDownloadItemAdapter adapter(
-          row.guid, history::ToContentDownloadId(row.id), row.current_path,
-          row.target_path, row.url_chain, row.referrer_url, row.site_url,
-          row.tab_url, row.tab_referrer_url, base::nullopt, row.mime_type,
-          row.original_mime_type, row.start_time, row.end_time, row.etag,
-          row.last_modified, row.received_bytes, row.total_bytes, std::string(),
-          history::ToContentDownloadState(row.state),
-          history::ToContentDownloadDangerType(row.danger_type),
-          history::ToContentDownloadInterruptReason(row.interrupt_reason),
-          row.opened, row.last_access_time, row.transient,
-          history::ToContentReceivedSlices(row.download_slice_info));
-      if (return_null_item) {
-        EXPECT_CALL(manager(), MockCreateDownloadItem(adapter))
-            .WillOnce(Return(nullptr));
-      } else {
-        EXPECT_CALL(manager(), MockCreateDownloadItem(adapter))
-            .WillOnce(DoAll(
-                InvokeWithoutArgs(
-                    this, &DownloadHistoryTest::CallOnDownloadCreatedInOrder),
-                Return(&item(index))));
+    std::vector<history::DownloadRow> rows;
+    for (const auto& entry : entries) {
+      rows.emplace_back(entry.row);
+      content::MockDownloadManager::CreateDownloadItemAdapter adapter =
+          GetCreateDownloadItemAdapterFromDownloadRow(entry.row);
+      switch (entry.result) {
+        case LoadDownloadRowResult::kRemoveDownload:
+          EXPECT_CALL(manager(), MockCreateDownloadItem(adapter))
+              .WillOnce(Return(nullptr));
+          break;
+        case LoadDownloadRowResult::kCreateDownload:
+          EXPECT_CALL(manager(), MockCreateDownloadItem(adapter))
+              .WillOnce(DoAll(
+                  InvokeWithoutArgs(
+                      this, &DownloadHistoryTest::CallOnDownloadCreatedInOrder),
+                  Return(&item(download_created_index_))));
+          break;
+        case LoadDownloadRowResult::kSkipCreation:
+          break;
       }
     }
     history_ = new FakeHistoryAdapter();
@@ -317,16 +347,11 @@
       download_vector->push_back(&item(i));
   }
 
-  void InitBasicItem(const base::FilePath::CharType* path,
-                     const char* url_string,
-                     const char* referrer_string,
-                     download::DownloadItem::DownloadState state,
-                     history::DownloadRow* row) {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
-    size_t index = items_.size();
-    items_.push_back(std::make_unique<StrictMockDownloadItem>());
-
+  void InitDownloadRow(const base::FilePath::CharType* path,
+                       const char* url_string,
+                       const char* referrer_string,
+                       download::DownloadItem::DownloadState state,
+                       history::DownloadRow* row) {
     base::Time now = base::Time::Now();
 
     row->current_path = base::FilePath(path);
@@ -355,6 +380,19 @@
     row->opened = false;
     row->last_access_time = now;
     row->transient = false;
+  }
+
+  void InitBasicItem(const base::FilePath::CharType* path,
+                     const char* url_string,
+                     const char* referrer_string,
+                     download::DownloadItem::DownloadState state,
+                     history::DownloadRow* row) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+    size_t index = items_.size();
+    items_.push_back(std::make_unique<StrictMockDownloadItem>());
+
+    InitDownloadRow(path, url_string, referrer_string, state, row);
 
     EXPECT_CALL(item(index), GetId()).WillRepeatedly(Return(row->id));
     EXPECT_CALL(item(index), GetGuid())
@@ -424,9 +462,6 @@
                                           row->by_ext_name);
 #endif
 
-    row->download_slice_info =
-        history::GetHistoryDownloadSliceInfos(item(index));
-
     std::vector<download::DownloadItem*> items;
     for (size_t i = 0; i < items_.size(); ++i) {
       items.push_back(&item(i));
@@ -435,6 +470,15 @@
         .WillRepeatedly(SetArgPointee<0>(items));
   }
 
+  void set_download_created_index(int index) {
+    download_created_index_ = index;
+  }
+
+  FakeHistoryAdapter* CreateHistoryAdapter() {
+    history_ = new FakeHistoryAdapter();
+    return history_;
+  }
+
  private:
   content::BrowserTaskEnvironment task_environment_;
   std::vector<std::unique_ptr<StrictMockDownloadItem>> items_;
@@ -458,8 +502,9 @@
                 "http://example.com/referrer.html",
                 download::DownloadItem::IN_PROGRESS, &row);
   {
-    std::vector<history::DownloadRow> rows = {row};
-    CreateDownloadHistory(std::move(rows));
+    std::vector<CreateDownloadHistoryEntry> entries = {
+        CreateDownloadHistoryEntry(row)};
+    CreateDownloadHistory(std::move(entries));
     ExpectNoDownloadCreated();
   }
   EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
@@ -655,8 +700,9 @@
                 "http://example.com/referrer1.html",
                 download::DownloadItem::COMPLETE, &row1);
   {
-    std::vector<history::DownloadRow> rows = {row0, row1};
-    CreateDownloadHistory(std::move(rows));
+    std::vector<CreateDownloadHistoryEntry> entries = {
+        CreateDownloadHistoryEntry(row0), CreateDownloadHistoryEntry(row1)};
+    CreateDownloadHistory(std::move(entries));
     ExpectNoDownloadCreated();
   }
 
@@ -761,8 +807,9 @@
 
   // Modify the item so it doesn't match the history record.
   EXPECT_CALL(item(0), GetReceivedBytes()).WillRepeatedly(Return(50));
-  std::vector<history::DownloadRow> rows = {row};
-  CreateDownloadHistory(std::move(rows));
+  std::vector<CreateDownloadHistoryEntry> entries = {
+      CreateDownloadHistoryEntry(row)};
+  CreateDownloadHistory(std::move(entries));
   EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
 
   // Modify the item, it should not trigger any updates.
@@ -812,10 +859,11 @@
   EXPECT_CALL(item(0), GetState())
       .WillRepeatedly(Return(download::DownloadItem::INTERRUPTED));
   EXPECT_CALL(item(0), IsDone()).WillRepeatedly(Return(true));
-  std::vector<history::DownloadRow> rows = {row};
+  std::vector<CreateDownloadHistoryEntry> entries = {
+      CreateDownloadHistoryEntry(row)};
 
   // Create the history and a db update should be triggered.
-  CreateDownloadHistory(std::move(rows));
+  CreateDownloadHistory(std::move(entries));
   EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
   row.interrupt_reason = download::DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN;
   row.state = history::DownloadState::INTERRUPTED;
@@ -829,8 +877,9 @@
                 "http://example.com/referrer.html",
                 download::DownloadItem::IN_PROGRESS, &row);
 
-  std::vector<history::DownloadRow> rows = {row};
-  CreateDownloadHistory(std::move(rows), true);
+  std::vector<CreateDownloadHistoryEntry> entries = {
+      CreateDownloadHistoryEntry(row, LoadDownloadRowResult::kRemoveDownload)};
+  CreateDownloadHistory(std::move(entries));
 
   // The download should be removed from history afterwards.
   IdSet ids;
@@ -865,4 +914,66 @@
   item(0).NotifyObserversDownloadUpdated();
   ExpectDownloadCreated(row);
 }
+
+// Tests that overwritten download is removed from history DB after the
+// expiration time.
+TEST_F(DownloadHistoryTest,
+       DownloadHistoryTest_OverwrittenDownloadRemovedAfterExpiration) {
+  std::map<std::string, std::string> params = {
+      {download::kOverwrittenDownloadDeleteTimeFinchKey, "0"}};
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeatureWithParameters(
+      download::features::kDeleteOverwrittenDownloads, params);
+  // Load a download from history, create the item, OnDownloadCreated,
+  // OnDownloadUpdated, OnDownloadRemoved.
+  history::DownloadRow row0, row1;
+  InitDownloadRow(FILE_PATH_LITERAL("/foo/bar.pdf"),
+                  "http://example.com/bar.pdf",
+                  "http://example.com/referrer.html",
+                  download::DownloadItem::COMPLETE, &row0);
+  InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
+                "http://example2.com/bar.pdf",
+                "http://example.com/referrer1.html",
+                download::DownloadItem::COMPLETE, &row1);
+  {
+    std::vector<CreateDownloadHistoryEntry> rows = {
+        CreateDownloadHistoryEntry(row0, LoadDownloadRowResult::kSkipCreation),
+        CreateDownloadHistoryEntry(row1)};
+    CreateDownloadHistory(std::move(rows));
+
+    ExpectNoDownloadCreated();
+  }
+
+  EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
+}
+
+// Tests that overwritten download is not removed from history DB before the
+// expiration time.
+TEST_F(DownloadHistoryTest,
+       DownloadHistoryTest_OverwrittenDownloadNotRemovedPriorToExpiration) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      download::features::kDeleteOverwrittenDownloads);
+  // Load a download from history, create the item, OnDownloadCreated,
+  // OnDownloadUpdated, OnDownloadRemoved.
+  history::DownloadRow row0, row1;
+  InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"), "http://example.com/bar.pdf",
+                "http://example.com/referrer.html",
+                download::DownloadItem::COMPLETE, &row0);
+  InitBasicItem(FILE_PATH_LITERAL("/foo/bar.pdf"),
+                "http://example2.com/bar.pdf",
+                "http://example.com/referrer1.html",
+                download::DownloadItem::COMPLETE, &row1);
+  {
+    std::vector<CreateDownloadHistoryEntry> rows = {
+        CreateDownloadHistoryEntry(row0), CreateDownloadHistoryEntry(row1)};
+    CreateDownloadHistory(std::move(rows));
+
+    ExpectNoDownloadCreated();
+  }
+
+  EXPECT_TRUE(DownloadHistory::IsPersisted(&item(0)));
+  EXPECT_TRUE(DownloadHistory::IsPersisted(&item(1)));
+}
+
 }  // anonymous namespace
diff --git a/chrome/browser/exo_parts.cc b/chrome/browser/exo_parts.cc
index 56e5e71..48becf1 100644
--- a/chrome/browser/exo_parts.cc
+++ b/chrome/browser/exo_parts.cc
@@ -4,304 +4,19 @@
 
 #include "chrome/browser/exo_parts.h"
 
-#include <string>
-#include <vector>
+#include <memory>
 
-#include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/external_arc/keyboard/arc_input_method_surface_manager.h"
 #include "ash/public/cpp/external_arc/message_center/arc_notification_surface_manager_impl.h"
 #include "ash/public/cpp/external_arc/overlay/arc_overlay_manager.h"
 #include "ash/public/cpp/external_arc/toast/arc_toast_surface_manager.h"
+#include "ash/public/cpp/keyboard/arc/arc_input_method_bounds_tracker.h"
 #include "ash/shell.h"
-#include "base/bind.h"
 #include "base/command_line.h"
-#include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/memory/ref_counted_memory.h"
-#include "base/strings/strcat.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/chromeos/crostini/crostini_shelf_utils.h"
-#include "chrome/browser/chromeos/crostini/crostini_util.h"
-#include "chrome/browser/chromeos/file_manager/app_id.h"
-#include "chrome/browser/chromeos/file_manager/fileapi_util.h"
-#include "chrome/browser/chromeos/file_manager/path_util.h"
-#include "chrome/browser/chromeos/guest_os/guest_os_share_path.h"
-#include "chrome/browser/chromeos/plugin_vm/plugin_vm_files.h"
-#include "chrome/browser/chromeos/plugin_vm/plugin_vm_util.h"
-#include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/common/chrome_switches.h"
-#include "components/exo/file_helper.h"
+#include "chrome/browser/chromeos/exo/chrome_file_helper.h"
 #include "components/exo/server/wayland_server_controller.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/common/drop_data.h"
-#include "net/base/filename_util.h"
-#include "storage/browser/file_system/external_mount_points.h"
-#include "storage/browser/file_system/file_system_context.h"
-#include "storage/browser/file_system/file_system_url.h"
-#include "storage/common/file_system/file_system_types.h"
-#include "ui/aura/client/aura_constants.h"
-#include "ui/base/dragdrop/file_info/file_info.h"
-
-namespace {
-
-constexpr char kMimeTypeArcUriList[] = "application/x-arc-uri-list";
-constexpr char kMimeTypeTextUriList[] = "text/uri-list";
-constexpr char kUriListSeparator[] = "\r\n";
-constexpr char kVmFileScheme[] = "vmfile";
-
-bool IsArcWindow(const aura::Window* window) {
-  return static_cast<ash::AppType>(window->GetProperty(
-             aura::client::kAppType)) == ash::AppType::ARC_APP;
-}
-
-storage::FileSystemContext* GetFileSystemContext() {
-  Profile* primary_profile = ProfileManager::GetPrimaryUserProfile();
-  if (!primary_profile)
-    return nullptr;
-
-  return file_manager::util::GetFileSystemContextForExtensionId(
-      primary_profile, file_manager::kFileManagerAppId);
-}
-
-void GetFileSystemUrlsFromPickle(
-    const base::Pickle& pickle,
-    std::vector<storage::FileSystemURL>* file_system_urls) {
-  storage::FileSystemContext* file_system_context = GetFileSystemContext();
-  if (!file_system_context)
-    return;
-
-  std::vector<content::DropData::FileSystemFileInfo> file_system_files;
-  if (!content::DropData::FileSystemFileInfo::ReadFileSystemFilesFromPickle(
-          pickle, &file_system_files))
-    return;
-
-  for (const auto& file_system_file : file_system_files) {
-    const storage::FileSystemURL file_system_url =
-        file_system_context->CrackURL(file_system_file.url);
-    if (file_system_url.is_valid())
-      file_system_urls->push_back(file_system_url);
-  }
-}
-
-void SendArcUrls(exo::FileHelper::SendDataCallback callback,
-                 const std::vector<GURL>& urls) {
-  std::vector<std::string> lines;
-  for (const GURL& url : urls) {
-    if (!url.is_valid())
-      continue;
-    lines.emplace_back(url.spec());
-  }
-  // Arc requires UTF16 for data.
-  base::string16 data =
-      base::UTF8ToUTF16(base::JoinString(lines, kUriListSeparator));
-  std::move(callback).Run(base::RefCountedString16::TakeString(&data));
-}
-
-void SendAfterShare(exo::FileHelper::SendDataCallback callback,
-                    scoped_refptr<base::RefCountedMemory> data,
-                    bool success,
-                    const std::string& failure_reason) {
-  if (!success)
-    LOG(ERROR) << "Error sharing paths for drag and drop: " << failure_reason;
-
-  // Still send the data, even if sharing failed.
-  std::move(callback).Run(data);
-}
-
-struct FileInfo {
-  base::FilePath path;
-  storage::FileSystemURL url;
-};
-
-void ShareAndSend(aura::Window* target,
-                  std::vector<FileInfo> files,
-                  exo::FileHelper::SendDataCallback callback) {
-  Profile* primary_profile = ProfileManager::GetPrimaryUserProfile();
-
-  aura::Window* toplevel = target->GetToplevelWindow();
-  bool is_crostini = crostini::IsCrostiniWindow(toplevel);
-  bool is_plugin_vm = plugin_vm::IsPluginVmAppWindow(toplevel);
-
-  base::FilePath vm_mount;
-  std::string vm_name;
-  if (is_crostini) {
-    vm_mount = crostini::ContainerChromeOSBaseDirectory();
-    vm_name = crostini::kCrostiniDefaultVmName;
-  } else if (is_plugin_vm) {
-    vm_mount = plugin_vm::ChromeOSBaseDirectory();
-    vm_name = plugin_vm::kPluginVmName;
-  }
-
-  const std::string vm_prefix =
-      base::StrCat({kVmFileScheme, ":", vm_name, ":"});
-  std::vector<std::string> lines_to_send;
-  auto* share_path = guest_os::GuestOsSharePath::GetForProfile(primary_profile);
-  std::vector<base::FilePath> paths_to_share;
-
-  for (auto& info : files) {
-    base::FilePath path_to_send = info.path;
-    if (is_crostini || is_plugin_vm) {
-      // Check if it is a path inside the VM: 'vmfile:<vm_name>:'.
-      if (base::StartsWith(info.path.value(), vm_prefix,
-                           base::CompareCase::SENSITIVE)) {
-        path_to_send =
-            base::FilePath(info.path.value().substr(vm_prefix.size()));
-      } else if (file_manager::util::ConvertFileSystemURLToPathInsideVM(
-                     primary_profile, info.url, vm_mount,
-                     /*map_crostini_home=*/is_crostini, &path_to_send)) {
-        // Convert to path inside the VM and check if the path needs sharing.
-        if (!share_path->IsPathShared(vm_name, info.path))
-          paths_to_share.emplace_back(info.path);
-      } else {
-        LOG(WARNING) << "Could not convert path " << info.path;
-        continue;
-      }
-    }
-    lines_to_send.emplace_back(net::FilePathToFileURL(path_to_send).spec());
-  }
-
-  std::string joined = base::JoinString(lines_to_send, kUriListSeparator);
-  auto data = base::RefCountedString::TakeString(&joined);
-  if (!paths_to_share.empty()) {
-    share_path->SharePaths(
-        vm_name, std::move(paths_to_share),
-        /*persist=*/false,
-        base::BindOnce(&SendAfterShare, std::move(callback), std::move(data)));
-  } else {
-    std::move(callback).Run(std::move(data));
-  }
-}
-
-class ChromeFileHelper : public exo::FileHelper {
- public:
-  ChromeFileHelper() = default;
-  ~ChromeFileHelper() override = default;
-
-  // exo::FileHelper:
-  std::vector<ui::FileInfo> GetFilenames(
-      aura::Window* source,
-      const std::vector<uint8_t>& data) const override {
-    Profile* primary_profile = ProfileManager::GetPrimaryUserProfile();
-    aura::Window* toplevel = source->GetToplevelWindow();
-    bool is_crostini = crostini::IsCrostiniWindow(toplevel);
-    bool is_plugin_vm = plugin_vm::IsPluginVmAppWindow(toplevel);
-
-    base::FilePath vm_mount;
-    std::string vm_name;
-    if (is_crostini) {
-      vm_mount = crostini::ContainerChromeOSBaseDirectory();
-      vm_name = crostini::kCrostiniDefaultVmName;
-    } else if (is_plugin_vm) {
-      vm_mount = plugin_vm::ChromeOSBaseDirectory();
-      vm_name = plugin_vm::kPluginVmName;
-    }
-
-    std::string lines(data.begin(), data.end());
-    std::vector<ui::FileInfo> filenames;
-
-    base::FilePath path;
-    storage::FileSystemURL url;
-    for (const base::StringPiece& line : base::SplitStringPiece(
-             lines, "\n", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
-      if (!net::FileURLToFilePath(GURL(line), &path))
-        continue;
-
-      // Convert the VM path to a path in the host if possible (in homedir or
-      // /mnt/chromeos for crostini; in //ChromeOS for Plugin VM), otherwise
-      // prefix with 'vmfile:<vm_name>:' to avoid VMs spoofing host paths.
-      // E.g. crostini /etc/mime.types => vmfile:termina:/etc/mime.types.
-      if (is_crostini || is_plugin_vm) {
-        if (file_manager::util::ConvertPathInsideVMToFileSystemURL(
-                primary_profile, path, vm_mount,
-                /*map_crostini_home=*/is_crostini, &url)) {
-          path = url.path();
-        } else {
-          path = base::FilePath(
-              base::StrCat({kVmFileScheme, ":", vm_name, ":", path.value()}));
-        }
-      }
-      filenames.emplace_back(ui::FileInfo(path, base::FilePath()));
-    }
-    return filenames;
-  }
-
-  std::string GetMimeTypeForUriList(aura::Window* target) const override {
-    return IsArcWindow(target->GetToplevelWindow()) ? kMimeTypeArcUriList
-                                                    : kMimeTypeTextUriList;
-  }
-
-  void SendFileInfo(aura::Window* target,
-                    const std::vector<ui::FileInfo>& files,
-                    exo::FileHelper::SendDataCallback callback) const override {
-    // ARC converts to ArcUrl and uses utf-16.
-    if (IsArcWindow(target->GetToplevelWindow())) {
-      std::vector<std::string> lines;
-      GURL url;
-      for (const auto& info : files) {
-        if (file_manager::util::ConvertPathToArcUrl(info.path, &url)) {
-          lines.emplace_back(url.spec());
-        }
-      }
-      base::string16 data =
-          base::UTF8ToUTF16(base::JoinString(lines, kUriListSeparator));
-      std::move(callback).Run(base::RefCountedString16::TakeString(&data));
-      return;
-    }
-
-    storage::ExternalMountPoints* mount_points =
-        storage::ExternalMountPoints::GetSystemInstance();
-    base::FilePath virtual_path;
-    std::vector<FileInfo> list;
-
-    for (const auto& info : files) {
-      // Convert absolute host path to FileSystemURL if possible.
-      storage::FileSystemURL url;
-      if (mount_points->GetVirtualPath(info.path, &virtual_path)) {
-        url = mount_points->CreateCrackedFileSystemURL(
-            url::Origin(), storage::kFileSystemTypeExternal, virtual_path);
-      }
-      list.push_back({info.path, std::move(url)});
-    }
-
-    ShareAndSend(target, std::move(list), std::move(callback));
-  }
-
-  bool HasUrlsInPickle(const base::Pickle& pickle) const override {
-    std::vector<storage::FileSystemURL> file_system_urls;
-    GetFileSystemUrlsFromPickle(pickle, &file_system_urls);
-    return !file_system_urls.empty();
-  }
-
-  void SendPickle(aura::Window* target,
-                  const base::Pickle& pickle,
-                  exo::FileHelper::SendDataCallback callback) override {
-    std::vector<storage::FileSystemURL> file_system_urls;
-    GetFileSystemUrlsFromPickle(pickle, &file_system_urls);
-
-    // ARC FileSystemURLs are converted to Content URLs.
-    if (IsArcWindow(target->GetToplevelWindow())) {
-      if (file_system_urls.empty()) {
-        std::move(callback).Run(nullptr);
-        return;
-      }
-      file_manager::util::ConvertToContentUrls(
-          file_system_urls, base::BindOnce(&SendArcUrls, std::move(callback)));
-      return;
-    }
-
-    std::vector<FileInfo> list;
-    for (const auto& url : file_system_urls)
-      list.push_back({url.path(), url});
-
-    ShareAndSend(target, std::move(list), std::move(callback));
-  }
-};
-
-}  // namespace
 
 // static
 std::unique_ptr<ExoParts> ExoParts::CreateIfNecessary() {
@@ -322,7 +37,7 @@
 ExoParts::ExoParts()
     : arc_overlay_manager_(std::make_unique<ash::ArcOverlayManager>()) {
   wayland_server_ = exo::WaylandServerController::CreateIfNecessary(
-      std::make_unique<ChromeFileHelper>(),
+      std::make_unique<chromeos::ChromeFileHelper>(),
       std::make_unique<ash::ArcNotificationSurfaceManagerImpl>(),
       std::make_unique<ash::ArcInputMethodSurfaceManager>(),
       std::make_unique<ash::ArcToastSurfaceManager>());
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 565ae33..f3d8b5b 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2742,12 +2742,12 @@
   {
     "name": "form-controls-dark-mode",
     "owners": [ "sasebree@microsoft.com", "masonfreed", "yuzhehan", "//third_party/blink/renderer/core/OWNERS" ],
-    "expiry_milestone": 90
+    "expiry_milestone": 92
   },
   {
     "name": "form-controls-refresh",
     "owners": [ "iopopesc@microsoft.com", "masonfreed", "yuzhehan", "//third_party/blink/renderer/core/OWNERS" ],
-    "expiry_milestone": 88
+    "expiry_milestone": 92
   },
   {
     "name": "fractional-scroll-offsets",
diff --git a/chrome/browser/flags/BUILD.gn b/chrome/browser/flags/BUILD.gn
index e72e27c..f30ca33d 100644
--- a/chrome/browser/flags/BUILD.gn
+++ b/chrome/browser/flags/BUILD.gn
@@ -18,6 +18,7 @@
   deps = [
     "//base:base_java",
     "//base:jni_java",
+    "//build:chromeos_buildflags",
     "//chrome/browser/preferences:java",
     "//third_party/android_deps:androidx_annotation_annotation_java",
   ]
diff --git a/chrome/browser/page_load_metrics/observers/session_restore_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/session_restore_page_load_metrics_observer.cc
index 01840ab3..d71ada9 100644
--- a/chrome/browser/page_load_metrics/observers/session_restore_page_load_metrics_observer.cc
+++ b/chrome/browser/page_load_metrics/observers/session_restore_page_load_metrics_observer.cc
@@ -43,10 +43,8 @@
   }
 
   // The navigation should be from the last session.
-  DCHECK(navigation_handle->GetRestoreType() ==
-             content::RestoreType::LAST_SESSION_EXITED_CLEANLY ||
-         navigation_handle->GetRestoreType() ==
-             content::RestoreType::LAST_SESSION_CRASHED);
+  DCHECK_EQ(content::RestoreType::LAST_SESSION,
+            navigation_handle->GetRestoreType());
 
   return CONTINUE_OBSERVING;
 }
diff --git a/chrome/browser/page_load_metrics/observers/session_restore_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/session_restore_page_load_metrics_observer_unittest.cc
index cef5299..a0f6b0f 100644
--- a/chrome/browser/page_load_metrics/observers/session_restore_page_load_metrics_observer_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/session_restore_page_load_metrics_observer_unittest.cc
@@ -130,8 +130,7 @@
     entries.emplace_back(std::move(entry));
 
     content::NavigationController& controller = contents->GetController();
-    controller.Restore(0, content::RestoreType::LAST_SESSION_EXITED_CLEANLY,
-                       &entries);
+    controller.Restore(0, content::RestoreType::LAST_SESSION, &entries);
     ASSERT_EQ(0u, entries.size());
     ASSERT_EQ(1, controller.GetEntryCount());
 
diff --git a/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java b/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java
index 0e65d8c..cb72f9c6 100644
--- a/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java
+++ b/chrome/browser/paint_preview/android/javatests/src/org/chromium/chrome/browser/paint_preview/services/PaintPreviewTabServiceTest.java
@@ -99,6 +99,8 @@
         activity.getWindow().setLocalFocus(true, true);
         TestThreadUtils.runOnUiThreadBlocking(() -> {
             InstrumentationRegistry.getInstrumentation().callActivityOnRestart(activity);
+            InstrumentationRegistry.getInstrumentation().callActivityOnStart(activity);
+            InstrumentationRegistry.getInstrumentation().callActivityOnResume(activity);
         });
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
diff --git a/chrome/browser/resources/new_tab_page/realbox.js b/chrome/browser/resources/new_tab_page/realbox.js
index 7b442480..8c38c374 100644
--- a/chrome/browser/resources/new_tab_page/realbox.js
+++ b/chrome/browser/resources/new_tab_page/realbox.js
@@ -380,7 +380,6 @@
       // mechanism via which inline autocompletion is shown in the realbox.
       this.queryAutocomplete_(inputValue, e.isComposing);
     } else {
-      this.matchesAreVisible = false;
       this.clearAutocompleteMatches_();
     }
 
@@ -470,20 +469,21 @@
     // of the realbox wrapper.
     const relatedTarget = /** @type {Element} */ (e.relatedTarget);
     if (!this.$.inputWrapper.contains(relatedTarget)) {
-      // Unselect the selected match and clear the input if the input was empty
-      // when the matches arrived.
       if (this.lastQueriedInput_ === '') {
-        this.$.matches.unselect();
+        // Clear the input as well as the matches if the input was empty when
+        // the matches arrived.
         this.updateInput_({text: '', inline: ''});
-      }
-      this.matchesAreVisible = false;
+        this.clearAutocompleteMatches_();
+      } else {
+        this.matchesAreVisible = false;
 
-      // Stop autocomplete but leave (potentially stale) results and continue
-      // listening for key presses. These stale results should never be shown.
-      // They correspond to the potentially stale suggestion left in the realbox
-      // when blurred. That stale result may be navigated to by focusing and
-      // pressing 'Enter'.
-      this.pageHandler_.stopAutocomplete(/*clearResult=*/ false);
+        // Stop autocomplete but leave (potentially stale) results and continue
+        // listening for key presses. These stale results should never be shown.
+        // They correspond to the potentially stale suggestion left in the
+        // realbox when blurred. That stale result may be navigated to by
+        // focusing and pressing 'Enter'.
+        this.pageHandler_.stopAutocomplete(/*clearResult=*/ false);
+      }
     }
   }
 
@@ -561,7 +561,6 @@
 
     if (e.key === 'Escape' && this.selectedMatchIndex_ === 0) {
       this.updateInput_({text: '', inline: ''});
-      this.matchesAreVisible = false;
       this.clearAutocompleteMatches_();
       e.preventDefault();
       return;
@@ -668,6 +667,7 @@
    * @private
    */
   clearAutocompleteMatches_() {
+    this.matchesAreVisible = false;
     this.result_ = null;
     this.$.matches.unselect();
     this.pageHandler_.stopAutocomplete(/*clearResult=*/ true);
diff --git a/chrome/browser/resources/new_tab_page/realbox_dropdown.html b/chrome/browser/resources/new_tab_page/realbox_dropdown.html
index e963cb22..e64e8cf 100644
--- a/chrome/browser/resources/new_tab_page/realbox_dropdown.html
+++ b/chrome/browser/resources/new_tab_page/realbox_dropdown.html
@@ -59,7 +59,7 @@
 <iron-selector id="selector" selectable="ntp-realbox-match"
     items="{{selectableMatchElements_}}" selected="{{selectedMatchIndex}}"
     selected-class="selected">
-  <template is="dom-repeat" items="[[groupIds_]]" as="groupId">
+  <template is="dom-repeat" id="groups" items="[[groupIds_]]" as="groupId">
     <template is="dom-if" if="[[groupHasHeader_(groupId)]]">
       <!-- Header cannot be tabbed into but gets focus when clicked. This stops
            the dropdown from losing focus and closing as a result. -->
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
index c788a9fd..797c25a 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js
@@ -96,7 +96,7 @@
       return loadTimeData.getStringF(
           'triggeredResetPageTitle', this.triggeredResetToolName_);
     }
-    return loadTimeData.getStringF('resetDialogCommit');
+    return loadTimeData.getStringF('resetDialogTitle');
   },
 
   /** @override */
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
index 3f37d8e..9309aef 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -1637,7 +1637,8 @@
 }
 
 bool ChromePasswordProtectionService::UserClickedThroughSBInterstitial(
-    content::WebContents* web_contents) {
+    PasswordProtectionRequest* request) {
+  content::WebContents* web_contents = request->web_contents();
   SBThreatType current_threat_type;
   if (!ui_manager_->IsUrlWhitelistedOrPendingForWebContents(
           web_contents->GetLastCommittedURL().GetWithEmptyPath(),
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.h b/chrome/browser/safe_browsing/chrome_password_protection_service.h
index d5f6eaa..16ac8385 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.h
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.h
@@ -207,10 +207,10 @@
   bool HasUnhandledEnterprisePasswordReuse(
       content::WebContents* web_contents) const;
 
-  // If user has clicked through any Safe Browsing interstitial on this given
-  // |web_contents|.
+  // If user has clicked through any Safe Browsing interstitial on |request|'s
+  // web contents.
   bool UserClickedThroughSBInterstitial(
-      content::WebContents* web_contents) override;
+      PasswordProtectionRequest* request) override;
 
   // If |prefs::kPasswordProtectionWarningTrigger| is not managed by enterprise
   // policy, this function should always return PHISHING_REUSE. Otherwise,
diff --git a/chrome/browser/sessions/session_restore_android.cc b/chrome/browser/sessions/session_restore_android.cc
index 3ea43e77..7b06b51 100644
--- a/chrome/browser/sessions/session_restore_android.cc
+++ b/chrome/browser/sessions/session_restore_android.cc
@@ -37,8 +37,7 @@
   content::WebContents* raw_new_web_contents = new_web_contents.get();
   int selected_index = session_tab.normalized_navigation_index();
   new_web_contents->GetController().Restore(
-      selected_index, content::RestoreType::LAST_SESSION_EXITED_CLEANLY,
-      &entries);
+      selected_index, content::RestoreType::LAST_SESSION, &entries);
 
   TabAndroid* current_tab = TabAndroid::FromWebContents(web_contents);
   DCHECK(current_tab);
diff --git a/chrome/browser/sessions/session_restore_interactive_uitest.cc b/chrome/browser/sessions/session_restore_interactive_uitest.cc
index ec4e4d1..da8763f 100644
--- a/chrome/browser/sessions/session_restore_interactive_uitest.cc
+++ b/chrome/browser/sessions/session_restore_interactive_uitest.cc
@@ -79,7 +79,13 @@
   GURL url1_;
 };
 
-IN_PROC_BROWSER_TEST_F(SessionRestoreInteractiveTest, FocusOnLaunch) {
+// TODO(https://crbug.com/1152160): Enable FocusOnLaunch on Lacros builds.
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#define MAYBE_FocusOnLaunch DISABLED_FocusOnLaunch
+#else
+#define MAYBE_FocusOnLaunch FocusOnLaunch
+#endif
+IN_PROC_BROWSER_TEST_F(SessionRestoreInteractiveTest, MAYBE_FocusOnLaunch) {
   ui_test_utils::NavigateToURL(browser(), url1_);
 
   Browser* new_browser = QuitBrowserAndRestore(browser(), 1);
diff --git a/chrome/browser/sessions/session_restore_observer_unittest.cc b/chrome/browser/sessions/session_restore_observer_unittest.cc
index d4f7891..f56ea21f 100644
--- a/chrome/browser/sessions/session_restore_observer_unittest.cc
+++ b/chrome/browser/sessions/session_restore_observer_unittest.cc
@@ -99,7 +99,7 @@
     std::vector<std::unique_ptr<content::NavigationEntry>> entries;
     entries.push_back(content::NavigationEntry::Create());
     test_contents->GetController().Restore(
-        0, content::RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+        0, content::RestoreType::LAST_SESSION, &entries);
     // TabLoadTracker needs the resource_coordinator WebContentsData to be
     // initialized, which is needed by TabLoader.
     resource_coordinator::ResourceCoordinatorTabHelper::CreateForWebContents(
diff --git a/chrome/browser/sessions/session_restore_stats_collector_unittest.cc b/chrome/browser/sessions/session_restore_stats_collector_unittest.cc
index 985d450..b6e7ecf5 100644
--- a/chrome/browser/sessions/session_restore_stats_collector_unittest.cc
+++ b/chrome/browser/sessions/session_restore_stats_collector_unittest.cc
@@ -181,8 +181,8 @@
         test_web_contents_factory_->CreateWebContents(&testing_profile_);
     std::vector<std::unique_ptr<content::NavigationEntry>> entries;
     entries.push_back(content::NavigationEntry::Create());
-    contents->GetController().Restore(
-        0, content::RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+    contents->GetController().Restore(0, content::RestoreType::LAST_SESSION,
+                                      &entries);
     // Create a last active time in the past.
     content::WebContentsTester::For(contents)->SetLastActiveTime(
         base::TimeTicks::Now() - base::TimeDelta::FromMinutes(1));
diff --git a/chrome/browser/sessions/tab_loader_unittest.cc b/chrome/browser/sessions/tab_loader_unittest.cc
index b4431b46..be0ad62 100644
--- a/chrome/browser/sessions/tab_loader_unittest.cc
+++ b/chrome/browser/sessions/tab_loader_unittest.cc
@@ -100,7 +100,7 @@
     std::vector<std::unique_ptr<content::NavigationEntry>> entries;
     entries.push_back(content::NavigationEntry::Create());
     test_contents->GetController().Restore(
-        0, content::RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+        0, content::RestoreType::LAST_SESSION, &entries);
     // TabLoadTracker needs the resource_coordinator WebContentsData to be
     // initialized.
     ResourceCoordinatorTabHelper::CreateForWebContents(test_contents);
diff --git a/chrome/browser/sessions/tab_restore_browsertest.cc b/chrome/browser/sessions/tab_restore_browsertest.cc
index aa9c1050..55df063 100644
--- a/chrome/browser/sessions/tab_restore_browsertest.cc
+++ b/chrome/browser/sessions/tab_restore_browsertest.cc
@@ -1437,7 +1437,7 @@
 // Test that it is possible to navigate back to a restored about:blank history
 // entry with a non-null initiator origin.  This test cases covers
 // https://crbug.com/1116320 - a scenario where the restore type is different
-// from LAST_SESSION_EXITED_CLEANLY (e.g. the test below uses CURRENT_SESSION).
+// from LAST_SESSION (e.g. the test below uses CURRENT_SESSION).
 //
 // See also MultiOriginSessionRestoreTest.BackToAboutBlank1
 IN_PROC_BROWSER_TEST_F(TabRestoreTest, BackToAboutBlank) {
diff --git a/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/SettingsActivityTestRule.java b/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/SettingsActivityTestRule.java
index 250dbd2e..22bcb58 100644
--- a/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/SettingsActivityTestRule.java
+++ b/chrome/browser/settings/android/java/src/org/chromium/chrome/browser/settings/SettingsActivityTestRule.java
@@ -8,17 +8,15 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.lifecycle.Stage;
 
 import androidx.fragment.app.Fragment;
 
-import org.hamcrest.Matchers;
 import org.junit.Assert;
 
-import org.chromium.base.ActivityState;
-import org.chromium.base.ApplicationStatus;
-import org.chromium.base.test.util.Criteria;
-import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.BaseActivityTestRule;
+import org.chromium.base.test.util.ApplicationTestUtils;
+
 /**
  * Activity test rule that launch {@link SettingsActivity} in tests.
  *
@@ -28,7 +26,7 @@
  * @param <T> Fragment that will be attached to the SettingsActivity.
  */
 public class SettingsActivityTestRule<T extends Fragment>
-        extends ActivityTestRule<SettingsActivity> {
+        extends BaseActivityTestRule<SettingsActivity> {
     private final Class<T> mFragmentClass;
 
     /**
@@ -36,16 +34,7 @@
      * @param fragmentClass Fragment that will be attached after the activity starts.
      */
     public SettingsActivityTestRule(Class<T> fragmentClass) {
-        this(fragmentClass, false);
-    }
-
-    /**
-     * Create the settings activity test rule with an specific fragment class.
-     * @param fragmentClass Fragment that will be attached after the activity starts.
-     * @param initialTouchMode Whether in touch mode after the activity starts.
-     */
-    public SettingsActivityTestRule(Class<T> fragmentClass, boolean initialTouchMode) {
-        super(SettingsActivity.class, initialTouchMode, false);
+        super(SettingsActivity.class);
         mFragmentClass = fragmentClass;
     }
 
@@ -67,35 +56,9 @@
         SettingsLauncher settingsLauncher = new SettingsLauncherImpl();
         Intent intent = settingsLauncher.createSettingsActivityIntent(
                 context, mFragmentClass.getName(), fragmentArgs);
-        SettingsActivity activity = super.launchActivity(intent);
-        Assert.assertNotNull(activity);
-
-        return activity;
-    }
-
-    /**
-     * We need to ensure that SettingsActivity gets destroyed in the TestRule because sometimes
-     * it uses the mock signin environment like fake AccountManagerFacade, if the activity starts
-     * with the stub then it also needs to finish with it. That's why we need to wait till the
-     * activity state becomes destroyed before tearing down the mock signin environment.
-     */
-    @Override
-    protected void afterActivityFinished() {
-        super.afterActivityFinished();
-        waitTillActivityIsDestroyed();
-    }
-
-    /**
-     * Block the execution till the SettingsActivity is destroyed.
-     */
-    public void waitTillActivityIsDestroyed() {
-        SettingsActivity activity = getActivity();
-        if (activity != null) {
-            CriteriaHelper.pollUiThread(() -> {
-                Criteria.checkThat(ApplicationStatus.getStateForActivity(activity),
-                        Matchers.is(ActivityState.DESTROYED));
-            });
-        }
+        launchActivity(intent);
+        ApplicationTestUtils.waitForActivityState(getActivity(), Stage.RESUMED);
+        return getActivity();
     }
 
     /**
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 2a6e2b64..e7fdfaa 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -5421,8 +5421,7 @@
   entries.push_back(std::move(restored_entry));
   content::TestNavigationObserver observer(raw_tab2);
   raw_tab2->GetController().Restore(
-      entries.size() - 1, content::RestoreType::LAST_SESSION_EXITED_CLEANLY,
-      &entries);
+      entries.size() - 1, content::RestoreType::LAST_SESSION, &entries);
   raw_tab2->GetController().LoadIfNecessary();
   observer.Wait();
   ssl_test_util::CheckAuthenticatedState(raw_tab2, AuthState::NONE);
diff --git a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
index de92a5d..da7c6a5 100644
--- a/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
+++ b/chrome/browser/tab/java/src/org/chromium/chrome/browser/tab/TabWebContentsDelegateAndroid.java
@@ -14,11 +14,6 @@
  */
 public abstract class TabWebContentsDelegateAndroid extends WebContentsDelegateAndroid {
     /**
-     * Returns {@link WebDisplayMode} value.
-     */
-    protected abstract int getDisplayMode();
-
-    /**
      * Returns whether the page should resume accepting requests for the new window. This is
      * used when window creation is asynchronous and the navigations need to be delayed.
      */
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 5419b6e..8a8e55af6 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -343,6 +343,7 @@
     "//base:i18n",
     "//base/allocator:buildflags",
     "//build:branding_buildflags",
+    "//build:chromeos_buildflags",
     "//cc/paint",
     "//chrome:extra_resources",
     "//chrome:resources",
@@ -2089,11 +2090,6 @@
       "views/extensions/request_file_system_dialog_view.h",
       "views/frame/browser_frame_ash.cc",
       "views/frame/browser_frame_ash.h",
-      "views/frame/browser_frame_header_chromeos.cc",
-      "views/frame/browser_frame_header_chromeos.h",
-      "views/frame/browser_non_client_frame_view_chromeos.cc",
-      "views/frame/browser_non_client_frame_view_chromeos.h",
-      "views/frame/browser_non_client_frame_view_factory_chromeos.cc",
       "views/frame/custom_tab_browser_frame.cc",
       "views/frame/custom_tab_browser_frame.h",
       "views/frame/immersive_mode_controller_chromeos.cc",
@@ -2735,8 +2731,17 @@
     }
   }
 
-  # TODO(crbug.com/1052397): Rename GN variable. This is the lacros browser.
-  if (chromeos_is_browser_only) {
+  if (is_chromeos_ash || is_chromeos_lacros) {
+    sources += [
+      "views/frame/browser_frame_header_chromeos.cc",
+      "views/frame/browser_frame_header_chromeos.h",
+      "views/frame/browser_non_client_frame_view_chromeos.cc",
+      "views/frame/browser_non_client_frame_view_chromeos.h",
+      "views/frame/browser_non_client_frame_view_factory_chromeos.cc",
+    ]
+  }
+
+  if (is_chromeos_lacros) {
     sources += [
       "views/chrome_browser_main_extra_parts_views_lacros.cc",
       "views/chrome_browser_main_extra_parts_views_lacros.h",
@@ -4312,9 +4317,13 @@
       "//ui/wm",
     ]
 
+    if (!is_chromeos && !chromeos_is_browser_only) {
+      sources +=
+          [ "views/frame/browser_non_client_frame_view_factory_views.cc" ]
+    }
+
     if (!is_chromeos) {
       sources += [
-        "views/frame/browser_non_client_frame_view_factory_views.cc",
         "views/frame/desktop_browser_frame_aura.cc",
         "views/frame/desktop_browser_frame_aura.h",
       ]
@@ -4619,6 +4628,7 @@
   ]
   public_deps = [ ":ui" ]
   deps = [
+    "//build:chromeos_buildflags",
     "//chrome/app/theme:theme_resources",
     "//chrome/browser",
     "//chrome/browser/devtools",
diff --git a/chrome/browser/ui/app_list/DEPS b/chrome/browser/ui/app_list/DEPS
index acf33052..c36945dc 100644
--- a/chrome/browser/ui/app_list/DEPS
+++ b/chrome/browser/ui/app_list/DEPS
@@ -1,3 +1,11 @@
 include_rules = [
   "+components/services/app_service/public",
 ]
+
+specific_include_rules = {
+  "app_service_app_item_browsertest\.cc": [
+    "+ash/app_list/app_list_controller_impl.h",
+    "+ash/app_list/model/app_list_item.h",
+    "+ash/shell.h",
+  ],
+}
diff --git a/chrome/browser/ui/app_list/app_list_model_updater.h b/chrome/browser/ui/app_list/app_list_model_updater.h
index c42fef03..8c6eabd 100644
--- a/chrome/browser/ui/app_list/app_list_model_updater.h
+++ b/chrome/browser/ui/app_list/app_list_model_updater.h
@@ -73,6 +73,7 @@
   virtual void SetItemNameAndShortName(const std::string& id,
                                        const std::string& name,
                                        const std::string& short_name) {}
+  virtual void SetAppStatus(const std::string& id, ash::AppStatus app_status) {}
   virtual void SetItemPosition(const std::string& id,
                                const syncer::StringOrdinal& new_position) {}
   virtual void SetItemIsPersistent(const std::string& id, bool is_persistent) {}
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_item.cc b/chrome/browser/ui/app_list/app_service/app_service_app_item.cc
index 2a3107f..887d084 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_app_item.cc
+++ b/chrome/browser/ui/app_list/app_service/app_service_app_item.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/app_list/app_service/app_service_app_item.h"
 
 #include "ash/public/cpp/app_list/app_list_config.h"
+#include "ash/public/cpp/shelf_types.h"
 #include "base/bind.h"
 #include "base/check.h"
 #include "base/compiler_specific.h"
@@ -68,6 +69,17 @@
     is_platform_app_ =
         app_update.IsPlatformApp() == apps::mojom::OptionalBool::kTrue;
   }
+
+  if (in_constructor || app_update.ReadinessChanged() ||
+      app_update.PausedChanged()) {
+    if (app_update.Readiness() == apps::mojom::Readiness::kDisabledByPolicy) {
+      SetAppStatus(ash::AppStatus::kBlocked);
+    } else if (app_update.Paused() == apps::mojom::OptionalBool::kTrue) {
+      SetAppStatus(ash::AppStatus::kPaused);
+    } else {
+      SetAppStatus(ash::AppStatus::kReady);
+    }
+  }
 }
 
 void AppServiceAppItem::Activate(int event_flags) {
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_item_browsertest.cc b/chrome/browser/ui/app_list/app_service/app_service_app_item_browsertest.cc
new file mode 100644
index 0000000..6e497b4
--- /dev/null
+++ b/chrome/browser/ui/app_list/app_service/app_service_app_item_browsertest.cc
@@ -0,0 +1,153 @@
+// Copyright 2020 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 "ash/app_list/app_list_controller_impl.h"
+#include "ash/app_list/model/app_list_item.h"
+#include "ash/public/cpp/app_list/app_list_types.h"
+#include "ash/public/cpp/shelf_types.h"
+#include "ash/shell.h"
+#include "chrome/browser/apps/app_service/app_service_proxy.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
+#include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/app_list/app_list_client_impl.h"
+#include "content/public/test/browser_test.h"
+#include "content/public/test/test_utils.h"
+
+namespace {
+
+void UpdateAppRegistryCache(Profile* profile,
+                            const std::string& app_id,
+                            bool block,
+                            bool pause) {
+  std::vector<apps::mojom::AppPtr> apps;
+  apps::mojom::AppPtr app = apps::mojom::App::New();
+  app->app_type = apps::mojom::AppType::kExtension;
+  app->app_id = app_id;
+
+  if (block)
+    app->readiness = apps::mojom::Readiness::kDisabledByPolicy;
+  else
+    app->readiness = apps::mojom::Readiness::kReady;
+
+  if (pause)
+    app->paused = apps::mojom::OptionalBool::kTrue;
+  else
+    app->paused = apps::mojom::OptionalBool::kFalse;
+
+  apps.push_back(std::move(app));
+
+  apps::AppServiceProxyFactory::GetForProfile(profile)
+      ->AppRegistryCache()
+      .OnApps(std::move(apps));
+}
+
+ash::AppListItem* GetAppListItem(const std::string& id) {
+  ash::AppListControllerImpl* controller =
+      ash::Shell::Get()->app_list_controller();
+  ash::AppListModel* model = controller->GetModel();
+  return model->FindItem(id);
+}
+
+}  // namespace
+
+class AppServiceAppItemBrowserTest : public extensions::PlatformAppBrowserTest {
+ public:
+  AppServiceAppItemBrowserTest() = default;
+  ~AppServiceAppItemBrowserTest() override = default;
+
+  // extensions::PlatformAppBrowserTest:
+  void SetUpOnMainThread() override {
+    extensions::PlatformAppBrowserTest::SetUpOnMainThread();
+
+    AppListClientImpl* client = AppListClientImpl::GetInstance();
+    ASSERT_TRUE(client);
+
+    // Associate |client| with the current profile.
+    client->UpdateProfile();
+  }
+};
+
+// Test the app status when the paused app is blocked, un-paused, and un-blocked
+IN_PROC_BROWSER_TEST_F(AppServiceAppItemBrowserTest,
+                       VerifyAppStatusForPausedApp) {
+  const extensions::Extension* extension_app =
+      LoadAndLaunchPlatformApp("launch", "Launched");
+  ASSERT_TRUE(extension_app);
+
+  ash::AppListItem* item = GetAppListItem(extension_app->id());
+  ASSERT_TRUE(item);
+
+  // Set the app as paused.
+  UpdateAppRegistryCache(profile(), extension_app->id(), false /* block */,
+                         true /* pause */);
+  EXPECT_EQ(ash::AppStatus::kPaused, item->app_status());
+
+  // Set the app as blocked, and paused.
+  UpdateAppRegistryCache(profile(), extension_app->id(), true /* block */,
+                         true /* pause */);
+  EXPECT_EQ(ash::AppStatus::kBlocked, item->app_status());
+
+  // Set the app as blocked, but not paused.
+  UpdateAppRegistryCache(profile(), extension_app->id(), true /* block */,
+                         false /* pause */);
+  EXPECT_EQ(ash::AppStatus::kBlocked, item->app_status());
+
+  // Set the app as neither blocked, nor paused.
+  UpdateAppRegistryCache(profile(), extension_app->id(), false /* block */,
+                         false /* pause */);
+  EXPECT_EQ(ash::AppStatus::kReady, item->app_status());
+}
+
+// Test the app status when the blocked app is paused, un-blocked, and un-paused
+IN_PROC_BROWSER_TEST_F(AppServiceAppItemBrowserTest,
+                       VerifyAppStatusForBlockedApp) {
+  const extensions::Extension* extension_app =
+      LoadAndLaunchPlatformApp("launch", "Launched");
+  ASSERT_TRUE(extension_app);
+
+  ash::AppListItem* item = GetAppListItem(extension_app->id());
+  ASSERT_TRUE(item);
+
+  // Set the app as blocked.
+  UpdateAppRegistryCache(profile(), extension_app->id(), true /* block */,
+                         false /* pause */);
+  EXPECT_EQ(ash::AppStatus::kBlocked, item->app_status());
+
+  // Set the app as blocked, and paused.
+  UpdateAppRegistryCache(profile(), extension_app->id(), true /* block */,
+                         true /* pause */);
+  EXPECT_EQ(ash::AppStatus::kBlocked, item->app_status());
+
+  // Set the app as not blocked, but paused.
+  UpdateAppRegistryCache(profile(), extension_app->id(), false /* block */,
+                         true /* pause */);
+  EXPECT_EQ(ash::AppStatus::kPaused, item->app_status());
+
+  // Set the app as neither blocked, nor paused.
+  UpdateAppRegistryCache(profile(), extension_app->id(), false /* block */,
+                         false /* pause */);
+  EXPECT_EQ(ash::AppStatus::kReady, item->app_status());
+}
+
+// Test the app status when the app is both blocked and paused.
+IN_PROC_BROWSER_TEST_F(AppServiceAppItemBrowserTest,
+                       VerifyAppStatusForBlockedAndPausedApp) {
+  const extensions::Extension* extension_app =
+      LoadAndLaunchPlatformApp("launch", "Launched");
+  ASSERT_TRUE(extension_app);
+
+  ash::AppListItem* item = GetAppListItem(extension_app->id());
+  ASSERT_TRUE(item);
+
+  // Set the app as blocked, and paused.
+  UpdateAppRegistryCache(profile(), extension_app->id(), true /* block */,
+                         true /* pause */);
+  EXPECT_EQ(ash::AppStatus::kBlocked, item->app_status());
+
+  // Set the app as neither blocked, nor paused.
+  UpdateAppRegistryCache(profile(), extension_app->id(), false /* block */,
+                         false /* pause */);
+  EXPECT_EQ(ash::AppStatus::kReady, item->app_status());
+}
diff --git a/chrome/browser/ui/app_list/chrome_app_list_item.cc b/chrome/browser/ui/app_list/chrome_app_list_item.cc
index 6b877c76..faf376a 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_item.cc
+++ b/chrome/browser/ui/app_list/chrome_app_list_item.cc
@@ -187,6 +187,13 @@
     updater->SetItemNameAndShortName(id(), name, short_name);
 }
 
+void ChromeAppListItem::SetAppStatus(ash::AppStatus app_status) {
+  metadata_->app_status = app_status;
+  AppListModelUpdater* updater = model_updater();
+  if (updater)
+    updater->SetAppStatus(id(), app_status);
+}
+
 void ChromeAppListItem::SetFolderId(const std::string& folder_id) {
   metadata_->folder_id = folder_id;
   AppListModelUpdater* updater = model_updater();
diff --git a/chrome/browser/ui/app_list/chrome_app_list_item.h b/chrome/browser/ui/app_list/chrome_app_list_item.h
index eb5dbc5..8a93f56 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_item.h
+++ b/chrome/browser/ui/app_list/chrome_app_list_item.h
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "ash/public/cpp/app_list/app_list_types.h"
+#include "ash/public/cpp/shelf_types.h"
 #include "chrome/browser/ui/app_list/app_context_menu.h"
 #include "chrome/browser/ui/app_list/app_list_syncable_service.h"
 #include "ui/gfx/image/image_skia.h"
@@ -59,6 +60,7 @@
   const std::string& folder_id() const { return metadata_->folder_id; }
   const syncer::StringOrdinal& position() const { return metadata_->position; }
   const std::string& name() const { return metadata_->name; }
+  ash::AppStatus app_status() const { return metadata_->app_status; }
   bool is_folder() const { return metadata_->is_folder; }
   bool is_persistent() const { return metadata_->is_persistent; }
   const gfx::ImageSkia& icon() const { return metadata_->icon; }
@@ -73,6 +75,7 @@
   void SetName(const std::string& name);
   void SetNameAndShortName(const std::string& name,
                            const std::string& short_name);
+  void SetAppStatus(ash::AppStatus app_status);
   void SetFolderId(const std::string& folder_id);
   void SetPosition(const syncer::StringOrdinal& position);
   void SetIsPageBreak(bool is_page_break);
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
index 0224163..165572a7 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater.cc
@@ -215,6 +215,18 @@
   app_list_controller_->SetItemMetadata(id, std::move(data));
 }
 
+void ChromeAppListModelUpdater::SetAppStatus(const std::string& id,
+                                             ash::AppStatus app_status) {
+  if (!app_list_controller_)
+    return;
+  ChromeAppListItem* item = FindItem(id);
+  if (!item)
+    return;
+  std::unique_ptr<ash::AppListItemMetadata> data = item->CloneMetadata();
+  data->app_status = app_status;
+  app_list_controller_->SetItemMetadata(id, std::move(data));
+}
+
 void ChromeAppListModelUpdater::SetItemPosition(
     const std::string& id,
     const syncer::StringOrdinal& new_position) {
diff --git a/chrome/browser/ui/app_list/chrome_app_list_model_updater.h b/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
index 2656f7e..43c75b6 100644
--- a/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
+++ b/chrome/browser/ui/app_list/chrome_app_list_model_updater.h
@@ -52,6 +52,7 @@
   void SetItemNameAndShortName(const std::string& id,
                                const std::string& name,
                                const std::string& short_name) override;
+  void SetAppStatus(const std::string& id, ash::AppStatus app_status) override;
   void SetItemPosition(const std::string& id,
                        const syncer::StringOrdinal& new_position) override;
   void SetItemIsPersistent(const std::string& id, bool is_persistent) override;
diff --git a/chrome/browser/ui/app_list/search/cros_action_history/cros_action_recorder.cc b/chrome/browser/ui/app_list/search/cros_action_history/cros_action_recorder.cc
index 37d8a37..29746e34 100644
--- a/chrome/browser/ui/app_list/search/cros_action_history/cros_action_recorder.cc
+++ b/chrome/browser/ui/app_list/search/cros_action_history/cros_action_recorder.cc
@@ -359,16 +359,18 @@
 
   if (ConsumePrefix(&action_name, kSearchResultLaunchedPrefix)) {
     // SearchReultLaunched.
-    metrics::structured::events::CrOSActionEvent_SearchResultLaunched()
-        .SetQuery(base::NumberToString(FindWithDefault(conditions, "Query")))
-        .SetResultType(FindWithDefault(conditions, "ResultType"))
-        .SetSearchResultId(action_name)
-        .SetSequenceId(sequence_id_)
-        .SetTimeSinceLastAction(time_since_last_action)
-        .Record();
+    metrics::structured::events::hindsight::
+        CrOSActionEvent_SearchResultLaunched()
+            .SetQuery(
+                base::NumberToString(FindWithDefault(conditions, "Query")))
+            .SetResultType(FindWithDefault(conditions, "ResultType"))
+            .SetSearchResultId(action_name)
+            .SetSequenceId(sequence_id_)
+            .SetTimeSinceLastAction(time_since_last_action)
+            .Record();
   } else if (ConsumePrefix(&action_name, kFileOpenedPrefix)) {
     // FileOpened.
-    metrics::structured::events::CrOSActionEvent_FileOpened()
+    metrics::structured::events::hindsight::CrOSActionEvent_FileOpened()
         .SetFilename(action_name)
         .SetOpenType(FindWithDefault(conditions, "open_type"))
         .SetSequenceId(sequence_id_)
@@ -376,7 +378,7 @@
         .Record();
   } else if (ConsumePrefix(&action_name, kSettingChangedPrefix)) {
     // SettingChanged.
-    metrics::structured::events::CrOSActionEvent_SettingChanged()
+    metrics::structured::events::hindsight::CrOSActionEvent_SettingChanged()
         .SetSettingId(FindWithDefault(conditions, "SettingId"))
         .SetSettingType(FindWithDefault(conditions, "SettingType"))
         .SetPreviousValue(FindWithDefault(conditions, "PreviousValue"))
@@ -386,20 +388,22 @@
         .Record();
   } else if (ConsumePrefix(&action_name, kTabNavigatedPrefix)) {
     // Navigate to a new tab.
-    metrics::structured::events::CrOSActionEvent_TabEvent_TabNavigated()
-        .SetURL(action_name)
-        .SetVisibility(FindWithDefault(conditions, "Visibility"))
-        .SetPageTransition(FindWithDefault(conditions, "PageTransition"))
-        .SetSequenceId(sequence_id_)
-        .SetTimeSinceLastAction(time_since_last_action)
-        .Record();
+    metrics::structured::events::hindsight::
+        CrOSActionEvent_TabEvent_TabNavigated()
+            .SetURL(action_name)
+            .SetVisibility(FindWithDefault(conditions, "Visibility"))
+            .SetPageTransition(FindWithDefault(conditions, "PageTransition"))
+            .SetSequenceId(sequence_id_)
+            .SetTimeSinceLastAction(time_since_last_action)
+            .Record();
   } else if (ConsumePrefix(&action_name, kTabReactivatedPrefix)) {
     // Reactivate an old tab.
-    metrics::structured::events::CrOSActionEvent_TabEvent_TabReactivated()
-        .SetURL(action_name)
-        .SetSequenceId(sequence_id_)
-        .SetTimeSinceLastAction(time_since_last_action)
-        .Record();
+    metrics::structured::events::hindsight::
+        CrOSActionEvent_TabEvent_TabReactivated()
+            .SetURL(action_name)
+            .SetSequenceId(sequence_id_)
+            .SetTimeSinceLastAction(time_since_last_action)
+            .Record();
   } else if (ConsumePrefix(&action_name, kTabOpenedPrefix)) {
     // Open a tab from current tab.
     // current tab is stored as a condition with value -1.
@@ -410,7 +414,7 @@
       }
     }
 
-    metrics::structured::events::CrOSActionEvent_TabEvent_TabOpened()
+    metrics::structured::events::hindsight::CrOSActionEvent_TabEvent_TabOpened()
         .SetURL(current_url)
         .SetURLOpened(action_name)
         .SetWindowOpenDisposition(
diff --git a/chrome/browser/ui/app_list/search/search_controller.cc b/chrome/browser/ui/app_list/search/search_controller.cc
index 00797ae..09516fa 100644
--- a/chrome/browser/ui/app_list/search/search_controller.cc
+++ b/chrome/browser/ui/app_list/search/search_controller.cc
@@ -227,7 +227,7 @@
     base::Time::Exploded now_exploded;
     now.LocalExplode(&now_exploded);
 
-    metrics::structured::events::LauncherUsage()
+    metrics::structured::events::launcher_usage::LauncherUsage()
         .SetTarget(NormalizeId(app_launch_data.id))
         .SetApp(last_launched_app_id_)
         .SetSearchQuery(base::UTF16ToUTF8(last_query_))
diff --git a/chrome/browser/ui/browser_tabrestore.cc b/chrome/browser/ui/browser_tabrestore.cc
index 7fed1c0..4999186 100644
--- a/chrome/browser/ui/browser_tabrestore.cc
+++ b/chrome/browser/ui/browser_tabrestore.cc
@@ -39,14 +39,6 @@
 
 namespace {
 
-RestoreType GetRestoreType(Browser* browser, bool from_last_session) {
-  if (!from_last_session)
-    return RestoreType::CURRENT_SESSION;
-  return browser->profile()->GetLastSessionExitType() == Profile::EXIT_CRASHED
-             ? RestoreType::LAST_SESSION_CRASHED
-             : RestoreType::LAST_SESSION_EXITED_CLEANLY;
-}
-
 std::unique_ptr<WebContents> CreateRestoredTab(
     Browser* browser,
     const std::vector<SerializedNavigationEntry>& navigations,
@@ -90,9 +82,11 @@
   ua_override.ua_metadata_override = blink::UserAgentMetadata::Demarshal(
       user_agent_override.opaque_ua_metadata_override);
   web_contents->SetUserAgentOverride(ua_override, false);
-  web_contents->GetController().Restore(
-      selected_navigation, GetRestoreType(browser, from_last_session),
-      &entries);
+  web_contents->GetController().Restore(selected_navigation,
+                                        from_last_session
+                                            ? RestoreType::LAST_SESSION
+                                            : RestoreType::CURRENT_SESSION,
+                                        &entries);
   DCHECK_EQ(0u, entries.size());
 
   return web_contents;
diff --git a/chrome/browser/ui/views/BUILD.gn b/chrome/browser/ui/views/BUILD.gn
index 7c9e5d3..54829b2 100644
--- a/chrome/browser/ui/views/BUILD.gn
+++ b/chrome/browser/ui/views/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/ui.gni")
 import("//ui/views/features.gni")
 
@@ -26,6 +27,7 @@
   deps = [
     "//base",
     "//build:branding_buildflags",
+    "//build:chromeos_buildflags",
     "//chrome/app:command_ids",
     "//chrome/app:generated_resources",
     "//components/keep_alive_registry",
@@ -40,7 +42,7 @@
     "//url",
   ]
 
-  if (is_chromeos) {
+  if (is_chromeos_ash) {
     deps += [ "//ash" ]
   }
 }
diff --git a/chrome/browser/ui/views/accelerator_table.cc b/chrome/browser/ui/views/accelerator_table.cc
index 3208202..2b6eed0 100644
--- a/chrome/browser/ui/views/accelerator_table.cc
+++ b/chrome/browser/ui/views/accelerator_table.cc
@@ -11,6 +11,7 @@
 #include "base/stl_util.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "printing/buildflags/buildflags.h"
 #include "ui/base/accelerators/accelerator.h"
@@ -30,7 +31,7 @@
 //      modifier.
 //   2) Update GetShortcutsNotPresentInMainMenu() in
 //      global_keyboard_shortcuts_mac.mm.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     {ui::VKEY_F7, ui::EF_NONE, IDC_CARET_BROWSING_TOGGLE},
 #endif
     {ui::VKEY_F12, ui::EF_NONE, IDC_DEV_TOOLS_TOGGLE},
@@ -58,7 +59,9 @@
     {ui::VKEY_S, ui::EF_PLATFORM_ACCELERATOR, IDC_SAVE_PAGE},
     {ui::VKEY_9, ui::EF_PLATFORM_ACCELERATOR, IDC_SELECT_LAST_TAB},
     {ui::VKEY_NUMPAD9, ui::EF_PLATFORM_ACCELERATOR, IDC_SELECT_LAST_TAB},
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
     {ui::VKEY_9, ui::EF_ALT_DOWN, IDC_SELECT_LAST_TAB},
     {ui::VKEY_NUMPAD9, ui::EF_ALT_DOWN, IDC_SELECT_LAST_TAB},
     {ui::VKEY_NEXT, ui::EF_CONTROL_DOWN | ui::EF_SHIFT_DOWN, IDC_MOVE_TAB_NEXT},
@@ -88,7 +91,9 @@
     {ui::VKEY_NUMPAD7, ui::EF_PLATFORM_ACCELERATOR, IDC_SELECT_TAB_6},
     {ui::VKEY_8, ui::EF_PLATFORM_ACCELERATOR, IDC_SELECT_TAB_7},
     {ui::VKEY_NUMPAD8, ui::EF_PLATFORM_ACCELERATOR, IDC_SELECT_TAB_7},
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
     {ui::VKEY_1, ui::EF_ALT_DOWN, IDC_SELECT_TAB_0},
     {ui::VKEY_NUMPAD1, ui::EF_ALT_DOWN, IDC_SELECT_TAB_0},
     {ui::VKEY_2, ui::EF_ALT_DOWN, IDC_SELECT_TAB_1},
@@ -131,7 +136,7 @@
     {ui::VKEY_M, ui::EF_SHIFT_DOWN | ui::EF_PLATFORM_ACCELERATOR,
      IDC_SHOW_AVATAR_MENU},
 
-  // Platform-specific key maps.
+// Platform-specific key maps.
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
     {ui::VKEY_BROWSER_BACK, ui::EF_NONE, IDC_BACK},
     {ui::VKEY_BROWSER_FORWARD, ui::EF_NONE, IDC_FORWARD},
@@ -141,7 +146,7 @@
     {ui::VKEY_BROWSER_REFRESH, ui::EF_SHIFT_DOWN, IDC_RELOAD_BYPASSING_CACHE},
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     // On Chrome OS, VKEY_BROWSER_SEARCH is handled in Ash.
     {ui::VKEY_BACK, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
      IDC_CLEAR_BROWSING_DATA},
@@ -181,7 +186,7 @@
 #if BUILDFLAG(ENABLE_PRINTING)
     {ui::VKEY_P, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, IDC_BASIC_PRINT},
 #endif  // ENABLE_PRINTING
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     {ui::VKEY_DELETE, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
      IDC_CLEAR_BROWSING_DATA},
 #endif  // !OS_CHROMEOS
@@ -207,7 +212,7 @@
     {ui::VKEY_J, ui::EF_CONTROL_DOWN, IDC_SHOW_DOWNLOADS},
     {ui::VKEY_H, ui::EF_CONTROL_DOWN, IDC_SHOW_HISTORY},
     {ui::VKEY_U, ui::EF_CONTROL_DOWN, IDC_VIEW_SOURCE},
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     // On Chrome OS, these keys are assigned to change UI scale.
     {ui::VKEY_OEM_MINUS, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN,
      IDC_ZOOM_MINUS},
@@ -220,7 +225,7 @@
 #endif  // !OS_MAC
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Accelerators to enable if features::IsNewShortcutMappingEnabled is false.
 const AcceleratorMapping kDisableWithNewMappingAcceleratorMap[] = {
     // On Chrome OS, Control + Search + 7 toggles caret browsing.
@@ -257,7 +262,7 @@
     accelerators->insert(accelerators->begin(), std::begin(kAcceleratorMap),
                          std::end(kAcceleratorMap));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     if (::features::IsNewShortcutMappingEnabled()) {
       accelerators->insert(accelerators->begin(),
                            std::begin(kEnableWithNewMappingAcceleratorMap),
diff --git a/chrome/browser/ui/views/accelerator_table_unittest.cc b/chrome/browser/ui/views/accelerator_table_unittest.cc
index cca3dba..3a01050f 100644
--- a/chrome/browser/ui/views/accelerator_table_unittest.cc
+++ b/chrome/browser/ui/views/accelerator_table_unittest.cc
@@ -10,10 +10,11 @@
 
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/events/event_constants.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/accelerators.h"
 #endif
 
@@ -47,7 +48,7 @@
   }
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST(AcceleratorTableTest, CheckDuplicatedAcceleratorsAsh) {
   std::set<AcceleratorMapping, Cmp> accelerators;
   const std::vector<AcceleratorMapping> accelerator_list(GetAcceleratorList());
@@ -104,6 +105,6 @@
         << (ash_entry.action);
   }
 }
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/views/accelerator_utils_aura.cc b/chrome/browser/ui/views/accelerator_utils_aura.cc
index 88db4a20..75f1b15 100644
--- a/chrome/browser/ui/views/accelerator_utils_aura.cc
+++ b/chrome/browser/ui/views/accelerator_utils_aura.cc
@@ -4,18 +4,19 @@
 
 #include <stddef.h>
 
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/views/accelerator_table.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "ui/base/accelerators/accelerator.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/accelerators.h"
 #endif
 
 namespace chrome {
 
 bool IsChromeAccelerator(const ui::Accelerator& accelerator) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   for (size_t i = 0; i < ash::kAcceleratorDataLength; ++i) {
     const ash::AcceleratorData& accel_data = ash::kAcceleratorData[i];
     if (accel_data.keycode == accelerator.key_code() &&
diff --git a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
index 24b791b..5808e00 100644
--- a/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
+++ b/chrome/browser/ui/views/accessibility/caption_bubble_controller_views_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_mock_time_message_loop_task_runner.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
@@ -504,7 +505,7 @@
     EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_TAB, false,
                                                 false, false, false));
   }
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
   // Check the native widget has focus.
   aura::client::FocusClient* focus_client =
       aura::client::GetFocusClient(GetCaptionWidget()->GetNativeView());
@@ -539,7 +540,7 @@
   // Next tab exits the bubble entirely.
   EXPECT_TRUE(ui_test_utils::SendKeyPressSync(browser(), ui::VKEY_TAB, false,
                                               false, false, false));
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
   // The native widget should no longer have focus.
   EXPECT_FALSE(GetCaptionWidget()->GetNativeView() ==
                focus_client->GetFocusedWindow());
diff --git a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc
index 4b3f387d..289986f 100644
--- a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc
+++ b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.cc
@@ -10,6 +10,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_navigator.h"
@@ -36,7 +37,7 @@
 #include "ui/views/controls/styled_label.h"
 #include "ui/views/layout/box_layout.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #endif
 
@@ -44,7 +45,7 @@
 
 AppUninstallDialogView* g_app_uninstall_dialog_view = nullptr;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 bool IsArcShortcutApp(Profile* profile, const std::string& app_id) {
   ArcAppListPrefs* arc_prefs = ArcAppListPrefs::Get(profile);
   DCHECK(arc_prefs);
@@ -61,7 +62,7 @@
                                     const std::string& app_id,
                                     const std::string& app_name) {
   using apps::mojom::AppType;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // On ChromeOS, all app types exist, but Arc shortcut apps get the regular
   // extension uninstall title.
   if (app_type == AppType::kArc && IsArcShortcutApp(profile, app_id))
@@ -154,14 +155,14 @@
       NOTREACHED();
       break;
     case apps::mojom::AppType::kArc:
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       InitializeViewForArcApp(profile, app_id);
 #else
       NOTREACHED();
 #endif
       break;
     case apps::mojom::AppType::kPluginVm:
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       InitializeViewWithMessage(l10n_util::GetStringFUTF16(
           IDS_PLUGIN_VM_UNINSTALL_PROMPT_BODY, base::UTF8ToUTF16(app_name)));
 #else
@@ -169,7 +170,7 @@
 #endif
       break;
     case apps::mojom::AppType::kCrostini:
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       InitializeViewWithMessage(l10n_util::GetStringUTF16(
           IDS_CROSTINI_APPLICATION_UNINSTALL_CONFIRM_BODY));
 #else
@@ -297,7 +298,7 @@
   InitializeCheckbox(app_start_url);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AppUninstallDialogView::InitializeViewForArcApp(
     Profile* profile,
     const std::string& app_id) {
diff --git a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.h b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.h
index 00e3475..19020c34 100644
--- a/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.h
+++ b/chrome/browser/ui/views/apps/app_dialog/app_uninstall_dialog_view.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/apps/app_service/uninstall_dialog.h"
 #include "chrome/browser/ui/views/apps/app_dialog/app_dialog_view.h"
 #include "components/services/app_service/public/mojom/types.mojom-forward.h"
@@ -53,7 +54,7 @@
 
   void InitializeViewForExtension(Profile* profile, const std::string& app_id);
   void InitializeViewForWebApp(Profile* profile, const std::string& app_id);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void InitializeViewForArcApp(Profile* profile, const std::string& app_id);
   void InitializeViewWithMessage(const base::string16& message);
 #endif
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.cc
index 7b5065d..0754507 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.cc
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.cc
@@ -8,6 +8,7 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/common/buildflags.h"
 #include "ui/base/accelerators/accelerator.h"
@@ -27,7 +28,7 @@
 #include "ui/views/window/native_frame_view.h"
 #include "ui/views/window/non_client_view.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/app_list/app_list_color_provider.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "ui/views/background.h"
@@ -44,7 +45,7 @@
     views::BubbleBorder::SMALL_SHADOW;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // The background for App List dialogs, which appears as a rounded rectangle
 // with the same border radius and color as the app list contents.
 class AppListOverlayBackground : public views::Background {
@@ -70,7 +71,7 @@
  private:
   DISALLOW_COPY_AND_ASSIGN(AppListOverlayBackground);
 };
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Base container for modal dialogs. Encases a content view in a modal dialog
 // with an accelerator to close on escape.
@@ -101,7 +102,7 @@
   DISALLOW_COPY_AND_ASSIGN(BaseDialogContainer);
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 // The contents view for an App List Dialog, which covers the entire app list
 // and adds a close button.
@@ -145,7 +146,7 @@
   DISALLOW_COPY_AND_ASSIGN(AppListDialogContainer);
 };
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // A BubbleFrameView that allows its client view to extend all the way to the
 // top of the dialog, overlapping the BubbleFrameView's close button. This
@@ -210,12 +211,12 @@
 
 }  // namespace
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 views::DialogDelegateView* CreateAppListContainerForView(
     std::unique_ptr<views::View> view) {
   return new AppListDialogContainer(std::move(view));
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 views::DialogDelegateView* CreateDialogContainerForView(
     std::unique_ptr<views::View> view,
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.h b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.h
index 61c9757..7f288ae 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.h
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_container.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/callback_forward.h"
+#include "build/chromeos_buildflags.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace views {
@@ -15,14 +16,14 @@
 class View;
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Creates a new dialog containing |view| that can be displayed inside the app
 // list, covering the entire app list and adding a close button.
 views::DialogDelegateView* CreateAppListContainerForView(
     std::unique_ptr<views::View> view);
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Creates a new native dialog of the given |size| containing |view| with a
 // close button and draggable titlebar.
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc
index d6c4715c..1509aad4 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views.cc
@@ -12,6 +12,7 @@
 #include "base/feature_list.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/apps/app_info_dialog.h"
@@ -43,7 +44,7 @@
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
@@ -68,7 +69,7 @@
 }
 
 bool CanShowAppInfoDialog(Profile* profile, const std::string& extension_id) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   bool is_system_web_app = web_app::WebAppProvider::Get(profile)
                                ->system_web_app_manager()
                                .IsSystemWebApp(extension_id);
@@ -93,7 +94,7 @@
   return CanPlatformShowAppInfoDialog();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void ShowAppInfoInAppList(gfx::NativeWindow parent,
                           const gfx::Rect& app_info_bounds,
                           Profile* profile,
@@ -159,7 +160,7 @@
   dialog_body_contents->AddChildView(
       std::make_unique<AppInfoPermissionsPanel>(profile, app));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // When Google Play Store is enabled and the Settings app is available, show
   // the "Manage supported links" link for Chrome.
   if (app->id() == extension_misc::kChromeAppId &&
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc
index 3c67cb2..5e78dd8 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_dialog_views_unittest.cc
@@ -11,6 +11,7 @@
 
 #include "base/macros.h"
 #include "base/run_loop.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/test_extension_environment.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -28,7 +29,7 @@
 #include "ui/views/widget/widget_observer.h"
 #include "ui/views/window/dialog_delegate.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/shelf_model.h"  // nogncheck
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_test.h"
@@ -36,7 +37,7 @@
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 namespace {
 
 std::vector<arc::mojom::AppInfoPtr> GetArcSettingsAppInfo() {
@@ -88,7 +89,7 @@
   // Overridden from testing::Test:
   void SetUp() override {
     BrowserWithTestWindowTest::SetUp();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     shelf_model_ = std::make_unique<ash::ShelfModel>();
     chrome_launcher_controller_ = std::make_unique<ChromeLauncherController>(
         extension_environment_.profile(), shelf_model_.get());
@@ -104,7 +105,7 @@
     CloseAppInfo();
     extension_ = nullptr;
     chrome_app_ = nullptr;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     arc_test_.TearDown();
     chrome_launcher_controller_.reset();
     shelf_model_.reset();
@@ -177,7 +178,7 @@
   extensions::TestExtensionEnvironment extension_environment_{
       extensions::TestExtensionEnvironment::Type::
           kInheritExistingTaskEnvironment};
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   std::unique_ptr<ash::ShelfModel> shelf_model_;
   std::unique_ptr<ChromeLauncherController> chrome_launcher_controller_;
   ArcAppTest arc_test_;
@@ -221,7 +222,7 @@
   browser_window->Close();
   browser_window.reset();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   chrome_launcher_controller_.reset();
   shelf_model_.reset();
   arc_test_.TearDown();
@@ -286,7 +287,7 @@
   EXPECT_FALSE(widget_);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(AppInfoDialogViewsTest, ArcAppInfoLinks) {
   ShowAppInfo(extension_misc::kChromeAppId);
   EXPECT_FALSE(widget_->IsClosed());
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc b/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc
index 724e9f9..5d1fa3fb 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.h"
 
 #include "base/memory/ptr_util.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
@@ -22,7 +23,7 @@
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // gn check complains on Linux Ozone.
 #include "ash/public/cpp/shelf_model.h"  // nogncheck
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
@@ -50,7 +51,7 @@
     Profile* profile,
     const extensions::Extension* app) {
   if (CanCreateShortcuts(app) ||
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       CanSetPinnedToShelf(profile, app) ||
 #endif
       CanUninstallApp(profile, app))
@@ -68,7 +69,7 @@
                 IDS_APPLICATION_INFO_CREATE_SHORTCUTS_BUTTON_TEXT)));
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (CanSetPinnedToShelf(profile_, app_)) {
     pin_to_shelf_button_ = AddChildView(std::make_unique<views::MdTextButton>(
         base::BindRepeating(&AppInfoFooterPanel::SetPinnedToShelf,
@@ -91,7 +92,7 @@
   }
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AppInfoFooterPanel::UpdatePinButtons(bool focus_visible_button) {
   if (pin_to_shelf_button_ && unpin_from_shelf_button_) {
     const bool was_pinned =
@@ -130,16 +131,16 @@
 
 // static
 bool AppInfoFooterPanel::CanCreateShortcuts(const extensions::Extension* app) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Ash platforms can't create shortcuts.
   return false;
 #else
   // Extensions and the Chrome component app can't have shortcuts.
   return app->id() != extension_misc::kChromeAppId && !app->is_extension();
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AppInfoFooterPanel::SetPinnedToShelf(bool value) {
   DCHECK(CanSetPinnedToShelf(profile_, app_));
   ash::ShelfModel* shelf_model =
@@ -163,7 +164,7 @@
          (GetPinnableForAppID(app->id(), profile) ==
           AppListControllerDelegate::PIN_EDITABLE);
 }
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 void AppInfoFooterPanel::UninstallApp() {
   DCHECK(CanUninstallApp(profile_, app_));
diff --git a/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.h b/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.h
index 2a791f6..4a1c9179 100644
--- a/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.h
+++ b/chrome/browser/ui/views/apps/app_info_dialog/app_info_footer_panel.h
@@ -10,6 +10,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
 #include "chrome/browser/ui/views/apps/app_info_dialog/app_info_panel.h"
 
@@ -41,12 +42,12 @@
 
   void CreateButtons();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Updates the visibility of the pin/unpin buttons so that only one is visible
   // at a time. If |focus_button| is true, sets the focus to whichever button is
   // now visible.
   void UpdatePinButtons(bool focus_visible_button);
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // Overridden from ExtensionUninstallDialog::Delegate:
   void OnExtensionUninstallDialogClosed(bool did_start_uninstall,
@@ -56,13 +57,13 @@
   void CreateShortcuts();
   static bool CanCreateShortcuts(const extensions::Extension* app);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Pins and unpins the app from the shelf. Must only be called if
   // CanSetPinnedToShelf() returns true.
   void SetPinnedToShelf(bool value);
   static bool CanSetPinnedToShelf(Profile* profile,
                                   const extensions::Extension* app);
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // Uninstall the app. Must only be called if CanUninstallApp() returns true.
   void UninstallApp();
@@ -71,10 +72,10 @@
 
   // UI elements on the dialog. Elements are null if they are not displayed.
   views::View* create_shortcuts_button_ = nullptr;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   views::View* pin_to_shelf_button_ = nullptr;
   views::View* unpin_from_shelf_button_ = nullptr;
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   views::View* remove_button_ = nullptr;
 
   std::unique_ptr<extensions::ExtensionUninstallDialog>
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
index 41fcd29..2cd0147 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views.cc
@@ -11,6 +11,7 @@
 #include "base/no_destructor.h"
 #include "base/stl_util.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/extensions/chrome_app_icon.h"
@@ -147,7 +148,7 @@
       widget()->SetBounds(window_bounds);
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (create_params.is_ime_window)
     return;
 #endif
diff --git a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
index 20e5897f..de3e83c 100644
--- a/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
+++ b/chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.cc
@@ -9,6 +9,7 @@
 #include "apps/ui/views/app_window_frame_view.h"
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/views/apps/app_window_easy_resize_window_targeter.h"
 #include "chrome/browser/ui/views/apps/shaped_app_window_targeter.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
@@ -19,7 +20,9 @@
 #include "ui/gfx/image/image_skia.h"
 #include "ui/views/widget/widget.h"
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 #include "chrome/browser/shell_integration_linux.h"
 #endif
 
@@ -56,7 +59,9 @@
     const AppWindow::CreateParams& create_params,
     views::Widget::InitParams* init_params,
     views::Widget* widget) {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   std::string app_name =
       web_app::GenerateApplicationNameFromAppId(app_window()->extension_id());
   // Set up a custom WM_CLASS for app windows. This allows task switchers in
@@ -66,7 +71,7 @@
   init_params->wm_class_class = shell_integration_linux::GetProgramClassClass();
   const char kX11WindowRoleApp[] = "app";
   init_params->wm_role_name = std::string(kX11WindowRoleApp);
-#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#endif  // defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 
   ChromeNativeAppWindowViews::OnBeforeWidgetInit(create_params, init_params,
                                                  widget);
diff --git a/chrome/browser/ui/views/apps/shaped_app_window_targeter_unittest.cc b/chrome/browser/ui/views/apps/shaped_app_window_targeter_unittest.cc
index c3e73c3..66f1f965 100644
--- a/chrome/browser/ui/views/apps/shaped_app_window_targeter_unittest.cc
+++ b/chrome/browser/ui/views/apps/shaped_app_window_targeter_unittest.cc
@@ -10,6 +10,7 @@
 #include "apps/ui/views/app_window_frame_view.h"
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/views/apps/chrome_native_app_window_views_aura.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
@@ -239,7 +240,7 @@
     EXPECT_EQ(window, move.target());
   }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   // The non standard app frame has a easy resize targetter installed.
   std::unique_ptr<views::NonClientFrameView> frame(
       app_window_views()->CreateNonStandardAppFrame());
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc
index 4f14252..83fbe812 100644
--- a/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_browsertest.cc
@@ -16,6 +16,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/autofill/autofill_uitest_util.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
@@ -173,7 +174,7 @@
             fake_server::CreateFakeServerHttpPostProviderFactory(
                 GetFakeServer()->AsWeakPtr()));
     std::string username;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     // In ChromeOS browser tests, the profile may already by authenticated with
     // stub account |user_manager::kStubUserEmail|.
     CoreAccountInfo info =
@@ -997,7 +998,7 @@
 
 // TODO(crbug.com/932818): Remove the condition once the experiment is enabled
 // on ChromeOS.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 // Ensures that the credit card icon will show in status chip.
 IN_PROC_BROWSER_TEST_F(LocalCardMigrationBrowserTestForStatusChip,
                        CreditCardIconShownInStatusChip) {
@@ -1150,7 +1151,7 @@
                    ->IsAnimating());
 }
 
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 class LocalCardMigrationBrowserTestForFixedLogging
     : public LocalCardMigrationBrowserTest {
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
index e6ad00b1..55e0eea 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_card_bubble_views_browsertest.cc
@@ -13,6 +13,7 @@
 #include "base/test/metrics/user_action_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/autofill/autofill_uitest_util.h"
 #include "chrome/browser/autofill/personal_data_manager_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
@@ -90,7 +91,7 @@
 #include "chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
@@ -179,7 +180,7 @@
                 GetFakeServer()->AsWeakPtr()));
 
     std::string username;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     // In ChromeOS browser tests, the profile may already by authenticated with
     // stub account |user_manager::kStubUserEmail|.
     CoreAccountInfo info =
@@ -733,7 +734,7 @@
     SubmitFormAndWaitForCardLocalSaveBubble();
     ReduceAnimationTime();
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
 #endif
 
@@ -741,7 +742,7 @@
     // animation -- followed by the sign-in promo (if not on Chrome OS).
     ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON);
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     // Wait for and then close the promo.
     WaitForObservedEvent();
     ClickOnCloseButton();
@@ -862,7 +863,7 @@
 
 // Tests the sign in promo bubble. Ensures that clicking the [Save] button
 // on the local save bubble successfully causes the sign in promo to show.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
                        Local_ClickingSaveShowsSigninPromo) {
   FillForm();
@@ -934,7 +935,7 @@
 
 // Tests the sign in promo bubble. Ensures that signin impression is recorded
 // when promo is shown.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTest,
                        Local_Metrics_SigninImpressionSigninPromo) {
   FillForm();
@@ -1019,7 +1020,7 @@
     : public SaveCardBubbleViewsFullFormBrowserTest {
  public:
   SaveCardBubbleViewsFullFormBrowserTestSettings() {
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     feature_list_.InitWithFeatures(
         /*enabled_features=*/{},
         /*disabled_features=*/{features::kAutofillCreditCardUploadFeedback,
@@ -1102,7 +1103,7 @@
 
 // On Chrome OS, the test profile starts with a primary account already set, so
 // sync-the-transport tests don't apply.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Sets up Chrome with Sync-the-transport mode enabled, with the Wallet datatype
 // as enabled type.
@@ -2198,7 +2199,7 @@
 
 // TODO(crbug.com/932818): Remove the condition once the experiment is enabled
 // on ChromeOS.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 // Ensures that the credit card icon will show in status chip.
 IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTestForStatusChip,
                        CreditCardIconShownInStatusChip) {
@@ -2447,7 +2448,7 @@
   EXPECT_FALSE(GetSaveCardIconView()->GetVisible());
   EXPECT_FALSE(GetSaveCardBubbleViews());
 }
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 // TODO(crbug.com/932818): Remove this once the experiment is fully launched.
 class SaveCardBubbleViewsFullFormBrowserTestForManageCard
@@ -2494,7 +2495,7 @@
 
 // Tests the manage cards bubble. Ensures that sign-in impression is recorded
 // correctly.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 IN_PROC_BROWSER_TEST_F(SaveCardBubbleViewsFullFormBrowserTestForManageCard,
                        Local_Metrics_SigninImpressionManageCards) {
   FillForm();
@@ -2530,7 +2531,7 @@
   SubmitFormAndWaitForCardLocalSaveBubble();
   ReduceAnimationTime();
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
 #endif
 
@@ -2538,7 +2539,7 @@
   // animation -- followed by the sign-in promo (if not on Chrome OS).
   ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON);
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   // Wait for and then close the promo.
   WaitForObservedEvent();
   ClickOnCloseButton();
@@ -2565,7 +2566,7 @@
   SubmitFormAndWaitForCardLocalSaveBubble();
   ReduceAnimationTime();
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   ResetEventWaiterForSequence({DialogEvent::BUBBLE_SHOWN});
 #endif
 
@@ -2573,7 +2574,7 @@
   // animation -- followed by the sign-in promo (if not on Chrome OS).
   ClickOnDialogViewWithIdAndWait(DialogViewId::OK_BUTTON);
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   // Wait for and then close the promo.
   WaitForObservedEvent();
   ClickOnCloseButton();
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_manage_cards_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/save_card_manage_cards_bubble_views.cc
index 2a2876bb..4ed5424 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_manage_cards_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_card_manage_cards_bubble_views.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/views/autofill/payments/dialog_view_ids.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
@@ -17,7 +18,7 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/layout/box_layout.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h"
 #endif
 
@@ -51,7 +52,7 @@
 
 std::unique_ptr<views::View>
 SaveCardManageCardsBubbleViews::CreateSigninPromoView() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // ChromeOS does not show the signin promo.
   return nullptr;
 #else
diff --git a/chrome/browser/ui/views/autofill/payments/save_card_sign_in_promo_bubble_views.cc b/chrome/browser/ui/views/autofill/payments/save_card_sign_in_promo_bubble_views.cc
index b226a67..4882885 100644
--- a/chrome/browser/ui/views/autofill/payments/save_card_sign_in_promo_bubble_views.cc
+++ b/chrome/browser/ui/views/autofill/payments/save_card_sign_in_promo_bubble_views.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/views/autofill/payments/dialog_view_ids.h"
@@ -17,7 +18,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/layout/box_layout.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h"
 #endif
 
@@ -44,7 +45,7 @@
       provider->GetDistanceMetric(views::DISTANCE_UNRELATED_CONTROL_VERTICAL)));
   view->SetID(DialogViewId::SIGN_IN_PROMO_VIEW);
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   sync_promo_delegate_ =
       std::make_unique<SaveCardSignInPromoBubbleViews::SyncPromoDelegate>(
           controller(),
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
index 5c81512d..52637f6b 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -22,6 +22,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/managed_bookmark_service_factory.h"
@@ -1948,7 +1949,7 @@
 }
 
 void BookmarkBarView::UpdateBookmarksSeparatorVisibility() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Ash does not paint the bookmarks separator line because it looks odd on
   // the flat background.  We keep it present for layout, but don't draw it.
   bookmarks_separator_view_->SetVisible(false);
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc
index 7ebf5fc4..6642d5f 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/bookmarks/managed_bookmark_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
@@ -404,7 +405,7 @@
   EXPECT_EQ("a1 b1 c d1 e f1", GetStringForVisibleButtons());
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 // Verifies that the apps shortcut is shown or hidden following the policy
 // value. This policy (and the apps shortcut) isn't present on ChromeOS.
 TEST_F(BookmarkBarViewTest, ManagedShowAppsShortcutInBookmarksBar) {
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc
index d1e6a1ac..5a0a361 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_sign_in_delegate_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/test_extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
@@ -31,7 +32,7 @@
 #include "ui/events/event_constants.h"
 #include "ui/gfx/range/range.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/profiles/profile_menu_view.h"
 #endif
 
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
index 543b951..374484e 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view.cc
@@ -6,6 +6,7 @@
 
 #include "base/metrics/user_metrics.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/profiles/profile.h"
@@ -24,7 +25,7 @@
 #include "ui/base/models/dialog_model.h"
 #include "ui/views/bubble/bubble_dialog_model_host.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h"
 #endif
 
@@ -165,9 +166,9 @@
     bool already_bookmarked) {
   if (bookmark_bubble_)
     return;
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   BubbleSyncPromoDelegate* const delegate_ptr = delegate.get();
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
   bookmarks::BookmarkModel* bookmark_model =
       BookmarkModelFactory::GetForBrowserContext(profile);
   const bookmarks::BookmarkNode* bookmark_node =
@@ -224,12 +225,11 @@
   // bubbles.
   auto bubble = std::make_unique<views::BubbleDialogModelHost>(
       std::move(dialog_model), anchor_view, views::BubbleBorder::TOP_RIGHT);
-  bubble->SelectAllText(kBookmarkName);
   bookmark_bubble_ = bubble.get();
   if (highlighted_button)
     bubble->SetHighlightedButton(highlighted_button);
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   if (SyncPromoUI::ShouldShowSyncPromo(profile)) {
     // TODO(pbos): Consider adding model support for footnotes so that this does
     // not need to be tied to views.
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
index cd4db2b7..0f44d39 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
@@ -26,7 +27,7 @@
 
   // DialogBrowserTest:
   void ShowUi(const std::string& name) override {
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     signin::IdentityManager* identity_manager =
         IdentityManagerFactory::GetForProfile(browser()->profile());
     if (name == "bookmark_details") {
@@ -55,7 +56,7 @@
 };
 
 // ChromeOS is always signed in.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 IN_PROC_BROWSER_TEST_F(BookmarkBubbleViewBrowserTest,
                        InvokeUi_bookmark_details) {
   ShowAndVerifyUi();
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
index 6a6397c..499d6ce 100644
--- a/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/bookmarks/bookmark_bubble_view_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/bind.h"
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/sync/bubble_sync_promo_delegate.h"
@@ -104,9 +105,9 @@
   CreateBubbleView();
   views::View* footnote =
       BookmarkBubbleView::bookmark_bubble()->GetFootnoteViewForTesting();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   EXPECT_FALSE(footnote);
-#else  // !defined(OS_CHROMEOS)
+#else  // !BUILDFLAG(IS_CHROMEOS_ASH)
   EXPECT_TRUE(footnote);
 #endif
 }
diff --git a/chrome/browser/ui/views/certificate_selector.cc b/chrome/browser/ui/views/certificate_selector.cc
index 7c18f94..94f8b58 100644
--- a/chrome/browser/ui/views/certificate_selector.cc
+++ b/chrome/browser/ui/views/certificate_selector.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/certificate_viewer.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/grit/generated_resources.h"
@@ -31,7 +32,7 @@
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/widget/widget.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
 #include "extensions/browser/extension_registry.h"
@@ -130,7 +131,7 @@
   // |provider_names| and |identities_| are parallel arrays.
   // The entry at index |i| is the provider name for |identities_[i]|.
   std::vector<std::string> provider_names;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   chromeos::CertificateProviderService* service =
       chromeos::CertificateProviderServiceFactory::GetForBrowserContext(
           web_contents->GetBrowserContext());
diff --git a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
index f249000d..e9dedfa 100644
--- a/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
+++ b/chrome/browser/ui/views/chrome_browser_main_extra_parts_views.cc
@@ -8,6 +8,7 @@
 
 #include "base/command_line.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/net/system_network_context_manager.h"
 #include "chrome/browser/ui/commander/commander.h"
@@ -35,7 +36,9 @@
 #include "ui/wm/core/wm_state.h"
 #endif  // defined(USE_AURA)
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -45,7 +48,7 @@
 #include "chrome/grit/generated_resources.h"
 #include "content/public/common/content_switches.h"
 #include "ui/base/l10n/l10n_util.h"
-#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#endif  // defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 
 // This connector is used in ui_devtools's TracingAgent to hook up with the
 // tracing service.
@@ -85,7 +88,7 @@
 }
 
 void ChromeBrowserMainExtraPartsViews::PreCreateThreads() {
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
   views::InstallDesktopScreenIfNecessary();
 #endif
 }
@@ -115,7 +118,9 @@
         return controller;
       }));
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   // On the Linux desktop, we want to prevent the user from logging in as root,
   // so that we don't destroy the profile. Now that we have some minimal ui
   // initialized, check to see if we're running as root and bail if we are.
@@ -146,7 +151,7 @@
   base::RunLoop().RunUntilIdle();
 
   exit(EXIT_FAILURE);
-#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#endif  // defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 }
 
 void ChromeBrowserMainExtraPartsViews::PostBrowserStart() {
diff --git a/chrome/browser/ui/views/chrome_typography.h b/chrome/browser/ui/views/chrome_typography.h
index cfe3b72..518a4db 100644
--- a/chrome/browser/ui/views/chrome_typography.h
+++ b/chrome/browser/ui/views/chrome_typography.h
@@ -6,17 +6,18 @@
 #define CHROME_BROWSER_UI_VIEWS_CHROME_TYPOGRAPHY_H_
 
 #include "base/macros.h"
+#include "build/chromeos_buildflags.h"
 #include "ui/gfx/font.h"
 #include "ui/views/style/typography.h"
 #include "ui/views/style/typography_provider.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // gn check complains on Linux Ozone.
 #include "ash/public/cpp/ash_typography.h"  // nogncheck
 #endif
 
 enum ChromeTextContext {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   CHROME_TEXT_CONTEXT_START = ash::ASH_TEXT_CONTEXT_END,
 #else
   CHROME_TEXT_CONTEXT_START = views::style::VIEWS_TEXT_CONTEXT_END,
@@ -70,7 +71,7 @@
 };
 
 enum ChromeTextStyle {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   CHROME_TEXT_STYLE_START = ash::ASH_TEXT_STYLE_END,
 #else
   CHROME_TEXT_STYLE_START = views::style::VIEWS_TEXT_STYLE_END,
diff --git a/chrome/browser/ui/views/chrome_typography_provider.cc b/chrome/browser/ui/views/chrome_typography_provider.cc
index 0b2628e..0e11d53 100644
--- a/chrome/browser/ui/views/chrome_typography_provider.cc
+++ b/chrome/browser/ui/views/chrome_typography_provider.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/chrome_typography_provider.h"
 
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "ui/base/resource/resource_bundle.h"
@@ -20,7 +21,7 @@
 #include "ui/native_theme/native_theme_win.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // gn check complains on Linux Ozone.
 #include "ash/public/cpp/ash_typography.h"  // nogncheck
 #endif
@@ -39,7 +40,7 @@
   int size_delta = kDefaultSize - gfx::PlatformFont::kDefaultBaseFontSize;
   gfx::Font::Weight font_weight = gfx::Font::Weight::NORMAL;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   ash::ApplyAshFontStyles(context, style, &size_delta, &font_weight);
 #endif
 
@@ -81,7 +82,7 @@
     // Secondary font is for double-digit counts. Because we have control over
     // system fonts on ChromeOS, we can just choose a condensed font. For other
     // platforms we adjust size.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     typeface = "Roboto Condensed";
 #else
     size_delta -= 2;
diff --git a/chrome/browser/ui/views/chrome_views_delegate.cc b/chrome/browser/ui/views/chrome_views_delegate.cc
index be87920..55b75ba5 100644
--- a/chrome/browser/ui/views/chrome_views_delegate.cc
+++ b/chrome/browser/ui/views/chrome_views_delegate.cc
@@ -6,6 +6,7 @@
 
 #include "base/check_op.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_window_state.h"
@@ -20,7 +21,7 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/views/widget/widget.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/app_types.h"
 #include "chrome/browser/ui/views/touch_selection_menu_runner_chromeos.h"
 #include "chromeos/ui/frame/frame_utils.h"
@@ -59,7 +60,7 @@
 // ChromeViewsDelegate --------------------------------------------------------
 
 ChromeViewsDelegate::ChromeViewsDelegate() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // ViewsDelegate's constructor may have created a menu runner already, and
   // since TouchSelectionMenuRunner is a singleton with checks to not
   // initialize it if there is already an existing runner we need to first
@@ -129,7 +130,7 @@
     dictionary->GetBoolean("maximized", &maximized);
   *show_state = maximized ? ui::SHOW_STATE_MAXIMIZED : ui::SHOW_STATE_NORMAL;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   AdjustSavedWindowPlacementChromeOS(widget, bounds);
 #endif
   return true;
@@ -159,7 +160,7 @@
 void ChromeViewsDelegate::OnBeforeWidgetInit(
     views::Widget::InitParams* params,
     views::internal::NativeWidgetDelegate* delegate) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Only for dialog widgets, if this is not going to be a transient child,
   // then we mark it as an OS system app, otherwise its transient root's app
   // type should be used.
@@ -167,11 +168,11 @@
     params->init_properties_container.SetProperty(
         aura::client::kAppType, static_cast<int>(ash::AppType::SYSTEM_APP));
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // We need to determine opacity if it's not already specified.
   if (params->opacity == views::Widget::InitParams::WindowOpacity::kInferred) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     chromeos::ResolveInferredOpacity(params);
 #else
     params->opacity = views::Widget::InitParams::WindowOpacity::kOpaque;
diff --git a/chrome/browser/ui/views/chrome_views_delegate.h b/chrome/browser/ui/views/chrome_views_delegate.h
index 98de769..7ea8195 100644
--- a/chrome/browser/ui/views/chrome_views_delegate.h
+++ b/chrome/browser/ui/views/chrome_views_delegate.h
@@ -14,6 +14,7 @@
 #include "base/location.h"
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "ui/views/views_delegate.h"
 
 class ScopedKeepAlive;
@@ -32,7 +33,7 @@
                                const std::string& window_name,
                                gfx::Rect* bounds,
                                ui::WindowShowState* show_state) const override;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   ProcessMenuAcceleratorResult ProcessAcceleratorWhileMenuShowing(
       const ui::Accelerator& accelerator) override;
   std::unique_ptr<views::NonClientFrameView> CreateDefaultNonClientFrameView(
@@ -44,7 +45,9 @@
   HICON GetSmallWindowIcon() const override;
   int GetAppbarAutohideEdges(HMONITOR monitor,
                              base::OnceClosure callback) override;
-#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   gfx::ImageSkia* GetDefaultWindowIcon() const override;
   bool WindowManagerProvidesTitleBar(bool maximized) override;
 #endif
@@ -72,7 +75,7 @@
                                 int edges);
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Called from GetSavedWindowPlacement() on ChromeOS to adjust the bounds.
   void AdjustSavedWindowPlacementChromeOS(const views::Widget* widget,
                                           gfx::Rect* bounds) const;
diff --git a/chrome/browser/ui/views/chrome_web_dialog_view.cc b/chrome/browser/ui/views/chrome_web_dialog_view.cc
index c21561b..8852378 100644
--- a/chrome/browser/ui/views/chrome_web_dialog_view.cc
+++ b/chrome/browser/ui/views/chrome_web_dialog_view.cc
@@ -7,13 +7,14 @@
 #include <memory>
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
 #include "ui/views/controls/webview/web_dialog_view.h"
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/multi_user_window_manager.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -22,7 +23,7 @@
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_helper.h"
 #include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace chrome {
 namespace {
@@ -64,14 +65,14 @@
     params = std::move(*extra_params);
   params.delegate = view;
   params.parent = parent;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (!parent && delegate->GetDialogModalType() == ui::MODAL_TYPE_SYSTEM) {
     int container_id = ash_util::GetSystemModalDialogContainerId();
     ash_util::SetupWidgetInitParamsForContainer(&params, container_id);
   }
 #endif
   gfx::NativeWindow window = CreateWebDialogWidget(std::move(params), view);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   const user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(
           Profile::FromBrowserContext(context));
diff --git a/chrome/browser/ui/views/commander_frontend_views.cc b/chrome/browser/ui/views/commander_frontend_views.cc
index c7123f7..8068b50 100644
--- a/chrome/browser/ui/views/commander_frontend_views.cc
+++ b/chrome/browser/ui/views/commander_frontend_views.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/task_manager/web_contents_tags.h"
@@ -73,7 +74,7 @@
       base::BindRepeating(&CommanderFrontendViews::OnViewModelUpdated,
                           weak_ptr_factory_.GetWeakPtr()));
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   ProfileManager* profile_manager = g_browser_process->profile_manager();
   profile_manager->CreateProfileAsync(
       ProfileManager::GetSystemProfilePath(),
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc
index c6dbf3d..0e8d6e2 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_list_view.cc
@@ -9,6 +9,7 @@
 #include <utility>
 
 #include "base/numerics/ranges.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/media/webrtc/desktop_media_list.h"
 #include "chrome/browser/media/webrtc/window_icon_util.h"
 #include "chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.h"
@@ -21,7 +22,7 @@
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/base/resource/resource_bundle.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ui/aura/window.h"
 #endif
 
@@ -31,7 +32,7 @@
 
 const int kDesktopMediaSourceViewGroupId = 1;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Here we are going to display default app icon for app windows without an
 // icon, and display product logo for chrome browser windows.
 gfx::ImageSkia LoadDefaultIcon(aura::Window* window) {
@@ -168,7 +169,7 @@
   source_view->SetGroup(kDesktopMediaSourceViewGroupId);
   if (source.id.type == DesktopMediaID::TYPE_WINDOW) {
     gfx::ImageSkia icon_image = GetWindowIcon(source.id);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     // Empty icons are used to represent default icon for aura windows. By
     // detecting this, we load the default icon from resource.
     if (icon_image.isNull()) {
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
index 33361e37..d0676ecc 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -10,6 +10,7 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/media/webrtc/desktop_media_list.h"
 #include "chrome/browser/media/webrtc/desktop_media_picker_manager.h"
 #include "chrome/browser/ui/browser_dialogs.h"
@@ -44,7 +45,7 @@
 
 namespace {
 
-#if !defined(OS_CHROMEOS) && defined(USE_AURA)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && defined(USE_AURA)
 DesktopMediaID::Id AcceleratedWidgetToDesktopMediaId(
     gfx::AcceleratedWidget accelerated_widget) {
 #if defined(OS_WIN)
@@ -240,7 +241,7 @@
     dialog_window_id = DesktopMediaID::RegisterNativeWindow(
         DesktopMediaID::TYPE_WINDOW, widget->GetNativeWindow());
 
-#if !defined(OS_CHROMEOS) && defined(USE_AURA)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && defined(USE_AURA)
     // Set native window ID if the windows is outside Ash.
     dialog_window_id.id = AcceleratedWidgetToDesktopMediaId(
         widget->GetNativeWindow()->GetHost()->GetAcceleratedWidget());
diff --git a/chrome/browser/ui/views/exclusive_access_bubble_views.cc b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
index 282a0433..1555846 100644
--- a/chrome/browser/ui/views/exclusive_access_bubble_views.cc
+++ b/chrome/browser/ui/views/exclusive_access_bubble_views.cc
@@ -13,6 +13,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
 #include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
@@ -54,7 +55,7 @@
   auto content_view = std::make_unique<SubtleNotificationView>();
   view_ = content_view.get();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Technically the exit fullscreen key on ChromeOS is F11 and the
   // "Fullscreen" key on the keyboard is just translated to F11 or F4 (which
   // is also a toggle-fullscreen command on ChromeOS). However most Chromebooks
diff --git a/chrome/browser/ui/views/extensions/extension_dialog.cc b/chrome/browser/ui/views/extensions/extension_dialog.cc
index b19fad12..e2443ff 100644
--- a/chrome/browser/ui/views/extensions/extension_dialog.cc
+++ b/chrome/browser/ui/views/extensions/extension_dialog.cc
@@ -7,6 +7,7 @@
 #include <memory>
 #include <utility>
 
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_view_host.h"
 #include "chrome/browser/extensions/extension_view_host_factory.h"
@@ -28,7 +29,7 @@
 #include "ui/views/widget/widget.h"
 #include "url/gurl.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/tablet_mode.h"
 #include "chromeos/ui/base/window_properties.h"
 #include "ui/aura/window.h"
@@ -180,7 +181,7 @@
   SetTitle(init_params.title);
 
   bool can_resize = true;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Prevent dialog resize mouse cursor in tablet mode, crbug.com/453634.
   if (ash::TabletMode::Get() && ash::TabletMode::Get()->InTabletMode())
     can_resize = false;
@@ -222,7 +223,7 @@
   bounds.AdjustToFit(screen_rect);
   window->SetBounds(bounds);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   aura::Window* native_view = window->GetNativeWindow();
   if (init_params.title_color) {
     // Frame active color changes the title color when dialog is active.
diff --git a/chrome/browser/ui/views/extensions/extension_dialog.h b/chrome/browser/ui/views/extensions/extension_dialog.h
index e783397..f61c4cea 100644
--- a/chrome/browser/ui/views/extensions/extension_dialog.h
+++ b/chrome/browser/ui/views/extensions/extension_dialog.h
@@ -12,6 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/optional.h"
 #include "base/strings/string16.h"
+#include "build/chromeos_buildflags.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 #include "third_party/skia/include/core/SkColor.h"
@@ -56,7 +57,7 @@
     // Text for the dialog title, it should be already localized.
     base::string16 title;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     // |title_color| customizes the color of the window title.
     base::Optional<SkColor> title_color;
     // |title_inactive_color| customizes the color of the window title when
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
index 191c0ab..70cc552 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view.cc
@@ -8,6 +8,7 @@
 #include "base/strings/strcat.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/signin/signin_ui_util.h"
 #include "chrome/browser/ui/browser.h"
@@ -38,7 +39,7 @@
 #include "ui/views/controls/link.h"
 #include "ui/views/layout/box_layout.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/sync/dice_bubble_sync_promo_view.h"
 #endif
 
@@ -91,7 +92,7 @@
 std::unique_ptr<views::View> CreateSigninPromoView(
     Profile* profile,
     BubbleSyncPromoDelegate* delegate) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // ChromeOS does not show the signin promo.
   return nullptr;
 #else
diff --git a/chrome/browser/ui/views/extensions/extension_installed_bubble_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_installed_bubble_view_browsertest.cc
index 0fb6c90b..cef203a 100644
--- a/chrome/browser/ui/views/extensions/extension_installed_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extension_installed_bubble_view_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include <algorithm>
 
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/ui/extensions/extension_install_ui_default.h"
@@ -87,7 +88,7 @@
   observer.Wait();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // None of these tests work when run under Ash, because they need an
 // AuraTestHelper constructed at an inconvenient time in test setup, which
 // InProcessBrowserTest is not equipped to handle.
diff --git a/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc b/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc
index 7063146..8b4e5f218 100644
--- a/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extension_message_bubble_view_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/extensions/extension_message_bubble_browsertest.h"
 #include "chrome/browser/ui/extensions/settings_api_bubble_helpers.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
@@ -363,13 +364,13 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     LegacyExtensionMessageBubbleViewBrowserTest::SetUpCommandLine(command_line);
 // The NTP bubble is only enabled by default on Mac, Windows, and CrOS.
-#if !defined(OS_WIN) && !defined(OS_MAC) && !defined(OS_CHROMEOS)
+#if !defined(OS_WIN) && !defined(OS_MAC) && !BUILDFLAG(IS_CHROMEOS_ASH)
     extensions::SetNtpPostInstallUiEnabledForTesting(true);
 #endif
   }
 
   void TearDownOnMainThread() override {
-#if !defined(OS_WIN) && !defined(OS_MAC) && !defined(OS_CHROMEOS)
+#if !defined(OS_WIN) && !defined(OS_MAC) && !BUILDFLAG(IS_CHROMEOS_ASH)
     extensions::SetNtpPostInstallUiEnabledForTesting(false);
 #endif
     LegacyExtensionMessageBubbleViewBrowserTest::TearDownOnMainThread();
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_item_unittest.cc b/chrome/browser/ui/views/extensions/extensions_menu_item_unittest.cc
index 272280a..f4bb0f7 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_item_unittest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_item_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/user_action_tester.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/toolbar/test_toolbar_action_view_controller.h"
 #include "chrome/browser/ui/views/extensions/extensions_menu_button.h"
 #include "chrome/browser/ui/views/hover_button_controller.h"
@@ -28,7 +29,7 @@
         views::Widget::InitParams::TYPE_POPUP);
     init_params.ownership =
         views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-#if !defined(OS_CHROMEOS) && !defined(OS_MAC)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_MAC)
     // This was copied from BookmarkBarViewTest:
     // On Chrome OS, this always creates a NativeWidgetAura, but it should
     // create a DesktopNativeWidgetAura for Mash. We can get by without manually
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
index 19d794c..bd3edb5 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view_browsertest.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/chrome_test_extension_loader.h"
 #include "chrome/browser/extensions/extension_action_runner.h"
 #include "chrome/browser/extensions/extension_context_menu_model.h"
@@ -62,7 +63,9 @@
   }
 
   void ShowUi(const std::string& name) override {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
     // The extensions menu can appear offscreen on Linux, so verifying bounds
     // makes the tests flaky.
     set_should_verify_dialog_bounds(false);
diff --git a/chrome/browser/ui/views/external_protocol_dialog.cc b/chrome/browser/ui/views/external_protocol_dialog.cc
index be89aa5da..f74b178 100644
--- a/chrome/browser/ui/views/external_protocol_dialog.cc
+++ b/chrome/browser/ui/views/external_protocol_dialog.cc
@@ -8,6 +8,7 @@
 
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/external_protocol/external_protocol_handler.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/shell_integration.h"
@@ -44,7 +45,7 @@
 
 }  // namespace
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 // static
 void ExternalProtocolHandler::RunExternalProtocolDialog(
     const GURL& url,
@@ -65,7 +66,7 @@
   new ExternalProtocolDialog(web_contents, url, program_name,
                              initiating_origin);
 }
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 ExternalProtocolDialog::ExternalProtocolDialog(
     WebContents* web_contents,
diff --git a/chrome/browser/ui/views/frame/browser_frame.cc b/chrome/browser/ui/views/frame/browser_frame.cc
index 63e32cc..fb4c9b3 100644
--- a/chrome/browser/ui/views/frame/browser_frame.cc
+++ b/chrome/browser/ui/views/frame/browser_frame.cc
@@ -11,6 +11,7 @@
 #include "base/debug/leak_annotations.h"
 #include "base/i18n/rtl.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
@@ -34,18 +35,22 @@
 #include "ui/views/controls/menu/menu_runner.h"
 #include "ui/views/widget/native_widget.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "components/user_manager/user_manager.h"
 #endif
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 #include "ui/display/screen.h"
 #endif
 
 namespace {
 
 bool IsUsingGtkTheme(Profile* profile) {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   return ThemeServiceFactory::GetForProfile(profile)->UsingSystemTheme();
 #else
   return false;
@@ -204,7 +209,9 @@
 
 void BrowserFrame::OnNativeWidgetWorkspaceChanged() {
   chrome::SaveWindowWorkspace(browser_view_->browser(), GetWorkspace());
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   // If the window was sent to a different workspace, prioritize it if
   // it was sent to the current workspace and deprioritize it
   // otherwise.  This is done by MoveBrowsersInWorkspaceToFront()
@@ -250,7 +257,7 @@
 }
 
 ui::MenuModel* BrowserFrame::GetSystemMenuModel() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (user_manager::UserManager::IsInitialized() &&
       user_manager::UserManager::Get()->GetLoggedInUsers().size() > 1) {
     // In Multi user mode, the number of users as well as the order of users
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index 91c9912..fb94fb3 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
 
 #include "base/metrics/histogram_macros.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/avatar_menu.h"
@@ -301,13 +302,13 @@
   }
 
   bool should_leave_to_top_container = false;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // In immersive mode, the caption buttons container is reparented to the
   // TopContainerView and hence |rect| should not be claimed here.  See
   // BrowserNonClientFrameViewAsh::OnImmersiveRevealStarted().
   should_leave_to_top_container =
       browser_view_->immersive_mode_controller()->IsRevealed();
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   if (!browser_view_->IsTabStripVisible()) {
     // Claim |rect| if it is above the top of the topmost client area view.
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc
index 4bad8a14..71632fb 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
@@ -155,7 +156,9 @@
   ASSERT_TRUE(theme_service->UsingSystemTheme());
 
   InstallAndLaunchBookmarkApp();
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   // On Linux, the system theme is the GTK theme and should change the frame
   // color to the system color (not the app theme color); otherwise the title
   // and border would clash horribly with the GTK title bar.
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
index 9c75ba8..4f375120 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos.cc
@@ -68,6 +68,10 @@
 #include "chrome/browser/ui/ash/session_util.h"
 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chromeos/ui/frame/interior_resize_handler_targeter.h"
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
+
 namespace {
 
 // Color for the window title text.
@@ -95,11 +99,14 @@
     BrowserView* browser_view)
     : BrowserNonClientFrameView(frame, browser_view) {
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-  // TODO(https://crbug.com/1067535): Check whether Ash/Chrome and Lacros
-  // will share the same ResizeHandler class.
   ash::window_util::InstallResizeHandleWindowTargeterForWindow(
       frame->GetNativeWindow());
 #endif
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+  frame->GetNativeWindow()->SetEventTargeter(
+      std::make_unique<chromeos::InteriorResizeHandleTargeter>());
+#endif
 }
 
 BrowserNonClientFrameViewChromeOS::~BrowserNonClientFrameViewChromeOS() {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc
index e19d778e..6e614c4e 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_chromeos_browsertest.cc
@@ -16,6 +16,7 @@
 #include "base/scoped_observation.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/command_updater.h"
@@ -1112,7 +1113,7 @@
 }
 
 // TODO(): Flaky crash on Chrome OS debug.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_BrowserCommandFocusToolbarGeolocation \
   DISABLED_BrowserCommandFocusToolbarGeolocation
 #else
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
index 07b2d66..49fcdc5 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_factory_views.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -13,7 +14,9 @@
 #include "chrome/browser/ui/views/frame/glass_browser_frame_view.h"
 #endif
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 #include "chrome/browser/ui/views/frame/desktop_linux_browser_frame_view.h"
 #include "chrome/browser/ui/views/frame/desktop_linux_browser_frame_view_layout.h"
 #include "ui/views/linux_ui/linux_ui.h"
@@ -27,7 +30,9 @@
 std::unique_ptr<OpaqueBrowserFrameView> CreateOpaqueBrowserFrameView(
     BrowserFrame* frame,
     BrowserView* browser_view) {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   auto* linux_ui = views::LinuxUI::instance();
   auto* profile = browser_view->browser()->profile();
   auto* theme_service_factory = ThemeServiceFactory::GetForProfile(profile);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_unittest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_unittest.cc
index 4957827..58cb717 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_unittest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/command_line.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
@@ -76,7 +77,9 @@
 };
 
 // TODO(crbug.com/1011339): Flaky on Linux TSAN.
-#if (defined(OS_LINUX) || defined(OS_CHROMEOS)) && defined(THREAD_SANITIZER)
+#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH) || \
+     BUILDFLAG(IS_CHROMEOS_LACROS)) &&                  \
+    defined(THREAD_SANITIZER)
 #define MAYBE_HitTestTabstrip DISABLED_HitTestTabstrip
 #else
 #define MAYBE_HitTestTabstrip HitTestTabstrip
@@ -112,7 +115,7 @@
 // ChromeOS, so there is no non-client area in the tab strip to test for.
 // TODO (tbergquist): Investigate whether we can key off this condition in an
 // OS-agnostic way.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !BUILDFLAG(IS_CHROMEOS_LACROS)
   // Hits non-client portions of the tab strip (the top left corner of the
   // first tab).
   EXPECT_TRUE(frame_view_->HitTestRect(
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 1b19a87b..28f5c8d 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -206,7 +206,7 @@
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/accelerators.h"
 #include "ash/public/cpp/desks_helper.h"
 #include "ash/public/cpp/metrics_util.h"
@@ -216,7 +216,7 @@
 #include "ui/compositor/throughput_tracker.h"
 #else
 #include "chrome/browser/ui/signin_view_controller.h"
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_MAC)
 #include "chrome/browser/global_keyboard_shortcuts_mac.h"
@@ -265,7 +265,7 @@
 // locate this object using just the handle.
 const char* const kBrowserViewKey = "__BROWSER_VIEW__";
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // UMA histograms that record animation smoothness for tab loading animation.
 constexpr char kTabLoadingSmoothnessHistogramName[] =
     "Chrome.Tabs.AnimationSmoothness.TabLoading";
@@ -413,7 +413,7 @@
 };
 
 bool ShouldShowWindowIcon(const Browser* browser) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // For Chrome OS only, trusted windows (apps and settings) do not show a
   // window icon, crbug.com/119411. Child windows (i.e. popups) do show an icon.
   if (browser->is_trusted_source())
@@ -833,7 +833,7 @@
 // BrowserView, BrowserWindow implementation:
 
 void BrowserView::Show() {
-#if !defined(OS_WIN) && !defined(OS_CHROMEOS)
+#if !defined(OS_WIN) && !BUILDFLAG(IS_CHROMEOS_ASH)
   // The Browser associated with this browser window must become the active
   // browser at the time |Show()| is called. This is the natural behavior under
   // Windows and Chrome OS, but other platforms will not trigger
@@ -869,13 +869,13 @@
     SetFocusToLocationBar(false);
   }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   if (features::IsAccessibilityFocusHighlightEnabled() &&
       !accessibility_focus_highlight_) {
     accessibility_focus_highlight_ =
         std::make_unique<AccessibilityFocusHighlight>(this);
   }
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void BrowserView::ShowInactive() {
@@ -937,7 +937,7 @@
   if (!native_win)
     return true;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   return ash::DesksHelper::Get()->BelongsToActiveDesk(native_win);
 #elif defined(OS_WIN)
   if (base::win::GetVersion() < base::win::Version::WIN10)
@@ -968,7 +968,7 @@
          workspace_guid == GUID_NULL;
 #else
   return true;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void BrowserView::SetTopControlsShownRatio(content::WebContents* web_contents,
@@ -1036,7 +1036,7 @@
 void BrowserView::UpdateLoadingAnimations(bool should_animate) {
   if (should_animate) {
     if (!loading_animation_timer_.IsRunning()) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       loading_animation_tracker_.emplace(
         GetWidget()->GetCompositor()->RequestNewThroughputTracker());
       loading_animation_tracker_->Start(ash::metrics_util::ForSmoothness(
@@ -1051,7 +1051,7 @@
   } else {
     if (loading_animation_timer_.IsRunning()) {
       loading_animation_timer_.Stop();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       loading_animation_tracker_->Stop();
 #endif
       // Loads are now complete, update the state if a task was scheduled.
@@ -1415,7 +1415,7 @@
   // already. On Chrome OS, changing focus makes a view believe it has a focus
   // even if the widget doens't have a focus. Either cases, we need to ignore
   // this when the browser window isn't active.
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
   if (!IsActive())
     return;
 #endif
@@ -1507,7 +1507,9 @@
 void BrowserView::TabDraggingStatusChanged(bool is_dragging) {
   // TODO(crbug.com/1110266): Remove explicit OS_CHROMEOS check once OS_LINUX
   // CrOS cleanup is done.
-#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
   contents_web_view_->SetFastResize(is_dragging);
   if (!is_dragging) {
     // When tab dragging is ended, we need to make sure the web contents get
@@ -1887,7 +1889,9 @@
   const bool should_use_native_frame = frame_->ShouldUseNativeFrame();
 
   bool must_regenerate_frame;
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   // GTK and user theme changes can both change frame buttons, so the frame
   // always needs to be regenerated on Linux.
   must_regenerate_frame = true;
@@ -1968,13 +1972,13 @@
     return content::KeyboardEventProcessingResult::NOT_HANDLED;
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (ash::AcceleratorController::Get()->IsDeprecated(accelerator)) {
     return (event.GetType() == blink::WebInputEvent::Type::kRawKeyDown)
                ? content::KeyboardEventProcessingResult::NOT_HANDLED_IS_SHORTCUT
                : content::KeyboardEventProcessingResult::NOT_HANDLED;
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   content::KeyboardEventProcessingResult result =
       frame_->PreHandleKeyboardEvent(event);
@@ -2163,7 +2167,7 @@
     return true;
   }
 
-#if defined(USE_AURA) && defined(OS_CHROMEOS)
+#if defined(USE_AURA) && BUILDFLAG(IS_CHROMEOS_ASH)
   // On Aura window manager controls all windows so settings focus via PostTask
   // will make only worse because posted task will keep trying to steal focus.
   queue->ActivateModalDialog();
@@ -2391,7 +2395,7 @@
     return false;
   if (browser_->app_controller())
     return true;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // On ChromeOS, the tabbed browser always use a static image for the window
   // icon. See GetWindowIcon().
   if (browser_->is_type_normal())
@@ -2416,7 +2420,7 @@
 #endif
 
 bool BrowserView::ShouldShowWindowTitle() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // For Chrome OS only, trusted windows (apps and settings) do not show a
   // title, crbug.com/119411. Child windows (i.e. popups) do show a title.
   if (browser_->is_trusted_source())
@@ -2445,7 +2449,7 @@
   if (app_controller)
     return app_controller->GetWindowIcon();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
   if (browser_->is_type_normal()) {
     return rb.GetImageNamed(IDR_CHROME_APP_ICON_192).AsImageSkia();
@@ -2864,7 +2868,7 @@
 
   toolbar_->Init();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // TopControlsSlideController must be initialized here in AddedToWidget()
   // rather than Init() as it depends on the browser frame being ready.
   // It also needs to be after the |toolbar_| had been initialized since it uses
@@ -3291,7 +3295,7 @@
 }
 
 bool BrowserView::ShouldUseImmersiveFullscreenForUrl(const GURL& url) const {
-#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
   // Kiosk mode needs the whole screen.
   if (chrome::IsRunningInAppMode())
     return false;
@@ -3377,7 +3381,7 @@
       base::RecordAction(base::UserMetricsAction("Accel_NewTabInGroup"));
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Collect information about the relative popularity of various accelerators
   // on Chrome OS.
   switch (command_id) {
@@ -3434,7 +3438,7 @@
   profiles::BubbleViewMode bubble_view_mode;
   profiles::BubbleViewModeFromAvatarBubbleMode(mode, GetProfile(),
                                                &bubble_view_mode);
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   if (SigninViewController::ShouldShowSigninForMode(bubble_view_mode)) {
     browser_->signin_view_controller()->ShowSignin(bubble_view_mode,
                                                    access_point);
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index a4a3ffc..7782b63 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -19,6 +19,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/banners/app_banner_manager.h"
 #include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/extensions/extension_commands_global_registry.h"
@@ -78,7 +79,7 @@
 class WebContentsCloseHandler;
 class WebUITabStripContainerView;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 namespace ui {
 class ThroughputTracker;
 }
@@ -966,7 +967,7 @@
 
   OnLinkOpeningFromGestureCallbackList link_opened_from_gesture_callbacks_;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // |loading_animation_tracker_| is used to measure animation smoothness for
   // tab loading animation.
   base::Optional<ui::ThroughputTracker> loading_animation_tracker_;
diff --git a/chrome/browser/ui/views/frame/browser_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
index 17e38f7..9ff318c 100644
--- a/chrome/browser/ui/views/frame/browser_view_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_view_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/accessibility/caption_controller.h"
 #include "chrome/browser/accessibility/caption_controller_factory.h"
 #include "chrome/browser/devtools/devtools_window_testing.h"
@@ -413,7 +414,7 @@
         browser_view()->AcceleratorPressed(ui::Accelerator(ui::VKEY_F6, 0)));
   }
 
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
   // Check the native widget has focus.
   aura::client::FocusClient* focus_client =
       aura::client::GetFocusClient(bubble->GetWidget()->GetNativeView());
@@ -429,7 +430,7 @@
   EXPECT_FALSE(bubble->HasFocus());
   EXPECT_FALSE(bubble->GetFocusManager()->GetFocusedView());
   EXPECT_TRUE(browser_view()->GetWidget()->GetFocusManager()->GetFocusedView());
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
   // The bubble's native widget should no longer have focus.
   EXPECT_FALSE(bubble->GetWidget()->GetNativeView() ==
                focus_client->GetFocusedWindow());
diff --git a/chrome/browser/ui/views/frame/browser_window_factory.cc b/chrome/browser/ui/views/frame/browser_window_factory.cc
index a848be4..65d2f1af 100644
--- a/chrome/browser/ui/views/frame/browser_window_factory.cc
+++ b/chrome/browser/ui/views/frame/browser_window_factory.cc
@@ -6,7 +6,7 @@
 
 #include "chrome/browser/ui/views/frame/browser_frame.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/frame/custom_tab_browser_frame.h"
 #endif
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
@@ -16,6 +16,7 @@
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #endif
+#include "build/chromeos_buildflags.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/views/widget/widget.h"
 
@@ -28,7 +29,7 @@
   // so we don't need to do anything with the pointer.
   BrowserView* view = new BrowserView(std::move(browser));
   BrowserFrame* browser_frame = nullptr;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (view->browser()->is_type_custom_tab())
     browser_frame = new CustomTabBrowserFrame(view);
 #endif
diff --git a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_views.cc b/chrome/browser/ui/views/frame/immersive_mode_controller_factory_views.cc
index f61a134..3650cc3d 100644
--- a/chrome/browser/ui/views/frame/immersive_mode_controller_factory_views.cc
+++ b/chrome/browser/ui/views/frame/immersive_mode_controller_factory_views.cc
@@ -7,7 +7,7 @@
 #include "build/build_config.h"
 #include "build/chromeos_buildflags.h"
 
-#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
 #include "chrome/browser/ui/views/frame/immersive_mode_controller_chromeos.h"
 #endif
 
@@ -18,13 +18,13 @@
 namespace chrome {
 
 std::unique_ptr<ImmersiveModeController> CreateImmersiveModeController() {
-#if defined(OS_CHROMEOS) || BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
   return std::make_unique<ImmersiveModeControllerChromeos>();
 #elif defined(OS_MAC)
   return CreateImmersiveModeControllerMac();
 #else
   return std::make_unique<ImmersiveModeControllerStub>();
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index a3e770fc..922d8b0 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -9,6 +9,7 @@
 
 #include "build/build_config.h"
 #include "build/buildflag.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/frame/browser_frame.h"
@@ -464,7 +465,9 @@
 
 OpaqueBrowserFrameView::FrameButtonStyle
 OpaqueBrowserFrameView::GetFrameButtonStyle() const {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   return FrameButtonStyle::kMdButton;
 #else
   return FrameButtonStyle::kImageButton;
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_browsertest.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_browsertest.cc
index bf764b1f..734bb99 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_browsertest.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_browsertest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/frame/opaque_browser_frame_view.h"
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -51,7 +52,8 @@
     // browser windows, see |CreateBrowserNonClientFrameView()|.
     bool is_opaque_browser_frame_view =
         frame_view->GetClassName() == OpaqueBrowserFrameView::kClassName;
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#if defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
+    !BUILDFLAG(IS_CHROMEOS_LACROS)
     DCHECK(is_opaque_browser_frame_view);
 #else
     if (!is_opaque_browser_frame_view)
@@ -102,7 +104,8 @@
             gfx::kGoogleGrey900);
 }
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#if defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
+    !BUILDFLAG(IS_CHROMEOS_LACROS)
 // The app theme color should be ignored in system theme mode.
 IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest, SystemThemeColor) {
   SetThemeMode(ThemeMode::kSystem);
@@ -133,7 +136,7 @@
   EXPECT_EQ(web_app_frame_toolbar_->active_color_for_testing(),
             expected_caption_color);
 }
-#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#endif  // defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 
 IN_PROC_BROWSER_TEST_F(WebAppOpaqueBrowserFrameViewTest, LightThemeColor) {
   if (!InstallAndLaunchWebApp(SK_ColorYELLOW))
diff --git a/chrome/browser/ui/views/frame/system_menu_model_builder.cc b/chrome/browser/ui/views/frame/system_menu_model_builder.cc
index d16e9b7..7121a87 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_builder.cc
+++ b/chrome/browser/ui/views/frame/system_menu_model_builder.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/toolbar/app_menu_model.h"
@@ -18,7 +19,7 @@
 #include "ui/base/accelerators/accelerator.h"
 #include "ui/base/models/simple_menu_model.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/multi_user_window_manager.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
@@ -63,7 +64,9 @@
 
 void SystemMenuModelBuilder::BuildSystemMenuForBrowserWindow(
     ui::SimpleMenuModel* model) {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   model->AddItemWithStringId(IDC_MINIMIZE_WINDOW, IDS_MINIMIZE_WINDOW_MENU);
   model->AddItemWithStringId(IDC_MAXIMIZE_WINDOW, IDS_MAXIMIZE_WINDOW_MENU);
   model->AddItemWithStringId(IDC_RESTORE_WINDOW, IDS_RESTORE_WINDOW_MENU);
@@ -78,7 +81,9 @@
     model->AddSeparator(ui::NORMAL_SEPARATOR);
     model->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
   }
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   model->AddSeparator(ui::NORMAL_SEPARATOR);
   model->AddCheckItemWithStringId(IDC_USE_SYSTEM_TITLE_BAR,
                                   IDS_SHOW_WINDOW_DECORATIONS_MENU);
@@ -116,7 +121,9 @@
     model->AddSeparator(ui::NORMAL_SEPARATOR);
     model->AddItemWithStringId(IDC_TASK_MANAGER, IDS_TASK_MANAGER);
   }
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   model->AddSeparator(ui::NORMAL_SEPARATOR);
   model->AddItemWithStringId(IDC_CLOSE_WINDOW, IDS_CLOSE);
 #endif
@@ -133,7 +140,7 @@
 }
 
 void SystemMenuModelBuilder::AppendTeleportMenu(ui::SimpleMenuModel* model) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   DCHECK(browser()->window());
 
   // Avoid appending the teleport menu for the settings window.  This window's
diff --git a/chrome/browser/ui/views/frame/system_menu_model_delegate.cc b/chrome/browser/ui/views/frame/system_menu_model_delegate.cc
index 4a23a20..de9b1146 100644
--- a/chrome/browser/ui/views/frame/system_menu_model_delegate.cc
+++ b/chrome/browser/ui/views/frame/system_menu_model_delegate.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/frame/system_menu_model_delegate.h"
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/command_updater.h"
 #include "chrome/browser/profiles/profile.h"
@@ -15,7 +16,9 @@
 #include "components/sessions/core/tab_restore_service.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #endif
@@ -30,7 +33,9 @@
 SystemMenuModelDelegate::~SystemMenuModelDelegate() {}
 
 bool SystemMenuModelDelegate::IsCommandIdChecked(int command_id) const {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   if (command_id == IDC_USE_SYSTEM_TITLE_BAR) {
     PrefService* prefs = browser_->profile()->GetPrefs();
     return !prefs->GetBoolean(prefs::kUseCustomChromeFrame);
@@ -44,7 +49,9 @@
 }
 
 bool SystemMenuModelDelegate::IsCommandIdVisible(int command_id) const {
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   bool is_maximized = browser_->window()->IsMaximized();
   switch (command_id) {
     case IDC_MAXIMIZE_WINDOW:
diff --git a/chrome/browser/ui/views/frame/test_with_browser_view.cc b/chrome/browser/ui/views/frame/test_with_browser_view.cc
index a50d0d5..7de8d85 100644
--- a/chrome/browser/ui/views/frame/test_with_browser_view.cc
+++ b/chrome/browser/ui/views/frame/test_with_browser_view.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "chrome/browser/autocomplete/chrome_autocomplete_provider_client.h"
 #include "chrome/browser/extensions/extension_action_test_util.h"
@@ -33,7 +34,7 @@
 #include "content/public/test/test_utils.h"
 #include "services/network/test/test_url_loader_factory.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
 #include "chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h"
 #endif
@@ -68,7 +69,7 @@
 TestWithBrowserView::~TestWithBrowserView() {}
 
 void TestWithBrowserView::SetUp() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   chromeos::input_method::InitializeForTesting(
       new chromeos::input_method::MockInputMethodManagerImpl);
 #endif
@@ -89,7 +90,7 @@
   browser_view_ = nullptr;
   content::RunAllTasksUntilIdle();
   BrowserWithTestWindowTest::TearDown();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   chromeos::input_method::Shutdown();
 #endif
 }
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
index 057a440..297cce74 100644
--- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
+++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos_browsertest.cc
@@ -19,6 +19,7 @@
 #include "base/command_line.h"
 #include "base/path_service.h"
 #include "base/strings/safe_sprintf.h"
+#include "build/chromeos_buildflags.h"
 #include "cc/base/math_util.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -745,7 +746,7 @@
       scrollable_page_contents));
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // http://crbug.com/1127805: Flaky on Chrome OS builders
 #define MAYBE_TestClosingATab DISABLED_TestClosingATab
 #else
diff --git a/chrome/browser/ui/views/frame/webui_tab_strip_field_trial.cc b/chrome/browser/ui/views/frame/webui_tab_strip_field_trial.cc
index 06a2330..d9143d9 100644
--- a/chrome/browser/ui/views/frame/webui_tab_strip_field_trial.cc
+++ b/chrome/browser/ui/views/frame/webui_tab_strip_field_trial.cc
@@ -8,15 +8,16 @@
 #include "base/logging.h"
 #include "base/no_destructor.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/ui/ui_features.h"
 
 // Platform-specific headers for detecting tablet devices.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/tablet_mode.h"
 #elif defined(OS_WIN)
 #include <windows.h>
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace {
 
@@ -78,7 +79,7 @@
 
 // static
 bool WebUITabStripFieldTrial::DeviceIsTabletModeCapable() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   return ash::TabletMode::IsBoardTypeMarkedAsTabletCapable();
 #elif defined(OS_WIN)
   return HasBuiltInTouchScreen();
@@ -88,5 +89,5 @@
   // devices, it'll do no better than the existing field trial. So,
   // return false and don't record this synthetic field trial.
   return false;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
diff --git a/chrome/browser/ui/views/frame/webui_tab_strip_field_trial_browsertest.cc b/chrome/browser/ui/views/frame/webui_tab_strip_field_trial_browsertest.cc
index d99ee91e..1c00cbb 100644
--- a/chrome/browser/ui/views/frame/webui_tab_strip_field_trial_browsertest.cc
+++ b/chrome/browser/ui/views/frame/webui_tab_strip_field_trial_browsertest.cc
@@ -15,6 +15,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_field_trial_list_resetter.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "components/variations/active_field_trials.h"
@@ -22,9 +23,9 @@
 #include "content/public/test/browser_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/ash_switches.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace {
 
@@ -120,7 +121,7 @@
 }
 
 // The following tests depend on ash.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Overrides the device's tablet mode capability, forcing it to appear
 // as a tablet.
@@ -188,4 +189,4 @@
   EXPECT_FALSE(IsInGroup("Default"));
 }
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/frame/webui_tab_strip_interactive_uitest.cc b/chrome/browser/ui/views/frame/webui_tab_strip_interactive_uitest.cc
index 01b27606..b329032 100644
--- a/chrome/browser/ui/views/frame/webui_tab_strip_interactive_uitest.cc
+++ b/chrome/browser/ui/views/frame/webui_tab_strip_interactive_uitest.cc
@@ -5,6 +5,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/ui_features.h"
 #include "chrome/browser/ui/view_ids.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -21,10 +22,10 @@
 #include "ui/base/pointer/touch_ui_controller.h"
 #include "ui/views/controls/webview/webview.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chromeos/ui/frame/immersive/immersive_fullscreen_controller.h"
 #include "chromeos/ui/frame/immersive/immersive_fullscreen_controller_test_api.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 class WebUITabStripInteractiveTest : public InProcessBrowserTest {
  public:
@@ -131,7 +132,7 @@
   EXPECT_FALSE(container->bounds().IsEmpty());
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Regression test for crbug.com/1112028
 IN_PROC_BROWSER_TEST_F(WebUITabStripInteractiveTest, CanUseInImmersiveMode) {
@@ -187,4 +188,4 @@
   EXPECT_TRUE(immersive_mode_controller->IsRevealed());
 }
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
index dc4c0e1f..adb0f7c 100644
--- a/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
+++ b/chrome/browser/ui/views/global_media_controls/media_dialog_view_interactive_browsertest.cc
@@ -39,7 +39,7 @@
 using media_session::mojom::MediaSessionAction;
 
 // Global Media Controls are not supported on Chrome OS.
-#if !BUILDFLAG(IS_LACROS)
+#if !BUILDFLAG(IS_CHROMEOS_LACROS)
 
 namespace {
 
@@ -969,4 +969,4 @@
             base::UTF16ToUTF8(GetLiveCaptionTitleLabel()->GetText()));
 }
 
-#endif  // !BUILDFLAG(IS_LACROS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_LACROS)
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view.cc b/chrome/browser/ui/views/intent_picker_bubble_view.cc
index b60da29..f2519f1 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view.cc
@@ -11,6 +11,7 @@
 #include "base/i18n/rtl.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/apps/intent_helper/intent_picker_constants.h"
 #include "chrome/browser/apps/intent_helper/intent_picker_helpers.h"
 #include "chrome/browser/platform_util.h"
@@ -39,9 +40,9 @@
 #include "ui/views/layout/grid_layout.h"
 #include "ui/views/metadata/metadata_impl_macros.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace {
 
@@ -368,13 +369,13 @@
   size_t i = 0;
   size_t to_erase = app_info_.size();
   for (const auto& app_info : app_info_) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     if (arc::ArcIntentHelperBridge::IsIntentHelperPackage(
             app_info.launch_name)) {
       to_erase = i;
       continue;
     }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
     auto app_button = std::make_unique<IntentPickerLabelButton>(
         base::BindRepeating(&IntentPickerBubbleView::AppButtonPressed,
                             base::Unretained(this), i),
diff --git a/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc b/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc
index 3c471b1..b5fd8585 100644
--- a/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/intent_picker_bubble_view_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/callback_helpers.h"
 #include "base/macros.h"
 #include "base/optional.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/apps/intent_helper/apps_navigation_types.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
@@ -28,7 +29,7 @@
 #include "url/gurl.h"
 #include "url/origin.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/arc/intent_helper/arc_intent_picker_app_fetcher.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #endif
@@ -43,7 +44,7 @@
 // ChromeOS-only, so for this unit test to match the behavior of
 // IntentPickerBubbleView on non-ChromeOS platforms, if needs to not filter any
 // packages.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const char* kArcIntentHelperPackageName =
     arc::ArcIntentHelperBridge::kArcIntentHelperPackageName;
 bool (*IsIntentHelperPackage)(const std::string&) =
diff --git a/chrome/browser/ui/views/keyboard_access_browsertest.cc b/chrome/browser/ui/views/keyboard_access_browsertest.cc
index f064f95..312993ee 100644
--- a/chrome/browser/ui/views/keyboard_access_browsertest.cc
+++ b/chrome/browser/ui/views/keyboard_access_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -203,7 +204,7 @@
   if (focus_omnibox)
     browser()->window()->GetLocationBar()->FocusLocation(false);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Chrome OS doesn't have a way to just focus the app menu, so we use Alt+F to
   // bring up the menu.
   ASSERT_TRUE(ui_test_utils::SendKeyPressSync(
@@ -228,7 +229,7 @@
 
   // See above comment. Since we already brought up the menu, no need to do this
   // on ChromeOS.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   if (alternate_key_sequence)
     SendKeyPress(browser(), ui::VKEY_DOWN);
   else
@@ -385,7 +386,7 @@
 }
 
 // http://crbug.com/62310.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_TestMenuKeyboardAccess DISABLED_TestMenuKeyboardAccess
 #elif defined(OS_MAC)
 // No keyboard shortcut for the Chrome menu on Mac: http://crbug.com/823952
@@ -399,7 +400,7 @@
 }
 
 // http://crbug.com/62310.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_TestAltMenuKeyboardAccess DISABLED_TestAltMenuKeyboardAccess
 #elif defined(OS_MAC)
 // No keyboard shortcut for the Chrome menu on Mac: http://crbug.com/823952
diff --git a/chrome/browser/ui/views/layout_provider_unittest.cc b/chrome/browser/ui/views/layout_provider_unittest.cc
index 7f83061..a22b4dac 100644
--- a/chrome/browser/ui/views/layout_provider_unittest.cc
+++ b/chrome/browser/ui/views/layout_provider_unittest.cc
@@ -5,6 +5,7 @@
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
 #include "chrome/browser/ui/views/chrome_typography_provider.h"
@@ -417,7 +418,7 @@
 // versions, but on ChromeOS, there is only one OS version, so we can rely on
 // consistent behavior. Also ChromeOS is the only place where
 // IDS_UI_FONT_FAMILY_CROS works, which this test uses to control results.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Ensure the omnibox font is always 14pt, even in Hebrew. On ChromeOS, Hebrew
 // has a larger default font size applied from the resource bundle, but the
@@ -473,4 +474,4 @@
                                                      kDecorationRequestedSize));
 }
 
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
index b927429..523d124 100644
--- a/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
+++ b/chrome/browser/ui/views/location_bar/custom_tab_bar_view.cc
@@ -8,6 +8,7 @@
 
 #include "base/metrics/user_metrics.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
@@ -46,7 +47,7 @@
 #include "ui/views/view_class_properties.h"
 #include "url/gurl.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chromeos/ui/base/chromeos_ui_constants.h"
 #else
 #include "chrome/browser/themes/theme_properties.h"
@@ -225,7 +226,7 @@
   // mode. Find a better place to set it.
   gfx::Insets interior_margin =
       GetLayoutInsets(LayoutInset::TOOLBAR_INTERIOR_MARGIN);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (browser_->is_type_custom_tab()) {
     web_app_menu_button_ = AddChildView(std::make_unique<WebAppMenuButton>(
         browser_view, l10n_util::GetStringUTF16(
@@ -448,7 +449,7 @@
 // drawing the separator the current frame color should be queried directly and
 // not assume knowledge of what the color might be.
 SkColor CustomTabBarView::GetDefaultFrameColor() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Ash system frames differ from ChromeOS browser frames.
   return chromeos::kDefaultFrameColor;
 #else
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc
index 9f78f20..d9b5f06 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
 #include "chrome/test/views/chrome_views_test_base.h"
@@ -21,7 +22,7 @@
 #include "ui/views/controls/image_view.h"
 #include "ui/views/widget/widget_utils.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ui/aura/window.h"
 #endif
 
diff --git a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
index 4fd5800..343f983 100644
--- a/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/location_bar/zoom_bubble_view_browsertest.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/location_bar/zoom_bubble_view.h"
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_test.h"
@@ -22,7 +23,7 @@
 #include "ui/views/test/test_widget_observer.h"
 #include "ui/views/test/widget_test.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/frame/immersive_mode_controller_chromeos.h"
 #include "chromeos/ui/frame/immersive/immersive_fullscreen_controller_test_api.h"
 #endif
@@ -95,7 +96,7 @@
 // bubble should close and re-show in a new un-anchored position.
 //
 // TODO(crbug.com/1142682): Fails on Lacros bots.
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
 #define MAYBE_AnchorPositionsInFullscreen DISABLED_AnchorPositionsInFullscreen
 #else
 #define MAYBE_AnchorPositionsInFullscreen AnchorPositionsInFullscreen
@@ -126,7 +127,7 @@
   }
   EXPECT_FALSE(ZoomBubbleView::GetZoomBubble());
 
-#if defined(OS_MAC) || defined(OS_CHROMEOS)
+#if defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
   const bool should_show_toolbar = true;
 #else
   const bool should_show_toolbar = false;
@@ -175,7 +176,7 @@
   }
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Test whether the zoom bubble is anchored and whether it is visible when in
 // immersive fullscreen.
 IN_PROC_BROWSER_TEST_F(ZoomBubbleBrowserTest, ImmersiveFullscreen) {
@@ -236,7 +237,7 @@
     waiter.Wait();
   }
 }
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Tests that trying to open zoom bubble with stale WebContents is safe.
 IN_PROC_BROWSER_TEST_F(ZoomBubbleBrowserTest, NoWebContentsIsSafe) {
diff --git a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc
index d8bbf6d..c17318fc 100644
--- a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc
+++ b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.cc
@@ -8,6 +8,7 @@
 #include "base/check.h"
 #include "base/macros.h"
 #include "base/notreached.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/content_settings/mixed_content_settings_tab_helper.h"
@@ -46,7 +47,7 @@
 #include "chrome/browser/global_keyboard_shortcuts_mac.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/window_properties.h"
 #include "base/callback.h"
 #include "base/scoped_observation.h"
@@ -58,7 +59,7 @@
 
 using content::WebContents;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Observes the NativeWindow hosting the receiver view to look for fullscreen
 // state changes.  This helps monitor fullscreen changes that don't go through
 // the normal key accelerator to display and hide the location bar.
@@ -191,7 +192,7 @@
 
   location_bar_view_->Init();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   window_observer_ = std::make_unique<FullscreenWindowObserver>(
       GetWidget()->GetNativeWindow(),
       base::BindRepeating(&PresentationReceiverWindowView::OnFullscreenChanged,
@@ -290,7 +291,7 @@
     ExclusiveAccessBubbleType bubble_type,
     const int64_t display_id) {
   frame_->SetFullscreen(true);
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   OnFullscreenChanged();
 #endif
   UpdateExclusiveAccessExitBubbleContent(url, bubble_type,
@@ -300,7 +301,7 @@
 
 void PresentationReceiverWindowView::ExitFullscreen() {
   frame_->SetFullscreen(false);
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   OnFullscreenChanged();
 #endif
 }
@@ -310,7 +311,7 @@
     ExclusiveAccessBubbleType bubble_type,
     ExclusiveAccessBubbleHideCallback bubble_first_hide_callback,
     bool force_update) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // On Chrome OS, we will not show the toast for the normal browser fullscreen
   // mode.  The 'F11' text is confusing since how to access F11 on a Chromebook
   // is not common knowledge and there is also a dedicated fullscreen toggle
diff --git a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h
index e789d046..da66aa85 100644
--- a/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h
+++ b/chrome/browser/ui/views/media_router/presentation_receiver_window_view.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/command_updater_delegate.h"
 #include "chrome/browser/command_updater_impl.h"
 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
@@ -25,7 +26,7 @@
 class PresentationReceiverWindowFrame;
 class LocationBarModelImpl;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 class FullscreenWindowObserver;
 #endif
 
@@ -126,7 +127,7 @@
   ui::Accelerator fullscreen_accelerator_;
   std::unique_ptr<ExclusiveAccessBubbleViews> exclusive_access_bubble_;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   std::unique_ptr<FullscreenWindowObserver> window_observer_;
 #endif
 
diff --git a/chrome/browser/ui/views/media_router/presentation_receiver_window_view_browsertest.cc b/chrome/browser/ui/views/media_router/presentation_receiver_window_view_browsertest.cc
index 61e3532..7814a5f 100644
--- a/chrome/browser/ui/views/media_router/presentation_receiver_window_view_browsertest.cc
+++ b/chrome/browser/ui/views/media_router/presentation_receiver_window_view_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/media_router/presentation_receiver_window_delegate.h"
@@ -25,7 +26,7 @@
 #include "ui/views/view.h"
 #include "url/gurl.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/window_properties.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
@@ -108,7 +109,7 @@
   DISALLOW_COPY_AND_ASSIGN(PresentationReceiverWindowViewBrowserTest);
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 IN_PROC_BROWSER_TEST_F(PresentationReceiverWindowViewBrowserTest,
                        ChromeOSHardwareFullscreenButton) {
   // Bypass ExclusiveAccessContext and default accelerator to simulate hardware
diff --git a/chrome/browser/ui/views/menu_interactive_uitest.cc b/chrome/browser/ui/views/menu_interactive_uitest.cc
index 34236cd..d0f7a8f 100644
--- a/chrome/browser/ui/views/menu_interactive_uitest.cc
+++ b/chrome/browser/ui/views/menu_interactive_uitest.cc
@@ -7,6 +7,7 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/views/native_widget_factory.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -25,7 +26,7 @@
 #include "ui/views/test/widget_test.h"
 #include "ui/views/widget/widget.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ui/accessibility/platform/ax_platform_node.h"
 #endif
 
@@ -78,7 +79,7 @@
     first_item_->GetViewAccessibility().GetAccessibleNodeData(&item_node_data);
     EXPECT_EQ(item_node_data.role, ax::mojom::Role::kMenuItem);
 
-#if !defined(OS_CHROMEOS)  // ChromeOS does not use popup focus override.
+#if !BUILDFLAG(IS_CHROMEOS_ASH)  // ChromeOS does not use popup focus override.
     EXPECT_TRUE(first_item_->GetViewAccessibility().IsFocusedForTesting());
 #endif
     ui::AXNodeData menu_node_data;
@@ -106,7 +107,7 @@
 };
 
 IN_PROC_BROWSER_TEST_F(MenuControllerUITest, TestMouseOverShownMenu) {
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   ui::AXPlatformNode::NotifyAddAXModeFlags(ui::kAXModeComplete);
 #endif
 
@@ -114,7 +115,7 @@
   Widget* widget = new views::Widget;
   Widget::InitParams params(Widget::InitParams::TYPE_WINDOW);
   params.bounds = {0, 0, 200, 200};
-#if !defined(OS_CHROMEOS) && !defined(OS_MAC)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_MAC)
   params.native_widget = CreateNativeWidget(
       NativeWidgetType::DESKTOP_NATIVE_WIDGET_AURA, &params, widget);
 #endif
@@ -149,7 +150,7 @@
   EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuPopupEnd), 1);
   EXPECT_EQ(ax_counter.GetCount(ax::mojom::Event::kMenuEnd), 1);
   EXPECT_FALSE(first_item_->IsSelected());
-#if !defined(OS_CHROMEOS)  // ChromeOS does not use popup focus override.
+#if !BUILDFLAG(IS_CHROMEOS_ASH)  // ChromeOS does not use popup focus override.
   EXPECT_FALSE(first_item_->GetViewAccessibility().IsFocusedForTesting());
 #endif
   menu_runner_->RunMenuAt(widget, nullptr, gfx::Rect(),
@@ -164,7 +165,7 @@
   // Process event(s), and check what's selected in the menu.
   RunPendingMessages();
   EXPECT_FALSE(first_item_->IsSelected());
-#if !defined(OS_CHROMEOS)  // ChromeOS does not use popup focus override.
+#if !BUILDFLAG(IS_CHROMEOS_ASH)  // ChromeOS does not use popup focus override.
   EXPECT_FALSE(first_item_->GetViewAccessibility().IsFocusedForTesting());
   EXPECT_TRUE(button.GetViewAccessibility().IsFocusedForTesting());
 #endif
@@ -176,12 +177,12 @@
                                            run_loop2.QuitClosure());
   run_loop2.Run();
   EXPECT_TRUE(first_item_->IsSelected());
-#if !defined(OS_CHROMEOS)  // ChromeOS does not use popup focus override.
+#if !BUILDFLAG(IS_CHROMEOS_ASH)  // ChromeOS does not use popup focus override.
   EXPECT_TRUE(first_item_->GetViewAccessibility().IsFocusedForTesting());
   EXPECT_FALSE(button.GetViewAccessibility().IsFocusedForTesting());
 #endif
   menu_runner_->Cancel();
-#if !defined(OS_CHROMEOS)  // ChromeOS does not use popup focus override.
+#if !BUILDFLAG(IS_CHROMEOS_ASH)  // ChromeOS does not use popup focus override.
   EXPECT_FALSE(first_item_->GetViewAccessibility().IsFocusedForTesting());
   EXPECT_TRUE(button.GetViewAccessibility().IsFocusedForTesting());
 #endif
diff --git a/chrome/browser/ui/views/message_box_dialog.cc b/chrome/browser/ui/views/message_box_dialog.cc
index 2c96b4f..310a313 100644
--- a/chrome/browser/ui/views/message_box_dialog.cc
+++ b/chrome/browser/ui/views/message_box_dialog.cc
@@ -13,6 +13,7 @@
 #include "base/run_loop.h"
 #include "base/task/current_thread.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/simple_message_box_internal.h"
 #include "chrome/browser/ui/views/message_box_dialog.h"
@@ -28,7 +29,7 @@
 #include "ui/views/widget/widget.h"
 #include "ui/views/window/dialog_delegate.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chromeos/ui/base/window_properties.h"
 #include "ui/aura/window.h"  // nogncheck
 #endif
@@ -195,7 +196,7 @@
 
 void MessageBoxDialog::OnWidgetActivationChanged(views::Widget* widget,
                                                  bool active) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (GetWidget()->GetNativeWindow()->GetProperty(
           chromeos::kIsShowingInOverviewKey)) {
     // Prevent this from closing while starting overview mode for better UX.
@@ -221,7 +222,7 @@
     : window_title_(title),
       type_(type),
       message_box_view_(new views::MessageBoxView(message)) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   SetModalType(is_system_modal ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_WINDOW);
 #else
   DCHECK(!is_system_modal);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 5f9370b1..08b9ad0 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -20,6 +20,7 @@
 #include "base/task/thread_pool.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/command_updater.h"
 #include "chrome/browser/profiles/profile.h"
@@ -399,7 +400,7 @@
 }
 
 OmniboxViewViews::~OmniboxViewViews() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   chromeos::input_method::InputMethodManager::Get()->
       RemoveCandidateWindowObserver(this);
 #endif
@@ -439,7 +440,7 @@
   constexpr gfx::Insets kTextfieldInsets(3);
   SetBorder(views::CreateEmptyBorder(kTextfieldInsets));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   chromeos::input_method::InputMethodManager::Get()->
       AddCandidateWindowObserver(this);
 #endif
@@ -1242,7 +1243,7 @@
 }
 
 bool OmniboxViewViews::IsImeShowingPopup() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   return ime_candidate_window_open_;
 #else
   return GetInputMethod() ? GetInputMethod()->IsCandidatePopupOpen() : false;
@@ -2155,7 +2156,7 @@
          !model()->is_caret_visible() && !model()->is_keyword_selected();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void OmniboxViewViews::CandidateWindowOpened(
       chromeos::input_method::InputMethodManager* manager) {
   ime_candidate_window_open_ = true;
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.h b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
index 4bb177088..d17714b 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/scoped_observation.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/send_tab_to_self/send_tab_to_self_sub_menu_model.h"
 #include "components/omnibox/browser/omnibox_view.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -31,7 +32,7 @@
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ui/base/ime/chromeos/input_method_manager.h"
 #endif
 
@@ -55,7 +56,7 @@
 // Views-implementation of OmniboxView.
 class OmniboxViewViews : public OmniboxView,
                          public views::Textfield,
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
                          public chromeos::input_method::InputMethodManager::
                              CandidateWindowObserver,
 #endif
@@ -445,7 +446,7 @@
   bool ShouldShowPlaceholderText() const override;
 
   // chromeos::input_method::InputMethodManager::CandidateWindowObserver:
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void CandidateWindowOpened(
       chromeos::input_method::InputMethodManager* manager) override;
   void CandidateWindowClosed(
@@ -616,7 +617,7 @@
   // |location_bar_view_| can be NULL in tests.
   LocationBarView* location_bar_view_;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // True if the IME candidate window is open. When this is true, we want to
   // avoid showing the popup. So far, the candidate window is detected only
   // on Chrome OS.
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
index ff1191b4..280b237 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_browsertest.cc
@@ -10,6 +10,7 @@
 #include "base/feature_list.h"
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/search_engines/template_url_service_factory.h"
 #include "chrome/browser/ui/browser.h"
@@ -226,7 +227,9 @@
   ASSERT_NO_FATAL_FAILURE(ClickBrowserWindowCenter());
   ASSERT_NO_FATAL_FAILURE(Click(ui_controls::MIDDLE,
                                 click_location, click_location));
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   EXPECT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
 #else
   EXPECT_FALSE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
@@ -234,7 +237,9 @@
   EXPECT_FALSE(omnibox_view->IsSelectAll());
 }
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 IN_PROC_BROWSER_TEST_F(OmniboxViewViewsTest, SelectionClipboard) {
   OmniboxView* omnibox_view = NULL;
   ASSERT_NO_FATAL_FAILURE(GetOmniboxViewForBrowser(browser(), &omnibox_view));
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
index 7822b3d..0c6c18cc 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views_unittest.cc
@@ -16,6 +16,7 @@
 #include "base/test/simple_test_clock.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
@@ -54,7 +55,7 @@
 #include "ui/gfx/render_text_test_api.h"
 #include "ui/views/controls/textfield/textfield_test_api.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/input_method/input_method_configuration.h"
 #include "chrome/browser/chromeos/input_method/mock_input_method_manager_impl.h"
 #endif
@@ -620,7 +621,7 @@
   widget_ = CreateTestWidget();
   widget_->Show();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   chromeos::input_method::InitializeForTesting(
       new chromeos::input_method::MockInputMethodManagerImpl);
 #endif
@@ -646,7 +647,7 @@
   util_.reset();
   profile_.reset();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   chromeos::input_method::Shutdown();
 #endif
   ChromeViewsTestBase::TearDown();
diff --git a/chrome/browser/ui/views/overlay/close_image_button.cc b/chrome/browser/ui/views/overlay/close_image_button.cc
index 7bc1f27..79b969d 100644
--- a/chrome/browser/ui/views/overlay/close_image_button.cc
+++ b/chrome/browser/ui/views/overlay/close_image_button.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/overlay/close_image_button.h"
 
+#include "build/chromeos_buildflags.h"
 #include "chrome/grit/generated_resources.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -42,7 +43,7 @@
 void CloseImageButton::SetPosition(
     const gfx::Size& size,
     OverlayWindowViews::WindowQuadrant quadrant) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (quadrant == OverlayWindowViews::WindowQuadrant::kBottomLeft) {
     ImageButton::SetPosition(
         gfx::Point(kCloseButtonMargin, kCloseButtonMargin));
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.cc b/chrome/browser/ui/views/overlay/overlay_window_views.cc
index 6bbefe36..eec1cbc 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.cc
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.cc
@@ -12,6 +12,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -41,7 +42,7 @@
 #include "ui/views/window/non_client_view.h"
 #include "ui/views/window/window_resize_utils.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/window_properties.h"  // nogncheck
 #include "ui/aura/window.h"
@@ -62,7 +63,7 @@
 // The opacity of the controls scrim.
 constexpr double kControlsScrimOpacity = 0.6;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // The opacity of the resize handle control.
 constexpr double kResizeHandleOpacity = 0.38;
 #endif
@@ -148,7 +149,7 @@
       return window_component;
     }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     // If the resize handle is clicked on, we want to force the hit test to
     // force a resize drag.
     if (window->AreControlsVisible() &&
@@ -397,7 +398,7 @@
             overlay->RecordButtonPressed(OverlayWindowControl::kSkipAd);
           },
           base::Unretained(this)));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   auto resize_handle_view = std::make_unique<views::ResizeHandleButton>(
       views::Button::PressedCallback());
 #endif
@@ -450,7 +451,7 @@
   skip_ad_controls_view->layer()->SetFillsBoundsOpaquely(true);
   skip_ad_controls_view->layer()->SetName("SkipAdControlsView");
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // views::View that shows the affordance that the window can be resized. ----
   resize_handle_view->SetPaintToLayer(ui::LAYER_TEXTURED);
   resize_handle_view->layer()->SetFillsBoundsOpaquely(false);
@@ -476,7 +477,7 @@
       AddChildView(&view_holder_, std::move(next_track_controls_view));
   skip_ad_controls_view_ =
       AddChildView(&view_holder_, std::move(skip_ad_controls_view));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   resize_handle_view_ =
       AddChildView(&view_holder_, std::move(resize_handle_view));
 #endif
@@ -484,9 +485,9 @@
 }
 
 void OverlayWindowViews::OnRootViewReady() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   GetNativeWindow()->SetProperty(ash::kWindowPipTypeKey, true);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   GetRootView()->SetPaintToLayer(ui::LAYER_TEXTURED);
   GetRootView()->layer()->SetName("RootView");
@@ -554,7 +555,7 @@
   // is accessible via accessibility tools.
   skip_ad_controls_view_->ToggleVisibility(is_visible && show_skip_ad_button_);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   GetResizeHandleLayer()->SetVisible(is_visible);
 #endif
 }
@@ -585,7 +586,7 @@
 
   WindowQuadrant quadrant = GetCurrentWindowQuadrant(GetBounds(), controller_);
   close_controls_view_->SetPosition(GetBounds().size(), quadrant);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   resize_handle_view_->SetPosition(GetBounds().size(), quadrant);
 #endif
 
@@ -716,7 +717,7 @@
 void OverlayWindowViews::ShowInactive() {
   views::Widget::ShowInactive();
   views::Widget::SetVisibleOnAllWorkspaces(true);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // For rounded corners.
   if (ash::features::IsPipRoundedCornersEnabled()) {
     decorator_ = std::make_unique<ash::RoundedCornerDecorator>(
@@ -843,7 +844,7 @@
   // window.
   UpdateMaxSize(GetWorkAreaForWindow());
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Update the positioning of some icons when the window is moved.
   WindowQuadrant quadrant = GetCurrentWindowQuadrant(GetBounds(), controller_);
   close_controls_view_->SetPosition(GetBounds().size(), quadrant);
@@ -998,7 +999,7 @@
   return close_controls_view_->GetMirroredBounds();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 gfx::Rect OverlayWindowViews::GetResizeHandleControlsBounds() {
   return resize_handle_view_->GetMirroredBounds();
 }
@@ -1016,7 +1017,7 @@
   return previous_track_controls_view_->GetMirroredBounds();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 int OverlayWindowViews::GetResizeHTComponent() const {
   return resize_handle_view_->GetHTComponent();
 }
@@ -1037,7 +1038,7 @@
 ui::Layer* OverlayWindowViews::GetCloseControlsLayer() {
   return close_controls_view_->layer();
 }
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 ui::Layer* OverlayWindowViews::GetResizeHandleLayer() {
   return resize_handle_view_->layer();
 }
@@ -1105,7 +1106,7 @@
   return close_controls_view_->origin();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 gfx::Point OverlayWindowViews::resize_handle_position_for_testing() const {
   return resize_handle_view_->origin();
 }
diff --git a/chrome/browser/ui/views/overlay/overlay_window_views.h b/chrome/browser/ui/views/overlay/overlay_window_views.h
index f99818a..315698a 100644
--- a/chrome/browser/ui/views/overlay/overlay_window_views.h
+++ b/chrome/browser/ui/views/overlay/overlay_window_views.h
@@ -8,10 +8,11 @@
 #include "content/public/browser/overlay_window.h"
 
 #include "base/timer/timer.h"
+#include "build/chromeos_buildflags.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/views/widget/widget.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/rounded_corner_decorator.h"
 #endif
 
@@ -211,7 +212,7 @@
   views::TrackImageButton* next_track_controls_view_ = nullptr;
   views::SkipAdLabelButton* skip_ad_controls_view_ = nullptr;
   views::ResizeHandleButton* resize_handle_view_ = nullptr;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   std::unique_ptr<ash::RoundedCornerDecorator> decorator_;
 #endif
 
diff --git a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
index 88d6c6d0..e695ba4d 100644
--- a/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
+++ b/chrome/browser/ui/views/page_action/pwa_install_view_browsertest.cc
@@ -8,6 +8,7 @@
 #include "base/run_loop.h"
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/banners/test_app_banner_manager_desktop.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -37,14 +38,14 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/views/view_observer.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "components/arc/arc_util.h"
 #include "components/arc/test/connection_holder_util.h"
 #include "components/arc/test/fake_app_instance.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace {
 
@@ -103,9 +104,9 @@
   void SetUpCommandLine(base::CommandLine* command_line) override {
     extensions::ExtensionBrowserTest::SetUpCommandLine(command_line);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     arc::SetArcAvailableCommandLineForTesting(command_line);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
     command_line->AppendSwitchASCII(
         network::switches::kUnsafelyTreatInsecureOriginAsSecure,
@@ -113,9 +114,9 @@
   }
 
   void SetUpInProcessBrowserTestFixture() override {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     arc::ArcSessionManager::SetUiEnabledForTesting(false);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   }
 
   void SetUpOnMainThread() override {
@@ -620,7 +621,7 @@
       "Manifest listing related chrome app"));
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Omnibox install promotion should not show if prefer_related_applications is
 // true and an ARC app listed as related.
 IN_PROC_BROWSER_TEST_F(PwaInstallViewBrowserTest,
@@ -648,4 +649,4 @@
       banners::AppBannerManager::GetInstallableWebAppName(web_contents_),
       "Manifest listing related android app"));
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
index d17168bc..f960f36 100644
--- a/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
+++ b/chrome/browser/ui/views/page_info/page_info_bubble_view.cc
@@ -17,6 +17,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/certificate_viewer.h"
 #include "chrome/browser/content_settings/page_specific_content_settings_delegate.h"
 #include "chrome/browser/infobars/infobar_service.h"
@@ -331,7 +332,7 @@
   layout->set_main_axis_alignment(views::BoxLayout::MainAxisAlignment::kStart);
   password_reuse_button_container_->SetLayoutManager(std::move(layout));
 
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
   if (change_password_button) {
     password_reuse_button_container_->AddChildView(
         std::move(change_password_button));
diff --git a/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc b/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc
index d42da7a..573edd0 100644
--- a/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/passwords/manage_passwords_icon_view_interactive_uitest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/macros.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/passwords/manage_passwords_test.h"
 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller_mock.h"
@@ -132,10 +133,10 @@
 
 // TODO(crbug.com/932818): Remove the condition once the experiment is enabled
 // on ChromeOS. For now, on ChromeOS, we only test the non-experimental branch.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 INSTANTIATE_TEST_SUITE_P(All,
                          ManagePasswordsIconViewTest,
                          ::testing::Values(false));
 #else
 INSTANTIATE_TEST_SUITE_P(All, ManagePasswordsIconViewTest, ::testing::Bool());
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/passwords/password_save_update_view.cc b/chrome/browser/ui/views/passwords/password_save_update_view.cc
index 7fff93f..ede3ea09 100644
--- a/chrome/browser/ui/views/passwords/password_save_update_view.cc
+++ b/chrome/browser/ui/views/passwords/password_save_update_view.cc
@@ -12,6 +12,7 @@
 #include "base/feature_list.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/passwords/manage_passwords_view_utils.h"
@@ -419,7 +420,7 @@
 }
 
 void PasswordSaveUpdateView::ReplaceWithPromo() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   NOTREACHED();
 #else
   RemoveAllChildViews(true);
@@ -441,7 +442,7 @@
   DialogModelChanged();
 
   SizeToContents();
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void PasswordSaveUpdateView::UpdateBubbleUIElements() {
diff --git a/chrome/browser/ui/views/payments/payment_request_browsertest.cc b/chrome/browser/ui/views/payments/payment_request_browsertest.cc
index 0fc3021..60ba651 100644
--- a/chrome/browser/ui/views/payments/payment_request_browsertest.cc
+++ b/chrome/browser/ui/views/payments/payment_request_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/test/test_browser_dialog.h"
@@ -26,7 +27,7 @@
 #include "ui/views/controls/styled_label.h"
 #include "url/gurl.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #endif
@@ -346,7 +347,7 @@
 
 // Tests that clicking the settings link brings the user to settings.
 IN_PROC_BROWSER_TEST_F(PaymentRequestSettingsLinkTest, ClickSettingsLink) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Install the Settings App.
   web_app::WebAppProvider::Get(browser()->profile())
       ->system_web_app_manager()
diff --git a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
index 4fd84739..e6573cb5 100644
--- a/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
+++ b/chrome/browser/ui/views/payments/payment_request_dialog_view.cc
@@ -96,7 +96,7 @@
   }
   RemoveChildViewT(view_stack_);
   controller_map_.clear();
-  request_->UserCancelled();
+  request_->OnUserCancelled();
 }
 
 bool PaymentRequestDialogView::ShouldShowCloseButton() const {
diff --git a/chrome/browser/ui/views/permission_bubble/permission_bubble_interactive_uitest.cc b/chrome/browser/ui/views/permission_bubble/permission_bubble_interactive_uitest.cc
index 076e1e9b..6f8b7b2 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_bubble_interactive_uitest.cc
+++ b/chrome/browser/ui/views/permission_bubble/permission_bubble_interactive_uitest.cc
@@ -6,6 +6,7 @@
 
 #include "base/run_loop.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -138,7 +139,7 @@
   std::unique_ptr<test::PermissionRequestManagerTestApi> test_api_;
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // TODO(crbug.com/1072425): views::test::WidgetTest::GetAllWidgets() crashes
 // on Chrome OS, need to investigate\fix that.
 #define MAYBE_CmdWClosesWindow DISABLED_CmdWClosesWindow
diff --git a/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view_browsertest.cc b/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view_browsertest.cc
index 22f61ff9..e2948c9b 100644
--- a/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view_browsertest.cc
+++ b/chrome/browser/ui/views/permission_bubble/permission_prompt_bubble_view_browsertest.cc
@@ -5,6 +5,7 @@
 #include "base/feature_list.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
 #include "chrome/browser/custom_handlers/register_protocol_handler_permission_request.h"
 #include "chrome/browser/download/download_permission_request.h"
@@ -331,7 +332,7 @@
 }
 
 // ContentSettingsType::PROTECTED_MEDIA_IDENTIFIER is ChromeOS only.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 IN_PROC_BROWSER_TEST_P(PermissionPromptBubbleViewBrowserTest,
                        InvokeUi_protected_media) {
   ShowAndVerifyUi();
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
index 8b50d0b..6bd8ff68 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/profiles/avatar_toolbar_button_delegate.h"
 
 #include "base/check_op.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
@@ -19,7 +20,7 @@
 #include "components/signin/public/identity_manager/consent_level.h"
 #include "ui/base/resource/resource_bundle.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chromeos/constants/chromeos_features.h"
 #endif
 
@@ -123,7 +124,7 @@
       OnRefreshTokensLoaded();
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (!base::FeatureList::IsEnabled(chromeos::features::kAvatarToolbarButton)) {
     // On CrOS this button should only show as badging for Incognito and Guest
     // sessions. It's only enabled for Incognito where a menu is available for
@@ -131,7 +132,7 @@
     avatar_toolbar_button_->SetEnabled(
         state == AvatarToolbarButton::State::kIncognitoProfile);
   }
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 base::string16 AvatarToolbarButtonDelegate::GetProfileName() const {
diff --git a/chrome/browser/ui/views/profiles/avatar_toolbar_button_unittest.cc b/chrome/browser/ui/views/profiles/avatar_toolbar_button_unittest.cc
index c5d3d10..c85e4a2 100644
--- a/chrome/browser/ui/views/profiles/avatar_toolbar_button_unittest.cc
+++ b/chrome/browser/ui/views/profiles/avatar_toolbar_button_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/profiles/avatar_toolbar_button.h"
 
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
@@ -13,7 +14,7 @@
 using AvatarToolbarButtonTest = TestWithBrowserView;
 
 // CrOS only shows the avatar button for incognito/guest.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 
 TEST_F(AvatarToolbarButtonTest, HighlightMeetsMinimumContrast) {
   auto* button = browser_view()->GetWidget()->GetContentsView()->AddChildView(
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.cc b/chrome/browser/ui/views/profiles/profile_menu_view.cc
index fbca109..3a5697d 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view.cc
@@ -14,6 +14,7 @@
 #include "base/metrics/user_metrics.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
@@ -204,7 +205,7 @@
   BuildFeatureButtons();
 
 //  ChromeOS doesn't support multi-profile.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   if (!(IsGuest(profile) &&
         base::FeatureList::IsEnabled(features::kNewProfilePicker))) {
     BuildProfileManagementHeading();
@@ -322,7 +323,7 @@
 
 void ProfileMenuView::OnSyncErrorButtonClicked(
     sync_ui_util::AvatarSyncErrorType error) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // On ChromeOS, sync errors are fixed by re-signing into the OS.
   chrome::AttemptUserExit();
 #else
@@ -393,7 +394,7 @@
       signin_metrics::AccessPoint::ACCESS_POINT_AVATAR_BUBBLE_SIGN_IN);
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void ProfileMenuView::OnSignoutButtonClicked() {
   RecordClick(ActionableItem::kSignoutButton);
   if (!perform_menu_actions())
@@ -447,7 +448,7 @@
     return;
   chrome::ShowSettingsSubPage(browser(), chrome::kManageProfileSubPage);
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 void ProfileMenuView::OnCookiesClearedOnExitLinkClicked() {
   RecordClick(ActionableItem::kCookiesClearedOnExitLink);
@@ -473,7 +474,7 @@
   base::string16 profile_name;
   base::Optional<EditButtonParams> edit_button_params;
 // Profile names are not supported on ChromeOS.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   size_t num_of_profiles =
       g_browser_process->profile_manager()->GetNumberOfProfiles();
   if (num_of_profiles > 1 || !profile_attributes->IsUsingDefaultName() ||
@@ -591,7 +592,7 @@
                             base::Unretained(this), account_info.value()),
         /*show_badge=*/true);
   } else {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     // There is always an account on ChromeOS.
     NOTREACHED();
 #else
@@ -652,7 +653,7 @@
     }
   }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   const bool has_primary_account =
       !IsGuest(profile) && identity_manager->HasPrimaryAccount();
   // The sign-out button is always at the bottom.
@@ -666,7 +667,7 @@
 #endif
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void ProfileMenuView::BuildProfileManagementHeading() {
   SetProfileManagementHeading(
       UseNewPicker()
@@ -726,4 +727,4 @@
                             base::Unretained(this)));
   }
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view.h b/chrome/browser/ui/views/profiles/profile_menu_view.h
index 93cf67a..b1b448a 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view.h
+++ b/chrome/browser/ui/views/profiles/profile_menu_view.h
@@ -13,6 +13,7 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/avatar_menu.h"
 #include "chrome/browser/profiles/avatar_menu_observer.h"
 #include "chrome/browser/sync/sync_ui_util.h"
@@ -57,7 +58,7 @@
   void OnSyncErrorButtonClicked(sync_ui_util::AvatarSyncErrorType error);
   void OnSigninAccountButtonClicked(AccountInfo account);
   void OnCookiesClearedOnExitLinkClicked();
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   void OnSignoutButtonClicked();
   void OnSigninButtonClicked();
   void OnOtherProfileSelected(const base::FilePath& profile_path);
@@ -77,7 +78,7 @@
   void BuildAutofillButtons();
   void BuildSyncInfo();
   void BuildFeatureButtons();
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   void BuildSelectableProfiles();
   void BuildProfileManagementHeading();
   void BuildProfileManagementFeatureButtons();
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
index bf51229..4d9a74d 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_base.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/scoped_observation.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
@@ -47,7 +48,7 @@
 #include "ui/views/layout/flex_layout_types.h"
 #include "ui/views/view_class_properties.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/sync/dice_signin_button_view.h"
 #endif
 
diff --git a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
index 4b39cee..aede51f 100644
--- a/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
+++ b/chrome/browser/ui/views/profiles/profile_menu_view_browsertest.cc
@@ -17,6 +17,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
@@ -865,8 +866,10 @@
 
 // TODO(https://crbug.com/1125474): Remove OS_CHROMEOS and enable for Lacros
 // when supported.
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
 #if defined(OS_WIN) || defined(OS_MAC) || \
-    (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+    (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
 // List of actionable items in the correct order as they appear in the menu.
 // If a new button is added to the menu, it should also be added to this list.
 constexpr ProfileMenuViewBase::ActionableItem
@@ -907,8 +910,8 @@
     EphemeralGuestProfileMenuClickTest,
     ::testing::Range(size_t(0),
                      base::size(kActionableItems_EphemeralGuestProfile)));
-#endif  // defined(OS_WIN) || defined(OS_MAC) || (defined(OS_LINUX) &&
-        // !defined(OS_CHROMEOS))
+#endif  // defined(OS_WIN) || defined(OS_MAC) || (defined(OS_LINUX) ||
+        // BUILDFLAG(IS_CHROMEOS_LACROS))
 
 class ProfileMenuClickKeyAcceleratorTest : public ProfileMenuClickTestBase {
  public:
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.h b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.h
index ea51afd..e5544d99 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.h
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller.h
@@ -9,15 +9,16 @@
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "base/util/timer/wall_clock_timer.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "chrome/browser/upgrade_detector/upgrade_observer.h"
 #include "components/prefs/pref_change_registrar.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_chromeos.h"
 #else
 #include "chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_platform_impl_desktop.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace base {
 class Clock;
diff --git a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc
index 0e3274a..d82f5f7e 100644
--- a/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc
+++ b/chrome/browser/ui/views/relaunch_notification/relaunch_notification_controller_unittest.cc
@@ -20,6 +20,7 @@
 #include "base/time/tick_clock.h"
 #include "base/time/time.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/upgrade_detector/upgrade_detector.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
@@ -27,7 +28,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/shell.h"
 #include "ash/test/ash_test_helper.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
@@ -40,7 +41,7 @@
 #else
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/frame/test_with_browser_view.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 using ::testing::_;
 using ::testing::Eq;
@@ -766,7 +767,7 @@
   ::testing::Mock::VerifyAndClearExpectations(&mock_controller_delegate);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 class RelaunchNotificationControllerPlatformImplTest : public ::testing::Test {
  protected:
diff --git a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
index 5f26798..43f86bb 100644
--- a/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
+++ b/chrome/browser/ui/views/renderer_context_menu/render_view_context_menu_views.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string16.h"
 #include "base/task/current_thread.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
@@ -214,7 +215,7 @@
         return true;
       }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       // Chromebooks typically do not have an F11 key, so do not show an
       // accelerator here.
       return false;
@@ -248,7 +249,7 @@
 #endif
 
     case IDC_CONTENT_CLIPBOARD_HISTORY_MENU:
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       *accel = ui::Accelerator(ui::VKEY_V, ui::EF_COMMAND_DOWN);
       return true;
 #else
diff --git a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
index e1d1f24..5e86073 100644
--- a/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
+++ b/chrome/browser/ui/views/screen_capture_notification_ui_views.cc
@@ -7,6 +7,7 @@
 #include "base/macros.h"
 #include "base/scoped_multi_source_observation.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/views/chrome_views_export.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/theme_resources.h"
@@ -29,7 +30,7 @@
 #include "ui/views/win/hwnd_util.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/shell.h"
 #endif
 
@@ -195,7 +196,7 @@
   params.z_order = ui::ZOrderLevel::kFloatingUIElement;
   params.name = "ScreenCaptureNotificationUIViews";
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // TODO(sergeyu): The notification bar must be shown on the monitor that's
   // being captured. Make sure it's always the case. Currently we always capture
   // the primary monitor.
diff --git a/chrome/browser/ui/views/sharing/click_to_call_browsertest.cc b/chrome/browser/ui/views/sharing/click_to_call_browsertest.cc
index 5cced076..e6fc025c 100644
--- a/chrome/browser/ui/views/sharing/click_to_call_browsertest.cc
+++ b/chrome/browser/ui/views/sharing/click_to_call_browsertest.cc
@@ -13,6 +13,7 @@
 #include "base/test/bind.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/policy/policy_test_utils.h"
 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
@@ -373,7 +374,7 @@
 }
 
 // TODO(himanshujaju) - Add chromeos test for same flow.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, LeftClick_ChooseDevice) {
   Init(sync_pb::SharingSpecificFields::CLICK_TO_CALL_V2,
        sync_pb::SharingSpecificFields::UNKNOWN);
@@ -445,7 +446,7 @@
       GetPageActionIconView(PageActionIconType::kClickToCall)->GetBubble();
   ASSERT_NE(nullptr, bubble);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Ensure that the dialog shows the origin in column id 1.
   EXPECT_NE(nullptr, static_cast<views::GridLayout*>(
                          bubble->GetContentsView()->GetLayoutManager())
@@ -453,7 +454,7 @@
 #else
   // Ensure that the dialog shows the origin in the footnote.
   EXPECT_NE(nullptr, bubble->GetFootnoteViewForTesting());
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 IN_PROC_BROWSER_TEST_F(ClickToCallBrowserTest, NavigateDifferentOrigin) {
diff --git a/chrome/browser/ui/views/sharing/sharing_dialog_view.cc b/chrome/browser/ui/views/sharing/sharing_dialog_view.cc
index 5b7e201..92a032c2 100644
--- a/chrome/browser/ui/views/sharing/sharing_dialog_view.cc
+++ b/chrome/browser/ui/views/sharing/sharing_dialog_view.cc
@@ -8,6 +8,7 @@
 #include "base/optional.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/sharing/sharing_app.h"
 #include "chrome/browser/sharing/sharing_metrics.h"
@@ -33,7 +34,7 @@
 #include "ui/views/layout/box_layout.h"
 #include "url/origin.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/page_action/page_action_icon_type.h"
 #include "chrome/browser/ui/views/intent_picker_bubble_view.h"
 #endif
@@ -197,7 +198,7 @@
 // static
 views::BubbleDialogDelegateView* SharingDialogView::GetAsBubbleForClickToCall(
     SharingDialog* dialog) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (!dialog) {
     auto* bubble = IntentPickerBubbleView::intent_picker_bubble();
     if (bubble && bubble->icon_type() == PageActionIconType::kClickToCall)
diff --git a/chrome/browser/ui/views/status_bubble_views.cc b/chrome/browser/ui/views/status_bubble_views.cc
index 08cf487..df98294 100644
--- a/chrome/browser/ui/views/status_bubble_views.cc
+++ b/chrome/browser/ui/views/status_bubble_views.cc
@@ -17,6 +17,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "cc/paint/paint_flags.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "components/url_formatter/elide_url.h"
@@ -45,7 +46,7 @@
 #include "ui/views/widget/widget.h"
 #include "url/gurl.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/window_properties.h"
 #include "ui/aura/window.h"
 #endif
@@ -663,11 +664,11 @@
     params.parent = frame->GetNativeView();
     params.context = frame->GetNativeWindow();
     params.name = "StatusBubble";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     params.init_properties_container.SetProperty(ash::kHideInOverviewKey, true);
     params.init_properties_container.SetProperty(ash::kHideInDeskMiniViewKey,
                                                  true);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
     popup_->Init(std::move(params));
     // We do our own animation and don't want any from the system.
     popup_->SetVisibilityChangedAnimationsEnabled(false);
diff --git a/chrome/browser/ui/views/status_icons/status_tray_linux.cc b/chrome/browser/ui/views/status_icons/status_tray_linux.cc
index 6bba045..c74b608 100644
--- a/chrome/browser/ui/views/status_icons/status_tray_linux.cc
+++ b/chrome/browser/ui/views/status_icons/status_tray_linux.cc
@@ -7,8 +7,9 @@
 #include <memory>
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.h"
 
 StatusTrayLinux::StatusTrayLinux() {
@@ -27,7 +28,7 @@
 std::unique_ptr<StatusTray> StatusTray::Create() {
   return std::make_unique<StatusTrayLinux>();
 }
-#else  // defined(OS_CHROMEOS)
+#else  // BUILDFLAG(IS_CHROMEOS_ASH)
 std::unique_ptr<StatusTray> StatusTray::Create() {
   return nullptr;
 }
diff --git a/chrome/browser/ui/views/tab_dialogs_views.cc b/chrome/browser/ui/views/tab_dialogs_views.cc
index fe0bcc8..4b364af 100644
--- a/chrome/browser/ui/views/tab_dialogs_views.cc
+++ b/chrome/browser/ui/views/tab_dialogs_views.cc
@@ -8,12 +8,13 @@
 #include <utility>
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/views/collected_cookies_views.h"
 #include "chrome/browser/ui/views/hung_renderer_view.h"
 #include "chrome/browser/ui/views/passwords/password_bubble_view_base.h"
 #include "content/public/browser/web_contents.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/sync/profile_signin_confirmation_dialog_views.h"
 #endif
 
@@ -62,7 +63,7 @@
     Profile* profile,
     const std::string& username,
     std::unique_ptr<ui::ProfileSigninConfirmationDelegate> delegate) {
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   ProfileSigninConfirmationDialogViews::ShowDialog(browser, profile, username,
                                                    std::move(delegate));
 #else
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc
index 01695dc..8c73fc2 100644
--- a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc
+++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.cc
@@ -10,6 +10,7 @@
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/profiles/profile_manager.h"
@@ -34,7 +35,7 @@
 
 namespace {
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 const int kContentsBorderThickness = 5;
 const float kContentsBorderOpacity = 0.50;
 const SkColor kContentsBorderColor = gfx::kGoogleBlue500;
@@ -77,7 +78,7 @@
 
 void SetContentsBorderVisible(content::WebContents* contents, bool visible) {
   // TODO(https://crbug.com/1030925) fix contents border on ChromeOS.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   if (!contents)
     return;
   Browser* browser = chrome::FindBrowserWithWebContents(contents);
@@ -128,7 +129,7 @@
   shared_tab_name_ = GetTabName(shared_tab_);
   profile_ = ProfileManager::GetLastUsedProfileAllowedByPolicy();
   // TODO(https://crbug.com/1030925) fix contents border on ChromeOS.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   InitContentsBorderWidget(shared_tab_);
 #endif
 }
diff --git a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
index 4933983..3cea05d 100644
--- a/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
+++ b/chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/views/tab_sharing/tab_sharing_ui_views.h"
 
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/ui/browser.h"
@@ -91,7 +92,7 @@
                 int shared_tab_index,
                 size_t infobar_count = 1,
                 bool has_border = true) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     // TODO(https://crbug.com/1030925) fix contents border on ChromeOS.
     has_border = false;
 #endif
@@ -335,7 +336,7 @@
   // Check that the border is only displayed on the last shared tab (known
   // limitation https://crbug.com/996631).
   views::Widget* contents_border = GetContentsBorder(browser());
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // TODO(https://crbug.com/1030925) fix contents border on ChromeOS.
   EXPECT_EQ(nullptr, contents_border);
 #else
diff --git a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
index a36951c..e59304b 100644
--- a/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
+++ b/chrome/browser/ui/views/tabs/browser_tab_strip_controller.cc
@@ -16,6 +16,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/autocomplete/autocomplete_classifier_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -79,7 +80,7 @@
 bool DetermineTabStripLayoutStacked(PrefService* prefs, bool* adjust_layout) {
   *adjust_layout = false;
   // For ash, always allow entering stacked mode.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   *adjust_layout = true;
   return prefs->GetBoolean(prefs::kTabStripStackedLayout);
 #else
diff --git a/chrome/browser/ui/views/tabs/new_tab_button.cc b/chrome/browser/ui/views/tabs/new_tab_button.cc
index c94ab7d..a63fdc3 100644
--- a/chrome/browser/ui/views/tabs/new_tab_button.cc
+++ b/chrome/browser/ui/views/tabs/new_tab_button.cc
@@ -9,6 +9,7 @@
 
 #include "base/strings/string_number_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/layout_constants.h"
@@ -57,7 +58,9 @@
 NewTabButton::NewTabButton(TabStrip* tab_strip, PressedCallback callback)
     : views::ImageButton(std::move(callback)), tab_strip_(tab_strip) {
   SetAnimateOnStateChange(true);
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   SetTriggerableEventFlags(GetTriggerableEventFlags() |
                            ui::EF_MIDDLE_MOUSE_BUTTON);
 #endif
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.cc b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
index 3355b104..96e0925 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.cc
@@ -17,6 +17,7 @@
 #include "base/numerics/safe_conversions.h"
 #include "base/stl_util.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -50,7 +51,7 @@
 #include "ui/views/view_tracker.h"
 #include "ui/views/widget/root_view.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/ash_features.h"
 #include "ash/public/cpp/tablet_mode.h"
 #include "ash/public/cpp/window_properties.h"  // nogncheck
@@ -89,7 +90,7 @@
 // maximized size.
 constexpr int kMaximizedWindowInset = 10;  // DIPs.
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Returns the aura::Window which stores the window properties for tab-dragging.
 aura::Window* GetWindowForTabDraggingProperties(const TabDragContext* context) {
@@ -176,7 +177,7 @@
   return true;
 }
 
-#endif  // #if defined(OS_CHROMEOS)
+#endif  // #if BUILDFLAG(IS_CHROMEOS_ASH)
 
 void SetCapture(TabDragContext* context) {
   context->AsView()->GetWidget()->SetCapture(context->AsView());
@@ -296,7 +297,7 @@
 
 TabDragController::TabDragData::TabDragData(TabDragData&&) = default;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 // The class to track the current deferred target tabstrip and also to observe
 // its native window's property ash::kIsDeferredTabDraggingTargetWindowKey.
@@ -591,7 +592,7 @@
         drag_offset = GetWindowOffset(point_in_screen);
       }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       StoreCurrentDraggedBrowserBoundsInTabletMode(widget->GetNativeWindow(),
                                                    new_bounds);
 #endif
@@ -624,7 +625,7 @@
     return;
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // It's possible that in Chrome OS we defer the windows that are showing in
   // overview to attach into during dragging. If so we need to attach the
   // dragged tabs to it first.
@@ -697,7 +698,7 @@
   // NULL out source_context_ so that we don't attempt to add back to it (in
   // the case of a revert).
   source_context_ = nullptr;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Also update the source window info for the current dragged window.
   if (attached_context_) {
     GetWindowForTabDraggingProperties(attached_context_)
@@ -881,11 +882,11 @@
     // ReleaseCapture() is going to result in calling back to us (because it
     // results in a move). That'll cause all sorts of problems.  Reset the
     // observer so we don't get notified and process the event.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     if (widget_observation_.IsObservingSource(move_loop_widget_))
       widget_observation_.RemoveObservation();
     move_loop_widget_ = nullptr;
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
     views::Widget* browser_widget = GetAttachedBrowserWidget();
     // Need to release the drag controller before starting the move loop as it's
     // going to trigger capture lost, which cancels drag.
@@ -898,7 +899,9 @@
     else
       SetCapture(target_context);
 
-#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
     // EndMoveLoop is going to snap the window back to its original location.
     // Hide it so users don't see this. Hiding a window in Linux aura causes
     // it to lose capture so skip it.
@@ -1365,7 +1368,7 @@
       ui::TransferTouchesBehavior::kDontCancel);
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // On ChromeOS, Detach should release capture; |can_release_capture_| is
   // false on ChromeOS because it can cancel touches, but for this cases
   // the touches are already transferred, so releasing is fine. Without
@@ -1552,7 +1555,7 @@
 }
 
 void TabDragController::PerformDeferredAttach() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   TabDragContext* deferred_target_context =
       deferred_target_context_observer_->deferred_target_context();
   if (!deferred_target_context)
@@ -1804,7 +1807,7 @@
   if (was_source_fullscreen_)
     GetAttachedBrowserWidget()->SetFullscreen(true);
 #endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (was_source_fullscreen_) {
     // In fullscreen mode it is only possible to get here if the source
     // was in "immersive fullscreen" mode, so toggle it back on.
@@ -1836,7 +1839,7 @@
     if (!widget_window)
       return;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     // TODO(varkha): The code below ensures that the phantom drag widget
     // is shown on top of browser windows. The code should be moved to ash/
     // and the phantom should be able to assert its top-most state on its own.
@@ -1921,7 +1924,7 @@
     new_bounds.set_height(std::max(max_size.height() / 2, new_bounds.height()));
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (ash::TabletMode::Get()->InTabletMode()) {
     new_bounds = GetDraggedBrowserBoundsInTabletMode(
         source->AsView()->GetWidget()->GetNativeWindow());
@@ -1961,7 +1964,7 @@
     views::Widget* widget,
     const gfx::Point& point_in_screen) {
   gfx::Rect bounds = widget->GetWindowBoundsInScreen();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (ash::TabletMode::Get()->InTabletMode())
     bounds = GetDraggedBrowserBoundsInTabletMode(widget->GetNativeWindow());
 #endif
@@ -2048,7 +2051,7 @@
 }
 
 gfx::Point TabDragController::GetCursorScreenPoint() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (event_source_ == EVENT_SOURCE_TOUCH &&
       aura::Env::GetInstance()->is_touch_down()) {
     views::Widget* widget = GetAttachedBrowserWidget();
@@ -2092,7 +2095,9 @@
     if (dragged_window)
       exclude.insert(dragged_window);
   }
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   // Exclude windows which are pending deletion via Browser::TabStripEmpty().
   // These windows can be returned in the Linux Aura port because the browser
   // window which was used for dragging is not hidden once all of its tabs are
@@ -2109,7 +2114,7 @@
 }
 
 void TabDragController::SetTabDraggingInfo() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   TabDragContext* dragged_context =
       attached_context_ ? attached_context_ : source_context_;
   DCHECK(dragged_context->IsDragSessionActive() &&
@@ -2128,7 +2133,7 @@
 }
 
 void TabDragController::ClearTabDraggingInfo() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   TabDragContext* dragged_context =
       attached_context_ ? attached_context_ : source_context_;
   DCHECK(!dragged_context->IsDragSessionActive() ||
@@ -2307,7 +2312,7 @@
 
 void TabDragController::SetDeferredTargetTabstrip(
     TabDragContext* deferred_target_context) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (!deferred_target_context_observer_) {
     deferred_target_context_observer_ =
         std::make_unique<DeferredTargetTabstripObserver>();
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller.h b/chrome/browser/ui/views/tabs/tab_drag_controller.h
index bed51f2e..fcdf471 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller.h
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller.h
@@ -13,6 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observation.h"
 #include "base/timer/timer.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/tabs/tab_strip_model_observer.h"
 #include "chrome/browser/ui/views/tabs/tab_drag_context.h"
 #include "chrome/browser/ui/views/tabs/tab_strip_types.h"
@@ -146,7 +147,7 @@
  private:
   friend class TabDragControllerTest;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   class DeferredTargetTabstripObserver;
 #endif
 
@@ -543,7 +544,7 @@
   // null if the dragged Tab is detached.
   TabDragContext* attached_context_;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Observe the target TabDragContext to attach to after the drag
   // ends. It's only possible to happen in Chrome OS tablet mode, if the dragged
   // tabs are dragged over an overview window, we should wait until the drag
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
index 69e2c7c8..b96aef2 100644
--- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
+++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -27,6 +27,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/installable/installable_metrics.h"
 #include "chrome/browser/ui/browser.h"
@@ -75,12 +76,12 @@
 #include "ui/aura/window_targeter.h"
 #endif
 
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h"
 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/ash_switches.h"
 #include "ash/public/cpp/split_view_test_api.h"
 #include "ash/public/cpp/test/shell_test_api.h"
@@ -108,7 +109,9 @@
 #include "base/mac/mac_util.h"
 #endif
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 #include "chrome/browser/ui/views/frame/desktop_browser_frame_aura_linux.h"
 #define DESKTOP_BROWSER_FRAME_AURA DesktopBrowserFrameAuraLinux
 #else
@@ -137,7 +140,7 @@
   int id_;
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 aura::Window* GetWindowForTabStrip(TabStrip* tab_strip) {
   return tab_strip ? tab_strip->GetWidget()->GetNativeWindow() : nullptr;
 }
@@ -322,7 +325,7 @@
 }
 
 bool GetIsDragged(Browser* browser) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   return ash::WindowState::Get(browser->window()->GetNativeWindow())
       ->is_dragged();
 #endif
@@ -331,7 +334,7 @@
 
 }  // namespace
 
-#if !defined(OS_CHROMEOS) && defined(USE_AURA)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && defined(USE_AURA)
 
 // Following classes verify a crash scenario. Specifically on Windows when focus
 // changes it can trigger capture being lost. This was causing a crash in tab
@@ -450,7 +453,7 @@
       const DetachToBrowserTabDragControllerTest&) = delete;
 
   void SetUpOnMainThread() override {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     root_ = browser()->window()->GetNativeWindow()->GetRootWindow();
     // Disable flings which might otherwise inadvertently be generated from
     // tests' touch events.
@@ -470,7 +473,7 @@
         INPUT_SOURCE_MOUSE : INPUT_SOURCE_TOUCH;
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   bool SendTouchEventsSync(int action, int id, const gfx::Point& location) {
     base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
     if (!ui_controls::SendTouchEventsNotifyWhenDone(
@@ -490,7 +493,7 @@
           ui_test_utils::SendMouseEventsSync(
               ui_controls::LEFT, ui_controls::DOWN);
     }
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     return SendTouchEventsSync(ui_controls::PRESS, id, location);
 #else
     NOTREACHED();
@@ -501,7 +504,7 @@
   bool DragInputTo(const gfx::Point& location) {
     if (input_source() == INPUT_SOURCE_MOUSE)
       return ui_test_utils::SendMouseMoveSync(location);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     return SendTouchEventsSync(ui_controls::MOVE, 0, location);
 #else
     NOTREACHED();
@@ -512,7 +515,7 @@
   bool DragInputToAsync(const gfx::Point& location) {
     if (input_source() == INPUT_SOURCE_MOUSE)
       return ui_controls::SendMouseMove(location.x(), location.y());
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     return ui_controls::SendTouchEvents(ui_controls::MOVE, 0, location.x(),
                                         location.y());
 #else
@@ -528,7 +531,7 @@
           location.x(), location.y(), std::move(task));
     }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     return ui_controls::SendTouchEventsNotifyWhenDone(
         ui_controls::MOVE, 0, location.x(), location.y(), std::move(task));
 #else
@@ -544,7 +547,7 @@
                    : ui_test_utils::SendMouseEventsSync(ui_controls::LEFT,
                                                         ui_controls::UP);
     }
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     return async ? ui_controls::SendTouchEvents(ui_controls::RELEASE, id, 0, 0)
                  : SendTouchEventsSync(ui_controls::RELEASE, id, gfx::Point());
 #else
@@ -576,7 +579,7 @@
     aura::Env::GetInstance()->SetLastMouseLocation(location);
     if (input_source() == INPUT_SOURCE_MOUSE)
       return ui_test_utils::SendMouseMoveSync(location);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     return SendTouchEventsSync(ui_controls::MOVE, 0, location);
 #else
     NOTREACHED();
@@ -593,7 +596,7 @@
   bool IsTabDraggingInfoSet(TabStrip* attached_tabstrip,
                             TabStrip* source_tabstrip) {
     DCHECK(attached_tabstrip);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     aura::Window* dragged_window =
         test::GetWindowForTabStrip(attached_tabstrip);
     attached_tabstrip->GetWidget()->GetNativeWindow();
@@ -613,7 +616,7 @@
   // browser window.
   bool IsTabDraggingInfoCleared(TabStrip* attached_tabstrip) {
     DCHECK(attached_tabstrip);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     aura::Window* dragged_window =
         test::GetWindowForTabStrip(attached_tabstrip);
     return !dragged_window->GetProperty(ash::kIsDraggingTabsKey) &&
@@ -665,7 +668,7 @@
   Browser* browser() const { return InProcessBrowserTest::browser(); }
 
  private:
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // The root window for the event generator.
   aura::Window* root_ = nullptr;
 #endif
@@ -1481,7 +1484,7 @@
 
 namespace {
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 bool IsWindowPositionManaged(aura::Window* window) {
   return window->GetProperty(ash::kWindowPositionManagedTypeKey);
 }
@@ -1704,7 +1707,7 @@
 }
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 // This test makes sense only on Chrome OS where we have the immersive
 // fullscreen mode. The detached tab to a new browser window should remain in
@@ -2727,7 +2730,7 @@
   ASSERT_FALSE(TabDragController::IsActive());
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 namespace {
 
 void DragInMaximizedWindowStep2(DetachToBrowserTabDragControllerTest* test,
@@ -3215,7 +3218,9 @@
 
   // TODO(crbug.com/1110266): Remove explicit OS_CHROMEOS check once OS_LINUX
   // CrOS cleanup is done.
-#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
   // Get this new created window for the drag. It should have fast resize set.
   Browser* new_browser = test->browser_list->get(2);
   EXPECT_TRUE(WebContentsIsFastResized(new_browser));
@@ -3616,7 +3621,7 @@
 }
 
 // Crashes on ChromeOS. crbug.com/1003288
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_DragBrowserWindowWhenMajorityOfBoundsInSecondDisplay \
   DISABLED_CDragBrowserWindowWhenMajorityOfBoundsInSecondDisplay
 #else
@@ -4344,9 +4349,9 @@
   EXPECT_EQ(2u, browser_list->size());
 }
 
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 INSTANTIATE_TEST_SUITE_P(TabDragging,
                          DetachToBrowserTabDragControllerTest,
                          ::testing::Values("mouse", "touch"));
diff --git a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
index cba52641..4139d63b 100644
--- a/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
+++ b/chrome/browser/ui/views/tabs/tab_hover_card_bubble_view.cc
@@ -11,6 +11,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/metrics/tab_count_metrics.h"
 #include "chrome/browser/themes/theme_properties.h"
@@ -50,7 +51,7 @@
 #include "ui/base/win/shell.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/metrics_util.h"
 #include "base/optional.h"
 #endif
@@ -59,7 +60,7 @@
 // Maximum number of lines that a title label occupies.
 constexpr int kHoverCardTitleMaxLines = 2;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // UMA histograms that record animation smoothness for fade-in and fade-out
 // animations of tab hover card.
 constexpr char kHoverCardFadeInSmoothnessHistogramName[] =
@@ -209,7 +210,7 @@
     widget_->Show();
     fade_animation_ = std::make_unique<gfx::LinearAnimation>(this);
     fade_animation_->SetDuration(kFadeInDuration);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     throughput_tracker_.emplace(
         widget_->GetCompositor()->RequestNewThroughputTracker());
     throughput_tracker_->Start(ash::metrics_util::ForSmoothness(
@@ -226,7 +227,7 @@
     fade_animation_ = std::make_unique<gfx::LinearAnimation>(this);
     set_animation_state(FadeAnimationState::FADE_OUT);
     fade_animation_->SetDuration(kFadeOutDuration);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     throughput_tracker_.emplace(
         widget_->GetCompositor()->RequestNewThroughputTracker());
     throughput_tracker_->Start(ash::metrics_util::ForSmoothness(
@@ -240,7 +241,7 @@
       return;
 
     fade_animation_->Stop();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     throughput_tracker_->Cancel();
 #endif
     set_animation_state(FadeAnimationState::IDLE);
@@ -268,14 +269,14 @@
 
   void AnimationEnded(const gfx::Animation* animation) override {
     AnimationProgressed(animation);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     throughput_tracker_->Stop();
 #endif
     set_animation_state(FadeAnimationState::IDLE);
   }
 
   views::Widget* const widget_;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   base::Optional<ui::ThroughputTracker> throughput_tracker_;
 #endif
   std::unique_ptr<gfx::LinearAnimation> fade_animation_;
diff --git a/chrome/browser/ui/views/tabs/tab_strip.cc b/chrome/browser/ui/views/tabs/tab_strip.cc
index caf4768..8b334f9 100644
--- a/chrome/browser/ui/views/tabs/tab_strip.cc
+++ b/chrome/browser/ui/views/tabs/tab_strip.cc
@@ -31,6 +31,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/timer/elapsed_timer.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/ui/layout_constants.h"
@@ -2892,7 +2893,7 @@
 // everything shifts. Instead we wait for the release.
 //
 // TODO(sky): revisit this when touch events are really plumbed through.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   constexpr auto kMouseMoveTime = base::TimeDelta::FromMilliseconds(200);
   constexpr int kMouseMoveCountBeforeConsiderReal = 3;
 #endif
@@ -2914,7 +2915,7 @@
       break;
 
     case ui::ET_MOUSE_MOVED: {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       // Ash does not synthesize mouse events from touch events.
       SetResetToShrinkOnExit(true);
 #else
diff --git a/chrome/browser/ui/views/task_manager_view.cc b/chrome/browser/ui/views/task_manager_view.cc
index 699a49c4..08c2d31 100644
--- a/chrome/browser/ui/views/task_manager_view.cc
+++ b/chrome/browser/ui/views/task_manager_view.cc
@@ -8,6 +8,7 @@
 
 #include "base/callback_helpers.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/profiles/profile_window.h"
@@ -34,14 +35,14 @@
 #include "ui/views/view.h"
 #include "ui/views/widget/widget.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/shelf_item.h"
 #include "ash/public/cpp/window_properties.h"
 #include "chrome/grit/theme_resources.h"
 #include "ui/aura/window.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image_skia.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_WIN)
 #include "chrome/browser/shell_integration_win.h"
@@ -95,7 +96,7 @@
   g_task_manager_view->SelectTaskOfActiveTab(browser);
   g_task_manager_view->GetWidget()->Show();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   aura::Window* window = g_task_manager_view->GetWidget()->GetNativeWindow();
   // An app id for task manager windows, also used to identify the shelf item.
   // Generated as crx_file::id_util::GenerateId("org.chromium.taskmanager")
@@ -166,7 +167,7 @@
 }
 
 gfx::ImageSkia TaskManagerView::GetWindowIcon() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   return *ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(
       IDR_ASH_SHELF_ICON_TASK_MANAGER);
 #else
diff --git a/chrome/browser/ui/views/test/view_event_test_base.cc b/chrome/browser/ui/views/test/view_event_test_base.cc
index caefa134..b37f8c4b 100644
--- a/chrome/browser/ui/views/test/view_event_test_base.cc
+++ b/chrome/browser/ui/views/test/view_event_test_base.cc
@@ -8,6 +8,7 @@
 #include "base/location.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/test/base/chrome_unit_test_suite.h"
 #include "chrome/test/base/interactive_test_utils.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -17,7 +18,7 @@
 #include "ui/views/widget/widget.h"
 #include "ui/views/widget/widget_delegate.h"
 
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ui/display/screen.h"
 #include "ui/views/widget/desktop_aura/desktop_screen.h"
 
@@ -25,9 +26,10 @@
 #include "ui/views/test/test_desktop_screen_x11.h"
 #endif  // defined(USE_X11)
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_OZONE)
+#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && defined(USE_OZONE)
 #include "ui/views/test/test_desktop_screen_ozone.h"
-#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_OZONE)
+#endif  // (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) &&
+        // defined(USE_OZONE)
 #endif
 
 namespace {
@@ -95,7 +97,7 @@
   // in a new process.
   mojo::core::Init();
 
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
   // TODO(pkasting): Determine why the TestScreen in AuraTestHelper is
   // insufficient for these tests, then either bolster/replace it or fix the
   // tests.
@@ -104,7 +106,7 @@
   if (!features::IsUsingOzonePlatform())
     views::test::TestDesktopScreenX11::GetInstance();
 #endif  // defined(USE_X11)
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_OZONE)
+#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && defined(USE_OZONE)
   if (!display::Screen::GetScreen())
     display::Screen::SetScreenInstance(
         views::test::TestDesktopScreenOzone::GetInstance());
diff --git a/chrome/browser/ui/views/test/view_event_test_base.h b/chrome/browser/ui/views/test/view_event_test_base.h
index f9b2509..9c4dd72 100644
--- a/chrome/browser/ui/views/test/view_event_test_base.h
+++ b/chrome/browser/ui/views/test/view_event_test_base.h
@@ -19,9 +19,10 @@
 #include "base/run_loop.h"
 #include "base/threading/thread.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/test/views/chrome_views_test_base.h"
 
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
 namespace display {
 class Screen;
 }
@@ -122,7 +123,7 @@
   // failures invokes Done.
   void RunTestMethod(base::OnceClosure task);
 
-#if defined(USE_AURA) && !defined(OS_CHROMEOS)
+#if defined(USE_AURA) && !BUILDFLAG(IS_CHROMEOS_ASH)
   std::unique_ptr<display::Screen> screen_;
 #endif
 
diff --git a/chrome/browser/ui/views/toolbar/app_menu.cc b/chrome/browser/ui/views/toolbar/app_menu.cc
index 9638ae8e..23d02c8 100644
--- a/chrome/browser/ui/views/toolbar/app_menu.cc
+++ b/chrome/browser/ui/views/toolbar/app_menu.cc
@@ -17,6 +17,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
@@ -90,7 +91,7 @@
 // Horizontal padding on the edges of the in-menu buttons.
 const int kHorizontalPadding = 15;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Extra horizontal space to reserve for the fullscreen button.
 const int kFullscreenPadding = 74;
 // Padding to left and right of the XX% label.
@@ -1023,7 +1024,7 @@
     MenuItemView* item =
         AddMenuItem(parent, menu_index, model, i, model->GetTypeAt(i));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     if (model->GetCommandIdAt(i) == IDC_EDIT_MENU ||
         model->GetCommandIdAt(i) == IDC_ZOOM_MENU) {
       // ChromeOS adds extra vertical space for the menu buttons.
@@ -1079,7 +1080,7 @@
         break;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       case IDC_TAKE_SCREENSHOT:
         DCHECK(!screenshot_menu_item_);
         screenshot_menu_item_ = item;
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
index 2afb7cc..4b44a49 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
@@ -11,6 +11,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "build/chromeos_buildflags.h"
 #include "cc/paint/paint_flags.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_otr_state.h"
@@ -49,9 +50,9 @@
 #include "ui/views/view.h"
 #include "ui/views/view_class_properties.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/ash/keyboard/chrome_keyboard_controller_client.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace {
 
@@ -162,7 +163,7 @@
   if (IsMenuShowing())
     return;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   auto* keyboard_client = ChromeKeyboardControllerClient::Get();
   if (keyboard_client->is_keyboard_visible())
     keyboard_client->HideKeyboard(ash::HideReason::kSystem);
diff --git a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
index de1e3da..b36586b4 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_action_view_interactive_uitest.cc
@@ -9,6 +9,7 @@
 #include "base/test/scoped_feature_list.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/ui/extensions/extension_action_view_controller.h"
@@ -211,7 +212,7 @@
 // TODO(crbug.com/963678): fails on ChromeOS as it's assuming SendMouseMove()
 // synchronously updates the location of the mouse (which is needed by
 // SendMouseClick()).
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
 // TODO(pkasting): https://crbug.com/911374 Menu controller thinks the mouse is
 // already down when handling the left click.
 // TODO(crbug.com/1092372): Flaky on Win7.
@@ -383,7 +384,7 @@
 // TODO(crbug.com/963678): fails on ChromeOS as it's assuming SendMouseMove()
 // synchronously updates the location of the mouse (which is needed by
 // SendMouseClick()).
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_ActivateOverflowedToolbarActionWithKeyboard \
   DISABLED_ActivateOverflowedToolbarActionWithKeyboard
 #else
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc
index 08e2d3e..7c69efc 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -12,6 +12,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/themes/theme_properties.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
@@ -470,7 +471,7 @@
 
   gfx::Rect menu_anchor_bounds = GetAnchorBoundsInScreen();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // A window won't overlap between displays on ChromeOS.
   // Use the left bound of the display on which
   // the menu button exists.
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.cc b/chrome/browser/ui/views/toolbar/toolbar_view.cc
index 058a014..89ec773 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.cc
@@ -16,6 +16,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/command_updater.h"
 #include "chrome/browser/media/router/media_router_feature.h"
@@ -94,7 +95,7 @@
 #include "chrome/browser/ui/views/critical_notification_bubble_view.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chromeos/constants/chromeos_features.h"
 #else
 #include "chrome/browser/signin/signin_global_error_factory.h"
@@ -113,7 +114,7 @@
 
 // Gets the display mode for a given browser.
 ToolbarView::DisplayMode GetDisplayMode(Browser* browser) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (browser->is_type_custom_tab())
     return ToolbarView::DisplayMode::CUSTOM_TAB;
 #endif
@@ -241,7 +242,7 @@
   std::unique_ptr<ToolbarAccountIconContainerView>
       toolbar_account_icon_container;
   bool show_avatar_toolbar_button = true;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (!base::FeatureList::IsEnabled(chromeos::features::kAvatarToolbarButton)) {
     // ChromeOS only badges Incognito and Guest icons in the browser window.
     show_avatar_toolbar_button = browser_->profile()->IsOffTheRecord() ||
@@ -301,12 +302,12 @@
   LoadImages();
 
   // Start global error services now so we set the icon on the menu correctly.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   SigninGlobalErrorFactory::GetForProfile(browser_->profile());
 #if defined(OS_WIN) || defined(OS_MAC)
   RecoveryInstallGlobalErrorFactory::GetForProfile(browser_->profile());
 #endif
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // Set the button icon based on the system state. Do this after
   // |app_menu_button_| has been added as a bubble may be shown that needs
@@ -440,7 +441,7 @@
       GetPageActionIconView(PageActionIconType::kBookmarkStar);
 
   std::unique_ptr<BubbleSyncPromoDelegate> delegate;
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   // ChromeOS does not show the signin promo.
   delegate = std::make_unique<BookmarkBubbleSignInDelegate>(browser_);
 #endif
@@ -910,7 +911,7 @@
 }
 
 void ToolbarView::ShowOutdatedInstallNotification(bool auto_update_enabled) {
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   OutdatedUpgradeBubbleView::ShowBubble(app_menu_button_, browser_,
                                         auto_update_enabled);
 #endif
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view.h b/chrome/browser/ui/views/toolbar/toolbar_view.h
index 1a00af8..2cf0996 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view.h
+++ b/chrome/browser/ui/views/toolbar/toolbar_view.h
@@ -12,6 +12,7 @@
 #include "base/observer_list.h"
 #include "base/optional.h"
 #include "base/scoped_observation.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/command_observer.h"
 #include "chrome/browser/ui/page_action/page_action_icon_type.h"
 #include "chrome/browser/ui/toolbar/app_menu_icon_controller.h"
@@ -33,11 +34,11 @@
 #include "ui/views/view.h"
 #include "url/origin.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/arc/intent_helper/arc_intent_picker_app_fetcher.h"
 #include "components/arc/intent_helper/arc_intent_helper_bridge.h"
 #include "components/arc/mojom/intent_helper.mojom-forward.h"  // nogncheck https://crbug.com/784179
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 class AppMenuButton;
 class AvatarToolbarButton;
diff --git a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
index 48535ca..7c2aec6 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_view_interactive_uitest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
 #include "chrome/browser/browser_process.h"
@@ -355,7 +356,7 @@
 }
 
 // TODO(crbug.com/991596): Setup test profiles properly for CrOS.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_ToolbarForGuestHasNoExtensionsToolbarContainer \
   DISABLED_ToolbarForGuestHasNoExtensionsToolbarContainer
 #else
diff --git a/chrome/browser/ui/views/translate/translate_language_browsertest.cc b/chrome/browser/ui/views/translate/translate_language_browsertest.cc
index 734ff17..136670c 100644
--- a/chrome/browser/ui/views/translate/translate_language_browsertest.cc
+++ b/chrome/browser/ui/views/translate/translate_language_browsertest.cc
@@ -1,6 +1,8 @@
 // Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
+#include "build/chromeos_buildflags.h"
+
 #if defined(USE_AURA)
 
 #include <stddef.h>
@@ -241,7 +243,9 @@
 }
 
 // https://crbug.com/863241
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 #define MAYBE_DontLogInIncognito DISABLED_DontLogInIncognito
 #else
 #define MAYBE_DontLogInIncognito DontLogInIncognito
diff --git a/chrome/browser/ui/views/update_recommended_message_box.cc b/chrome/browser/ui/views/update_recommended_message_box.cc
index 01fe7b4..0882311 100644
--- a/chrome/browser/ui/views/update_recommended_message_box.cc
+++ b/chrome/browser/ui/views/update_recommended_message_box.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/views/update_recommended_message_box.h"
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -16,7 +17,7 @@
 #include "ui/views/controls/message_box_view.h"
 #include "ui/views/widget/widget.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/power/power_manager_client.h"
 #endif
@@ -42,7 +43,7 @@
   SetOwnedByWidget(true);
   SetTitle(IDS_UPDATE_RECOMMENDED_DIALOG_TITLE);
   base::string16 update_message;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   update_message = l10n_util::GetStringUTF16(IDS_UPDATE_RECOMMENDED);
 #else
   update_message = l10n_util::GetPluralStringFUTF16(
@@ -66,7 +67,7 @@
 }
 
 bool UpdateRecommendedMessageBox::ShouldShowWindowTitle() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   return false;
 #else
   return true;
diff --git a/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_browsertest.cc
index 5f2e9673..5118c70 100644
--- a/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/view_ids.h"
@@ -85,7 +86,7 @@
 
   views::View* const window_title =
       helper()->frame_view()->GetViewByID(VIEW_ID_WINDOW_TITLE);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
   EXPECT_FALSE(window_title);
 #else
   EXPECT_EQ(window_title->parent(), helper()->frame_view());
@@ -115,7 +116,8 @@
   const int original_left_container_width = toolbar_left_container->width();
   EXPECT_GT(original_left_container_width, 0);
 
-#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(OS_WIN) || (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
+                        !BUILDFLAG(IS_CHROMEOS_LACROS))
   const int original_window_title_width = window_title->width();
   EXPECT_GT(original_window_title_width, 0);
 #endif
@@ -139,7 +141,8 @@
   EXPECT_TRUE(toolbar_left_container->GetVisible());
   EXPECT_EQ(toolbar_left_container->width(), original_left_container_width);
 
-#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(OS_WIN) || (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
+                        !BUILDFLAG(IS_CHROMEOS_LACROS))
   EXPECT_GT(window_title->width(), 0);
   EXPECT_LT(window_title->width(), original_window_title_width);
 #endif
@@ -164,7 +167,8 @@
   EXPECT_FALSE(toolbar_left_container->GetVisible());
 
   // The window title should be clipped to 0 width.
-#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+#if defined(OS_WIN) || (defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_ASH) && \
+                        !BUILDFLAG(IS_CHROMEOS_LACROS))
   EXPECT_EQ(window_title->width(), 0);
 #endif
 
@@ -183,7 +187,9 @@
       helper()->app_browser()->tab_strip_model()->GetActiveWebContents();
   content::AwaitDocumentOnLoadCompleted(web_contents);
 
-#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
   // Avoid dependence on Linux GTK+ Themes appearance setting.
 
   ToolbarButtonProvider* const toolbar_button_provider =
@@ -227,7 +233,7 @@
 
   auto* const window_title = static_cast<views::Label*>(
       helper()->frame_view()->GetViewByID(VIEW_ID_WINDOW_TITLE));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
   // Chrome OS PWA windows do not display app titles.
   EXPECT_EQ(nullptr, window_title);
   return;
diff --git a/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc b/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc
index 158a209b..4da44fd 100644
--- a/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_frame_toolbar_view.cc
@@ -13,6 +13,7 @@
 #include "base/task_runner.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/timer/timer.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/command_observer.h"
@@ -87,7 +88,7 @@
 
 constexpr int kPaddingBetweenNavigationButtons = 9;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 constexpr int kWebAppFrameLeftMargin = 4;
 #else
 constexpr int kWebAppFrameLeftMargin = 9;
diff --git a/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc
index ae3bdc14e..c4c2c4c 100644
--- a/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_tab_strip_browsertest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "base/test/scoped_feature_list.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser_commands.h"
@@ -126,7 +127,7 @@
 }
 
 // TODO(crbug.com/897314) Enabled tab strip for web apps on non-Chrome OS.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 IN_PROC_BROWSER_TEST_F(WebAppTabStripBrowserTest,
                        ActiveTabColorIsBackgroundColor) {
@@ -180,6 +181,6 @@
   }
 }
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace web_app
diff --git a/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_browsertest.cc b/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_browsertest.cc
index 07f4b7b..cc47f6b1 100644
--- a/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_browsertest.cc
+++ b/chrome/browser/ui/views/web_apps/web_app_uninstall_dialog_browsertest.cc
@@ -10,6 +10,7 @@
 #include "base/optional.h"
 #include "base/run_loop.h"
 #include "base/test/bind.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
@@ -153,7 +154,7 @@
   EXPECT_TRUE(was_uninstalled);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Test that we don't crash when uninstalling a web app from a web app window in
 // Ash. Context: crbug.com/825554
 IN_PROC_BROWSER_TEST_F(WebAppUninstallDialogViewBrowserTest,
@@ -176,7 +177,7 @@
     run_loop.RunUntilIdle();
   }
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 class WebAppUninstallDialogViewInteractiveBrowserTest
     : public DialogBrowserTest {
diff --git a/chrome/browser/ui/views/window_name_prompt.cc b/chrome/browser/ui/views/window_name_prompt.cc
index 449f9246..77b5983 100644
--- a/chrome/browser/ui/views/window_name_prompt.cc
+++ b/chrome/browser/ui/views/window_name_prompt.cc
@@ -43,9 +43,6 @@
 
   auto bubble = views::BubbleDialogModelHost::CreateModal(
       std::move(dialog_model), ui::MODAL_TYPE_WINDOW);
-  // TODO(pbos): Reconsider whether SetInitiallyFocusedView should imply
-  // initially-selected text.
-  bubble->SelectAllText(kWindowNameFieldId);
   return bubble;
 }
 
diff --git a/chrome/browser/ui/webui/about_ui.cc b/chrome/browser/ui/webui/about_ui.cc
index ea457a3..6c2f1250 100644
--- a/chrome/browser/ui/webui/about_ui.cc
+++ b/chrome/browser/ui/webui/about_ui.cc
@@ -39,6 +39,7 @@
 #include "base/threading/thread.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/about_flags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/defaults.h"
@@ -77,7 +78,7 @@
 #include "chrome/browser/ui/webui/theme_source.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include <map>
 
 #include "base/base64.h"
@@ -101,7 +102,7 @@
 constexpr char kStatsJsPath[] = "stats.js";
 constexpr char kStringsJsPath[] = "strings.js";
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 constexpr char kKeyboardUtilsPath[] = "keyboard_utils.js";
 
@@ -625,7 +626,7 @@
     int idr = IDR_ABOUT_UI_CREDITS_HTML;
     if (path == kCreditsJsPath)
       idr = IDR_ABOUT_UI_CREDITS_JS;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     else if (path == kKeyboardUtilsPath)
       idr = IDR_KEYBOARD_UTILS_JS;
 #endif
@@ -639,7 +640,7 @@
   } else if (source_name_ == chrome::kChromeUILinuxProxyConfigHost) {
     response = AboutLinuxProxyConfig();
 #endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   } else if (source_name_ == chrome::kChromeUIOSCreditsHost) {
     ChromeOSCreditsHandler::Start(path, std::move(callback));
     return;
@@ -649,7 +650,7 @@
 #endif
 #if !defined(OS_ANDROID)
   } else if (source_name_ == chrome::kChromeUITermsHost) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     if (!path.empty()) {
       ChromeOSTermsHandler::Start(path, std::move(callback));
       return;
@@ -672,19 +673,18 @@
 }
 
 std::string AboutUIHTMLSource::GetMimeType(const std::string& path) {
-  if (path == kCreditsJsPath     ||
-#if defined(OS_CHROMEOS)
+  if (path == kCreditsJsPath ||
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       path == kKeyboardUtilsPath ||
 #endif
-      path == kStatsJsPath       ||
-      path == kStringsJsPath) {
+      path == kStatsJsPath || path == kStringsJsPath) {
     return "application/javascript";
   }
   return "text/html";
 }
 
 bool AboutUIHTMLSource::ShouldAddContentSecurityPolicy() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (source_name_ == chrome::kChromeUIOSCreditsHost ||
       source_name_ == chrome::kChromeUICrostiniCreditsHost) {
     return false;
@@ -704,7 +704,7 @@
 
 std::string AboutUIHTMLSource::GetAccessControlAllowOriginForOrigin(
     const std::string& origin) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Allow chrome://oobe to load chrome://terms via XHR.
   if (source_name_ == chrome::kChromeUITermsHost &&
       base::StartsWith(chrome::kChromeUIOobeURL, origin,
diff --git a/chrome/browser/ui/webui/app_launcher_login_handler.cc b/chrome/browser/ui/webui/app_launcher_login_handler.cc
index 37b0093..8bd55aeb 100644
--- a/chrome/browser/ui/webui/app_launcher_login_handler.cc
+++ b/chrome/browser/ui/webui/app_launcher_login_handler.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
@@ -89,7 +90,7 @@
       "initializeSyncLogin",
       base::BindRepeating(&AppLauncherLoginHandler::HandleInitializeSyncLogin,
                           base::Unretained(this)));
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       "showSyncLoginUI",
       base::BindRepeating(&AppLauncherLoginHandler::HandleShowSyncLoginUI,
@@ -102,7 +103,7 @@
   UpdateLogin();
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void AppLauncherLoginHandler::HandleShowSyncLoginUI(
     const base::ListValue* args) {
   Profile* profile = Profile::FromWebUI(web_ui());
@@ -164,7 +165,7 @@
       }
     }
   } else {
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     // Chromeos does not show this status header.
     bool is_signin_allowed =
         profile->GetOriginalProfile()->GetPrefs()->GetBoolean(
@@ -202,7 +203,7 @@
 
 // static
 bool AppLauncherLoginHandler::ShouldShow(Profile* profile) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // For now we don't care about showing sync status on Chrome OS. The promo
   // UI and the avatar menu don't exist on that platform.
   return false;
diff --git a/chrome/browser/ui/webui/app_launcher_login_handler.h b/chrome/browser/ui/webui/app_launcher_login_handler.h
index da07c05d6..2a787f3 100644
--- a/chrome/browser/ui/webui/app_launcher_login_handler.h
+++ b/chrome/browser/ui/webui/app_launcher_login_handler.h
@@ -9,6 +9,7 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
 class Profile;
@@ -41,7 +42,7 @@
   // passed from JS and should be an empty list.
   void HandleInitializeSyncLogin(const base::ListValue* args);
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   // Called from JS when the user clicks the login container. It shows the
   // appropriate UI based on the current sync state. |args| is the list of
   // arguments passed from JS and should be an empty list.
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
index 1b1430c..af6b313 100644
--- a/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
+++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.cc
@@ -10,6 +10,7 @@
 #include "base/containers/flat_map.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/apps/app_service/app_service_proxy.h"
 #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/extensions/extension_service.h"
@@ -27,7 +28,7 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "components/arc/arc_prefs.h"
@@ -37,7 +38,7 @@
 
 namespace {
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 constexpr char kArcFrameworkPackage[] = "android";
 constexpr int kMinAndroidFrameworkVersion = 28;  // Android P
 #endif
@@ -51,11 +52,11 @@
   extension_misc::kChromeAppId,
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 constexpr char const* kAppIdsWithHiddenStoragePermission[] = {
     arc::kPlayStoreAppId,
 };
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 app_management::mojom::ExtensionAppPermissionMessagePtr
 CreateExtensionAppPermissionMessage(
@@ -77,7 +78,7 @@
 }
 
 bool ShouldHideStoragePermission(const std::string app_id) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   return base::Contains(kAppIdsWithHiddenStoragePermission, app_id);
 #else
   return false;
@@ -98,11 +99,11 @@
 
   Observe(&proxy->AppRegistryCache());
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (arc::IsArcAllowedForProfile(profile_)) {
     arc_app_list_prefs_observer_.Add(ArcAppListPrefs::Get(profile_));
   }
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 AppManagementPageHandler::~AppManagementPageHandler() {}
@@ -166,7 +167,7 @@
 
 void AppManagementPageHandler::SetPinned(const std::string& app_id,
                                          OptionalBool pinned) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   shelf_delegate_.SetPinned(app_id, pinned);
 #else
   NOTREACHED();
@@ -220,7 +221,7 @@
 
   // On other OS's, is_pinned defaults to OptionalBool::kUnknown, which is
   // used to represent the fact that there is no concept of being pinned.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   app->is_pinned = shelf_delegate_.IsPinned(update.AppId())
                        ? OptionalBool::kTrue
                        : OptionalBool::kFalse;
@@ -258,7 +259,7 @@
   Observe(nullptr);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // static
 bool AppManagementPageHandler::IsCurrentArcVersionSupported(Profile* profile) {
   if (arc::IsArcAllowedForProfile(profile)) {
@@ -285,4 +286,4 @@
   }
   OnArcVersionChanged(package_info.package_version);
 }
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/webui/app_management/app_management_page_handler.h b/chrome/browser/ui/webui/app_management/app_management_page_handler.h
index cd94f678..2d56a70e 100644
--- a/chrome/browser/ui/webui/app_management/app_management_page_handler.h
+++ b/chrome/browser/ui/webui/app_management/app_management_page_handler.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/scoped_observer.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/app_management/app_management.mojom-forward.h"
 #include "chrome/browser/ui/webui/app_management/app_management_shelf_delegate_chromeos.h"
 #include "components/services/app_service/public/cpp/app_registry_cache.h"
@@ -15,16 +16,16 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "mojo/public/cpp/bindings/remote.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #endif
 
 class Profile;
 
 class AppManagementPageHandler : public app_management::mojom::PageHandler,
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
                                  public ArcAppListPrefs::Observer,
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
                                  public apps::AppRegistryCache::Observer {
  public:
   AppManagementPageHandler(
@@ -33,14 +34,14 @@
       Profile* profile);
   ~AppManagementPageHandler() override;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   static bool IsCurrentArcVersionSupported(Profile* profile);
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   void OnPinnedChanged(const std::string& app_id, bool pinned);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void OnArcVersionChanged(int androidVersion);
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // app_management::mojom::PageHandler:
   void GetApps(GetAppsCallback callback) override;
@@ -62,13 +63,13 @@
   void OnAppRegistryCacheWillBeDestroyed(
       apps::AppRegistryCache* cache) override;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // ArcAppListPrefs::Observer:
   void OnPackageInstalled(
       const arc::mojom::ArcPackageInfo& package_info) override;
   void OnPackageModified(
       const arc::mojom::ArcPackageInfo& package_info) override;
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   mojo::Receiver<app_management::mojom::PageHandler> receiver_;
 
@@ -76,11 +77,11 @@
 
   Profile* profile_;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   ScopedObserver<ArcAppListPrefs, ArcAppListPrefs::Observer>
       arc_app_list_prefs_observer_{this};
   AppManagementShelfDelegate shelf_delegate_{this};
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   DISALLOW_COPY_AND_ASSIGN(AppManagementPageHandler);
 };
diff --git a/chrome/browser/ui/webui/bluetooth_internals/BUILD.gn b/chrome/browser/ui/webui/bluetooth_internals/BUILD.gn
index d2a1810..840035d 100644
--- a/chrome/browser/ui/webui/bluetooth_internals/BUILD.gn
+++ b/chrome/browser/ui/webui/bluetooth_internals/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/chromeos/ui_mode.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 
 source_set("bluetooth_internals") {
@@ -16,6 +17,7 @@
 
   deps = [
     ":mojo_bindings",
+    "//build:chromeos_buildflags",
     "//chrome/browser/resources/bluetooth_internals:resources",
     "//chrome/common",
     "//content/public/browser",
@@ -23,7 +25,7 @@
     "//ui/webui",
   ]
 
-  if (is_chromeos) {
+  if (is_chromeos_ash) {
     deps += [ "//chrome/browser/chromeos" ]
   }
 }
diff --git a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.cc b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.cc
index 33da2b1..66a8d850 100644
--- a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.cc
+++ b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.cc
@@ -9,6 +9,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/chromeos/bluetooth/debug_logs_manager.h"
 #include "device/bluetooth/adapter.h"
 #include "device/bluetooth/bluetooth_adapter_factory.h"
@@ -16,7 +17,7 @@
 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
 #include "url/gurl.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/bluetooth/debug_logs_manager.h"
 #endif
 
@@ -41,7 +42,7 @@
   mojo::PendingRemote<mojom::DebugLogsChangeHandler> handler_remote;
   bool initial_toggle_value = false;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   using chromeos::bluetooth::DebugLogsManager;
 
   // If no logs manager exists for this user, debug logs are not supported.
diff --git a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.h b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.h
index 16e715c..769d962 100644
--- a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.h
+++ b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.h
@@ -6,12 +6,13 @@
 #define CHROME_BROWSER_UI_WEBUI_BLUETOOTH_INTERNALS_BLUETOOTH_INTERNALS_HANDLER_H_
 
 #include "base/macros.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals.mojom.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 namespace chromeos {
 namespace bluetooth {
 class DebugLogsManager;
@@ -27,7 +28,7 @@
       mojo::PendingReceiver<mojom::BluetoothInternalsHandler> receiver);
   ~BluetoothInternalsHandler() override;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void set_debug_logs_manager(
       chromeos::bluetooth::DebugLogsManager* debug_logs_manager) {
     debug_logs_manager_ = debug_logs_manager;
@@ -45,7 +46,7 @@
 
   mojo::Receiver<mojom::BluetoothInternalsHandler> receiver_;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   chromeos::bluetooth::DebugLogsManager* debug_logs_manager_ = nullptr;
 #endif
 
diff --git a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc
index efc6427..c44cb0e 100644
--- a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc
+++ b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.h"
 
 #include "base/bind.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.h"
 #include "chrome/browser/ui/webui/webui_util.h"
@@ -13,7 +14,7 @@
 #include "chrome/grit/bluetooth_internals_resources_map.h"
 #include "content/public/browser/web_ui_data_source.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/bluetooth/debug_logs_manager_factory.h"
 #endif
 
@@ -49,7 +50,7 @@
     mojo::PendingReceiver<mojom::BluetoothInternalsHandler> receiver) {
   page_handler_ =
       std::make_unique<BluetoothInternalsHandler>(std::move(receiver));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   page_handler_->set_debug_logs_manager(
       chromeos::bluetooth::DebugLogsManagerFactory::GetForProfile(
           Profile::FromWebUI(web_ui())));
diff --git a/chrome/browser/ui/webui/certificate_manager_localized_strings_provider.cc b/chrome/browser/ui/webui/certificate_manager_localized_strings_provider.cc
index d250a38..56403b68 100644
--- a/chrome/browser/ui/webui/certificate_manager_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/certificate_manager_localized_strings_provider.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/certificate_manager_localized_strings_provider.h"
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/strings/grit/components_strings.h"
@@ -80,7 +81,7 @@
      IDS_SETTINGS_CERTIFICATE_MANAGER_CONFIRM_PASSWORD},
     {"certificateImportErrorFormat",
      IDS_SETTINGS_CERTIFICATE_MANAGER_IMPORT_ERROR_FORMAT},
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {"certificateProvisioningListHeader",
      IDS_SETTINGS_CERTIFICATE_MANAGER_PROVISIONING_LIST_HEADER},
     {"certificateProvisioningRefresh",
@@ -98,7 +99,7 @@
     {"certificateProvisioningLastUpdate",
      IDS_SETTINGS_CERTIFICATE_MANAGER_PROVISIONING_LAST_UPDATE},
     {"certificateProvisioningPublicKey", IDS_CERT_DETAILS_SUBJECT_KEY},
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
     // For A11y.
     {"menu", IDS_MENU},
   };
diff --git a/chrome/browser/ui/webui/certificates_handler.cc b/chrome/browser/ui/webui/certificates_handler.cc
index d6a44ad..fd97d423 100644
--- a/chrome/browser/ui/webui/certificates_handler.cc
+++ b/chrome/browser/ui/webui/certificates_handler.cc
@@ -25,6 +25,7 @@
 #include "base/task/thread_pool.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/certificate_viewer.h"
 #include "chrome/browser/profiles/profile.h"
@@ -573,7 +574,7 @@
 }
 
 void CertificatesHandler::HandleImportPersonal(const base::ListValue* args) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // When policy changes while user on the certificate manager page, the UI
   // doesn't update without page refresh and user can still see and use import
   // button. Because of this 'return' the button will do nothing.
@@ -810,14 +811,14 @@
 }
 
 void CertificatesHandler::HandleImportCA(const base::ListValue* args) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // When policy changes while user on the certificate manager page, the UI
   // doesn't update without page refresh and user can still see and use import
   // button. Because of this 'return' the button will do nothing.
   if (!IsCACertificateManagementAllowedPolicy(CertificateSource::kImported)) {
     return;
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   CHECK_EQ(1U, args->GetSize());
   AssignWebUICallbackId(args);
@@ -965,12 +966,12 @@
 void CertificatesHandler::CertificateManagerModelReady() {
   bool client_import_allowed = true;
   bool ca_import_allowed = true;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   client_import_allowed =
       IsClientCertificateManagementAllowedPolicy(Slot::kUser);
   ca_import_allowed =
       IsCACertificateManagementAllowedPolicy(CertificateSource::kImported);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   if (IsJavascriptAllowed()) {
     FireWebUIListener("client-import-allowed-changed",
                       base::Value(client_import_allowed));
@@ -1157,7 +1158,7 @@
   return cert_info_id_map_.Lookup(cert_info_id);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 bool CertificatesHandler::IsClientCertificateManagementAllowedPolicy(
     Slot slot) const {
   Profile* profile = Profile::FromWebUI(web_ui());
@@ -1185,7 +1186,7 @@
       return policy_value != CACertificateManagementPermission::kNone;
   }
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 bool CertificatesHandler::CanDeleteCertificate(
     const CertificateManagerModel::CertInfo* cert_info) const {
@@ -1195,7 +1196,7 @@
     return false;
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (cert_info->type() == net::CertType::USER_CERT) {
     return IsClientCertificateManagementAllowedPolicy(
         cert_info->device_wide() ? Slot::kSystem : Slot::kUser);
@@ -1206,7 +1207,7 @@
                                    : CertificateSource::kBuiltIn;
     return IsCACertificateManagementAllowedPolicy(source);
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   return true;
 }
 
@@ -1217,16 +1218,16 @@
        CertificateManagerModel::CertInfo::Source::kPolicy)) {
     return false;
   }
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   CertificateSource source = cert_info->can_be_deleted()
                                  ? CertificateSource::kImported
                                  : CertificateSource::kBuiltIn;
   return IsCACertificateManagementAllowedPolicy(source);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   return true;
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void CertificatesHandler::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
   // Allow users to manage all client certificates by default. This can be
@@ -1241,6 +1242,6 @@
       prefs::kCACertificateManagementAllowed,
       static_cast<int>(CACertificateManagementPermission::kAll));
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace certificate_manager
diff --git a/chrome/browser/ui/webui/certificates_handler.h b/chrome/browser/ui/webui/certificates_handler.h
index e346efa..ec6dda4 100644
--- a/chrome/browser/ui/webui/certificates_handler.h
+++ b/chrome/browser/ui/webui/certificates_handler.h
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/task/cancelable_task_tracker.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/certificate_manager_model.h"
 #include "content/public/browser/web_ui_message_handler.h"
 #include "net/cert/nss_cert_database.h"
@@ -23,7 +24,7 @@
 class PrefRegistrySyncable;
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 enum class Slot { kUser, kSystem };
 enum class CertificateSource { kBuiltIn, kImported };
 
@@ -50,7 +51,7 @@
   // Disallow users from managing certificates
   kNone = 2
 };
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace certificate_manager {
 
@@ -75,7 +76,7 @@
                     void* params) override;
   void FileSelectionCanceled(void* params) override;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Register profile preferences.
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 #endif
@@ -201,7 +202,7 @@
       const base::Value& args,
       size_t arg_index);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Returns true if the user may manage certificates on |slot| according
   // to ClientCertificateManagementAllowed policy.
   bool IsClientCertificateManagementAllowedPolicy(Slot slot) const;
@@ -209,7 +210,7 @@
   // Returns true if the user may manage certificates according
   // to CACertificateManagementAllowed policy.
   bool IsCACertificateManagementAllowedPolicy(CertificateSource source) const;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // Returns true if the certificate represented by |cert_info| can be deleted.
   bool CanDeleteCertificate(
diff --git a/chrome/browser/ui/webui/certificates_handler_unittest.cc b/chrome/browser/ui/webui/certificates_handler_unittest.cc
index 6ada07d..9d2e431 100644
--- a/chrome/browser/ui/webui/certificates_handler_unittest.cc
+++ b/chrome/browser/ui/webui/certificates_handler_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/certificates_handler.h"
 
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
 #include "chrome/test/base/testing_profile.h"
@@ -21,11 +22,11 @@
     pref_service_ = profile()->GetTestingPrefService();
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   bool IsCACertificateManagementAllowedPolicy(CertificateSource source) const {
     return cert_handler_.IsCACertificateManagementAllowedPolicy(source);
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   bool CanDeleteCertificate(
       const CertificateManagerModel::CertInfo* cert_info) const {
@@ -43,7 +44,7 @@
   sync_preferences::TestingPrefServiceSyncable* pref_service_ = nullptr;
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(CertificateHandlerTest, IsCACertificateManagementAllowedPolicyTest) {
   {
     pref_service_->SetInteger(
@@ -78,7 +79,7 @@
         IsCACertificateManagementAllowedPolicy(CertificateSource::kBuiltIn));
   }
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 TEST_F(CertificateHandlerTest, CanDeleteCertificateCommonTest) {
   CertificateManagerModel::CertInfo default_cert_info(
@@ -126,7 +127,7 @@
     EXPECT_TRUE(CanDeleteCertificate(&cert_info));
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   {
     pref_service_->SetInteger(
         prefs::kClientCertificateManagementAllowed,
@@ -162,7 +163,7 @@
     cert_info.device_wide_ = true;
     EXPECT_FALSE(CanDeleteCertificate(&cert_info));
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 TEST_F(CertificateHandlerTest, CanDeleteCACertificateTest) {
@@ -180,7 +181,7 @@
     EXPECT_TRUE(CanDeleteCertificate(&cert_info));
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   {
     pref_service_->SetInteger(
         prefs::kCACertificateManagementAllowed,
@@ -215,7 +216,7 @@
     cert_info.can_be_deleted_ = true;
     EXPECT_FALSE(CanDeleteCertificate(&cert_info));
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 TEST_F(CertificateHandlerTest, CanEditCertificateCommonTest) {
@@ -259,7 +260,7 @@
     EXPECT_FALSE(CanEditCertificate(&cert_info));
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   {
     pref_service_->SetInteger(
         prefs::kClientCertificateManagementAllowed,
@@ -295,7 +296,7 @@
     cert_info.device_wide_ = true;
     EXPECT_FALSE(CanEditCertificate(&cert_info));
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 TEST_F(CertificateHandlerTest, CanEditCACertificateTest) {
@@ -313,7 +314,7 @@
     EXPECT_TRUE(CanEditCertificate(&cert_info));
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   {
     pref_service_->SetInteger(
         prefs::kCACertificateManagementAllowed,
@@ -349,5 +350,5 @@
     cert_info.can_be_deleted_ = true;
     EXPECT_FALSE(CanEditCertificate(&cert_info));
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
diff --git a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
index e42e6dd..6cb4b41 100644
--- a/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
+++ b/chrome/browser/ui/webui/chrome_url_data_manager_browsertest.cc
@@ -5,6 +5,7 @@
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/url_constants.h"
@@ -277,7 +278,7 @@
     "chrome://offline-internals",
     "chrome://webapks",
 #endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "chrome://account-manager-error",
     "chrome://account-manager-welcome",
     "chrome://account-migration-welcome",
diff --git a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
index e64a11d..b1edfdd 100644
--- a/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
+++ b/chrome/browser/ui/webui/chrome_web_ui_controller_factory.cc
@@ -13,6 +13,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/about_flags.h"
 #include "chrome/browser/accessibility/accessibility_ui.h"
 #include "chrome/browser/buildflags.h"
@@ -152,7 +153,7 @@
 #include "media/base/media_switches.h"
 #endif  // defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "base/system/sys_info.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/device_sync/device_sync_client_factory.h"
@@ -225,7 +226,7 @@
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #endif
 
-#if defined(OS_CHROMEOS) && !defined(OFFICIAL_BUILD)
+#if BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OFFICIAL_BUILD)
 #include "chrome/browser/chromeos/web_applications/chrome_file_manager_ui_delegate.h"
 #include "chrome/browser/ui/webui/chromeos/emulator/device_emulator_ui.h"
 #include "chromeos/components/file_manager/file_manager_ui.h"
@@ -236,7 +237,7 @@
 #include "chromeos/components/telemetry_extension_ui/url_constants.h"
 #endif
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/webui/app_launcher_page_ui.h"
 #endif
 
@@ -244,7 +245,7 @@
 #include "chrome/browser/ui/webui/webui_js_error/webui_js_error_ui.h"
 #endif
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID)
 #include "chrome/browser/ui/sync/sync_promo_ui.h"
 #include "chrome/browser/ui/webui/browser_switch/browser_switch_ui.h"
 #include "chrome/browser/ui/webui/signin/profile_customization_ui.h"
@@ -330,7 +331,7 @@
   return new AboutUI(web_ui, url.host());
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 template <>
 WebUIController* NewWebUI<chromeos::OobeUI>(WebUI* web_ui, const GURL& url) {
   return new chromeos::OobeUI(web_ui, url);
@@ -457,14 +458,14 @@
           &chrome::ShowFeedbackDialogForWebUI,
           chrome::WebUIFeedbackSource::kConnectivityDiagnostics));
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
 template <>
 WebUIController* NewWebUI<WelcomeUI>(WebUI* web_ui, const GURL& url) {
   return new WelcomeUI(web_ui, url);
 }
-#endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#endif  // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
 
 bool IsAboutUI(const GURL& url) {
   return (url.host_piece() == chrome::kChromeUIChromeURLsHost ||
@@ -475,7 +476,7 @@
 #if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_OPENBSD)
           || url.host_piece() == chrome::kChromeUILinuxProxyConfigHost
 #endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
           || url.host_piece() == chrome::kChromeUIOSCreditsHost ||
           url.host_piece() == chrome::kChromeUICrostiniCreditsHost
 #endif
@@ -510,10 +511,10 @@
   if (url.host_piece() == chrome::kChromeUIAutofillInternalsHost)
     return &NewWebUI<AutofillInternalsUI>;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (url.host_piece() == chrome::kChromeUIAppDisabledHost)
     return &NewWebUI<chromeos::ChromeURLDisabledUI>;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   if (url.host_piece() == chrome::kChromeUIBluetoothInternalsHost)
     return &NewWebUI<BluetoothInternalsUI>;
@@ -586,14 +587,14 @@
     return &NewWebUI<VersionUI>;
 
 #if !defined(OS_ANDROID)
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   // AppLauncherPage is not needed on Android or ChromeOS.
   if (url.host_piece() == chrome::kChromeUIAppLauncherPageHost && profile &&
       extensions::ExtensionSystem::Get(profile)->extension_service() &&
       !profile->IsGuestSession()) {
     return &NewWebUI<AppLauncherPageUI>;
   }
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
   if (profile->IsGuestSession() &&
       (url.host_piece() == chrome::kChromeUIAppLauncherPageHost ||
        url.host_piece() == chrome::kChromeUIBookmarksHost ||
@@ -646,7 +647,7 @@
   if (url.host_piece() == chrome::kChromeUIConflictsHost)
     return &NewWebUI<ConflictsUI>;
 #endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (url.host_piece() == chrome::kChromeUIPasswordChangeHost) {
     if (!profile->GetPrefs()->GetBoolean(
             chromeos::prefs::kSamlInSessionPasswordChangeEnabled)) {
@@ -804,7 +805,7 @@
     }
   }
 #endif  // !defined(OFFICIAL_BUILD)
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
   if (url.host_piece() == chrome::kChromeUIWebUIJsErrorHost)
     return &NewWebUI<WebUIJsErrorUI>;
@@ -841,7 +842,7 @@
     return &NewWebUI<SyncConfirmationUI>;
   }
 #endif  // defined(OS_ANDROID)
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID)
   if (url.host_piece() == chrome::kChromeUIProfileCustomizationHost)
     return &NewWebUI<ProfileCustomizationUI>;
   if (url.host_piece() == chrome::kChromeUIProfilePickerHost)
@@ -928,8 +929,10 @@
   if (url.host_piece() == chrome::kChromeUIDiscardsHost)
     return &NewWebUI<DiscardsUI>;
 #endif
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
 #if defined(OS_WIN) || defined(OS_MAC) || \
-    (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+    (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
   if (url.host_piece() == chrome::kChromeUIBrowserSwitchHost)
     return &NewWebUI<BrowserSwitchUI>;
 #endif
@@ -1140,11 +1143,11 @@
     return FlagsUI::GetFaviconResourceBytes(scale_factor);
 
 #if !defined(OS_ANDROID)
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   // The Apps launcher page is not available on android or ChromeOS.
   if (page_url.host_piece() == chrome::kChromeUIAppLauncherPageHost)
     return AppLauncherPageUI::GetFaviconResourceBytes(scale_factor);
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
   // Bookmarks are part of NTP on Android.
   if (page_url.host_piece() == chrome::kChromeUIBookmarksHost)
@@ -1171,10 +1174,10 @@
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 #endif  // !defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (page_url.host_piece() == chrome::kChromeUIOSSettingsHost)
     return settings_utils::GetFaviconResourceBytes(scale_factor);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   return nullptr;
 }
diff --git a/chrome/browser/ui/webui/components/components_ui.cc b/chrome/browser/ui/webui/components/components_ui.cc
index 49b8400..1622d0b 100644
--- a/chrome/browser/ui/webui/components/components_ui.cc
+++ b/chrome/browser/ui/webui/components/components_ui.cc
@@ -16,6 +16,7 @@
 #include "base/macros.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/components/components_handler.h"
@@ -31,7 +32,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/webui/web_ui_util.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "components/user_manager/user_manager.h"
 #endif
 
@@ -61,7 +62,7 @@
 
   source->AddBoolean(
       "isGuest",
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       user_manager::UserManager::Get()->IsLoggedInAsGuest() ||
           user_manager::UserManager::Get()->IsLoggedInAsPublicAccount()
 #else
diff --git a/chrome/browser/ui/webui/constrained_web_dialog_ui_browsertest.cc b/chrome/browser/ui/webui/constrained_web_dialog_ui_browsertest.cc
index f78e91f..5fd54a7e 100644
--- a/chrome/browser/ui/webui/constrained_web_dialog_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/constrained_web_dialog_ui_browsertest.cc
@@ -11,6 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -149,7 +150,7 @@
 // Tests that dialog autoresizes based on web contents when autoresizing
 // is enabled.
 // Flaky on CrOS: http://crbug.com/928924
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_ContentResizeInAutoResizingDialog \
   DISABLED_ContentResizeInAutoResizingDialog
 #else
diff --git a/chrome/browser/ui/webui/crashes_ui.cc b/chrome/browser/ui/webui/crashes_ui.cc
index 4c857f49..fa9f7c3 100644
--- a/chrome/browser/ui/webui/crashes_ui.cc
+++ b/chrome/browser/ui/webui/crashes_ui.cc
@@ -18,6 +18,7 @@
 #include "base/system/sys_info.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/crash_upload_list/crash_upload_list.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/metrics/metrics_reporting_state.h"
@@ -37,7 +38,7 @@
 #include "google_apis/gaia/gaia_auth_util.h"
 #include "ui/base/resource/resource_bundle.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/debug_daemon/debug_daemon_client.h"
 #endif
@@ -91,7 +92,7 @@
   // Asynchronously fetches the list of crashes. Called from JS.
   void HandleRequestCrashes(const base::ListValue* args);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Asynchronously triggers crash uploading. Called from JS.
   void HandleRequestUploads(const base::ListValue* args);
 #endif
@@ -126,7 +127,7 @@
       base::BindRepeating(&CrashesDOMHandler::HandleRequestCrashes,
                           base::Unretained(this)));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       crash_reporter::kCrashesUIRequestCrashUpload,
       base::BindRepeating(&CrashesDOMHandler::HandleRequestUploads,
@@ -151,7 +152,7 @@
   }
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void CrashesDOMHandler::HandleRequestUploads(const base::ListValue* args) {
   chromeos::DebugDaemonClient* debugd_client =
       chromeos::DBusThreadManager::Get()->GetDebugDaemonClient();
@@ -176,7 +177,7 @@
       ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled();
 
   bool system_crash_reporter = false;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Chrome OS has a system crash reporter.
   system_crash_reporter = true;
 #endif
@@ -184,7 +185,9 @@
   bool using_crashpad = false;
 #if defined(OS_WIN) || defined(OS_MAC) || defined(OS_ANDROID)
   using_crashpad = true;
-#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   // ChromeOS uses crash_sender instead of Crashpad for uploads even when
   // Crashpad is enabled for dump generation.
   using_crashpad = crash_reporter::IsCrashpadEnabled();
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 41c46b8..4cc36f5 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -15,6 +15,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/chrome_extension_browser_constants.h"
 #include "chrome/browser/extensions/extension_checkup.h"
@@ -46,7 +47,7 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/webui/web_ui_util.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
 #include "chrome/browser/ui/webui/extensions/chromeos/kiosk_apps_handler.h"
 #endif
@@ -253,7 +254,7 @@
     {"viewIframe", IDS_EXTENSIONS_VIEW_IFRAME},
     {"viewServiceWorker", IDS_EXTENSIONS_SERVICE_WORKER_BACKGROUND},
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {"manageKioskApp", IDS_EXTENSIONS_MANAGE_KIOSK_APP},
     {"kioskAddApp", IDS_EXTENSIONS_KIOSK_ADD_APP},
     {"kioskAddAppHint", IDS_EXTENSIONS_KIOSK_ADD_APP_HINT},
@@ -286,7 +287,7 @@
                              GURL(chrome::kRemoveNonCWSExtensionURL),
                              g_browser_process->GetApplicationLocale())
                              .spec()));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   source->AddString(
       "kioskDisableBailoutWarningBody",
       l10n_util::GetStringFUTF16(
@@ -362,7 +363,7 @@
   source = CreateMdExtensionsSource(profile, *in_dev_mode_);
   ManagedUIHandler::Initialize(web_ui, source);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   auto kiosk_app_handler = std::make_unique<chromeos::KioskAppsHandler>(
       chromeos::OwnerSettingsServiceChromeOSFactory::GetForBrowserContext(
           profile));
diff --git a/chrome/browser/ui/webui/flags_ui.cc b/chrome/browser/ui/webui/flags_ui.cc
index 14c44937..fb662e12 100644
--- a/chrome/browser/ui/webui/flags_ui.cc
+++ b/chrome/browser/ui/webui/flags_ui.cc
@@ -14,6 +14,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/flags_ui_handler.h"
@@ -37,7 +38,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/resource/resource_bundle.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "base/command_line.h"
 #include "base/system/sys_info.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
@@ -71,7 +72,7 @@
       "trusted-types jstemplate;");
   source->AddString(flags_ui::kVersion, version_info::GetVersionNumber());
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (!user_manager::UserManager::Get()->IsCurrentUserOwner() &&
       base::SysInfo::IsRunningOnChromeOS()) {
     // Set the string to show which user can actually change the flags.
@@ -92,7 +93,7 @@
   return source;
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // On ChromeOS verifying if the owner is signed in is async operation and only
 // after finishing it the UI can be properly populated. This function is the
 // callback for whether the owner is signed in. It will respectively pick the
@@ -215,7 +216,7 @@
   FlagsUIHandler* handler = handler_owner.get();
   web_ui->AddMessageHandler(std::move(handler_owner));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Bypass possible incognito profile.
   Profile* original_profile = profile->GetOriginalProfile();
   if (base::SysInfo::IsRunningOnChromeOS() &&
diff --git a/chrome/browser/ui/webui/flags_ui.h b/chrome/browser/ui/webui/flags_ui.h
index 3809b151..98bd808 100644
--- a/chrome/browser/ui/webui/flags_ui.h
+++ b/chrome/browser/ui/webui/flags_ui.h
@@ -8,10 +8,11 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "ui/base/layout.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/settings/device_settings_service.h"
 #endif
 
diff --git a/chrome/browser/ui/webui/flags_ui_handler.cc b/chrome/browser/ui/webui/flags_ui_handler.cc
index 6746f3b..ce70adf 100644
--- a/chrome/browser/ui/webui/flags_ui_handler.cc
+++ b/chrome/browser/ui/webui/flags_ui_handler.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/flags_ui_handler.h"
 
 #include "base/bind.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/about_flags.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/common/channel_info.h"
@@ -12,7 +13,7 @@
 #include "components/flags_ui/flags_ui_constants.h"
 #include "components/version_info/channel.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "base/system/sys_info.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
 #include "components/account_id/account_id.h"
@@ -90,7 +91,7 @@
   results.SetBoolean(flags_ui::kShowOwnerWarning,
                      access_ == flags_ui::kGeneralAccessFlagsOnly);
 
-#if defined(OS_WIN) || defined(OS_MAC) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || defined(OS_MAC) || BUILDFLAG(IS_CHROMEOS_ASH)
   version_info::Channel channel = chrome::GetChannel();
   results.SetBoolean(
       flags_ui::kShowBetaChannelPromotion,
@@ -147,7 +148,7 @@
 
 void FlagsUIHandler::HandleRestartBrowser(const base::ListValue* args) {
   DCHECK(flags_storage_);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // On ChromeOS be less intrusive and restart inside the user session after
   // we apply the newly selected flags.
   base::CommandLine user_flags(base::CommandLine::NO_PROGRAM);
diff --git a/chrome/browser/ui/webui/help/test_version_updater.h b/chrome/browser/ui/webui/help/test_version_updater.h
index 82fcef9..8a521dd4 100644
--- a/chrome/browser/ui/webui/help/test_version_updater.h
+++ b/chrome/browser/ui/webui/help/test_version_updater.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/help/version_updater.h"
 
 // A very simple VersionUpdater implementation that immediately invokes the
@@ -27,7 +28,7 @@
 #if defined(OS_MAC)
   void PromoteUpdater() const override {}
 #endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void SetChannel(const std::string& channel,
                   bool is_powerwash_allowed) override {}
   void GetChannel(bool get_current_channel,
diff --git a/chrome/browser/ui/webui/help/version_updater.h b/chrome/browser/ui/webui/help/version_updater.h
index bab320e..937a28b3 100644
--- a/chrome/browser/ui/webui/help/version_updater.h
+++ b/chrome/browser/ui/webui/help/version_updater.h
@@ -10,11 +10,12 @@
 #include "base/callback.h"
 #include "base/strings/string16.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chromeos/dbus/update_engine_client.h"
 #include "third_party/cros_system_api/dbus/update_engine/dbus-constants.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace content {
 class WebContents;
@@ -47,7 +48,7 @@
 
   // TODO(jhawkins): Use a delegate interface instead of multiple callback
   // types.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   typedef base::Callback<void(const std::string&)> ChannelCallback;
   using EolInfoCallback =
       base::OnceCallback<void(chromeos::UpdateEngineClient::EolInfo eol_info)>;
@@ -96,7 +97,7 @@
   virtual void PromoteUpdater() const = 0;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   virtual void SetChannel(const std::string& channel,
                           bool is_powerwash_allowed) = 0;
   virtual void GetChannel(bool get_current_channel,
diff --git a/chrome/browser/ui/webui/local_state/local_state_ui.cc b/chrome/browser/ui/webui/local_state/local_state_ui.cc
index c933e042..7fa518e 100644
--- a/chrome/browser/ui/webui/local_state/local_state_ui.cc
+++ b/chrome/browser/ui/webui/local_state/local_state_ui.cc
@@ -12,6 +12,7 @@
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/url_constants.h"
@@ -27,11 +28,11 @@
 // On ChromeOS, the local state file contains some information about other
 // user accounts which we don't want to expose to other users. Use an allowlist
 // to only show variations and UMA related fields which don't contain PII.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define ENABLE_FILTERING true
 #else
 #define ENABLE_FILTERING false
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // UI Handler for chrome://local-state. Displays the Local State file as JSON.
 class LocalStateUIHandler : public content::WebUIMessageHandler {
diff --git a/chrome/browser/ui/webui/managed_ui_handler.cc b/chrome/browser/ui/webui/managed_ui_handler.cc
index cee8309..0f99789 100644
--- a/chrome/browser/ui/webui/managed_ui_handler.cc
+++ b/chrome/browser/ui/webui/managed_ui_handler.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
@@ -112,7 +113,7 @@
   auto update = std::make_unique<base::DictionaryValue>();
   update->SetKey("browserManagedByOrg",
                  base::Value(chrome::GetManagedUiWebUILabel(profile_)));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   update->SetKey("deviceManagedByOrg",
                  base::Value(chrome::GetDeviceManagedUiWebUILabel()));
 #endif
diff --git a/chrome/browser/ui/webui/managed_ui_handler_unittest.cc b/chrome/browser/ui/webui/managed_ui_handler_unittest.cc
index cc1126a..218dcbc4 100644
--- a/chrome/browser/ui/webui/managed_ui_handler_unittest.cc
+++ b/chrome/browser/ui/webui/managed_ui_handler_unittest.cc
@@ -6,6 +6,7 @@
 
 #include "base/token.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/test/base/testing_profile.h"
@@ -19,9 +20,9 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "components/policy/core/browser/browser_policy_connector_base.h"
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 class TestManagedUIHandler : public ManagedUIHandler {
  public:
@@ -111,7 +112,7 @@
   EXPECT_TRUE(IsSourceManaged());
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(ManagedUIHandlerTest, ManagedUIDisabledForChildAccount) {
   profile_policy_connector()->OverrideIsManagedForTesting(true);
   profile()->SetSupervisedUserId("supervised");
diff --git a/chrome/browser/ui/webui/management_ui.cc b/chrome/browser/ui/webui/management_ui.cc
index 7db259e..4774656 100644
--- a/chrome/browser/ui/webui/management_ui.cc
+++ b/chrome/browser/ui/webui/management_ui.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/management_ui_handler.h"
@@ -23,16 +24,16 @@
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/webui/web_ui_util.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/grit/chromium_strings.h"
 #include "ui/chromeos/devicetype_utils.h"
-#else  // defined(OS_CHROMEOS)
+#else  // BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/policy/chrome_browser_policy_connector.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace {
 
@@ -46,7 +47,7 @@
                     ManagementUI::GetManagementPageSubtitle(profile));
 
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {"learnMore", IDS_LEARN_MORE},
     {"localTrustRoots", IDS_MANAGEMENT_LOCAL_TRUST_ROOTS},
     {"managementTrustRootsConfigured", IDS_MANAGEMENT_TRUST_ROOTS_CONFIGURED},
@@ -74,7 +75,7 @@
      IDS_MANAGEMENT_REPORT_ANDROID_APPLICATIONS},
     {"proxyServerPrivacyDisclosure",
      IDS_MANAGEMENT_PROXY_SERVER_PRIVACY_DISCLOSURE},
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
     {"browserReporting", IDS_MANAGEMENT_BROWSER_REPORTING},
     {"browserReportingExplanation",
      IDS_MANAGEMENT_BROWSER_REPORTING_EXPLANATION},
@@ -128,7 +129,7 @@
                     l10n_util::GetStringFUTF16(
                         IDS_MANAGEMENT_EXTENSION_REPORT_SAFE_BROWSING_WARNINGS,
                         base::UTF8ToUTF16(safe_browsing::kSafeBrowsingUrl)));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   source->AddString("managementDeviceLearnMoreUrl",
                     chrome::kLearnMoreEnterpriseURL);
   source->AddString("managementAccountLearnMoreUrl",
@@ -137,7 +138,7 @@
                     l10n_util::GetStringFUTF16(
                         IDS_MANAGEMENT_REPORT_PLUGIN_VM,
                         l10n_util::GetStringUTF16(IDS_PLUGIN_VM_APP_NAME)));
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   source->UseStringsJs();
   source->EnableReplaceI18nInJS();
@@ -161,7 +162,7 @@
 
 // static
 base::string16 ManagementUI::GetManagementPageSubtitle(Profile* profile) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   const auto device_type = ui::GetChromeOSDeviceTypeResourceId();
@@ -184,7 +185,7 @@
   return l10n_util::GetStringFUTF16(IDS_MANAGEMENT_SUBTITLE_MANAGED_BY,
                                     l10n_util::GetStringUTF16(device_type),
                                     base::UTF8ToUTF16(account_manager));
-#else   // defined(OS_CHROMEOS)
+#else   // BUILDFLAG(IS_CHROMEOS_ASH)
   const auto account_manager = ManagementUIHandler::GetAccountManager(profile);
   const auto managed =
       profile->GetProfilePolicyConnector()->IsManaged() ||
@@ -199,7 +200,7 @@
                                       base::UTF8ToUTF16(account_manager));
   }
   return l10n_util::GetStringUTF16(IDS_MANAGEMENT_NOT_MANAGED_SUBTITLE);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 ManagementUI::ManagementUI(content::WebUI* web_ui) : WebUIController(web_ui) {
diff --git a/chrome/browser/ui/webui/management_ui_browsertest.cc b/chrome/browser/ui/webui/management_ui_browsertest.cc
index b7e639b..cecd6267 100644
--- a/chrome/browser/ui/webui/management_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/management_ui_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/json/json_reader.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/policy/chrome_browser_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/profiles/profile.h"
@@ -55,7 +56,7 @@
   DISALLOW_COPY_AND_ASSIGN(ManagementUITest);
 };
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 IN_PROC_BROWSER_TEST_F(ManagementUITest, ManagementStateChange) {
   profile_policy_connector()->OverrideIsManagedForTesting(false);
   ui_test_utils::NavigateToURL(browser(), GURL("chrome://management"));
@@ -118,4 +119,4 @@
 
   VerifyTexts(managed_value_ptr.get(), expected_managed_values);
 }
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/webui/management_ui_handler.cc b/chrome/browser/ui/webui/management_ui_handler.cc
index a559d06..0bd3bec 100644
--- a/chrome/browser/ui/webui/management_ui_handler.cc
+++ b/chrome/browser/ui/webui/management_ui_handler.cc
@@ -38,7 +38,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/webui/web_ui_util.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/crostini/crostini_features.h"
 #include "chrome/browser/chromeos/crostini/crostini_pref_names.h"
 #include "chrome/browser/chromeos/plugin_vm/plugin_vm_pref_names.h"
@@ -67,8 +67,9 @@
 #include "ui/chromeos/devicetype_utils.h"
 #else
 #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/common/extensions/permissions/chrome_permission_message_provider.h"
 #include "components/policy/core/common/policy_map.h"
@@ -157,7 +158,7 @@
   kUserActivity
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const char kManagementLogUploadEnabled[] = "managementLogUploadEnabled";
 const char kManagementReportActivityTimes[] = "managementReportActivityTimes";
 const char kManagementReportHardwareStatus[] = "managementReportHardwareStatus";
@@ -177,7 +178,7 @@
 const char kAccountManagedInfo[] = "accountManagedInfo";
 const char kDeviceManagedInfo[] = "deviceManagedInfo";
 const char kOverview[] = "overview";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 const char kCustomerLogo[] = "customerLogo";
 
@@ -189,20 +190,20 @@
   return profile->GetProfilePolicyConnector()->IsManaged();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 bool IsDeviceManaged() {
   return webui::IsEnterpriseManaged();
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 bool IsBrowserManaged() {
   return g_browser_process->browser_policy_connector()
       ->HasMachineLevelPolicies();
 }
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 enum class DeviceReportingType {
   kSupervisedUser,
@@ -260,7 +261,7 @@
   data.SetKey("reportingType", base::Value(ToJSDeviceReportingType(type)));
   report_sources->Append(std::move(data));
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 std::vector<base::Value> GetPermissionsForExtension(
     scoped_refptr<const extensions::Extension> extension) {
@@ -346,13 +347,13 @@
   if (!IsProfileManaged(profile))
     return std::string();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   const policy::UserCloudPolicyManagerChromeOS* user_cloud_policy_manager =
       profile->GetUserCloudPolicyManagerChromeOS();
 #else
   const policy::UserCloudPolicyManager* user_cloud_policy_manager =
       profile->GetUserCloudPolicyManager();
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   if (user_cloud_policy_manager) {
     const enterprise_management::PolicyData* policy =
@@ -385,12 +386,12 @@
                                              Profile* profile) {
   auto handler = std::make_unique<ManagementUIHandler>();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   handler->account_managed_ = IsProfileManaged(profile);
   handler->device_managed_ = IsDeviceManaged();
 #else
   handler->account_managed_ = IsProfileManaged(profile) || IsBrowserManaged();
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   web_ui->AddMessageHandler(std::move(handler));
 }
@@ -404,7 +405,7 @@
       "getExtensions",
       base::BindRepeating(&ManagementUIHandler::HandleGetExtensions,
                           base::Unretained(this)));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       "getLocalTrustRootsInfo",
       base::BindRepeating(&ManagementUIHandler::HandleGetLocalTrustRootsInfo,
@@ -418,7 +419,7 @@
       base::BindRepeating(
           &ManagementUIHandler::HandleGetPluginVmDataCollectionStatus,
           base::Unretained(this)));
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       "getThreatProtectionInfo",
       base::BindRepeating(&ManagementUIHandler::HandleGetThreatProtectionInfo,
@@ -545,7 +546,7 @@
   }
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const policy::DeviceCloudPolicyManagerChromeOS*
 ManagementUIHandler::GetDeviceCloudPolicyManager() const {
   // Only check for report status in managed environment.
@@ -691,7 +692,7 @@
 
 base::Value ManagementUIHandler::GetContextualManagedData(Profile* profile) {
   base::Value response(base::Value::Type::DICTIONARY);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   std::string enterprise_manager = GetDeviceManager();
   if (enterprise_manager.empty())
     enterprise_manager = GetAccountManager(profile);
@@ -713,7 +714,7 @@
         "extensionReportingTitle",
         l10n_util::GetStringUTF16(IDS_MANAGEMENT_EXTENSIONS_INSTALLED));
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     response.SetStringPath(
         "pageSubtitle", l10n_util::GetStringUTF16(
                             managed_() ? IDS_MANAGEMENT_SUBTITLE
@@ -728,7 +729,7 @@
             : l10n_util::GetStringFUTF16(
                   IDS_MANAGEMENT_NOT_MANAGED_SUBTITLE,
                   l10n_util::GetStringUTF16(device_type)));
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
   } else {
     response.SetStringPath(
@@ -736,7 +737,7 @@
         l10n_util::GetStringFUTF16(IDS_MANAGEMENT_EXTENSIONS_INSTALLED_BY,
                                    base::UTF8ToUTF16(enterprise_manager)));
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     response.SetStringPath(
         "pageSubtitle",
         managed_()
@@ -754,7 +755,7 @@
             : l10n_util::GetStringFUTF16(
                   IDS_MANAGEMENT_NOT_MANAGED_SUBTITLE,
                   l10n_util::GetStringUTF16(device_type)));
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
   }
   response.SetBoolPath("managed", managed_());
   GetManagementStatus(profile, &response);
@@ -822,13 +823,13 @@
     info.Append(std::move(value));
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   std::string enterprise_manager = GetDeviceManager();
   if (enterprise_manager.empty())
     enterprise_manager = GetAccountManager(profile);
 #else
   std::string enterprise_manager = GetAccountManager(profile);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   base::Value result(base::Value::Type::DICTIONARY);
   result.SetStringKey("description",
@@ -856,7 +857,7 @@
 }
 
 void ManagementUIHandler::AsyncUpdateLogo() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   const auto url = connector->GetCustomerLogoURL();
@@ -871,7 +872,7 @@
             ->GetURLLoaderFactoryForBrowserProcess()
             .get());
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void ManagementUIHandler::OnFetchComplete(const GURL& url,
@@ -884,7 +885,7 @@
   FireWebUIListener("managed_data_changed");
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AddStatusOverviewManagedDeviceAndAccount(
     base::Value* status,
     bool device_managed,
@@ -927,11 +928,11 @@
   return device_domain;
 }
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 void ManagementUIHandler::GetManagementStatus(Profile* profile,
                                               base::Value* status) const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   status->SetKey(kDeviceManagedInfo, base::Value());
   status->SetKey(kAccountManagedInfo, base::Value());
   status->SetKey(kOverview, base::Value());
@@ -957,7 +958,7 @@
   AddStatusOverviewManagedDeviceAndAccount(
       status, device_managed_, account_managed_ || primary_user_managed,
       device_manager, account_manager);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void ManagementUIHandler::HandleGetExtensions(const base::ListValue* args) {
@@ -978,7 +979,7 @@
                             powerful_extensions);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void ManagementUIHandler::HandleGetLocalTrustRootsInfo(
     const base::ListValue* args) {
   CHECK_EQ(1U, args->GetSize());
@@ -1029,7 +1030,7 @@
                             plugin_vm_data_collection_enabled);
 }
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 void ManagementUIHandler::HandleGetContextualManagedData(
     const base::ListValue* args) {
@@ -1062,14 +1063,14 @@
   FireWebUIListener("browser-reporting-info-updated", report_sources);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void ManagementUIHandler::NotifyPluginVmDataCollectionUpdated() {
   FireWebUIListener(
       "plugin-vm-data-collection-updated",
       base::Value(Profile::FromWebUI(web_ui())->GetPrefs()->GetBoolean(
           plugin_vm::prefs::kPluginVmDataCollectionAllowed)));
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 void ManagementUIHandler::NotifyThreatProtectionInfoUpdated() {
   FireWebUIListener("threat-protection-info-updated",
@@ -1098,7 +1099,7 @@
 void ManagementUIHandler::UpdateManagedState() {
   auto* profile = Profile::FromWebUI(web_ui());
   bool managed_state_changed = false;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   managed_state_changed |= account_managed_ != IsProfileManaged(profile);
   managed_state_changed |= device_managed_ != IsDeviceManaged();
   account_managed_ = IsProfileManaged(profile);
@@ -1107,7 +1108,7 @@
   managed_state_changed |=
       account_managed_ != (IsProfileManaged(profile) || IsBrowserManaged());
   account_managed_ = IsProfileManaged(profile) || IsBrowserManaged();
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   if (managed_state_changed)
     FireWebUIListener("managed_data_changed");
@@ -1142,13 +1143,13 @@
       base::BindRepeating(&ManagementUIHandler::UpdateManagedState,
                           base::Unretained(this)));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   pref_registrar_.Add(
       plugin_vm::prefs::kPluginVmDataCollectionAllowed,
       base::BindRepeating(
           &ManagementUIHandler::NotifyPluginVmDataCollectionUpdated,
           base::Unretained(this)));
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void ManagementUIHandler::RemoveObservers() {
diff --git a/chrome/browser/ui/webui/management_ui_handler.h b/chrome/browser/ui/webui/management_ui_handler.h
index 476e81b..7ca19bb 100644
--- a/chrome/browser/ui/webui/management_ui_handler.h
+++ b/chrome/browser/ui/webui/management_ui_handler.h
@@ -12,6 +12,7 @@
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
 #include "chrome/common/url_constants.h"
 #include "components/policy/core/common/policy_service.h"
@@ -24,7 +25,7 @@
 #include "extensions/common/extension_id.h"
 #include "url/gurl.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Constants defining the IDs for the localized strings sent to the page as
 // load time data.
 extern const char kManagementLogUploadEnabled[];
@@ -39,7 +40,7 @@
 extern const char kManagementCrostiniContainerConfiguration[];
 extern const char kManagementReportExtensions[];
 extern const char kManagementReportAndroidApplications[];
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 extern const char kCloudReportingExtensionId[];
 extern const char kOnPremReportingExtensionStableId[];
@@ -145,7 +146,7 @@
   virtual const extensions::Extension* GetEnabledExtension(
       const std::string& extensionId) const;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Protected for testing.
   virtual const std::string GetDeviceManager() const;
   virtual const policy::DeviceCloudPolicyManagerChromeOS*
@@ -165,15 +166,15 @@
   // the admin. If true, a warning will be added to the transparency panel to
   // inform the user that the admin may be able to see their network traffic.
   void AddProxyServerPrivacyDisclosure(base::Value* response) const;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
  private:
   void GetManagementStatus(Profile* profile, base::Value* status) const;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void HandleGetDeviceReportingInfo(const base::ListValue* args);
   void HandleGetPluginVmDataCollectionStatus(const base::ListValue* args);
   void HandleGetLocalTrustRootsInfo(const base::ListValue* args);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   void HandleGetExtensions(const base::ListValue* args);
   void HandleGetContextualManagedData(const base::ListValue* args);
@@ -186,9 +187,9 @@
   void OnFetchComplete(const GURL& url, const SkBitmap* bitmap) override;
 
   void NotifyBrowserReportingInfoUpdated();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void NotifyPluginVmDataCollectionUpdated();
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   void NotifyThreatProtectionInfoUpdated();
 
   // extensions::ExtensionRegistryObserver implementation.
diff --git a/chrome/browser/ui/webui/management_ui_handler_unittest.cc b/chrome/browser/ui/webui/management_ui_handler_unittest.cc
index 2816ae4..52f182a9 100644
--- a/chrome/browser/ui/webui/management_ui_handler_unittest.cc
+++ b/chrome/browser/ui/webui/management_ui_handler_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_refptr.h"
 #include "base/strings/utf_string_conversions.h"
 
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/management_ui_handler.h"
 #include "chrome/test/base/testing_profile.h"
 #include "components/policy/core/browser/browser_policy_connector.h"
@@ -29,7 +30,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "base/files/file_path.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/test_simple_task_runner.h"
@@ -84,7 +85,7 @@
 #include "components/policy/core/common/cloud/mock_user_cloud_policy_store.h"
 #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
 #include "services/network/test/test_network_connection_tracker.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 using testing::_;
 using testing::AnyNumber;
@@ -97,13 +98,13 @@
 struct ContextualManagementSourceUpdate {
   base::string16 extension_reporting_title;
   base::string16 subtitle;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   base::string16 management_overview;
   base::string16 update_required_eol;
   bool show_proxy_server_privacy_disclosure;
 #else
   base::string16 browser_management_notice;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   bool managed;
 };
 
@@ -111,12 +112,12 @@
 const char kDomain[] = "domain.com";
 const char kUser[] = "user@domain.com";
 const char kManager[] = "manager@domain.com";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const char kGaiaId[] = "gaia_id";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }  // namespace
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // This class is just to mock the behaviour of the few flags we need for
 // simulating the behaviour of the policy::DeviceStatusCollector.
 // The expected flags are passed to the constructor.
@@ -180,7 +181,7 @@
   }
   ~TestDeviceCloudPolicyManagerChromeOS() override = default;
 };
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 class TestManagementUIHandler : public ManagementUIHandler {
  public:
@@ -222,7 +223,7 @@
     return nullptr;
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   MOCK_METHOD(policy::DeviceCloudPolicyManagerChromeOS*,
               GetDeviceCloudPolicyManager,
               (),
@@ -241,7 +242,7 @@
 
   const std::string GetDeviceManager() const override { return device_domain; }
   void SetDeviceDomain(const std::string& domain) { device_domain = domain; }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
  private:
   bool cloud_reporting_extension_exists_ = false;
@@ -253,14 +254,14 @@
 // We need to use a different base class for ChromeOS and non ChromeOS case.
 // TODO(marcgrimme): refactor so that ChromeOS and non ChromeOS part is better
 // separated.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 using TestingBaseClass = chromeos::DeviceSettingsTestBase;
 #else
 using TestingBaseClass = testing::Test;
 #endif
 class ManagementUIHandlerTests : public TestingBaseClass {
  public:
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   ManagementUIHandlerTests()
       : TestingBaseClass(),
         handler_(&policy_service_),
@@ -321,7 +322,7 @@
     extracted_.extension_reporting_title =
         ExtractPathFromDict(data, "extensionReportingTitle");
     extracted_.subtitle = ExtractPathFromDict(data, "pageSubtitle");
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     extracted_.management_overview = ExtractPathFromDict(data, "overview");
     extracted_.update_required_eol = ExtractPathFromDict(data, "eolMessage");
     base::Optional<bool> showProxyDisclosure =
@@ -331,7 +332,7 @@
 #else
     extracted_.browser_management_notice =
         ExtractPathFromDict(data, "browserManagementNotice");
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
     base::Optional<bool> managed = data.FindBoolPath("managed");
     extracted_.managed = managed.has_value() && managed.value();
   }
@@ -377,7 +378,7 @@
     setup_config_.device_domain = "devicedomain.com";
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void SetUp() override {
     DeviceSettingsTestBase::SetUp();
     install_attributes_ =
@@ -452,7 +453,7 @@
     return handler_.GetDeviceReportingInfo(manager_.get(), status_collector,
                                            system_uploader, GetProfile());
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   void SetUpProfileAndHandler() {
     TestingProfile::Builder builder;
@@ -463,7 +464,7 @@
     profile_ = builder.Build();
     handler_.SetAccountManagedForTesting(GetTestConfig().managed_account);
     handler_.SetDeviceManagedForTesting(GetTestConfig().managed_device);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     handler_.SetDeviceDomain(GetTestConfig().device_domain);
 #endif
     base::Value data =
@@ -473,7 +474,7 @@
 
   bool GetManaged() const { return extracted_.managed; }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   base::string16 GetManagementOverview() const {
     return extracted_.management_overview;
   }
@@ -510,7 +511,7 @@
 
   TestConfig& GetTestConfig() { return setup_config_; }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void OnFatalError() { DCHECK(false); }
 
   std::unique_ptr<policy::UserCloudPolicyManagerChromeOS>
@@ -550,7 +551,7 @@
         base::ThreadTaskRunnerHandle::Get(),
         network::TestNetworkConnectionTracker::CreateGetter());
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
  protected:
   TestConfig setup_config_;
@@ -559,7 +560,7 @@
   policy::PolicyMap empty_policy_map_;
   base::string16 device_domain_;
   ContextualManagementSourceUpdate extracted_;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   std::unique_ptr<chromeos::ScopedStubInstallAttributes> install_attributes_;
   std::unique_ptr<crostini::FakeCrostiniFeatures> crostini_features_;
   TestingPrefServiceSimple local_state_;
@@ -604,7 +605,7 @@
   return AssertionSuccess();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 AssertionResult ReportingElementsToBeEQ(
     const char* elements_expr,
     const char* expected_elements_expr,
@@ -656,7 +657,7 @@
 }
 #endif
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(ManagementUIHandlerTests,
        ManagementContextualSourceUpdateUnmanagedNoDomain) {
   ResetTestConfig();
@@ -765,9 +766,9 @@
   EXPECT_TRUE(GetManaged());
 }
 
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(ManagementUIHandlerTests,
        ManagementContextualSourceUpdateManagedAccountKnownDomain) {
   const std::string domain = "manager.com";
@@ -1178,9 +1179,9 @@
   builder_known_domain.SetProfileName("managed@manager.com");
   auto profile_known_domain = builder_known_domain.Build();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   handler_.SetDeviceDomain("");
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
   EXPECT_CALL(policy_service_, GetPolicies(chrome_policies_namespace))
       .WillRepeatedly(ReturnRef(chrome_policies));
@@ -1275,7 +1276,7 @@
   builder_managed_user.SetProfileName(kUser);
   builder_managed_user.OverridePolicyConnectorIsManagedForTesting(true);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   TestingBrowserProcess::GetGlobal()->SetLocalState(nullptr);
   std::unique_ptr<TestingProfileManager> profile_manager =
       std::make_unique<TestingProfileManager>(
@@ -1288,7 +1289,7 @@
 #endif
   auto managed_user = builder_managed_user.Build();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   policy::UserCloudPolicyManagerChromeOS* policy_manager =
       managed_user->GetUserCloudPolicyManagerChromeOS();
   policy::MockCloudPolicyStore* mock_store =
diff --git a/chrome/browser/ui/webui/media/webrtc_logs_ui.cc b/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
index dd531c8..0e3f9cb 100644
--- a/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
+++ b/chrome/browser/ui/webui/media/webrtc_logs_ui.cc
@@ -19,6 +19,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/media/webrtc/webrtc_event_log_manager.h"
 #include "chrome/browser/profiles/profile.h"
@@ -37,7 +38,7 @@
 #include "content/public/browser/web_ui_message_handler.h"
 #include "ui/base/webui/web_ui_util.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #endif
 
diff --git a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
index 95dd5f51..99fb2d2 100644
--- a/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
+++ b/chrome/browser/ui/webui/ntp/ntp_resource_cache.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -62,7 +63,7 @@
 #include "ui/gfx/color_utils.h"
 #include "ui/native_theme/native_theme.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chromeos/strings/grit/chromeos_strings.h"
 #endif
@@ -77,7 +78,7 @@
 
 // The URL for the the Learn More page shown on incognito new tab.
 const char kLearnMoreIncognitoUrl[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=incognito";
 #else
     "https://support.google.com/chrome/?p=incognito";
@@ -85,7 +86,7 @@
 
 // The URL for the Learn More page shown on guest session new tab.
 const char kLearnMoreGuestSessionUrl[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=chromebook_guest";
 #else
     "https://support.google.com/chrome/?p=ui_guest";
@@ -410,7 +411,7 @@
       l10n_util::GetStringUTF16(IDS_NEW_TAB_TITLE));
   int guest_tab_idr = guest_ntp_info.html_idr;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   guest_tab_idr = IDR_GUEST_SESSION_TAB_HTML;
 
   policy::BrowserPolicyConnectorChromeOS* connector =
diff --git a/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc b/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc
index 1d3271b5..811053aa 100644
--- a/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/policy_indicator_localized_strings_provider.cc
@@ -5,12 +5,13 @@
 #include "chrome/browser/ui/webui/policy_indicator_localized_strings_provider.h"
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/grit/generated_resources.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "ui/base/webui/web_ui_util.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
 #endif
 
@@ -18,7 +19,7 @@
 
 void AddLocalizedStrings(content::WebUIDataSource* html_source) {
   int controlled_setting_policy_id = IDS_CONTROLLED_SETTING_POLICY;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (chromeos::DemoSession::IsDeviceInDemoMode())
     controlled_setting_policy_id = IDS_CONTROLLED_SETTING_DEMO_SESSION;
 #endif
@@ -30,7 +31,7 @@
     {"controlledSettingExtension", IDS_CONTROLLED_SETTING_EXTENSION},
     {"controlledSettingExtensionWithoutName",
      IDS_CONTROLLED_SETTING_EXTENSION_WITHOUT_NAME},
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {"controlledSettingShared", IDS_CONTROLLED_SETTING_SHARED},
     {"controlledSettingWithOwner", IDS_CONTROLLED_SETTING_WITH_OWNER},
     {"controlledSettingNoOwner", IDS_CONTROLLED_SETTING_NO_OWNER},
diff --git a/chrome/browser/ui/webui/policy_ui_browsertest.cc b/chrome/browser/ui/webui/policy_ui_browsertest.cc
index 7aa784c..cb5a97b 100644
--- a/chrome/browser/ui/webui/policy_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/policy_ui_browsertest.cc
@@ -19,6 +19,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/install_verifier.h"
 #include "chrome/browser/extensions/test_extension_system.h"
@@ -52,9 +53,9 @@
 #include "ui/shell_dialogs/select_file_policy.h"
 #include "url/gurl.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 using testing::_;
 using testing::Return;
@@ -159,7 +160,7 @@
   expected->SetPath({prefix, "application"}, base::Value(""));
   expected->SetPath({prefix, "version"}, base::Value(""));
   expected->SetPath({prefix, "revision"}, base::Value(""));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   expected->SetPath({prefix, "platform"}, base::Value(""));
 #else
   expected->SetPath({prefix, "OS"}, base::Value(""));
@@ -432,12 +433,12 @@
   // such policies.
   expected_values.SetDictionary("extensionPolicies",
                                 std::make_unique<base::DictionaryValue>());
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   expected_values.SetDictionary("loginScreenExtensionPolicies",
                                 std::make_unique<base::DictionaryValue>());
   expected_values.SetDictionary("deviceLocalAccountPolicies",
                                 std::make_unique<base::DictionaryValue>());
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   provider_.UpdateChromePolicy(values);
 
@@ -465,7 +466,7 @@
   // contents).
   VerifyExportingPolicies(expected_values);
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   // This also checks that we do not bypass the policy that blocks file
   // selection dialogs. This is a desktop only policy.
   values.Set(policy::key::kAllowFileSelectionDialogs,
@@ -596,11 +597,11 @@
   bool UseSigninProfile() const { return GetParam(); }
 
   Profile* extension_profile() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     if (UseSigninProfile()) {
       return chromeos::ProfileHelper::GetSigninProfile();
     }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
     return browser()->profile();
   }
 };
@@ -796,10 +797,10 @@
 
 INSTANTIATE_TEST_SUITE_P(All,
                          ExtensionPolicyUITest,
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
                          ::testing::Values(false, true)
-#else   // defined(OS_CHROMEOS)
+#else   // BUILDFLAG(IS_CHROMEOS_ASH)
                          ::testing::Values(false)
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 );
diff --git a/chrome/browser/ui/webui/policy_ui_handler.cc b/chrome/browser/ui/webui/policy_ui_handler.cc
index fb3f4d9c..ec28ccc 100644
--- a/chrome/browser/ui/webui/policy_ui_handler.cc
+++ b/chrome/browser/ui/webui/policy_ui_handler.cc
@@ -27,6 +27,7 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/policy/chrome_browser_policy_connector.h"
@@ -79,7 +80,7 @@
 #include "chrome/browser/ui/android/android_about_app_info.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/active_directory_policy_manager.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
@@ -217,7 +218,7 @@
                   GetTimeSinceLastRefreshString(last_refresh_time));
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Adds a new entry to |dict| with the affiliation status of the user associated
 // with |profile|. Device scope policy status providers call this method with
 // nullptr |profile|. In this case no entry is added as affiliation status only
@@ -240,7 +241,7 @@
                      off_hours_controller->is_off_hours_mode());
   }
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 void ExtractDomainFromUsername(base::DictionaryValue* dict) {
   std::string username;
@@ -310,7 +311,7 @@
   DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyStatusProvider);
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // A cloud policy status provider for user policy on Chrome OS.
 class UserCloudPolicyStatusProviderChromeOS
     : public UserCloudPolicyStatusProvider {
@@ -326,9 +327,9 @@
   Profile* profile_;
   DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyStatusProviderChromeOS);
 };
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
 class MachineLevelUserCloudPolicyStatusProvider
     : public PolicyStatusProvider,
       public policy::CloudPolicyStore::Observer {
@@ -348,9 +349,9 @@
 
   DISALLOW_COPY_AND_ASSIGN(MachineLevelUserCloudPolicyStatusProvider);
 };
-#endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#endif  // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // A cloud policy status provider for device policy.
 class DeviceCloudPolicyStatusProviderChromeOS
     : public CloudPolicyCoreStatusProvider {
@@ -514,7 +515,7 @@
   ExtractDomainFromUsername(dict);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 UserCloudPolicyStatusProviderChromeOS::UserCloudPolicyStatusProviderChromeOS(
     policy::CloudPolicyCore* core,
     Profile* profile)
@@ -532,9 +533,9 @@
   UserCloudPolicyStatusProvider::GetStatus(dict);
   GetUserAffiliationStatus(dict, profile_);
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
 
 MachineLevelUserCloudPolicyStatusProvider::
     MachineLevelUserCloudPolicyStatusProvider(policy::CloudPolicyCore* core)
@@ -604,9 +605,9 @@
   NotifyStatusChange();
 }
 
-#endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#endif  // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 DeviceCloudPolicyStatusProviderChromeOS::
     DeviceCloudPolicyStatusProviderChromeOS(
         policy::BrowserPolicyConnectorChromeOS* connector)
@@ -735,7 +736,7 @@
   dict->SetString("enterpriseDisplayDomain", enterprise_display_domain_);
 }
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
 UpdaterStatusProvider::UpdaterStatusProvider() {
@@ -843,7 +844,7 @@
 
 void PolicyUIHandler::RegisterMessages() {
   Profile* profile = Profile::FromWebUI(web_ui());
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   if (connector->IsEnterpriseManaged()) {
@@ -901,7 +902,7 @@
             manager->core());
   }
 #endif  // !defined(OS_ANDROID)
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_WIN) && BUILDFLAG(GOOGLE_CHROME_BRANDING)
   ReloadUpdaterPoliciesAndState();
@@ -1015,9 +1016,9 @@
   // Add extension policy names.
   AddExtensionPolicyNames(&names, policy::POLICY_DOMAIN_EXTENSIONS);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   AddExtensionPolicyNames(&names, policy::POLICY_DOMAIN_SIGNIN_EXTENSIONS);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
@@ -1049,14 +1050,14 @@
   DCHECK(names->is_dict());
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   Profile* extension_profile =
       policy_domain == policy::POLICY_DOMAIN_SIGNIN_EXTENSIONS
           ? chromeos::ProfileHelper::GetSigninProfile()
           : Profile::FromWebUI(web_ui());
-#else   // defined(OS_CHROMEOS)
+#else   // BUILDFLAG(IS_CHROMEOS_ASH)
   Profile* extension_profile = Profile::FromWebUI(web_ui());
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   scoped_refptr<policy::SchemaMap> schema_map =
       extension_profile->GetOriginalProfile()
@@ -1164,7 +1165,7 @@
 }
 
 void PolicyUIHandler::HandleReloadPolicies(const base::ListValue* args) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Allow user to manually fetch remote commands. Useful for testing or when
   // the invalidation service is not working properly.
   policy::CloudPolicyManager* const device_manager =
@@ -1232,7 +1233,7 @@
       cohort_name.c_str());
   chrome_metadata.SetKey("version", base::Value(version));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   chrome_metadata.SetKey("platform",
                          base::Value(chromeos::version_loader::GetVersion(
                              chromeos::version_loader::VERSION_FULL)));
diff --git a/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc b/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
index c48314e..62937ac 100644
--- a/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/pdf_printer_handler.cc
@@ -20,6 +20,7 @@
 #include "base/task/thread_pool.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_prefs.h"
@@ -49,7 +50,7 @@
 #include "components/printing/browser/printer_capabilities_mac.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #endif
 
@@ -254,7 +255,7 @@
 
   base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
   bool prompt_user = !cmdline->HasSwitch(switches::kKioskModePrinting);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   use_drive_mount_ =
       settings.FindBoolKey(kSettingPrintToGoogleDrive).value_or(false);
 #endif
@@ -430,7 +431,7 @@
 }
 
 base::FilePath PdfPrinterHandler::GetSaveLocation() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   drive::DriveIntegrationService* drive_service =
       drive::DriveIntegrationServiceFactory::GetForProfile(profile_);
   if (use_drive_mount_ && drive_service && drive_service->IsMounted()) {
diff --git a/chrome/browser/ui/webui/print_preview/pdf_printer_handler.h b/chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
index 26954ae..d796486f 100644
--- a/chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
+++ b/chrome/browser/ui/webui/print_preview/pdf_printer_handler.h
@@ -11,6 +11,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
 
@@ -108,7 +109,7 @@
   // The callback to call when complete.
   PrintCallback print_callback_;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Determines if the local Drive mount is sent to the file picker as the
   // default save location. Set to true for Save to Drive print jobs.
   bool use_drive_mount_ = false;
diff --git a/chrome/browser/ui/webui/print_preview/policy_settings.cc b/chrome/browser/ui/webui/print_preview/policy_settings.cc
index 28088a6..812407b 100644
--- a/chrome/browser/ui/webui/print_preview/policy_settings.cc
+++ b/chrome/browser/ui/webui/print_preview/policy_settings.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/ui/webui/print_preview/policy_settings.h"
 
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/pref_names.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 
@@ -18,7 +19,7 @@
                                 0);
   registry->RegisterIntegerPref(prefs::kPrintingBackgroundGraphicsDefault, 0);
   registry->RegisterDictionaryPref(prefs::kPrintingPaperSizeDefault);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   registry->RegisterIntegerPref(prefs::kPrintingAllowedColorModes, 0);
   registry->RegisterIntegerPref(prefs::kPrintingAllowedDuplexModes, 0);
   registry->RegisterIntegerPref(prefs::kPrintingAllowedPinModes, 0);
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
index adf2433..1a3c39c 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.cc
@@ -24,6 +24,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/app_mode/app_mode_utils.h"
 #include "chrome/browser/bad_message.h"
 #include "chrome/browser/browser_process.h"
@@ -78,7 +79,7 @@
 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
 #include "third_party/icu/source/i18n/unicode/ulocdata.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/account_manager/account_manager_util.h"
 #include "chrome/browser/chromeos/drive/drive_integration_service.h"
 #include "chrome/browser/device_identity/device_oauth2_token_service.h"
@@ -177,12 +178,12 @@
 // Name of a dictionary pref holding the policy value for the paper size
 // setting.
 const char kMediaSize[] = "mediaSize";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Name of a dictionary field holding policy value for the setting.
 const char kValue[] = "value";
 // Name of a dictionary pref holding the policy value for the sheets number.
 const char kSheets[] = "sheets";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 // Name of a dictionary field indicating whether the 'Save to PDF' destination
 // is disabled.
 const char kPdfPrinterDisabled[] = "pdfPrinterDisabled";
@@ -197,11 +198,11 @@
 // Print Preview will always send a request to the Google Cloud Print server on
 // load, to check the user's sign in state.
 const char kSyncAvailable[] = "syncAvailable";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Name of a dictionary field indicating whether the user's Drive directory is
 // mounted.
 const char kIsDriveMounted[] = "isDriveMounted";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Get the print job settings dictionary from |json_str|.
 // Returns |base::Value()| on failure.
@@ -226,7 +227,7 @@
     return UserActionBuckets::kOpenInMacPreview;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (base::FeatureList::IsEnabled(chromeos::features::kPrintSaveToDrive) &&
       settings.FindBoolKey(kSettingPrintToGoogleDrive).value_or(false)) {
     return UserActionBuckets::kPrintToGoogleDriveCros;
@@ -324,21 +325,21 @@
   if (!paper_size_policy.DictEmpty())
     policies.SetKey(kMediaSize, std::move(paper_size_policy));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (prefs.HasPrefPath(prefs::kPrintingMaxSheetsAllowed)) {
     base::Value sheets_policy(base::Value::Type::DICTIONARY);
     sheets_policy.SetIntKey(kValue,
                             prefs.GetInteger(prefs::kPrintingMaxSheetsAllowed));
     policies.SetKey(kSheets, std::move(sheets_policy));
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   return policies;
 }
 
 }  // namespace
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 class PrintPreviewHandler::AccessTokenService
     : public OAuth2AccessTokenManager::Consumer {
  public:
@@ -380,7 +381,7 @@
 
   DISALLOW_COPY_AND_ASSIGN(AccessTokenService);
 };
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 PrintPreviewHandler::PrintPreviewHandler() {
   ReportUserActionHistogram(UserActionBuckets::kPreviewStarted);
@@ -418,7 +419,7 @@
   web_ui()->RegisterMessageCallback(
       "signIn", base::BindRepeating(&PrintPreviewHandler::HandleSignin,
                                     base::Unretained(this)));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       "getAccessToken",
       base::BindRepeating(&PrintPreviewHandler::HandleGetAccessToken,
@@ -454,7 +455,7 @@
       base::BindRepeating(&PrintPreviewHandler::HandleManagePrinters,
                           base::Unretained(this)));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       "getEulaUrl", base::BindRepeating(&PrintPreviewHandler::HandleGetEulaUrl,
                                         base::Unretained(this)));
@@ -817,7 +818,7 @@
   Profile* profile = Profile::FromWebUI(web_ui());
   DCHECK(profile);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (chromeos::IsAccountManagerAvailable(profile)) {
     // Chrome OS Account Manager is enabled on this Profile and hence, all
     // account management flows will go through native UIs and not through a
@@ -844,7 +845,7 @@
   FireWebUIListener("check-for-account-update");
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void PrintPreviewHandler::HandleGetAccessToken(const base::ListValue* args) {
   std::string callback_id;
 
@@ -886,7 +887,7 @@
       regenerate_preview_request_count_);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void PrintPreviewHandler::HandleGetEulaUrl(const base::ListValue* args) {
   CHECK_EQ(2U, args->GetSize());
 
@@ -1020,7 +1021,7 @@
     GetUserAccountList(&initial_settings);
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (base::FeatureList::IsEnabled(chromeos::features::kPrintSaveToDrive)) {
     drive::DriveIntegrationService* drive_service =
         drive::DriveIntegrationServiceFactory::GetForProfile(
@@ -1028,7 +1029,7 @@
     initial_settings.SetBoolKey(kIsDriveMounted,
                                 drive_service && drive_service->IsMounted());
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   ResolveJavascriptCallback(base::Value(callback_id), initial_settings);
 }
@@ -1037,7 +1038,7 @@
   print_preview_ui()->OnClosePrintPreviewDialog();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void PrintPreviewHandler::SendAccessToken(const std::string& callback_id,
                                           const std::string& access_token) {
   VLOG(1) << "Get getAccessToken finished";
@@ -1399,7 +1400,7 @@
   FireWebUIListener("manipulate-settings-for-test", settings);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void PrintPreviewHandler::HandleRequestPrinterStatusUpdate(
     const base::ListValue* args) {
   CHECK_EQ(2U, args->GetSize());
@@ -1421,7 +1422,7 @@
 #endif
 
 void PrintPreviewHandler::HandleManagePrinters(const base::ListValue* args) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
       Profile::FromWebUI(web_ui()),
       chromeos::settings::mojom::kPrintingDetailsSubpagePath);
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler.h b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
index dd538d6..6853e6f 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler.h
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler.h
@@ -16,6 +16,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/timer/timer.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/buildflags.h"
 #include "components/prefs/pref_service.h"
 #include "components/printing/common/print.mojom.h"
@@ -146,7 +147,7 @@
   FRIEND_TEST_ALL_PREFIXES(PrintPreviewHandlerFailingTest,
                            GetPrinterCapabilities);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   class AccessTokenService;
 #endif
 
@@ -221,7 +222,7 @@
   // Called when the tab opened by HandleSignIn() is closed.
   void OnSignInTabClosed();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Generates new token and sends back to UI.
   void HandleGetAccessToken(const base::ListValue* args);
 #endif
@@ -238,7 +239,7 @@
   // dialog. |args| is unused.
   void HandleManagePrinters(const base::ListValue* args);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Gets the EULA URL.
   void HandleGetEulaUrl(const base::ListValue* args);
 #endif
@@ -246,7 +247,7 @@
   void SendInitialSettings(const std::string& callback_id,
                            const std::string& default_printer);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Send OAuth2 access token.
   void SendAccessToken(const std::string& callback_id,
                        const std::string& access_token);
@@ -311,7 +312,7 @@
   void OnPrintResult(const std::string& callback_id,
                      const base::Value& error);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Called to initiate a status request for a printer.
   void HandleRequestPrinterStatusUpdate(const base::ListValue* args);
 
@@ -336,7 +337,7 @@
   // The settings used for the most recent preview request.
   base::Value last_preview_settings_;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Holds token service to get OAuth2 access tokens.
   std::unique_ptr<AccessTokenService> token_service_;
 #endif
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc b/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
index c38d2769..0b94314e 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_handler_unittest.cc
@@ -22,6 +22,7 @@
 #include "base/test/icu_test_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/printing/print_test_utils.h"
 #include "chrome/browser/printing/print_view_manager.h"
 #include "chrome/browser/ui/webui/print_preview/fake_print_render_frame.h"
@@ -803,14 +804,14 @@
       std::move(expected_initial_settings_policy));
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(PrintPreviewHandlerTest, InitialSettingsMaxSheetsAllowedPolicy) {
   prefs()->SetInteger(prefs::kPrintingMaxSheetsAllowed, 2);
   Initialize();
   ValidateInitialSettingsValuePolicy(*web_ui()->call_data().back(), "sheets",
                                      base::Value(2));
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 TEST_F(PrintPreviewHandlerTest, GetPrinters) {
   Initialize();
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_metrics.cc b/chrome/browser/ui/webui/print_preview/print_preview_metrics.cc
index d00cef7..303f21d 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_metrics.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_metrics.cc
@@ -11,6 +11,7 @@
 #include "base/optional.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "printing/mojom/print.mojom.h"
 #include "printing/print_job_constants.h"
 #include "printing/print_settings.h"
@@ -171,10 +172,10 @@
     }
   }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (print_settings.FindStringKey(kSettingPinValue))
     ReportPrintSettingHistogram(PrintSettingsBuckets::kPin);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void ReportRegeneratePreviewRequestCountBeforeCancel(size_t count) {
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
index a1ddf703..a1f8da45 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui.cc
@@ -28,6 +28,7 @@
 #include "base/synchronization/lock.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/pdf/pdf_extension_util.h"
 #include "chrome/browser/printing/background_printing_manager.h"
@@ -84,7 +85,7 @@
 #if defined(OS_MAC)
 // U+0028 U+21E7 U+2318 U+0050 U+0029 in UTF8
 const char kBasicPrintShortcut[] = "\x28\xE2\x8c\xA5\xE2\x8C\x98\x50\x29";
-#elif !defined(OS_CHROMEOS)
+#elif !BUILDFLAG(IS_CHROMEOS_ASH)
 const char kBasicPrintShortcut[] = "(Ctrl+Shift+P)";
 #endif
 
@@ -311,7 +312,7 @@
     {"title", IDS_PRINT_PREVIEW_TITLE},
     {"top", IDS_PRINT_PREVIEW_TOP_MARGIN_LABEL},
     {"unsupportedCloudPrinter", IDS_PRINT_PREVIEW_UNSUPPORTED_CLOUD_PRINTER},
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {"configuringFailedText", IDS_PRINT_CONFIGURING_FAILED_TEXT},
     {"configuringInProgressText", IDS_PRINT_CONFIGURING_IN_PROGRESS_TEXT},
     {"optionPin", IDS_PRINT_PREVIEW_OPTION_PIN},
@@ -346,7 +347,7 @@
   source->AddString("gcpCertificateErrorLearnMoreURL",
                     chrome::kCloudPrintCertificateErrorLearnMoreURL);
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   const base::string16 shortcut_text(base::UTF8ToUTF16(kBasicPrintShortcut));
   source->AddString("systemDialogOption",
                     l10n_util::GetStringFUTF16(
@@ -362,7 +363,7 @@
 }
 
 void AddPrintPreviewFlags(content::WebUIDataSource* source, Profile* profile) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   source->AddBoolean("useSystemDefaultPrinter", false);
 #else
   bool system_default_printer = profile->GetPrefs()->GetBoolean(
@@ -385,7 +386,7 @@
           base::FeatureList::IsEnabled(features::kForceEnablePrivetPrinting));
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   source->AddBoolean(
       "showPrinterStatus",
       base::FeatureList::IsEnabled(chromeos::features::kPrinterStatus));
@@ -458,7 +459,7 @@
       "printPreviewPageSummaryLabel", IDS_PRINT_PREVIEW_PAGE_SUMMARY_LABEL);
   plural_string_handler->AddLocalizedString(
       "printPreviewSheetSummaryLabel", IDS_PRINT_PREVIEW_SHEET_SUMMARY_LABEL);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   plural_string_handler->AddLocalizedString(
       "sheetsLimitErrorMessage", IDS_PRINT_PREVIEW_SHEETS_LIMIT_ERROR_MESSAGE);
 #endif
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc b/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc
index 78e8255f..1052355 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_ui_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/task_manager/task_manager_browsertest_util.h"
@@ -58,7 +59,7 @@
 
   ASSERT_TRUE(chrome::IsCommandEnabled(browser(), IDC_PRINT));
 
-#if BUILDFLAG(ENABLE_PRINTING) && !defined(OS_CHROMEOS)
+#if BUILDFLAG(ENABLE_PRINTING) && !BUILDFLAG(IS_CHROMEOS_ASH)
   // This is analagous to ENABLE_BASIC_PRINT_DIALOG but helps to verify
   // that it is defined as expected.
   bool is_basic_print_expected = true;
diff --git a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
index c0bed875..4ff1f4d 100644
--- a/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
+++ b/chrome/browser/ui/webui/print_preview/print_preview_utils.cc
@@ -18,6 +18,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/printing/print_preview_dialog_controller.h"
 #include "chrome/browser/printing/print_view_manager.h"
 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
@@ -56,12 +57,12 @@
     for (const auto& opt_it : printer.options)
       options->SetString(opt_it.first, opt_it.second);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     printer_info->SetBoolean(
         kCUPSEnterprisePrinter,
         base::Contains(printer.options, kCUPSEnterprisePrinter) &&
             printer.options.at(kCUPSEnterprisePrinter) == kValueTrue);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
     printer_info->Set(kSettingPrinterOptions, std::move(options));
 
diff --git a/chrome/browser/ui/webui/print_preview/printer_handler.cc b/chrome/browser/ui/webui/print_preview/printer_handler.cc
index 2b2a952..e29f23e 100644
--- a/chrome/browser/ui/webui/print_preview/printer_handler.cc
+++ b/chrome/browser/ui/webui/print_preview/printer_handler.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/print_preview/printer_handler.h"
 
 #include "build/buildflag.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/print_preview/extension_printer_handler.h"
 #include "chrome/browser/ui/webui/print_preview/pdf_printer_handler.h"
 #include "chrome/common/buildflags.h"
@@ -13,7 +14,7 @@
 #include "chrome/browser/ui/webui/print_preview/privet_printer_handler.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/webui/print_preview/local_printer_handler_chromeos.h"
 #else
 #include "chrome/browser/ui/webui/print_preview/local_printer_handler_default.h"
@@ -31,7 +32,7 @@
 std::unique_ptr<PrinterHandler> PrinterHandler::CreateForLocalPrinters(
     content::WebContents* preview_web_contents,
     Profile* profile) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   return LocalPrinterHandlerChromeos::CreateDefault(profile,
                                                     preview_web_contents);
 #else
@@ -65,7 +66,7 @@
   NOTREACHED();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void PrinterHandler::StartGetEulaUrl(const std::string& destination_id,
                                      GetEulaUrlCallback callback) {
   NOTREACHED();
diff --git a/chrome/browser/ui/webui/print_preview/printer_handler.h b/chrome/browser/ui/webui/print_preview/printer_handler.h
index 6fa82c3..f9a02da 100644
--- a/chrome/browser/ui/webui/print_preview/printer_handler.h
+++ b/chrome/browser/ui/webui/print_preview/printer_handler.h
@@ -13,6 +13,7 @@
 #include "base/memory/ref_counted_memory.h"
 #include "base/strings/string16.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/buildflags.h"
 
 namespace content {
@@ -49,7 +50,7 @@
   using PrintCallback = base::OnceCallback<void(const base::Value& error)>;
   using GetPrinterInfoCallback =
       base::OnceCallback<void(const base::DictionaryValue& printer_info)>;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   using GetEulaUrlCallback =
       base::OnceCallback<void(const std::string& license)>;
   using PrinterStatusRequestCallback =
@@ -117,7 +118,7 @@
                           scoped_refptr<base::RefCountedMemory> print_data,
                           PrintCallback callback) = 0;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Starts getting the printer's PPD EULA URL with the provided destination ID.
   // |destination_id|: The ID of the printer.
   // |callback| should be called in response to the request.
diff --git a/chrome/browser/ui/webui/settings/about_handler.cc b/chrome/browser/ui/webui/settings/about_handler.cc
index bf04fc096..d4522c4e 100644
--- a/chrome/browser/ui/webui/settings/about_handler.cc
+++ b/chrome/browser/ui/webui/settings/about_handler.cc
@@ -27,6 +27,7 @@
 #include "base/values.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/ui/browser.h"
@@ -49,7 +50,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "v8/include/v8-version-string.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "base/i18n/time_formatting.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
@@ -79,7 +80,7 @@
 
 namespace {
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 
 // The directory containing the regulatory labels for supported
 // models/regions, relative to chromeos-assets directory
@@ -211,7 +212,7 @@
   return version_info;
 }
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 std::string UpdateStatusToString(VersionUpdater::Status status) {
   std::string status_str;
@@ -277,7 +278,7 @@
   web_ui()->RegisterMessageCallback(
       "openHelpPage", base::BindRepeating(&AboutHandler::HandleOpenHelpPage,
                                           base::Unretained(this)));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       "openOsHelpPage", base::BindRepeating(&AboutHandler::HandleOpenOsHelpPage,
                                             base::Unretained(this)));
@@ -328,7 +329,7 @@
                                             base::Unretained(this)));
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Handler for the product label image, which will be shown if available.
   content::URLDataSource::Add(profile_,
                               std::make_unique<chromeos::ImageSource>());
@@ -388,7 +389,7 @@
 
 void AboutHandler::RefreshUpdateStatus() {
 // On Chrome OS, do not check for an update automatically.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   static_cast<VersionUpdaterCros*>(version_updater_.get())
       ->GetUpdateStatus(
           base::Bind(&AboutHandler::SetUpdateStatus, base::Unretained(this)));
@@ -418,7 +419,7 @@
   chrome::ShowHelp(browser, chrome::HELP_SOURCE_WEBUI);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AboutHandler::HandleCheckInternetConnection(const base::ListValue* args) {
   CHECK_EQ(1U, args->GetSize());
   std::string callback_id;
@@ -620,7 +621,7 @@
   ResolveJavascriptCallback(base::Value(callback_id), response);
 }
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 void AboutHandler::RequestUpdate() {
   version_updater_->CheckForUpdate(
@@ -651,7 +652,7 @@
   event->SetString("version", version);
   // DictionaryValue does not support int64_t, so convert to string.
   event->SetString("size", base::NumberToString(size));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (status == VersionUpdater::FAILED_OFFLINE ||
       status == VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED) {
     base::string16 types_msg = GetAllowedConnectionTypesMessage();
@@ -662,7 +663,7 @@
   } else {
     event->Set("connectionTypes", std::make_unique<base::Value>());
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   FireWebUIListener("update-status-changed", *event);
 }
@@ -695,7 +696,7 @@
 }
 #endif  // defined(OS_MAC)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AboutHandler::OnRegulatoryLabelDirFound(
     std::string callback_id,
     const base::FilePath& label_dir_path) {
@@ -728,6 +729,6 @@
 
   ResolveJavascriptCallback(base::Value(callback_id), *regulatory_info);
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/about_handler.h b/chrome/browser/ui/webui/settings/about_handler.h
index bed6a0e..68754be 100644
--- a/chrome/browser/ui/webui/settings/about_handler.h
+++ b/chrome/browser/ui/webui/settings/about_handler.h
@@ -13,16 +13,17 @@
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/help/version_updater.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "chrome/browser/upgrade_detector/upgrade_observer.h"
 #include "components/policy/core/common/policy_service.h"
 #include "content/public/browser/web_ui_message_handler.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "base/task/cancelable_task_tracker.h"
 #include "chrome/browser/chromeos/tpm_firmware_update.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace base {
 class DictionaryValue;
@@ -82,7 +83,7 @@
   // Opens the help page. |args| must be empty.
   void HandleOpenHelpPage(const base::ListValue* args);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Checks if ReleaseNotes is enabled.
   void HandleGetEnabledReleaseNotes(const base::ListValue* args);
 
@@ -152,7 +153,7 @@
   void SetPromotionState(VersionUpdater::PromotionState state);
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void HandleGetRegulatoryInfo(const base::ListValue* args);
 
   // Callback for when the directory with the regulatory label image and alt
diff --git a/chrome/browser/ui/webui/settings/accessibility_main_handler.cc b/chrome/browser/ui/webui/settings/accessibility_main_handler.cc
index 20af59f6..54b8c63cf 100644
--- a/chrome/browser/ui/webui/settings/accessibility_main_handler.cc
+++ b/chrome/browser/ui/webui/settings/accessibility_main_handler.cc
@@ -8,6 +8,7 @@
 
 #include "base/bind.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/accessibility/accessibility_state_utils.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/renderer_context_menu/accessibility_labels_bubble_model.h"
@@ -37,19 +38,19 @@
 }
 
 void AccessibilityMainHandler::OnJavascriptAllowed() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   accessibility_subscription_ =
       chromeos::AccessibilityManager::Get()->RegisterCallback(
           base::BindRepeating(
               &AccessibilityMainHandler::OnAccessibilityStatusChanged,
               base::Unretained(this)));
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void AccessibilityMainHandler::OnJavascriptDisallowed() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   accessibility_subscription_ = {};
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void AccessibilityMainHandler::HandleA11yPageReady(
@@ -78,7 +79,7 @@
   FireWebUIListener("screen-reader-state-changed", result);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AccessibilityMainHandler::OnAccessibilityStatusChanged(
     const chromeos::AccessibilityStatusEventDetails& details) {
   if (details.notification_type ==
@@ -86,6 +87,6 @@
     SendScreenReaderStateChanged();
   }
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/accessibility_main_handler.h b/chrome/browser/ui/webui/settings/accessibility_main_handler.h
index 471690af..dc5269a 100644
--- a/chrome/browser/ui/webui/settings/accessibility_main_handler.h
+++ b/chrome/browser/ui/webui/settings/accessibility_main_handler.h
@@ -8,11 +8,12 @@
 #include <memory>
 
 #include "base/macros.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace base {
 class ListValue;
@@ -40,12 +41,12 @@
  private:
   void SendScreenReaderStateChanged();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void OnAccessibilityStatusChanged(
       const chromeos::AccessibilityStatusEventDetails& details);
 
   base::CallbackListSubscription accessibility_subscription_;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 };
 
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/appearance_handler.cc b/chrome/browser/ui/webui/settings/appearance_handler.cc
index c4f57a6..931649cc 100644
--- a/chrome/browser/ui/webui/settings/appearance_handler.cc
+++ b/chrome/browser/ui/webui/settings/appearance_handler.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/notreached.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
@@ -27,7 +28,9 @@
       "useDefaultTheme",
       base::BindRepeating(&AppearanceHandler::HandleUseDefaultTheme,
                           base::Unretained(this)));
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   web_ui()->RegisterMessageCallback(
       "useSystemTheme",
       base::BindRepeating(&AppearanceHandler::HandleUseSystemTheme,
@@ -39,7 +42,9 @@
   ThemeServiceFactory::GetForProfile(profile_)->UseDefaultTheme();
 }
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 void AppearanceHandler::HandleUseSystemTheme(const base::ListValue* args) {
   if (profile_->IsSupervised())
     NOTREACHED();
diff --git a/chrome/browser/ui/webui/settings/appearance_handler.h b/chrome/browser/ui/webui/settings/appearance_handler.h
index 961e16e..60f42a6 100644
--- a/chrome/browser/ui/webui/settings/appearance_handler.h
+++ b/chrome/browser/ui/webui/settings/appearance_handler.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
 namespace base {
@@ -36,7 +37,9 @@
   // Changes the UI theme of the browser to the default theme.
   void HandleUseDefaultTheme(const base::ListValue* args);
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   // Changes the UI theme of the browser to the system (GTK+) theme.
   void HandleUseSystemTheme(const base::ListValue* args);
 #endif
diff --git a/chrome/browser/ui/webui/settings/browser_lifetime_handler.cc b/chrome/browser/ui/webui/settings/browser_lifetime_handler.cc
index 02e3ff5..8b03ae3 100644
--- a/chrome/browser/ui/webui/settings/browser_lifetime_handler.cc
+++ b/chrome/browser/ui/webui/settings/browser_lifetime_handler.cc
@@ -7,22 +7,23 @@
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/tpm_firmware_update.h"
 #include "chrome/browser/ui/webui/webui_util.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/user_manager/user_manager.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace settings {
 
 namespace {
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Triggers a TPM firmware update using the least destructive mode from
 // |available_modes|.
 void TriggerTPMFirmwareUpdate(
@@ -47,7 +48,7 @@
     return;
   }
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace
 
@@ -62,7 +63,7 @@
   web_ui()->RegisterMessageCallback(
       "relaunch", base::BindRepeating(&BrowserLifetimeHandler::HandleRelaunch,
                                       base::Unretained(this)));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       "signOutAndRestart",
       base::BindRepeating(&BrowserLifetimeHandler::HandleSignOutAndRestart,
@@ -71,7 +72,7 @@
       "factoryReset",
       base::BindRepeating(&BrowserLifetimeHandler::HandleFactoryReset,
                           base::Unretained(this)));
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void BrowserLifetimeHandler::HandleRestart(
@@ -84,7 +85,7 @@
   chrome::AttemptRelaunch();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void BrowserLifetimeHandler::HandleSignOutAndRestart(
     const base::ListValue* args) {
   chrome::AttemptUserExit();
@@ -119,6 +120,6 @@
   // be launched (as if it was a restart).
   chrome::AttemptRelaunch();
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/browser_lifetime_handler.h b/chrome/browser/ui/webui/settings/browser_lifetime_handler.h
index b5394d16..6ded5ac3 100644
--- a/chrome/browser/ui/webui/settings/browser_lifetime_handler.h
+++ b/chrome/browser/ui/webui/settings/browser_lifetime_handler.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_BROWSER_LIFETIME_HANDLER_H_
 
 #include "base/macros.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
 namespace base {
@@ -27,10 +28,10 @@
  private:
   void HandleRestart(const base::ListValue* /*args*/);
   void HandleRelaunch(const base::ListValue* /*args*/);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void HandleSignOutAndRestart(const base::ListValue* /*args*/);
   void HandleFactoryReset(const base::ListValue* /*args*/);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   DISALLOW_COPY_AND_ASSIGN(BrowserLifetimeHandler);
 };
diff --git a/chrome/browser/ui/webui/settings/chromeos/constants/BUILD.gn b/chrome/browser/ui/webui/settings/chromeos/constants/BUILD.gn
index a2ed7da..af9c1c9 100644
--- a/chrome/browser/ui/webui/settings/chromeos/constants/BUILD.gn
+++ b/chrome/browser/ui/webui/settings/chromeos/constants/BUILD.gn
@@ -2,9 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/chromeos/ui_mode.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 
-assert(is_chromeos)
+assert(is_chromeos_ash)
 
 mojom("mojom") {
   sources = [
diff --git a/chrome/browser/ui/webui/settings/chromeos/search/BUILD.gn b/chrome/browser/ui/webui/settings/chromeos/search/BUILD.gn
index abbe2fc..0065095 100644
--- a/chrome/browser/ui/webui/settings/chromeos/search/BUILD.gn
+++ b/chrome/browser/ui/webui/settings/chromeos/search/BUILD.gn
@@ -2,9 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/chromeos/ui_mode.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 
-assert(is_chromeos)
+assert(is_chromeos_ash)
 
 mojom("mojo_bindings") {
   sources = [
diff --git a/chrome/browser/ui/webui/settings/custom_home_pages_table_model.cc b/chrome/browser/ui/webui/settings/custom_home_pages_table_model.cc
index 63dc7c8..b4b0df2 100644
--- a/chrome/browser/ui/webui/settings/custom_home_pages_table_model.cc
+++ b/chrome/browser/ui/webui/settings/custom_home_pages_table_model.cc
@@ -10,6 +10,7 @@
 #include "base/callback_helpers.h"
 #include "base/i18n/rtl.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
@@ -25,7 +26,7 @@
 #include "ui/gfx/codec/png_codec.h"
 #include "url/gurl.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/settings_window_manager_chromeos.h"
 #endif
 
@@ -210,7 +211,7 @@
   // Do not include incognito browsers.
   if (browser->profile() != profile_)
     return false;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Do not include the Settings window.
   if (chrome::SettingsWindowManager::GetInstance()->IsSettingsBrowser(
           browser)) {
diff --git a/chrome/browser/ui/webui/settings/downloads_handler.cc b/chrome/browser/ui/webui/settings/downloads_handler.cc
index 782935e..5e6b619 100644
--- a/chrome/browser/ui/webui/settings/downloads_handler.cc
+++ b/chrome/browser/ui/webui/settings/downloads_handler.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/metrics/user_metrics.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/download/download_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/chrome_select_file_policy.h"
@@ -19,7 +20,7 @@
 #include "content/public/browser/web_ui.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/file_manager/path_util.h"
 #endif
 
@@ -49,7 +50,7 @@
       "selectDownloadLocation",
       base::BindRepeating(&DownloadsHandler::HandleSelectDownloadLocation,
                           base::Unretained(this)));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       "getDownloadLocationText",
       base::BindRepeating(&DownloadsHandler::HandleGetDownloadLocationText,
@@ -116,7 +117,7 @@
   pref_service->SetFilePath(prefs::kSaveFileDefaultDirectory, path);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void DownloadsHandler::HandleGetDownloadLocationText(
     const base::ListValue* args) {
   AllowJavascript();
diff --git a/chrome/browser/ui/webui/settings/downloads_handler.h b/chrome/browser/ui/webui/settings/downloads_handler.h
index 5034556..fe06fab1 100644
--- a/chrome/browser/ui/webui/settings/downloads_handler.h
+++ b/chrome/browser/ui/webui/settings/downloads_handler.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "ui/shell_dialogs/select_file_dialog.h"
@@ -51,7 +52,7 @@
                     int index,
                     void* params) override;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Callback for the "getDownloadLocationText" message.  Converts actual
   // paths in chromeos to values suitable to display to users.
   // E.g. /home/chronos/u-<hash>/Downloads => "Downloads".
diff --git a/chrome/browser/ui/webui/settings/languages_handler.cc b/chrome/browser/ui/webui/settings/languages_handler.cc
index aeb49dd..50bf648 100644
--- a/chrome/browser/ui/webui/settings/languages_handler.cc
+++ b/chrome/browser/ui/webui/settings/languages_handler.cc
@@ -7,13 +7,14 @@
 #include "base/bind.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/common/pref_names.h"
 #include "components/language/core/browser/pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/web_ui.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/base/locale_util.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -23,7 +24,7 @@
 
 namespace settings {
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 LanguagesHandler::LanguagesHandler(Profile* profile) : profile_(profile) {}
 #else
 LanguagesHandler::LanguagesHandler() = default;
@@ -50,10 +51,10 @@
   AllowJavascript();
 
   std::string locale;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // On Chrome OS, an individual profile may have a preferred locale.
   locale = profile_->GetPrefs()->GetString(language::prefs::kApplicationLocale);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   if (locale.empty()) {
     locale = g_browser_process->local_state()->GetString(
@@ -74,7 +75,7 @@
 #if defined(OS_WIN)
   PrefService* prefs = g_browser_process->local_state();
   prefs->SetString(language::prefs::kApplicationLocale, language_code);
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
   // Secondary users and public session users cannot change the locale.
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
   const user_manager::User* user =
diff --git a/chrome/browser/ui/webui/settings/languages_handler.h b/chrome/browser/ui/webui/settings/languages_handler.h
index b150e0e..0e17ea9 100644
--- a/chrome/browser/ui/webui/settings/languages_handler.h
+++ b/chrome/browser/ui/webui/settings/languages_handler.h
@@ -6,9 +6,10 @@
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_LANGUAGES_HANDLER_H_
 
 #include "base/macros.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 class Profile;
 #endif
 
@@ -21,7 +22,7 @@
 // Chrome "Languages" settings page UI handler.
 class LanguagesHandler : public SettingsPageUIHandler {
  public:
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   explicit LanguagesHandler(Profile* profile);
 #else
   LanguagesHandler();
@@ -43,7 +44,7 @@
   // The actual UI language will not change until the next restart.
   void HandleSetProspectiveUILanguage(const base::ListValue* args);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   Profile* profile_;  // Weak pointer.
 #endif
 
diff --git a/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc b/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc
index c84c578..38b9a781 100644
--- a/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc
+++ b/chrome/browser/ui/webui/settings/metrics_reporting_handler.cc
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#if defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS)
+#include "build/chromeos_buildflags.h"
+
+#if defined(GOOGLE_CHROME_BUILD) && !BUILDFLAG(IS_CHROMEOS_ASH)
 
 #include "chrome/browser/ui/webui/settings/metrics_reporting_handler.h"
 
@@ -106,4 +108,4 @@
 
 }  // namespace settings
 
-#endif  // defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS)
+#endif  // defined(GOOGLE_CHROME_BUILD) && !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/webui/settings/metrics_reporting_handler.h b/chrome/browser/ui/webui/settings/metrics_reporting_handler.h
index 73cc5bd95..ca90350 100644
--- a/chrome/browser/ui/webui/settings/metrics_reporting_handler.h
+++ b/chrome/browser/ui/webui/settings/metrics_reporting_handler.h
@@ -5,7 +5,9 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_METRICS_REPORTING_HANDLER_H_
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_METRICS_REPORTING_HANDLER_H_
 
-#if defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS)
+#include "build/chromeos_buildflags.h"
+
+#if defined(GOOGLE_CHROME_BUILD) && !BUILDFLAG(IS_CHROMEOS_ASH)
 
 #include <memory>
 
@@ -68,6 +70,6 @@
 
 }  // namespace settings
 
-#endif  // defined(GOOGLE_CHROME_BUILD) && !defined(OS_CHROMEOS)
+#endif  // defined(GOOGLE_CHROME_BUILD) && !BUILDFLAG(IS_CHROMEOS_ASH)
 
 #endif  // CHROME_BROWSER_UI_WEBUI_SETTINGS_METRICS_REPORTING_HANDLER_H_
diff --git a/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc b/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc
index 189c2a8..c587ad61 100644
--- a/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/metrics_reporting_handler_unittest.cc
@@ -3,8 +3,9 @@
 // found in the LICENSE file.
 
 #include "build/branding_buildflags.h"
+#include "build/chromeos_buildflags.h"
 
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !defined(OS_CHROMEOS)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS_ASH)
 
 #include "chrome/browser/ui/webui/settings/metrics_reporting_handler.h"
 
@@ -124,4 +125,4 @@
 
 }  // namespace settings
 
-#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING) && !defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS_ASH)
diff --git a/chrome/browser/ui/webui/settings/on_startup_handler_unittest.cc b/chrome/browser/ui/webui/settings/on_startup_handler_unittest.cc
index 2b60755..d834616 100644
--- a/chrome/browser/ui/webui/settings/on_startup_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/on_startup_handler_unittest.cc
@@ -10,10 +10,11 @@
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
 #include "build/build_config.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "components/user_manager/scoped_user_manager.h"
 #endif
+#include "build/chromeos_buildflags.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
@@ -46,7 +47,7 @@
   void SetUp() override {
     ASSERT_TRUE(profile_manager_.SetUp());
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     chromeos::FakeChromeUserManager* fake_user_manager =
         new chromeos::FakeChromeUserManager;
     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
@@ -71,7 +72,7 @@
   TestingProfileManager profile_manager_;
   std::unique_ptr<TestOnStartupHandler> handler_;
   Profile* profile_;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
 #endif
   content::TestWebUI web_ui_;
diff --git a/chrome/browser/ui/webui/settings/people_handler.cc b/chrome/browser/ui/webui/settings/people_handler.cc
index ea6b036..66cfbd2b 100644
--- a/chrome/browser/ui/webui/settings/people_handler.cc
+++ b/chrome/browser/ui/webui/settings/people_handler.cc
@@ -16,6 +16,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
@@ -60,7 +61,7 @@
 #include "ui/base/webui/web_ui_util.h"
 #include "ui/gfx/image/image.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/webui/profile_helper.h"
 #endif
 
@@ -290,7 +291,7 @@
       "SyncPrefsDispatch",
       base::BindRepeating(&PeopleHandler::HandleSyncPrefsDispatch,
                           base::Unretained(this)));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       "AttemptUserExit",
       base::BindRepeating(&PeopleHandler::HandleAttemptUserExit,
@@ -353,7 +354,7 @@
   sync_service_observer_.RemoveAll();
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void PeopleHandler::DisplayGaiaLogin(signin_metrics::AccessPoint access_point) {
   // Advanced options are no longer being configured if the login screen is
   // visible. If the user exits the signin wizard after this without
@@ -630,7 +631,7 @@
   web_ui()->GetWebContents()->Focus();
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // On ChromeOS, we need to sign out the user session to fix an auth error, so
 // the user goes through the real signin flow to generate a new auth token.
 void PeopleHandler::HandleAttemptUserExit(const base::ListValue* args) {
@@ -650,9 +651,9 @@
 
   identity_manager->GetPrimaryAccountMutator()->RevokeSyncConsent();
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void PeopleHandler::HandleStartSignin(const base::ListValue* args) {
   AllowJavascript();
 
@@ -771,7 +772,7 @@
         if (sync_service) {
           DVLOG(1) << "Sync setup aborted by user action";
           sync_service->StopAndClear();
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
           // Sign out the user on desktop Chrome if they click cancel during
           // initial setup.
           if (!sync_service->GetUserSettings()->IsFirstSetupComplete()) {
@@ -1042,7 +1043,7 @@
 }
 
 void PeopleHandler::MaybeMarkSyncConfiguring() {
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   if (IsProfileAuthNeededOrHasErrors())
     return;
 #endif
diff --git a/chrome/browser/ui/webui/settings/people_handler.h b/chrome/browser/ui/webui/settings/people_handler.h
index a27f0a1..b6013d93 100644
--- a/chrome/browser/ui/webui/settings/people_handler.h
+++ b/chrome/browser/ui/webui/settings/people_handler.h
@@ -14,6 +14,7 @@
 #include "base/timer/timer.h"
 #include "build/build_config.h"
 #include "build/buildflag.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -154,12 +155,12 @@
   void HandleSetEncryption(const base::ListValue* args);
   void HandleShowSyncSetupUI(const base::ListValue* args);
   void HandleSyncPrefsDispatch(const base::ListValue* args);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   void HandleAttemptUserExit(const base::ListValue* args);
   void HandleTurnOnSync(const base::ListValue* args);
   void HandleTurnOffSync(const base::ListValue* args);
 #endif
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   void HandleStartSignin(const base::ListValue* args);
   void HandleSignout(const base::ListValue* args);
   void HandlePauseSync(const base::ListValue* args);
@@ -167,7 +168,7 @@
   void HandleStartKeyRetrieval(const base::ListValue* args);
   void HandleGetSyncStatus(const base::ListValue* args);
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   // Displays the GAIA login form.
   void DisplayGaiaLogin(signin_metrics::AccessPoint access_point);
 
diff --git a/chrome/browser/ui/webui/settings/people_handler_unittest.cc b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
index 81d64ca..ccc0fcaf 100644
--- a/chrome/browser/ui/webui/settings/people_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/people_handler_unittest.cc
@@ -17,6 +17,7 @@
 #include "base/test/mock_callback.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/defaults.h"
 #include "chrome/browser/first_run/first_run.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
@@ -204,7 +205,7 @@
   using PeopleHandler::is_configuring_sync;
 
  private:
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   void DisplayGaiaLoginInNewTabOrWindow(
       signin_metrics::AccessPoint access_point) override {}
 #endif
@@ -364,7 +365,7 @@
   DISALLOW_COPY_AND_ASSIGN(PeopleHandlerTest);
 };
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(PeopleHandlerTest, DisplayBasicLogin) {
   ASSERT_FALSE(identity_test_env()->identity_manager()->HasPrimaryAccount(
       ConsentLevel::kSync));
@@ -394,7 +395,7 @@
       LoginUIServiceFactory::GetForProfile(profile())->current_login_ui());
 }
 
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 TEST_F(PeopleHandlerTest, DisplayConfigureWithEngineDisabledAndCancel) {
   SigninUser();
@@ -1276,7 +1277,7 @@
 }
 #endif  // BUILDFLAG(ENABLE_DICE_SUPPORT)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Regression test for crash in guest mode. https://crbug.com/1040476
 TEST(PeopleHandlerGuestModeTest, GetStoredAccountsList) {
   content::BrowserTaskEnvironment task_environment;
@@ -1312,6 +1313,6 @@
   ASSERT_EQ(1u, accounts_list.size());
   EXPECT_EQ("user@gmail.com", accounts_list[0].FindKey("email")->GetString());
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/profile_info_handler.cc b/chrome/browser/ui/webui/settings/profile_info_handler.cc
index a43b21a..df6ca79 100644
--- a/chrome/browser/ui/webui/settings/profile_info_handler.cc
+++ b/chrome/browser/ui/webui/settings/profile_info_handler.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
@@ -13,7 +14,7 @@
 #include "chrome/common/pref_names.h"
 #include "ui/base/webui/web_ui_util.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/ui/webui/chromeos/user_image_source.h"
 #include "components/account_id/account_id.h"
@@ -34,7 +35,7 @@
     "profile-stats-count-ready";
 
 ProfileInfoHandler::ProfileInfoHandler(Profile* profile) : profile_(profile) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Set up the chrome://userimage/ source.
   content::URLDataSource::Add(profile,
                               std::make_unique<chromeos::UserImageSource>());
@@ -48,7 +49,7 @@
       "getProfileInfo",
       base::BindRepeating(&ProfileInfoHandler::HandleGetProfileInfo,
                           base::Unretained(this)));
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       "getProfileStatsCount",
       base::BindRepeating(&ProfileInfoHandler::HandleGetProfileStats,
@@ -60,7 +61,7 @@
   profile_observer_.Add(
       &g_browser_process->profile_manager()->GetProfileAttributesStorage());
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   user_manager_observer_.Add(user_manager::UserManager::Get());
 #endif
 }
@@ -71,12 +72,12 @@
   profile_observer_.Remove(
       &g_browser_process->profile_manager()->GetProfileAttributesStorage());
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   user_manager_observer_.Remove(user_manager::UserManager::Get());
 #endif
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void ProfileInfoHandler::OnUserImageChanged(const user_manager::User& user) {
   PushProfileInfo();
 }
@@ -103,7 +104,7 @@
   ResolveJavascriptCallback(*callback_id, *GetAccountNameAndIcon());
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void ProfileInfoHandler::HandleGetProfileStats(const base::ListValue* args) {
   AllowJavascript();
 
@@ -134,7 +135,7 @@
   std::string name;
   std::string icon_url;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   const user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
   DCHECK(user);
@@ -145,7 +146,7 @@
   scoped_refptr<base::RefCountedMemory> image =
       chromeos::UserImageSource::GetUserImage(user->GetAccountId());
   icon_url = webui::GetPngDataUrl(image->front(), image->size());
-#else   // !defined(OS_CHROMEOS)
+#else   // !BUILDFLAG(IS_CHROMEOS_ASH)
   ProfileAttributesEntry* entry;
   if (g_browser_process->profile_manager()
           ->GetProfileAttributesStorage()
@@ -159,7 +160,7 @@
         entry->GetAvatarIcon(), true, kAvatarIconSize, kAvatarIconSize);
     icon_url = webui::GetBitmapDataUrl(icon.AsBitmap());
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   auto response = std::make_unique<base::DictionaryValue>();
   response->SetString("name", name);
diff --git a/chrome/browser/ui/webui/settings/profile_info_handler.h b/chrome/browser/ui/webui/settings/profile_info_handler.h
index 354c27d..bc6195c 100644
--- a/chrome/browser/ui/webui/settings/profile_info_handler.h
+++ b/chrome/browser/ui/webui/settings/profile_info_handler.h
@@ -11,11 +11,12 @@
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile_attributes_storage.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "components/prefs/pref_change_registrar.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "components/user_manager/user_manager.h"
 #else
 #include "chrome/browser/profiles/profile_statistics_common.h"
@@ -26,7 +27,7 @@
 namespace settings {
 
 class ProfileInfoHandler : public SettingsPageUIHandler,
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
                            public user_manager::UserManager::Observer,
 #endif
                            public ProfileAttributesStorage::Observer {
@@ -42,7 +43,7 @@
   void OnJavascriptAllowed() override;
   void OnJavascriptDisallowed() override;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // user_manager::UserManager::Observer implementation.
   void OnUserImageChanged(const user_manager::User& user) override;
 #endif
@@ -60,7 +61,7 @@
   void HandleGetProfileInfo(const base::ListValue* args);
   void PushProfileInfo();
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   void HandleGetProfileStats(const base::ListValue* args);
 
   // Returns the sum of the counts of individual profile states. Returns 0 if
@@ -73,7 +74,7 @@
   // Weak pointer.
   Profile* profile_;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   ScopedObserver<user_manager::UserManager, user_manager::UserManager::Observer>
       user_manager_observer_{this};
 #endif
diff --git a/chrome/browser/ui/webui/settings/profile_info_handler_unittest.cc b/chrome/browser/ui/webui/settings/profile_info_handler_unittest.cc
index 8bccab5c..76feb8d 100644
--- a/chrome/browser/ui/webui/settings/profile_info_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/profile_info_handler_unittest.cc
@@ -8,6 +8,7 @@
 
 #include "base/memory/ptr_util.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
@@ -22,7 +23,7 @@
 #include "ui/gfx/codec/png_codec.h"
 #include "url/gurl.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "components/user_manager/scoped_user_manager.h"
 #endif
@@ -31,7 +32,7 @@
 
 namespace {
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 constexpr char fake_id[] = "fake_id";
 constexpr char fake_email[] = "fake_id@gmail.com";
 #endif
@@ -55,7 +56,7 @@
   void SetUp() override {
     ASSERT_TRUE(profile_manager_.SetUp());
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     chromeos::FakeChromeUserManager* fake_user_manager =
         new chromeos::FakeChromeUserManager;
     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
@@ -79,7 +80,7 @@
     ASSERT_TRUE(response->GetString("name", &name));
     ASSERT_TRUE(response->GetString("iconUrl", &icon_url));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     EXPECT_EQ(fake_id, name);
     EXPECT_FALSE(icon_url.empty());
 #else
@@ -105,7 +106,7 @@
   TestingProfileManager profile_manager_;
   content::TestWebUI web_ui_;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
 #endif
 
diff --git a/chrome/browser/ui/webui/settings/reset_settings_handler.cc b/chrome/browser/ui/webui/settings/reset_settings_handler.cc
index 78a086d..63809522 100644
--- a/chrome/browser/ui/webui/settings/reset_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/reset_settings_handler.cc
@@ -14,6 +14,7 @@
 #include "base/time/time.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/google/google_brand.h"
 #include "chrome/browser/net/system_network_context_manager.h"
@@ -31,10 +32,10 @@
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/reset/metrics.h"
 #include "chrome/common/pref_names.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_WIN)
 #include "chrome/browser/profile_resetter/triggered_profile_resetter.h"
@@ -122,12 +123,12 @@
       base::BindRepeating(
           &ResetSettingsHandler::HandleGetTriggeredResetToolName,
           base::Unretained(this)));
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui()->RegisterMessageCallback(
       "onPowerwashDialogShow",
       base::BindRepeating(&ResetSettingsHandler::OnShowPowerwashDialog,
                           base::Unretained(this)));
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void ResetSettingsHandler::HandleResetProfileSettings(
@@ -298,7 +299,7 @@
   ResolveJavascriptCallback(*callback_id, string_value);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void ResetSettingsHandler::OnShowPowerwashDialog(
      const base::ListValue* args) {
   UMA_HISTOGRAM_ENUMERATION(
@@ -306,6 +307,6 @@
       chromeos::reset::DIALOG_FROM_OPTIONS,
       chromeos::reset::DIALOG_VIEW_TYPE_SIZE);
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/reset_settings_handler.h b/chrome/browser/ui/webui/settings/reset_settings_handler.h
index c3b0ef8..2c08f8c 100644
--- a/chrome/browser/ui/webui/settings/reset_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/reset_settings_handler.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profile_resetter/profile_reset_report.pb.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 
@@ -87,10 +88,10 @@
       bool send_feedback,
       reset_report::ChromeResetReport::ResetRequestOrigin request_origin);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Will be called when powerwash dialog is shown.
   void OnShowPowerwashDialog(const base::ListValue* args);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   Profile* const profile_;
 
diff --git a/chrome/browser/ui/webui/settings/safety_check_handler.cc b/chrome/browser/ui/webui/settings/safety_check_handler.cc
index 1ba52b0..6c35ffb 100644
--- a/chrome/browser/ui/webui/settings/safety_check_handler.cc
+++ b/chrome/browser/ui/webui/settings/safety_check_handler.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/user_metrics_action.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h"
 #include "chrome/browser/password_manager/bulk_leak_check_service_factory.h"
@@ -39,7 +40,7 @@
 #include "components/chrome_cleaner/public/constants/constants.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ui/chromeos/devicetype_utils.h"
 #endif
 
@@ -565,7 +566,7 @@
     case UpdateStatus::kChecking:
       return base::UTF8ToUTF16("");
     case UpdateStatus::kUpdated:
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       return ui::SubstituteChromeOSDeviceType(IDS_SETTINGS_UPGRADE_UP_TO_DATE);
 #else
       return l10n_util::GetStringUTF16(IDS_SETTINGS_UPGRADE_UP_TO_DATE);
diff --git a/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc b/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc
index 8c11f5e..66a6a3c 100644
--- a/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/safety_check_handler_unittest.cc
@@ -18,6 +18,7 @@
 #include "base/test/metrics/user_action_tester.h"
 #include "base/types/strong_alias.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h"
 #include "chrome/browser/extensions/api/passwords_private/test_passwords_private_delegate.h"
 #include "chrome/browser/extensions/test_extension_service.h"
@@ -45,7 +46,7 @@
 #include "chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_controller_impl_win.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ui/chromeos/devicetype_utils.h"
 #endif
 
@@ -403,7 +404,7 @@
           kUpdates,
           static_cast<int>(SafetyCheckHandler::UpdateStatus::kUpdated));
   ASSERT_TRUE(event);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   base::string16 expected = base::ASCIIToUTF16("Your ") +
                             ui::GetChromeOSDeviceName() +
                             base::ASCIIToUTF16(" is up to date");
@@ -424,7 +425,7 @@
           kUpdates,
           static_cast<int>(SafetyCheckHandler::UpdateStatus::kUpdating));
   ASSERT_TRUE(event);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   VerifyDisplayString(event, "Updating your device");
 #else
   VerifyDisplayString(event, "Updating Browser");
@@ -442,7 +443,7 @@
           kUpdates,
           static_cast<int>(SafetyCheckHandler::UpdateStatus::kRelaunch));
   ASSERT_TRUE(event);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   VerifyDisplayString(
       event, "Nearly up to date! Restart your device to finish updating.");
 #else
diff --git a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
index dad23a4..c079d57 100644
--- a/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/settings_localized_strings_provider.cc
@@ -90,11 +90,11 @@
 #include "ui/base/webui/web_ui_util.h"
 #include "ui/strings/grit/ui_strings.h"
 
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
 #include "chrome/browser/lacros/account_manager_util.h"
-#endif  // BUILDFLAG(IS_LACROS)
+#endif  // BUILDFLAG(IS_CHROMEOS_LACROS)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/public/cpp/ash_switches.h"
 #include "chrome/browser/chromeos/account_manager/account_manager_util.h"
 #include "chrome/browser/chromeos/assistant/assistant_util.h"
@@ -108,7 +108,7 @@
 #include "chromeos/constants/chromeos_features.h"
 #include "components/user_manager/user_manager.h"
 #include "ui/chromeos/devicetype_utils.h"
-#else  // !defined(OS_CHROMEOS)
+#else  // !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/webui/settings/system_handler.h"
 #include "ui/accessibility/accessibility_features.h"
 #endif
@@ -156,7 +156,7 @@
     {"moreActions", IDS_SETTINGS_MORE_ACTIONS},
     {"ok", IDS_OK},
     {"restart", IDS_SETTINGS_RESTART},
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     {"restartToApplyChanges", IDS_SETTINGS_RESTART_TO_APPLY_CHANGES},
 #endif
     {"retry", IDS_SETTINGS_RETRY},
@@ -187,7 +187,7 @@
 
   html_source->AddBoolean(
       "isGuest",
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       user_manager::UserManager::Get()->IsLoggedInAsGuest() ||
           user_manager::UserManager::Get()->IsLoggedInAsPublicAccount());
 #else
@@ -215,11 +215,11 @@
      IDS_SETTINGS_CAPTIONS_ENABLE_LIVE_CAPTION_SUBTITLE},
     {"caretBrowsingTitle", IDS_SETTINGS_ENABLE_CARET_BROWSING_TITLE},
     {"caretBrowsingSubtitle", IDS_SETTINGS_ENABLE_CARET_BROWSING_SUBTITLE},
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {"manageAccessibilityFeatures",
      IDS_SETTINGS_ACCESSIBILITY_MANAGE_ACCESSIBILITY_FEATURES},
     {"androidAppsManageAppLinks", IDS_SETTINGS_ANDROID_APPS_MANAGE_APP_LINKS},
-#else  // !defined(OS_CHROMEOS)
+#else  // !BUILDFLAG(IS_CHROMEOS_ASH)
     {"focusHighlightLabel",
      IDS_SETTINGS_ACCESSIBILITY_FOCUS_HIGHLIGHT_DESCRIPTION},
 #endif
@@ -234,7 +234,7 @@
       "showExperimentalA11yLabels",
       base::FeatureList::IsEnabled(features::kExperimentalAccessibilityLabels));
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   html_source->AddBoolean(
       "showFocusHighlightOption",
       base::FeatureList::IsEnabled(features::kAccessibilityFocusHighlight));
@@ -261,7 +261,7 @@
     {"aboutGetHelpUsingChrome", IDS_SETTINGS_GET_HELP_USING_CHROME},
     {"aboutPageTitle", IDS_SETTINGS_ABOUT_PROGRAM},
     {"aboutProductTitle", IDS_PRODUCT_NAME},
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {"aboutUpdateOsSettingsLink",
      IDS_SETTINGS_ABOUT_SEE_OS_SETTINGS_FOR_UPDATE_MESSAGE},
 #endif
@@ -272,7 +272,7 @@
                          ManagementUI::GetManagementPageSubtitle(profile));
   html_source->AddString(
       "aboutUpgradeUpToDate",
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       ui::SubstituteChromeOSDeviceType(IDS_SETTINGS_UPGRADE_UP_TO_DATE));
 #else
       l10n_util::GetStringUTF16(IDS_SETTINGS_UPGRADE_UP_TO_DATE));
@@ -341,7 +341,9 @@
     {"minimumFont", IDS_SETTINGS_MINIMUM_FONT_SIZE_LABEL},
     {"tiny", IDS_SETTINGS_TINY_FONT_SIZE},
     {"huge", IDS_SETTINGS_HUGE_FONT_SIZE},
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
     {"systemTheme", IDS_SETTINGS_SYSTEM_THEME},
     {"useSystemTheme", IDS_SETTINGS_USE_SYSTEM_THEME},
     {"classicTheme", IDS_SETTINGS_CLASSIC_THEME},
@@ -432,7 +434,7 @@
   AddLocalizedStringsBulk(html_source, kLocalizedStrings);
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void AddDefaultBrowserStrings(content::WebUIDataSource* html_source) {
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
       {"defaultBrowser", IDS_SETTINGS_DEFAULT_BROWSER},
@@ -604,6 +606,7 @@
     {"triggeredResetPageExplanation",
      IDS_TRIGGERED_RESET_PROFILE_SETTINGS_EXPLANATION},
     {"triggeredResetPageTitle", IDS_TRIGGERED_RESET_PROFILE_SETTINGS_TITLE},
+    {"resetDialogTitle", IDS_SETTINGS_RESET_PROMPT_TITLE},
     {"resetDialogCommit", IDS_SETTINGS_RESET},
     {"resetPageFeedback", IDS_SETTINGS_RESET_PROFILE_FEEDBACK},
 
@@ -635,7 +638,7 @@
                          chrome::kAutomaticSettingsResetLearnMoreURL);
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void AddImportDataStrings(content::WebUIDataSource* html_source) {
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
       {"importTitle", IDS_SETTINGS_IMPORT_SETTINGS_TITLE},
@@ -715,7 +718,7 @@
   };
   AddLocalizedStringsBulk(html_source, kLocalizedStrings);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Only the Chrome OS help article explains how language order affects website
   // language.
   html_source->AddString(
@@ -729,7 +732,7 @@
       "languagesPageTitle",
       l10n_util::GetStringUTF16(IDS_SETTINGS_LANGUAGES_PAGE_TITLE));
 #endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
   const user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile);
@@ -749,10 +752,10 @@
                           base::FeatureList::IsEnabled(
                               chromeos::features::kLanguageSettingsUpdate));
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AddChromeOSUserStrings(content::WebUIDataSource* html_source,
                             Profile* profile) {
   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
@@ -1079,12 +1082,12 @@
           base::ASCIIToUTF16(chrome::kSyncLearnMoreURL)));
 
   bool is_guest_mode = false;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   is_guest_mode = user_manager::UserManager::Get()->IsLoggedInAsGuest() ||
                   user_manager::UserManager::Get()->IsLoggedInAsPublicAccount();
-#else   // !defined(OS_CHROMEOS)
+#else   // !BUILDFLAG(IS_CHROMEOS_ASH)
   is_guest_mode = profile->IsOffTheRecord();
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   autofill::PersonalDataManager* personal_data =
       autofill::PersonalDataManagerFactory::GetForProfile(profile);
   html_source->AddBoolean(
@@ -1117,7 +1120,7 @@
 
 void AddSignOutDialogStrings(content::WebUIDataSource* html_source,
                              Profile* profile) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   bool is_dice_enabled = false;
   bool use_browser_sync_consent =
       chromeos::features::ShouldUseBrowserSyncConsent();
@@ -1172,7 +1175,7 @@
                                   base::ASCIIToUTF16(sync_dashboard_url)));
   }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   html_source->AddString(
       "syncDisconnectManagedProfileExplanation",
       l10n_util::GetStringFUTF8(
@@ -1194,14 +1197,14 @@
     {"manageGoogleAccount", IDS_SETTINGS_MANAGE_GOOGLE_ACCOUNT},
     {"syncAndNonPersonalizedServices",
      IDS_SETTINGS_SYNC_SYNC_AND_NON_PERSONALIZED_SERVICES},
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {"accountManagerSubMenuLabel", IDS_SETTINGS_ACCOUNT_MANAGER_SUBMENU_LABEL},
 #else
     {"profileNameAndPicture", IDS_SETTINGS_PROFILE_NAME_AND_PICTURE},
 #endif
 
   // Manage profile strings:
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     {"showShortcutLabel", IDS_SETTINGS_PROFILE_SHORTCUT_TOGGLE_LABEL},
     {"nameInputLabel", IDS_SETTINGS_PROFILE_NAME_INPUT_LABEL},
     {"nameYourProfile", IDS_SETTING_NAME_YOUR_PROFILE},
@@ -1236,18 +1239,18 @@
           .spec());
   html_source->AddBoolean("profileShortcutsEnabled",
                           ProfileShortcutManager::IsFeatureEnabled());
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   html_source->AddLocalizedString(
       "editPerson", base::FeatureList::IsEnabled(features::kProfilesUIRevamp)
                         ? IDS_SETTINGS_CUSTOMIZE_PROFILE
                         : IDS_SETTINGS_EDIT_PERSON);
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Toggles the Chrome OS Account Manager submenu in the People section.
   html_source->AddBoolean("isAccountManagerEnabled",
                           chromeos::IsAccountManagerAvailable(profile));
-#elif BUILDFLAG(IS_LACROS)
+#elif BUILDFLAG(IS_CHROMEOS_LACROS)
   html_source->AddBoolean("isAccountManagerEnabled",
                           IsAccountManagerAvailable(profile));
 #endif
@@ -1255,7 +1258,7 @@
   AddSignOutDialogStrings(html_source, profile);
   AddSyncControlsStrings(html_source);
   AddSyncAccountControlStrings(html_source);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   AddPasswordPromptDialogStrings(html_source);
 #endif
   AddSyncPageStrings(html_source);
@@ -1542,7 +1545,7 @@
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
     {"addSite", IDS_SETTINGS_ADD_SITE},
     {"addSiteTitle", IDS_SETTINGS_ADD_SITE_TITLE},
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {"androidSmsNote", IDS_SETTINGS_ANDROID_SMS_NOTE},
 #endif
     {"appCacheOrigin", IDS_SETTINGS_COOKIES_LOCAL_STORAGE_ORIGIN_LABEL},
@@ -1697,7 +1700,7 @@
      IDS_SETTINGS_SITE_SETTINGS_PROTECTED_CONTENT_IDENTIFIERS},
     {"siteSettingsProtectedContentEnable",
      IDS_SETTINGS_SITE_SETTINGS_PROTECTED_CONTENT_ENABLE},
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_WIN)
     {"siteSettingsProtectedContentIdentifiersExplanation",
      IDS_SETTINGS_SITE_SETTINGS_PROTECTED_CONTENT_IDENTIFIERS_EXPLANATION},
     {"siteSettingsProtectedContentEnableIdentifiers",
@@ -2248,7 +2251,7 @@
   html_source->AddString("addSiteExceptionPlaceholder", "[*.]example.com");
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void AddSystemStrings(content::WebUIDataSource* html_source) {
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
     {"systemPageTitle", IDS_SETTINGS_SYSTEM},
@@ -2421,7 +2424,7 @@
   AddSearchStrings(html_source);
   AddSiteSettingsStrings(html_source, profile);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   AddChromeOSUserStrings(html_source, profile);
 #else
   AddDefaultBrowserStrings(html_source);
diff --git a/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc b/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
index fc55f42..b57dd85 100644
--- a/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
+++ b/chrome/browser/ui/webui/settings/settings_secure_dns_handler_browsertest.cc
@@ -6,6 +6,7 @@
 
 #include "base/test/metrics/histogram_tester.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/net/dns_probe_test_util.h"
 #include "chrome/browser/net/secure_dns_config.h"
@@ -268,7 +269,7 @@
 
 // On platforms where enterprise policies do not have default values, test
 // that DoH is disabled when non-DoH policies are set.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 IN_PROC_BROWSER_TEST_F(SecureDnsHandlerTest, OtherPoliciesSet) {
   policy::PolicyMap policy_map;
   SetPolicyForPolicyKey(&policy_map, policy::key::kIncognitoModeAvailability,
diff --git a/chrome/browser/ui/webui/settings/settings_ui.cc b/chrome/browser/ui/webui/settings/settings_ui.cc
index 1513107..340a0f9 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.cc
+++ b/chrome/browser/ui/webui/settings/settings_ui.cc
@@ -17,6 +17,7 @@
 #include "base/stl_util.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
 #include "chrome/browser/ui/hats/hats_service.h"
@@ -88,11 +89,11 @@
 #endif
 #endif  // defined(OS_WIN)
 
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/webui/settings/languages_handler.h"
-#endif  // defined(OS_WIN) || defined(OS_CHROMEOS)
+#endif  // defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/account_manager/account_manager_util.h"
@@ -115,14 +116,14 @@
 #include "components/arc/arc_util.h"
 #include "components/user_manager/user.h"
 #include "ui/base/ui_base_features.h"
-#else  // !defined(OS_CHROMEOS)
+#else  // !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/ui/webui/customize_themes/chrome_customize_themes_handler.h"
 #include "chrome/browser/ui/webui/settings/captions_handler.h"
 #include "chrome/browser/ui/webui/settings/settings_default_browser_handler.h"
 #include "chrome/browser/ui/webui/settings/settings_manage_profile_handler.h"
 #include "chrome/browser/ui/webui/settings/system_handler.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(USE_NSS_CERTS)
 #include "chrome/browser/ui/webui/certificates_handler.h"
@@ -148,10 +149,10 @@
 
 SettingsUI::SettingsUI(content::WebUI* web_ui)
     :
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
       ui::MojoWebUIController(web_ui, /*enable_chrome_send=*/true),
       customize_themes_factory_receiver_(this),
-#else  // !defined(OS_CHROMEOS)
+#else  // !BUILDFLAG(IS_CHROMEOS_ASH)
       content::WebUIController(web_ui),
 #endif
       webui_load_timer_(web_ui->GetWebContents(),
@@ -171,7 +172,7 @@
 #elif defined(OS_WIN) || defined(OS_MAC)
   AddSettingsPageUIHandler(std::make_unique<NativeCertificatesHandler>());
 #endif  // defined(USE_NSS_CERTS)
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   AddSettingsPageUIHandler(
       chromeos::cert_provisioning::CertificateProvisioningUiHandler::
           CreateForProfile(profile));
@@ -192,13 +193,13 @@
 #if defined(OS_WIN)
   AddSettingsPageUIHandler(std::make_unique<LanguagesHandler>());
 #endif  // defined(OS_WIN)
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   AddSettingsPageUIHandler(std::make_unique<LanguagesHandler>(profile));
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   AddSettingsPageUIHandler(
       std::make_unique<MediaDevicesSelectionHandler>(profile));
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !defined(OS_CHROMEOS)
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING) && !BUILDFLAG(IS_CHROMEOS_ASH)
   AddSettingsPageUIHandler(std::make_unique<MetricsReportingHandler>());
 #endif
   AddSettingsPageUIHandler(std::make_unique<OnStartupHandler>(profile));
@@ -216,7 +217,7 @@
   AddSettingsPageUIHandler(
       std::make_unique<SecurityKeysBioEnrollmentHandler>());
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   InitBrowserSettingsWebUIHandlers();
 #else
   AddSettingsPageUIHandler(
@@ -292,7 +293,7 @@
           features::kChromeCleanupScanCompletedNotification));
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   html_source->AddBoolean("splitSettingsSyncEnabled",
                           chromeos::features::IsSplitSettingsSyncEnabled());
   html_source->AddBoolean("useBrowserSyncConsent",
@@ -307,10 +308,10 @@
 
   // This is the browser settings page.
   html_source->AddBoolean("isOSSettings", false);
-#else   // defined(OS_CHROMEOS)
+#else   // BUILDFLAG(IS_CHROMEOS_ASH)
   html_source->AddBoolean("profilesUIRevamp", base::FeatureList::IsEnabled(
                                                   features::kProfilesUIRevamp));
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
   AddSettingsPageUIHandler(std::make_unique<AboutHandler>(profile));
   AddSettingsPageUIHandler(std::make_unique<ResetSettingsHandler>(profile));
@@ -348,7 +349,7 @@
 
 SettingsUI::~SettingsUI() = default;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void SettingsUI::InitBrowserSettingsWebUIHandlers() {
   Profile* profile = Profile::FromWebUI(web_ui());
 
@@ -393,7 +394,7 @@
   web_ui()->AddMessageHandler(
       std::make_unique<chromeos::settings::AndroidAppsHandler>(profile));
 }
-#else   // defined(OS_CHROMEOS)
+#else   // BUILDFLAG(IS_CHROMEOS_ASH)
 void SettingsUI::BindInterface(
     mojo::PendingReceiver<
         customize_themes::mojom::CustomizeThemesHandlerFactory>
@@ -402,7 +403,7 @@
     customize_themes_factory_receiver_.reset();
   customize_themes_factory_receiver_.Bind(std::move(pending_receiver));
 }
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 void SettingsUI::AddSettingsPageUIHandler(
     std::unique_ptr<content::WebUIMessageHandler> handler) {
@@ -420,7 +421,7 @@
   }
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 void SettingsUI::CreateCustomizeThemesHandler(
     mojo::PendingRemote<customize_themes::mojom::CustomizeThemesClient>
         pending_client,
@@ -430,7 +431,7 @@
       std::move(pending_client), std::move(pending_handler),
       web_ui()->GetWebContents(), Profile::FromWebUI(web_ui()));
 }
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 WEB_UI_CONTROLLER_TYPE_IMPL(SettingsUI)
 
diff --git a/chrome/browser/ui/webui/settings/settings_ui.h b/chrome/browser/ui/webui/settings/settings_ui.h
index 6da24f5e..e8e71c92 100644
--- a/chrome/browser/ui/webui/settings/settings_ui.h
+++ b/chrome/browser/ui/webui/settings/settings_ui.h
@@ -7,17 +7,18 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/webui_load_timer.h"
 #include "content/public/browser/web_ui_controller.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "mojo/public/cpp/bindings/pending_receiver.h"
 #include "mojo/public/cpp/bindings/pending_remote.h"
 #include "mojo/public/cpp/bindings/receiver.h"
 #include "ui/webui/mojo_web_ui_controller.h"
 #include "ui/webui/resources/cr_components/customize_themes/customize_themes.mojom.h"
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace content {
 class WebUIMessageHandler;
@@ -27,22 +28,22 @@
 class PrefRegistrySyncable;
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 class ChromeCustomizeThemesHandler;
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace settings {
 
 // The WebUI handler for chrome://settings.
 class SettingsUI :
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     // chrome://settings/manageProfile which only exists on !OS_CHROMEOS
     // requires mojo bindings.
     public ui::MojoWebUIController,
     public customize_themes::mojom::CustomizeThemesHandlerFactory
-#else   // !defined(OS_CHROMEOS)
+#else   // !BUILDFLAG(IS_CHROMEOS_ASH)
     public content::WebUIController
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 {
  public:
   static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
@@ -50,18 +51,18 @@
   explicit SettingsUI(content::WebUI* web_ui);
   ~SettingsUI() override;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Initializes the WebUI message handlers for CrOS-specific settings that are
   // still shown in the browser settings UI.
   void InitBrowserSettingsWebUIHandlers();
-#else   // defined(OS_CHROMEOS)
+#else   // BUILDFLAG(IS_CHROMEOS_ASH)
   // Instantiates the implementor of the
   // customize_themes::mojom::CustomizeThemesHandlerFactory mojo interface
   // passing the pending receiver that will be internally bound.
   void BindInterface(mojo::PendingReceiver<
                      customize_themes::mojom::CustomizeThemesHandlerFactory>
                          pending_receiver);
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
  private:
   void AddSettingsPageUIHandler(
@@ -70,7 +71,7 @@
   // Makes a request to show a HaTS survey.
   void TryShowHatsSurveyWithTimeout();
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   // customize_themes::mojom::CustomizeThemesHandlerFactory:
   void CreateCustomizeThemesHandler(
       mojo::PendingRemote<customize_themes::mojom::CustomizeThemesClient>
@@ -81,7 +82,7 @@
   std::unique_ptr<ChromeCustomizeThemesHandler> customize_themes_handler_;
   mojo::Receiver<customize_themes::mojom::CustomizeThemesHandlerFactory>
       customize_themes_factory_receiver_;
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
   WebuiLoadTimer webui_load_timer_;
 
diff --git a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
index c8ada0fe..dad35fd 100644
--- a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/system/sys_info.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
@@ -29,12 +30,12 @@
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/webui/web_ui_util.h"
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/nearby_sharing/common/nearby_share_features.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace settings {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 namespace {
 
 // Generates a Google Help URL which includes a "board type" parameter. Some
@@ -99,7 +100,7 @@
     {"urlKeyedAnonymizedDataCollectionDesc",
      IDS_SETTINGS_ENABLE_URL_KEYED_ANONYMIZED_DATA_COLLECTION_DESC},
     {"spellingPref", IDS_SETTINGS_SPELLING_PREF},
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     {"signinAllowedTitle", IDS_SETTINGS_SIGNIN_ALLOWED},
     {"signinAllowedDescription", IDS_SETTINGS_SIGNIN_ALLOWED_DESC},
 #endif
@@ -155,7 +156,7 @@
   AddLocalizedStringsBulk(html_source, kLocalizedStrings);
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AddPasswordPromptDialogStrings(content::WebUIDataSource* html_source) {
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
       {"passwordPromptTitle", IDS_SETTINGS_PEOPLE_PASSWORD_PROMPT_TITLE},
@@ -232,14 +233,14 @@
       "encryptWithSyncPassphraseLabel",
       l10n_util::GetStringFUTF8(
           IDS_SETTINGS_ENCRYPT_WITH_SYNC_PASSPHRASE_LABEL,
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
           GetHelpUrlWithBoard(chrome::kSyncEncryptionHelpURL)));
 #else
           base::ASCIIToUTF16(chrome::kSyncEncryptionHelpURL)));
 #endif
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AddNearbyShareData(content::WebUIDataSource* html_source) {
   static constexpr webui::LocalizedString kLocalizedStrings[] = {
       {"nearbyShareTitle", IDS_SETTINGS_NEARBY_SHARE_TITLE},
@@ -293,6 +294,6 @@
   html_source->OverrideContentSecurityPolicy(
       network::mojom::CSPDirectiveName::WorkerSrc, "worker-src blob: 'self';");
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace settings
diff --git a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h
index cf4f17a..d0138b68 100644
--- a/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h
+++ b/chrome/browser/ui/webui/settings/shared_settings_localized_strings_provider.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_SHARED_SETTINGS_LOCALIZED_STRINGS_PROVIDER_H_
 #define CHROME_BROWSER_UI_WEBUI_SETTINGS_SHARED_SETTINGS_LOCALIZED_STRINGS_PROVIDER_H_
 
+#include "build/chromeos_buildflags.h"
+
 namespace content {
 class WebUIDataSource;
 }  // namespace content
@@ -23,7 +25,7 @@
 // Adds strings used by the <settings-sync-account-control> element.
 void AddSyncAccountControlStrings(content::WebUIDataSource* html_source);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Adds strings used by the <settings-password-prompt-dialog> element.
 void AddPasswordPromptDialogStrings(content::WebUIDataSource* html_source);
 #endif
@@ -31,10 +33,10 @@
 // Adds strings used by the <settings-sync-page> element.
 void AddSyncPageStrings(content::WebUIDataSource* html_source);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Adds load time data used by the <settings-nearby-share-subpage>.
 void AddNearbyShareData(content::WebUIDataSource* html_source);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace settings
 
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.cc b/chrome/browser/ui/webui/settings/site_settings_handler.cc
index d08b33c3..305f59a 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.cc
@@ -19,6 +19,7 @@
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/bluetooth/bluetooth_chooser_context.h"
 #include "chrome/browser/bluetooth/bluetooth_chooser_context_factory.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
@@ -69,7 +70,7 @@
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/text/bytes_formatting.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "components/user_manager/user_manager.h"
 #endif
 
@@ -529,7 +530,7 @@
       base::Bind(&SiteSettingsHandler::SendCookieSettingDescription,
                  base::Unretained(this)));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   pref_change_registrar_->Add(
       prefs::kEnableDRM,
       base::Bind(&SiteSettingsHandler::OnPrefEnableDrmChanged,
@@ -543,7 +544,7 @@
   host_zoom_map_subscription_ = {};
   pref_change_registrar_->Remove(prefs::kBlockAutoplayEnabled);
   pref_change_registrar_->Remove(prefs::kCookieControlsMode);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   pref_change_registrar_->Remove(prefs::kEnableDRM);
 #endif
   observed_profiles_.RemoveAll();
@@ -573,7 +574,7 @@
                     base::Value(usage_string), base::Value(cookie_string));
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void SiteSettingsHandler::OnPrefEnableDrmChanged() {
   FireWebUIListener("prefEnableDrmChanged");
 }
@@ -692,7 +693,7 @@
       site_settings::ContentSettingsTypeFromGroupName(content_type);
 
   Profile* profile = profile_;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // ChromeOS special case: in Guest mode, settings are opened in Incognito
   // mode so we need the original profile to actually modify settings.
   if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler.h b/chrome/browser/ui/webui/settings/site_settings_handler.h
index 7e5f6da4..ed126ec 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler.h
+++ b/chrome/browser/ui/webui/settings/site_settings_handler.h
@@ -12,6 +12,7 @@
 
 #include "base/containers/flat_set.h"
 #include "base/scoped_observer.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browsing_data/cookies_tree_model.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_observer.h"
@@ -68,7 +69,7 @@
   void TreeNodeChanged(ui::TreeModel* model, ui::TreeModelNode* node) override;
   void TreeModelEndBatch(CookiesTreeModel* model) override;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // Alert the Javascript that the |kEnableDRM| pref has changed.
   void OnPrefEnableDrmChanged();
 #endif
diff --git a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
index 10d5fbf..c3df8ca 100644
--- a/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_handler_unittest.cc
@@ -19,6 +19,7 @@
 #include "base/test/simple_test_clock.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
@@ -67,7 +68,7 @@
 #include "ui/base/text/bytes_formatting.h"
 #include "ui/webui/webui_allowlist.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
 #include "components/user_manager/scoped_user_manager.h"
 #endif
@@ -154,7 +155,7 @@
             ContentSettingsType::NOTIFICATIONS)),
         kCookies(site_settings::ContentSettingsTypeToGroupName(
             ContentSettingsType::COOKIES)) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     user_manager_enabler_ = std::make_unique<user_manager::ScopedUserManager>(
         std::make_unique<chromeos::MockUserManager>());
 #endif
@@ -494,7 +495,7 @@
   web_app::TestAppRegistrar app_registrar_;
   content::TestWebUI web_ui_;
   std::unique_ptr<SiteSettingsHandler> handler_;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   std::unique_ptr<user_manager::ScopedUserManager> user_manager_enabler_;
 #endif
 };
diff --git a/chrome/browser/ui/webui/settings/site_settings_helper_unittest.cc b/chrome/browser/ui/webui/settings/site_settings_helper_unittest.cc
index f1418e4..5e3bac6 100644
--- a/chrome/browser/ui/webui/settings/site_settings_helper_unittest.cc
+++ b/chrome/browser/ui/webui/settings/site_settings_helper_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/guid.h"
 #include "base/json/json_reader.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/permissions/permission_decision_auto_blocker_factory.h"
 #include "chrome/browser/usb/usb_chooser_context.h"
@@ -416,7 +417,7 @@
   EXPECT_EQ(CONTENT_SETTING_ALLOW, content_setting);
 
 // ChromeOS - DRM disabled.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   profile.GetPrefs()->SetBoolean(prefs::kEnableDRM, false);
   // Note this is not testing |kContentType|, because this setting is only valid
   // for protected content.
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler.cc b/chrome/browser/ui/webui/signin/inline_login_handler.cc
index 6169bab..a77399c4 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/signin_promo.h"
@@ -229,10 +230,10 @@
 }
 
 void InlineLoginHandler::HandleDialogClose(const base::ListValue* args) {
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   // Does nothing if user manager is not showing.
   UserManagerProfileDialog::HideDialog();
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 void InlineLoginHandler::CloseDialogFromJavascript() {
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui.cc b/chrome/browser/ui/webui/signin/inline_login_ui.cc
index c6544bcf..64b912f 100644
--- a/chrome/browser/ui/webui/signin/inline_login_ui.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_ui.cc
@@ -11,6 +11,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
@@ -32,7 +33,7 @@
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "ui/resources/grit/webui_resources.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/supervised_user/supervised_user_features.h"
 #include "chrome/browser/ui/webui/chromeos/edu_account_login_handler_chromeos.h"
@@ -42,14 +43,14 @@
 #include "ui/strings/grit/ui_strings.h"
 #else
 #include "chrome/browser/ui/webui/signin/inline_login_handler_impl.h"
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 namespace {
 
 constexpr char kResourcesGeneratedPath[] =
     "@out_folder@/gen/chrome/browser/resources/";
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 void AddEduStrings(content::WebUIDataSource* source,
                    const base::string16& username) {
   source->AddLocalizedString("okButton", IDS_APP_OK);
@@ -102,7 +103,7 @@
   source->AddLocalizedString("eduCoexistenceErrorDescription",
                              IDS_EDU_COEXISTENCE_ERROR_DESCRIPTION);
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 content::WebUIDataSource* CreateWebUIDataSource() {
   content::WebUIDataSource* source =
@@ -124,7 +125,7 @@
   static constexpr webui::ResourcePath kResources[] = {
     {"inline_login_app.js", IDR_INLINE_LOGIN_APP_JS},
     {"inline_login_browser_proxy.js", IDR_INLINE_LOGIN_BROWSER_PROXY_JS},
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {"gaia_action_buttons.js", IDR_GAIA_ACTION_BUTTONS_JS},
     {"error_screen.js", IDR_ACCOUNT_MANAGER_COMPONENTS_ERROR_SCREEN_JS},
     {"edu", IDR_EDU_LOGIN_EDU_LOGIN_HTML},
@@ -165,7 +166,7 @@
     {"googleg.svg", IDR_ACCOUNT_MANAGER_WELCOME_GOOGLE_LOGO_SVG},
 #endif
     {"family_link_logo.svg", IDR_FAMILY_LINK_LOGO_SVG},
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   };
 
   webui::AddResourcePathsBulk(source, kResources);
@@ -175,7 +176,7 @@
       "accessibleCloseButtonLabel", IDS_SIGNIN_ACCESSIBLE_CLOSE_BUTTON);
   source->AddLocalizedString(
       "accessibleBackButtonLabel", IDS_SIGNIN_ACCESSIBLE_BACK_BUTTON);
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   source->AddLocalizedString("accountManagerErrorNoInternetTitle",
                              IDS_ACCOUNT_MANAGER_ERROR_NO_INTERNET_TITLE);
   source->AddLocalizedString("accountManagerErrorNoInternetBody",
@@ -192,7 +193,7 @@
 // Returns whether |url| can be displayed in a chrome://chrome-signin tab,
 // depending on the signin reason that is encoded in the url.
 bool IsValidChromeSigninReason(const GURL& url) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   return true;
 #else
   signin_metrics::Reason reason =
@@ -220,7 +221,7 @@
       return false;
   }
   NOTREACHED();
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }
 
 }  // namespace
@@ -231,14 +232,14 @@
 
   Profile* profile = Profile::FromWebUI(web_ui);
   content::WebUIDataSource* source = CreateWebUIDataSource();
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   base::string16 username =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile)->GetGivenName();
   AddEduStrings(source, username);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   content::WebUIDataSource::Add(profile, source);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui->AddMessageHandler(
       std::make_unique<chromeos::InlineLoginHandlerChromeOS>(
           base::BindRepeating(&WebDialogUIBase::CloseDialog,
@@ -262,7 +263,7 @@
 
 #else
   web_ui->AddMessageHandler(std::make_unique<InlineLoginHandlerImpl>());
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   web_ui->AddMessageHandler(std::make_unique<MetricsHandler>());
 
diff --git a/chrome/browser/ui/webui/signin/login_ui_service.cc b/chrome/browser/ui/webui/signin/login_ui_service.cc
index 99a69025..7f6b57a 100644
--- a/chrome/browser/ui/webui/signin/login_ui_service.cc
+++ b/chrome/browser/ui/webui/signin/login_ui_service.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/signin/login_ui_service.h"
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_attributes_entry.h"
@@ -17,12 +18,12 @@
 #include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
 #include "chrome/common/url_constants.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/user_manager.h"
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 LoginUIService::LoginUIService(Profile* profile)
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     : profile_(profile)
 #endif
 {
@@ -59,7 +60,7 @@
 
 void LoginUIService::ShowExtensionLoginPrompt(bool enable_sync,
                                               const std::string& email_hint) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   NOTREACHED();
 #else
   // There is no sign-in flow for guest or system profile.
@@ -95,7 +96,7 @@
 void LoginUIService::DisplayLoginResult(Browser* browser,
                                         const base::string16& error_message,
                                         const base::string16& email) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // ChromeOS doesn't have the avatar bubble so it never calls this function.
   NOTREACHED();
 #else
diff --git a/chrome/browser/ui/webui/signin/login_ui_service.h b/chrome/browser/ui/webui/signin/login_ui_service.h
index 1f96eb9..0fb9af0 100644
--- a/chrome/browser/ui/webui/signin/login_ui_service.h
+++ b/chrome/browser/ui/webui/signin/login_ui_service.h
@@ -12,6 +12,7 @@
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "base/strings/string16.h"
+#include "build/chromeos_buildflags.h"
 #include "components/keyed_service/core/keyed_service.h"
 
 class Browser;
@@ -107,7 +108,7 @@
  private:
   // Weak pointers to the recently opened UIs, with the most recent in front.
   std::list<LoginUI*> ui_list_;
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   Profile* profile_;
 #endif
 
diff --git a/chrome/browser/ui/webui/signin/login_ui_service_unittest.cc b/chrome/browser/ui/webui/signin/login_ui_service_unittest.cc
index e050533f..10f5692 100644
--- a/chrome/browser/ui/webui/signin/login_ui_service_unittest.cc
+++ b/chrome/browser/ui/webui/signin/login_ui_service_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/macros.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/test/base/testing_browser_process.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
@@ -16,7 +17,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/test_extension_system.h"
@@ -102,7 +103,7 @@
   EXPECT_TRUE(service.IsDisplayingProfileBlockedErrorMessage());
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 class LoginUIServiceExtensionLoginPromptTest
     : public BrowserWithTestWindowTest {
  public:
diff --git a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
index 4dda1834..a28d224 100644
--- a/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
+++ b/chrome/browser/ui/webui/signin/login_ui_test_utils.cc
@@ -14,6 +14,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/account_consistency_mode_manager.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
@@ -195,7 +196,7 @@
 
 enum class ReauthDialogAction { kConfirm, kCancel };
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 std::string GetButtonIdForSyncConfirmationDialogAction(
     SyncConfirmationDialogAction action) {
   switch (action) {
@@ -264,7 +265,7 @@
       web_contents, find_element_js, &message));
   return message == "Ok";
 }
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace
 
@@ -274,7 +275,7 @@
   static bool TryDismissSyncConfirmationDialog(
       Browser* browser,
       SyncConfirmationDialogAction action) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     NOTREACHED();
     return false;
 #else
@@ -303,7 +304,7 @@
   static bool TryCompleteSigninEmailConfirmationDialog(
       Browser* browser,
       SigninEmailConfirmationDialog::Action action) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     NOTREACHED();
     return false;
 #else
@@ -336,7 +337,7 @@
 
   static bool TryCompleteReauthConfirmationDialog(Browser* browser,
                                                   ReauthDialogAction action) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     NOTREACHED();
     return false;
 #else
@@ -435,7 +436,7 @@
 bool SignInWithUI(Browser* browser,
                   const std::string& username,
                   const std::string& password) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   NOTREACHED();
   return false;
 #else
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
index 759bd9f..7ee32e2d 100644
--- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
+++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler.cc
@@ -15,6 +15,7 @@
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "base/trace_event/trace_event.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/favicon/favicon_utils.h"
 #include "chrome/browser/profiles/profile.h"
@@ -31,7 +32,7 @@
 constexpr base::TimeDelta kTabsChangeDelay =
     base::TimeDelta::FromMilliseconds(50);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 constexpr char kFeedbackCategoryTag[] = "FromTabSearch";
 #else
 constexpr char kFeedbackCategoryTag[] = "FromTabSearchBrowser";
diff --git a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
index fce77f17..65732b4c7 100644
--- a/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
+++ b/chrome/browser/ui/webui/tab_search/tab_search_page_handler_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/timer/mock_timer.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/ui/browser_commands.h"
 #include "chrome/browser/ui/browser_list.h"
@@ -337,7 +338,7 @@
 }
 
 // TODO(crbug.com/1128855): Fix the test for Lacros build.
-#if BUILDFLAG(IS_LACROS)
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
 #define MAYBE_ShowFeedbackPage DISABLED_ShowFeedbackPage
 #else
 #define MAYBE_ShowFeedbackPage ShowFeedbackPage
diff --git a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc
index f615ed44..91a947a 100644
--- a/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc
+++ b/chrome/browser/ui/webui/tab_strip/tab_strip_ui_handler.cc
@@ -9,6 +9,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
 #include "base/values.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/extensions/extension_tab_util.h"
 #include "chrome/browser/favicon/favicon_utils.h"
@@ -544,7 +545,7 @@
                        ui::NativeTheme::GetInstanceForWeb()->GetSystemColor(
                            ui::NativeTheme::kColorId_FocusedBorderColor)));
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   colors.SetString(
       "--tabstrip-scrollbar-thumb-color-rgb",
       color_utils::SkColorToRgbString(color_utils::GetColorWithMaxContrast(
diff --git a/chrome/browser/ui/webui/version_ui.cc b/chrome/browser/ui/webui/version_ui.cc
index 6352e6db..065bb69b 100644
--- a/chrome/browser/ui/webui/version_ui.cc
+++ b/chrome/browser/ui/webui/version_ui.cc
@@ -10,6 +10,7 @@
 #include "base/i18n/message_formatter.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/chrome_content_browser_client.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/version_handler.h"
@@ -38,7 +39,7 @@
 #include "chrome/browser/ui/webui/theme_source.h"
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/ui/webui/version_handler_chromeos.h"
 #endif
 
@@ -70,14 +71,14 @@
     {version_ui::kProfilePathName, IDS_VERSION_UI_PROFILE_PATH},
     {version_ui::kVariationsName, IDS_VERSION_UI_VARIATIONS},
     {version_ui::kVariationsCmdName, IDS_VERSION_UI_VARIATIONS_CMD},
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     {version_ui::kARC, IDS_ARC_LABEL},
     {version_ui::kPlatform, IDS_PLATFORM_LABEL},
     {version_ui::kCustomizationId, IDS_VERSION_UI_CUSTOMIZATION_ID},
     {version_ui::kFirmwareVersion, IDS_VERSION_UI_FIRMWARE_VERSION},
 #else
     {version_ui::kOSName, IDS_VERSION_UI_OS},
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 #if defined(OS_ANDROID)
     {version_ui::kGmsName, IDS_VERSION_UI_GMS},
 #endif  // OS_ANDROID
@@ -100,7 +101,7 @@
     : content::WebUIController(web_ui) {
   Profile* profile = Profile::FromWebUI(web_ui);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   web_ui->AddMessageHandler(std::make_unique<VersionHandlerChromeOS>());
 #elif defined(OS_WIN)
   web_ui->AddMessageHandler(std::make_unique<VersionHandlerWindows>());
@@ -179,7 +180,7 @@
 
 #if defined(OS_MAC)
   html_source->AddString(version_ui::kOSType, base::mac::GetOSDisplayName());
-#elif !defined(OS_CHROMEOS)
+#elif !BUILDFLAG(IS_CHROMEOS_ASH)
   html_source->AddString(version_ui::kOSType, version_info::GetOSType());
 #endif  // OS_MAC
 
diff --git a/chrome/browser/ui/webui/webui_util.cc b/chrome/browser/ui/webui/webui_util.cc
index c8b718383..d07af57 100644
--- a/chrome/browser/ui/webui/webui_util.cc
+++ b/chrome/browser/ui/webui/webui_util.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ui/webui/webui_util.h"
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "content/public/browser/web_ui_data_source.h"
 #include "services/network/public/mojom/content_security_policy.mojom.h"
 #include "ui/base/webui/web_ui_util.h"
@@ -12,7 +13,7 @@
 #include "ui/resources/grit/webui_resources.h"
 #include "ui/resources/grit/webui_resources_map.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
@@ -76,7 +77,7 @@
 }
 
 bool IsEnterpriseManaged() {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   return connector->IsEnterpriseManaged();
diff --git a/chrome/browser/ui/webui/webui_webview_browsertest.cc b/chrome/browser/ui/webui/webui_webview_browsertest.cc
index 38f39d7c..0ed03532 100644
--- a/chrome/browser/ui/webui/webui_webview_browsertest.cc
+++ b/chrome/browser/ui/webui/webui_webview_browsertest.cc
@@ -7,6 +7,7 @@
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/renderer_context_menu/render_view_context_menu_test_util.h"
 #include "chrome/browser/signin/signin_promo.h"
@@ -31,7 +32,7 @@
 // http://crbug.com/653353
 #if !defined(OS_MAC)
 
-#if !defined(OS_CHROMEOS) && defined(USE_AURA)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && defined(USE_AURA)
 #include "ui/aura/window.h"
 
 namespace {
@@ -122,7 +123,7 @@
   }
 
   GURL GetWebViewEnabledWebUIURL() const {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     return GURL(chrome::kChromeUIOobeURL).Resolve("/login");
 #else
     return GURL(signin::GetEmbeddedPromoURL(
@@ -146,7 +147,7 @@
 }
 
 // TODO(crbug.com/861600) Flaky on CrOS trybots.
-#if defined(OS_CHROMEOS) && !defined(NDEBUG)
+#if BUILDFLAG(IS_CHROMEOS_ASH) && !defined(NDEBUG)
 #define MAYBE_ExecuteScriptCode DISABLED_ExecuteScriptCode
 #else
 #define MAYBE_ExecuteScriptCode ExecuteScriptCode
@@ -167,7 +168,7 @@
 }
 
 // TODO(crbug.com/751907) Flaky on CrOS trybots.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_AddContentScript DISABLED_AddContentScript
 #else
 #define MAYBE_AddContentScript AddContentScript
@@ -180,7 +181,7 @@
 }
 
 // TODO(crbug.com/751907) Flaky on CrOS trybots.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_AddMultiContentScripts DISABLED_AddMultiContentScripts
 #else
 #define MAYBE_AddMultiContentScripts AddMultiContentScripts
@@ -194,7 +195,7 @@
 }
 
 // TODO(crbug.com/751907) Flaky on CrOS trybots.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_AddContentScriptWithSameNameShouldOverwriteTheExistingOne \
   DISABLED_AddContentScriptWithSameNameShouldOverwriteTheExistingOne
 #else
@@ -211,7 +212,7 @@
       base::Value(GetTestUrl("empty.html").spec())));
 }
 
-#if defined(OS_CHROMEOS) && !defined(NDEBUG)
+#if BUILDFLAG(IS_CHROMEOS_ASH) && !defined(NDEBUG)
 // TODO(crbug.com/859320) Fails on CrOS dbg with --enable-features=Mash.
 #define MAYBE_AddContentScriptToOneWebViewShouldNotInjectToTheOtherWebView \
   DISABLED_AddContentScriptToOneWebViewShouldNotInjectToTheOtherWebView
@@ -230,7 +231,7 @@
 }
 
 // TODO(crbug.com/751907) Flaky on CrOS trybots.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_AddAndRemoveContentScripts DISABLED_AddAndRemoveContentScripts
 #else
 #define MAYBE_AddAndRemoveContentScripts AddAndRemoveContentScripts
@@ -244,7 +245,8 @@
       base::Value(GetTestUrl("empty.html").spec())));
 }
 
-#if defined(OS_CHROMEOS) && (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
+#if BUILDFLAG(IS_CHROMEOS_ASH) && \
+    (!defined(NDEBUG) || defined(ADDRESS_SANITIZER))
 // TODO(crbug.com/859320) Fails on CrOS dbg with --enable-features=Mash.
 // TODO(crbug.com/893472) Flaky on CrOS ASan LSan
 #define MAYBE_AddContentScriptsWithNewWindowAPI \
@@ -274,7 +276,7 @@
 }
 
 // TODO(crbug.com/662673) Flaky on CrOS trybots.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #define MAYBE_ContentScriptExistsAsLongAsWebViewTagExists \
   DISABLED_ContentScriptExistsAsLongAsWebViewTagExists
 #else
@@ -298,7 +300,7 @@
       base::Value(GetTestUrl("empty.html").spec())));
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // TODO(crbug.com/662673) Flaky on CrOS trybots.
 #define MAYBE_AddContentScriptIncognito DISABLED_AddContentScriptIncognito
 // Right now we only have incognito WebUI on CrOS, but this should
@@ -325,7 +327,7 @@
   EXPECT_FALSE(menu.IsItemPresent(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
 }
 
-#if !defined(OS_CHROMEOS) && defined(USE_AURA)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && defined(USE_AURA)
 IN_PROC_BROWSER_TEST_F(WebUIWebViewBrowserTest, DISABLED_DragAndDropToInput) {
   ui_test_utils::NavigateToURL(browser(), GetWebViewEnabledWebUIURL());
   ASSERT_TRUE(
diff --git a/chrome/browser/unload_browsertest.cc b/chrome/browser/unload_browsertest.cc
index 845d1591..f327108 100644
--- a/chrome/browser/unload_browsertest.cc
+++ b/chrome/browser/unload_browsertest.cc
@@ -30,6 +30,7 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 
@@ -616,6 +617,59 @@
   CheckTitle("only_one_unload");
 }
 
+// Tests that visibilitychange is only dispatched once on tab close.
+IN_PROC_BROWSER_TEST_F(UnloadTest, VisibilityChangeOnlyDispatchedOnce) {
+  EXPECT_TRUE(embedded_test_server()->Start());
+  // Start on a.com and open a popup to another page in a.com.
+  GURL opener_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
+  ui_test_utils::NavigateToURL(browser(), opener_url);
+  content::WebContents* opener_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+
+  GURL popup_url(embedded_test_server()->GetURL("a.com", "/title2.html"));
+  content::TestNavigationObserver popup_observer(nullptr);
+  popup_observer.StartWatchingNewWebContents();
+  EXPECT_TRUE(ExecuteScript(opener_contents,
+                            "window.open('" + popup_url.spec() + "');"));
+  popup_observer.Wait();
+  ASSERT_EQ(2, browser()->tab_strip_model()->count());
+  content::WebContents* popup_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  ASSERT_NE(opener_contents, popup_contents);
+  content::RenderFrameHost* popup_rfh = popup_contents->GetMainFrame();
+
+  // In the popup, add a visibilitychange handler that ensures we only see the
+  // visibilitychange event fired once on tab close.
+  EXPECT_TRUE(ExecJs(popup_rfh, R"(
+            localStorage.setItem('visibilitychange_storage', 'not_dispatched');
+            var dispatched_visibilitychange = false;
+            document.onvisibilitychange = function(e) {
+              if (dispatched_visibilitychange) {
+                // We shouldn't dispatch visibilitychange more than once.
+                localStorage.setItem('visibilitychange_storage',
+                  'dispatched_more_than_once');
+              } else if (document.visibilityState != 'hidden') {
+                // We should dispatch the event when the visibilityState is
+                // 'hidden'.
+                localStorage.setItem('visibilitychange_storage', 'not_hidden');
+              } else {
+                localStorage.setItem('visibilitychange_storage',
+                  'dispatched_once');
+              }
+              dispatched_visibilitychange = true;
+            })"));
+
+  // Close the popup.
+  content::WebContentsDestroyedWatcher destroyed_watcher(popup_contents);
+  EXPECT_TRUE(ExecuteScript(popup_contents, "window.close();"));
+  destroyed_watcher.Wait();
+
+  // Check that we've only dispatched visibilitychange once.
+  EXPECT_EQ("dispatched_once",
+            EvalJs(opener_contents,
+                   "localStorage.getItem('visibilitychange_storage')"));
+}
+
 IN_PROC_BROWSER_TEST_F(UnloadTest, BrowserListForceCloseAfterNormalClose) {
   NavigateToDataURL(BEFORE_UNLOAD_HTML, "beforeunload");
 
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java
index 553afdc..32e1f34e 100644
--- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java
+++ b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/Tutorial.java
@@ -13,18 +13,23 @@
     public final String accessibilityText;
     public final String videoUrl;
     public final String posterUrl;
+    public final String animatedGifUrl;
+    public final String thumbnailUrl;
     public final String captionUrl;
     public final String shareUrl;
     public final int videoLength;
 
     /** Constructor */
     public Tutorial(@FeatureType int featureType, String title, String videoUrl, String posterUrl,
-            String captionUrl, String shareUrl, int videoLength) {
+            String animatedGifUrl, String thumbnailUrl, String captionUrl, String shareUrl,
+            int videoLength) {
         this.featureType = featureType;
         this.title = title;
         this.accessibilityText = title;
         this.videoUrl = videoUrl;
         this.posterUrl = posterUrl;
+        this.animatedGifUrl = animatedGifUrl;
+        this.thumbnailUrl = thumbnailUrl;
         this.captionUrl = captionUrl;
         this.shareUrl = shareUrl;
         this.videoLength = videoLength;
diff --git a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java
index 4d999fd..2a35290 100644
--- a/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java
+++ b/chrome/browser/video_tutorials/android/java/src/org/chromium/chrome/browser/video_tutorials/test/TestVideoTutorialService.java
@@ -66,21 +66,27 @@
 
     private void initializeTutorialList() {
         mTutorials.add(new Tutorial(FeatureType.CHROME_INTRO, "Introduction to chrome",
-                "https://storage.googleapis.com/stock-wizard.appspot.com/portrait.jpg",
-                "https://storage.googleapis.com/stock-wizard.appspot.com/portrait.jpg",
+                "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.mp4",
+                "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png",
+                "https://www.gstatic.com/chrome/video-tutorials/gif/sample_anim.gif",
+                "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png",
                 "caption url", "share url", 25));
 
         mTutorials.add(new Tutorial(FeatureType.DOWNLOAD,
                 "How to use Google Chrome's download functionality",
-                "https://storage.googleapis.com/stock-wizard.appspot.com/portrait.jpg",
-                "https://storage.googleapis.com/stock-wizard.appspot.com/portrait.jpg",
+                "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.mp4",
+                "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png",
+                "https://www.gstatic.com/chrome/video-tutorials/gif/sample_anim.gif",
+                "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png",
                 "caption url", "share url", 35));
 
-        mTutorials.add(
-                new Tutorial(FeatureType.SEARCH, "How to efficiently search with Google Chrome",
-                        "https://storage.googleapis.com/stock-wizard.appspot.com/elephant.jpg ",
-                        "https://storage.googleapis.com/stock-wizard.appspot.com/elephant.jpg",
-                        "caption url", "share url", 335));
+        mTutorials.add(new Tutorial(FeatureType.SEARCH,
+                "How to efficiently search with Google Chrome",
+                "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.mp4",
+                "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png",
+                "https://www.gstatic.com/chrome/video-tutorials/gif/sample_anim.gif",
+                "https://www.gstatic.com/chrome/video-tutorials/images/1_Search_english.png",
+                "caption url", "share url", 335));
     }
 
     private void initializeLanguages() {
diff --git a/chrome/browser/video_tutorials/internal/BUILD.gn b/chrome/browser/video_tutorials/internal/BUILD.gn
index 9db20bb9..840a7e7d 100644
--- a/chrome/browser/video_tutorials/internal/BUILD.gn
+++ b/chrome/browser/video_tutorials/internal/BUILD.gn
@@ -88,6 +88,7 @@
       ":java_resources",
       "//base:base_java",
       "//base:jni_java",
+      "//chrome/browser/flags:java",
       "//chrome/browser/image_fetcher:java",
       "//chrome/browser/profiles/android:java",
       "//chrome/browser/video_tutorials:java",
@@ -101,6 +102,7 @@
       "//third_party/android_deps:androidx_annotation_annotation_java",
       "//third_party/android_deps:androidx_annotation_annotation_java",
       "//third_party/android_deps:androidx_recyclerview_recyclerview_java",
+      "//third_party/gif_player:gif_player_java",
       "//ui/android:ui_java",
     ]
 
@@ -180,6 +182,7 @@
       ":java",
       "//base:base_java",
       "//base:base_java_test_support",
+      "//chrome/browser/flags:java",
       "//chrome/browser/video_tutorials:java",
       "//chrome/browser/video_tutorials:test_support_java",
       "//chrome/test/android:chrome_java_test_support",
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java
index 7422a7a..c98f2e8 100644
--- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java
+++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/bridges/TutorialConversionBridge.java
@@ -25,10 +25,10 @@
 
     @CalledByNative
     private static Tutorial createTutorialAndMaybeAddToList(@Nullable List<Tutorial> list,
-            int featureType, String title, String videoUrl, String posterUrl, String captionUrl,
-            String shareUrl, int videoLength) {
-        Tutorial tutorial = new Tutorial(
-                featureType, title, videoUrl, posterUrl, captionUrl, shareUrl, videoLength);
+            int featureType, String title, String videoUrl, String posterUrl, String animatedGifUrl,
+            String thumbnailUrl, String captionUrl, String shareUrl, int videoLength) {
+        Tutorial tutorial = new Tutorial(featureType, title, videoUrl, posterUrl, animatedGifUrl,
+                thumbnailUrl, captionUrl, shareUrl, videoLength);
         if (list != null) list.add(tutorial);
         return tutorial;
     }
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java
index 5c418ff6..99332d1 100644
--- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java
+++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHCoordinatorImpl.java
@@ -5,22 +5,28 @@
 package org.chromium.chrome.browser.video_tutorials.iph;
 
 import android.content.Context;
+import android.graphics.Bitmap.Config;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.view.ViewStub;
 
 import org.chromium.base.Callback;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.image_fetcher.ImageFetcher;
 import org.chromium.chrome.browser.video_tutorials.Tutorial;
 import org.chromium.chrome.browser.video_tutorials.VideoTutorialUtils;
 import org.chromium.ui.modelutil.PropertyModel;
 import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
 
+import jp.tomorrowkey.android.gifplayer.BaseGifDrawable;
+
 /**
  * Creates and shows a video tutorial IPH. Requires a {@link ViewStub} to be passed which will
  * inflate when the IPH is shown.
  */
 public class VideoIPHCoordinatorImpl implements VideoIPHCoordinator {
+    private static final String VARIATION_USE_ANIMATED_GIF_URL = "use_animated_gif_url";
+
     private final Context mContext;
     private final PropertyModel mModel;
     private final VideoIPHView mView;
@@ -71,10 +77,20 @@
 
     private void fetchImage(
             Callback<Drawable> consumer, int widthPx, int heightPx, Tutorial tutorial) {
-        ImageFetcher.Params params = ImageFetcher.Params.create(tutorial.posterUrl,
+        boolean useAnimatedGifUrl = ChromeFeatureList.getFieldTrialParamByFeatureAsBoolean(
+                ChromeFeatureList.VIDEO_TUTORIALS, VARIATION_USE_ANIMATED_GIF_URL, false);
+        ImageFetcher.Params params = ImageFetcher.Params.create(
+                useAnimatedGifUrl ? tutorial.animatedGifUrl : tutorial.thumbnailUrl,
                 ImageFetcher.VIDEO_TUTORIALS_IPH_UMA_CLIENT_NAME, widthPx, heightPx);
-        mImageFetcher.fetchImage(params, bitmap -> {
-            consumer.onResult(new BitmapDrawable(mContext.getResources(), bitmap));
-        });
+        if (useAnimatedGifUrl) {
+            mImageFetcher.fetchGif(params, gifImage -> {
+                BaseGifDrawable baseGifDrawable = new BaseGifDrawable(gifImage, Config.ARGB_8888);
+                consumer.onResult(baseGifDrawable);
+            });
+        } else {
+            mImageFetcher.fetchImage(params, bitmap -> {
+                consumer.onResult(new BitmapDrawable(mContext.getResources(), bitmap));
+            });
+        }
     }
 }
\ No newline at end of file
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java
index 76bc411a..dac6a629 100644
--- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java
+++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/iph/VideoIPHTest.java
@@ -29,6 +29,7 @@
 import org.mockito.MockitoAnnotations;
 
 import org.chromium.base.Callback;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.video_tutorials.FeatureType;
 import org.chromium.chrome.browser.video_tutorials.R;
 import org.chromium.chrome.browser.video_tutorials.Tutorial;
@@ -37,6 +38,8 @@
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 import org.chromium.ui.test.util.DummyUiActivity;
 
+import java.util.HashMap;
+
 /**
  * Tests for {@link LanguagePickerCoordinator}.
  */
@@ -70,6 +73,7 @@
             TestImageFetcher imageFetcher = new TestImageFetcher(testImage);
             mCoordinator = new VideoIPHCoordinatorImpl(
                     viewStub, imageFetcher, mOnClickListener, mOnDismissListener);
+            ChromeFeatureList.setTestFeatures(new HashMap<>());
         });
     }
 
@@ -90,6 +94,7 @@
         return new Tutorial(FeatureType.DOWNLOAD,
                 "How to use Google Chrome's download functionality",
                 "https://xyz.example.com/xyz.mp4", "https://xyz.example.com/xyz.png",
+                "https://xyz.example.com/xyz.gif", "https://xyz.example.com/xyz.png",
                 "https://xyz.example.com/xyz.vtt", "https://xyz.example.com/xyz.mp4", 335);
     }
 
diff --git a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java
index 3547c03..c9b8bf3 100644
--- a/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java
+++ b/chrome/browser/video_tutorials/internal/android/java/src/org/chromium/chrome/browser/video_tutorials/list/TutorialListMediator.java
@@ -72,7 +72,7 @@
 
     private void fetchImage(
             Callback<Drawable> consumer, int widthPx, int heightPx, Tutorial tutorial) {
-        ImageFetcher.Params params = ImageFetcher.Params.create(tutorial.posterUrl,
+        ImageFetcher.Params params = ImageFetcher.Params.create(tutorial.thumbnailUrl,
                 ImageFetcher.VIDEO_TUTORIALS_LIST_UMA_CLIENT_NAME, widthPx, heightPx);
         mImageFetcher.fetchImage(params, bitmap -> {
             Drawable drawable = new BitmapDrawable(mContext.getResources(), bitmap);
diff --git a/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.cc b/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.cc
index 1d07c88..235f370 100644
--- a/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.cc
+++ b/chrome/browser/video_tutorials/internal/android/tutorial_conversion_bridge.cc
@@ -23,6 +23,8 @@
       ConvertUTF8ToJavaString(env, tutorial.title),
       ConvertUTF8ToJavaString(env, tutorial.video_url.spec()),
       ConvertUTF8ToJavaString(env, tutorial.poster_url.spec()),
+      ConvertUTF8ToJavaString(env, tutorial.animated_gif_url.spec()),
+      ConvertUTF8ToJavaString(env, tutorial.thumbnail_url.spec()),
       ConvertUTF8ToJavaString(env, tutorial.caption_url.spec()),
       ConvertUTF8ToJavaString(env, tutorial.share_url.spec()),
       tutorial.video_length);
diff --git a/chrome/browser/video_tutorials/internal/proto_conversions.cc b/chrome/browser/video_tutorials/internal/proto_conversions.cc
index f8cb439..cb58657 100644
--- a/chrome/browser/video_tutorials/internal/proto_conversions.cc
+++ b/chrome/browser/video_tutorials/internal/proto_conversions.cc
@@ -61,6 +61,8 @@
   proto->set_video_url(tutorial->video_url.spec());
   proto->set_share_url(tutorial->share_url.spec());
   proto->set_poster_url(tutorial->poster_url.spec());
+  proto->set_animated_gif_url(tutorial->animated_gif_url.spec());
+  proto->set_thumbnail_url(tutorial->thumbnail_url.spec());
   proto->set_caption_url(tutorial->caption_url.spec());
   proto->set_video_length(tutorial->video_length);
 }
@@ -73,6 +75,8 @@
   tutorial->video_url = GURL(proto->video_url());
   tutorial->share_url = GURL(proto->share_url());
   tutorial->poster_url = GURL(proto->poster_url());
+  tutorial->animated_gif_url = GURL(proto->animated_gif_url());
+  tutorial->thumbnail_url = GURL(proto->thumbnail_url());
   tutorial->caption_url = GURL(proto->caption_url());
   tutorial->video_length = proto->video_length();
 }
diff --git a/chrome/browser/video_tutorials/proto/video_tutorials.proto b/chrome/browser/video_tutorials/proto/video_tutorials.proto
index 1fbb86d..89ca7bf 100644
--- a/chrome/browser/video_tutorials/proto/video_tutorials.proto
+++ b/chrome/browser/video_tutorials/proto/video_tutorials.proto
@@ -40,10 +40,11 @@
   // The complete URL for the video.
   string video_url = 3;
 
-  // Youtube Video URL for sharing.
+  // The URL of the video for sharing.
   string share_url = 4;
 
-  // The complete URL of the thumbnail image.
+  // The URL of the video poster. Shown while the video is loading in the
+  // player.
   string poster_url = 5;
 
   // The URL of this video's caption.
@@ -51,6 +52,12 @@
 
   // Duration of the video in seconds.
   int64 video_length = 7;
+
+  // The URL of the animated thumbnail. Shown in the IPH cards.
+  string animated_gif_url = 8;
+
+  // The URL of the thumbnail image. Shown in the video list.
+  string thumbnail_url = 9;
 }
 
 // Response from the server containing tutorial groups for all languages.
diff --git a/chrome/browser/video_tutorials/test/test_utils.cc b/chrome/browser/video_tutorials/test/test_utils.cc
index a3e076d..cb60949 100644
--- a/chrome/browser/video_tutorials/test/test_utils.cc
+++ b/chrome/browser/video_tutorials/test/test_utils.cc
@@ -13,6 +13,8 @@
   *entry = Tutorial(
       FeatureType::kTest, kTestTitle, "https://www.example.com/video_url",
       "https://www.example.com/share_url", "https://www.example.com/poster_url",
+      "https://www.example.com/animated_gif_url",
+      "https://www.example.com/thumbnail_url",
       "https://www.example.com/caption_url", 60);
 }
 
diff --git a/chrome/browser/video_tutorials/tutorial.cc b/chrome/browser/video_tutorials/tutorial.cc
index 4e807b5..1ed16c2 100644
--- a/chrome/browser/video_tutorials/tutorial.cc
+++ b/chrome/browser/video_tutorials/tutorial.cc
@@ -13,6 +13,8 @@
                    const std::string& video_url,
                    const std::string& share_url,
                    const std::string& poster_url,
+                   const std::string& animated_gif_url,
+                   const std::string& thumbnail_url,
                    const std::string& caption_url,
                    int video_length)
     : feature(feature),
@@ -20,14 +22,18 @@
       video_url(video_url),
       share_url(share_url),
       poster_url(poster_url),
+      animated_gif_url(animated_gif_url),
+      thumbnail_url(thumbnail_url),
       caption_url(caption_url),
       video_length(video_length) {}
 
 bool Tutorial::operator==(const Tutorial& other) const {
   return feature == other.feature && title == other.title &&
          video_url == other.video_url && share_url == other.share_url &&
-         poster_url == other.poster_url && caption_url == other.caption_url &&
-         video_length == other.video_length;
+         poster_url == other.poster_url &&
+         animated_gif_url == other.animated_gif_url &&
+         thumbnail_url == other.thumbnail_url &&
+         caption_url == other.caption_url && video_length == other.video_length;
 }
 
 bool Tutorial::operator!=(const Tutorial& other) const {
diff --git a/chrome/browser/video_tutorials/tutorial.h b/chrome/browser/video_tutorials/tutorial.h
index 80936f20..626e8d3 100644
--- a/chrome/browser/video_tutorials/tutorial.h
+++ b/chrome/browser/video_tutorials/tutorial.h
@@ -36,6 +36,8 @@
            const std::string& video_url,
            const std::string& share_url,
            const std::string& poster_url,
+           const std::string& animated_gif_url,
+           const std::string& thumbnail_url,
            const std::string& caption_url,
            int video_length);
   ~Tutorial();
@@ -55,13 +57,20 @@
   // The URL of the video.
   GURL video_url;
 
-  // The URL of the poster image.
+  // The share URL for the video.
   GURL share_url;
 
-  // The URL of the subtitles.
+  // The URL of the poster image. Shown while the video is loading in the
+  // player.
   GURL poster_url;
 
-  // The share URL for the video.
+  // The URL of the animated gif image.
+  GURL animated_gif_url;
+
+  // The URL of the video thumbnail.
+  GURL thumbnail_url;
+
+  // The URL of the subtitles.
   GURL caption_url;
 
   // The length of the video in seconds.
diff --git a/chrome/browser/video_tutorials/tutorial_unittest.cc b/chrome/browser/video_tutorials/tutorial_unittest.cc
index c152717..f1182d07 100644
--- a/chrome/browser/video_tutorials/tutorial_unittest.cc
+++ b/chrome/browser/video_tutorials/tutorial_unittest.cc
@@ -14,7 +14,7 @@
 
 void ResetTutorialEntry(Tutorial* entry) {
   *entry = Tutorial(FeatureType::kTest, kTestTitle, kTestURL, kTestURL,
-                    kTestURL, kTestURL, 60);
+                    kTestURL, kTestURL, kTestURL, kTestURL, 60);
 }
 
 // Verify the copy/assign and compare operators for Tutorial struct.
diff --git a/chrome/build/linux.pgo.txt b/chrome/build/linux.pgo.txt
index a8f3be1..878469f6 100644
--- a/chrome/build/linux.pgo.txt
+++ b/chrome/build/linux.pgo.txt
@@ -1 +1 @@
-chrome-linux-master-1606154359-bcec197d59b03d3584048e9969b836c9e27febce.profdata
+chrome-linux-master-1606175959-14a3411953113a2fe64aa457a295c32153a3500e.profdata
diff --git a/chrome/build/mac.pgo.txt b/chrome/build/mac.pgo.txt
index 0a9c144..60a5b79 100644
--- a/chrome/build/mac.pgo.txt
+++ b/chrome/build/mac.pgo.txt
@@ -1 +1 @@
-chrome-mac-master-1606154359-5b79efba7e932d58ea0d577c610ff95eb947b3fb.profdata
+chrome-mac-master-1606175959-25d181192b782b01bd229877ae9d4ba54da15043.profdata
diff --git a/chrome/build/win64.pgo.txt b/chrome/build/win64.pgo.txt
index 39d95ba2..15a6f07 100644
--- a/chrome/build/win64.pgo.txt
+++ b/chrome/build/win64.pgo.txt
@@ -1 +1 @@
-chrome-win64-master-1606132785-17d21d0e147a4d4edd435db8e7a867f5c7c0da0c.profdata
+chrome-win64-master-1606165050-a3d889677a06d0e206b82027c298bfd0cf0af279.profdata
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 4d104f4..e42209c 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -5,6 +5,7 @@
 import("//build/buildflag_header.gni")
 import("//build/config/chrome_build.gni")  # For branding_file_path.
 import("//build/config/chromeos/ui_mode.gni")
+import("//build/config/chromeos/ui_mode.gni")
 import("//build/util/process_version.gni")
 import("//chrome/browser/downgrade/buildflags.gni")
 import("//chrome/common/features.gni")
@@ -60,7 +61,10 @@
     "channel_info.cc",
     "channel_info.h",
   ]
-  deps = [ "//build:branding_buildflags" ]
+  deps = [
+    "//build:branding_buildflags",
+    "//build:chromeos_buildflags",
+  ]
   public_deps = [
     "//base",
     "//components/version_info",
@@ -74,7 +78,7 @@
   } else if (is_android) {
     sources += [ "channel_info_android.cc" ]
     public_deps += [ "//components/version_info/android:channel_getter" ]
-  } else if (is_chromeos) {
+  } else if (is_chromeos_ash) {
     sources += [ "channel_info_chromeos.cc" ]
     deps += [ "//chromeos/crosapi/cpp" ]
   } else if (is_posix) {
@@ -235,6 +239,7 @@
 
   deps = [
     "//build:branding_buildflags",
+    "//build:chromeos_buildflags",
     "//components/crash/core/app",
     "//components/google/core/common",
     "//components/metrics:call_stack_profile_builder",
@@ -338,7 +343,7 @@
     public_deps += [ ":app_mode_app_support" ]
   }
 
-  if (is_chromeos) {
+  if (is_chromeos_ash) {
     assert(enable_extensions)
     sources += [
       "extensions/api/file_browser_handlers/file_browser_handler.cc",
@@ -363,7 +368,7 @@
       "//components/printing/common",
       "//printing",
     ]
-    if (enable_print_preview && !is_chromeos) {
+    if (enable_print_preview && !is_chromeos_ash) {
       # Part of the service_process_util code below is based on a model where
       # the cloud print service is a long-lived process independent of chrome,
       # which is not appropriate on android.
@@ -466,7 +471,7 @@
     deps += [ "//media/cdm:cdm_paths" ]  # Needed by chrome_content_client.cc
 
     if (enable_widevine) {
-      if (is_linux) {
+      if (is_linux || is_chromeos_lacros) {
         sources += [
           "media/component_widevine_cdm_hint_file_linux.cc",
           "media/component_widevine_cdm_hint_file_linux.h",
@@ -533,6 +538,7 @@
     ":version_header",
     "//base",
     "//build:branding_buildflags",
+    "//build:chromeos_buildflags",
     "//ppapi/buildflags",
   ]
 
@@ -554,6 +560,7 @@
     ":buildflags",
     ":non_code_constants",
     "//base",
+    "//build:chromeos_buildflags",
     "//components/offline_pages/buildflags",
     "//device/vr/buildflags",
     "//extensions/buildflags",
@@ -623,7 +630,7 @@
     # implemented in //ui/base, so we need that dependency.
     deps += [ "//ui/base" ]
   }
-  if (is_lacros) {
+  if (is_chromeos_lacros) {
     sources += [ "chrome_paths_lacros.cc" ]
     deps += [ "//chromeos/crosapi/cpp" ]
   } else if (is_linux || is_chromeos) {
@@ -782,7 +789,7 @@
   ]
 }
 
-if (enable_print_preview && !is_chromeos) {
+if (enable_print_preview && !is_chromeos_ash) {
   mojom("service_process_mojom") {
     sources = [
       "cloud_print.mojom",
diff --git a/chrome/common/apps/platform_apps/api/api_sources.gni b/chrome/common/apps/platform_apps/api/api_sources.gni
index 2d3c68a..927d476 100644
--- a/chrome/common/apps/platform_apps/api/api_sources.gni
+++ b/chrome/common/apps/platform_apps/api/api_sources.gni
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/features.gni")
 import("//chrome/common/features.gni")
 
@@ -17,7 +18,7 @@
   "webstore_widget_private.idl",
 ]
 
-if (is_chromeos) {
+if (is_chromeos_ash) {
   chrome_apps_api_schema_files_ += [ "arc_apps_private.idl" ]
 }
 
diff --git a/chrome/common/channel_info.h b/chrome/common/channel_info.h
index f9d5db6..5958587 100644
--- a/chrome/common/channel_info.h
+++ b/chrome/common/channel_info.h
@@ -8,6 +8,7 @@
 #include <string>
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 
 namespace base {
 class Environment;
@@ -61,7 +62,9 @@
 std::string GetChannelSuffixForDataDir();
 #endif
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 // Returns the channel-specific filename of the desktop shortcut used to launch
 // the browser.
 std::string GetDesktopName(base::Environment* env);
diff --git a/chrome/common/channel_info_posix.cc b/chrome/common/channel_info_posix.cc
index 88b20489b..6e592e2 100644
--- a/chrome/common/channel_info_posix.cc
+++ b/chrome/common/channel_info_posix.cc
@@ -8,6 +8,7 @@
 #include "base/strings/string_util.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "components/version_info/version_info.h"
 
 namespace chrome {
@@ -67,7 +68,9 @@
   }
 }
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 std::string GetDesktopName(base::Environment* env) {
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
   // Google Chrome packaged as a snap is a special case: the application name
@@ -96,7 +99,7 @@
   return "chromium-browser.desktop";
 #endif
 }
-#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS)
+#endif  // defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 
 version_info::Channel GetChannel() {
   return GetChannelImpl(nullptr);
diff --git a/chrome/common/chrome_constants.cc b/chrome/common/chrome_constants.cc
index 9fd86d0f..cc83774 100644
--- a/chrome/common/chrome_constants.cc
+++ b/chrome/common/chrome_constants.cc
@@ -6,6 +6,7 @@
 
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/chrome_version.h"
 
 #define FPL FILE_PATH_LITERAL
@@ -202,7 +203,7 @@
 
 const float kMaxShareOfExtensionProcesses = 0.30f;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const char kProfileDirPrefix[] = "u-";
 const char kLegacyProfileDir[] = "user";
 const char kTestUserProfileDir[] = "test-user";
diff --git a/chrome/common/chrome_constants.h b/chrome/common/chrome_constants.h
index 13d641e..4b3303f 100644
--- a/chrome/common/chrome_constants.h
+++ b/chrome/common/chrome_constants.h
@@ -11,6 +11,7 @@
 
 #include "base/files/file_path.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 
 namespace chrome {
 
@@ -95,7 +96,7 @@
 // installed.
 extern const float kMaxShareOfExtensionProcesses;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Chrome OS profile directories have custom prefix.
 // Profile path format: [user_data_dir]/u-[$hash]
 // Ex.: /home/chronos/u-0123456789
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc
index 1d8ff4a4..7323ffe 100644
--- a/chrome/common/chrome_content_client.cc
+++ b/chrome/common/chrome_content_client.cc
@@ -28,6 +28,7 @@
 #include "base/version.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/child_process_logging.h"
 #include "chrome/common/chrome_constants.h"
@@ -95,9 +96,9 @@
 // component updated CDM on all desktop platforms and remove this.
 // This file is In SHARED_INTERMEDIATE_DIR.
 #include "widevine_cdm_version.h"  // nogncheck
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/common/media/component_widevine_cdm_hint_file_linux.h"
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 #endif  // BUILDFLAG(ENABLE_WIDEVINE) && (defined(OS_LINUX) ||
         // defined(OS_CHROMEOS))
 
@@ -198,7 +199,7 @@
       false);
 }
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 // On desktop Linux, given |cdm_base_path| that points to a folder containing
 // the Widevine CDM and associated files, read the manifest included in that
 // directory and create a CdmInfo. If that is successful, return the CdmInfo. If
@@ -222,7 +223,7 @@
   return CreateWidevineCdmInfo(version, cdm_library_path,
                                std::move(capability));
 }
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 #endif  // (BUILDFLAG(BUNDLE_WIDEVINE_CDM) ||
         // BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)) && (defined(OS_LINUX) ||
         // defined(OS_CHROMEOS))
@@ -233,7 +234,7 @@
 // sandbox. On Windows and Mac, the bundled CDM is handled by the component
 // updater.
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 std::unique_ptr<content::CdmInfo> CreateCdmInfoForChromeOS(
     const base::FilePath& install_dir) {
   // On ChromeOS the Widevine CDM library is in the component directory and
@@ -269,7 +270,7 @@
   return CreateWidevineCdmInfo(base::Version(WIDEVINE_CDM_VERSION_STRING),
                                cdm_library_path, std::move(capability));
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // This code checks to see if the Widevine CDM was bundled with Chrome. If one
 // can be found and looks valid, it returns the CdmInfo for the CDM. Otherwise
@@ -283,7 +284,7 @@
         CHECK(base::PathService::Get(chrome::DIR_BUNDLED_WIDEVINE_CDM,
                                      &install_dir));
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
         // On ChromeOS the Widevine CDM library is in the component directory
         // (returned above) and does not have a manifest.
         // TODO(crbug.com/971433): Move Widevine CDM to a separate folder in
@@ -292,7 +293,7 @@
 #else
         // On desktop Linux the MANIFEST is bundled with the CDM.
         return CreateCdmInfoFromWidevineDirectory(install_dir);
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
       }());
   return s_cdm_info->get();
 }
@@ -508,7 +509,7 @@
 #if defined(OS_ANDROID)
     chrome::kAndroidAppScheme,
 #endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     chrome::kCrosScheme,
 #endif
 };
@@ -552,7 +553,7 @@
   schemes->csp_bypassing_schemes.push_back(extensions::kExtensionScheme);
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   schemes->local_schemes.push_back(content::kExternalFileScheme);
 #endif
 
diff --git a/chrome/common/chrome_features.cc b/chrome/common/chrome_features.cc
index 16861a6..6430af8 100644
--- a/chrome/common/chrome_features.cc
+++ b/chrome/common/chrome_features.cc
@@ -8,6 +8,7 @@
 #include "base/feature_list.h"
 #include "base/strings/string_split.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/chrome_switches.h"
 #include "extensions/buildflags/buildflags.h"
 #include "ppapi/buildflags/buildflags.h"
@@ -23,7 +24,7 @@
     "AcknowledgeNtpOverrideOnDeactivate", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables or disables logging for adaptive screen brightness on Chrome OS.
 const base::Feature kAdaptiveScreenBrightnessLogging{
     "AdaptiveScreenBrightnessLogging", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -34,7 +35,7 @@
     "AddToHomescreenMessaging", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Shows a setting that allows disabling mouse acceleration.
 const base::Feature kAllowDisableMouseAcceleration{
     "AllowDisableMouseAcceleration", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -50,13 +51,13 @@
                                        base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Controls whether web apps can be installed via APKs on Chrome OS.
 const base::Feature kApkWebAppInstalls{"ApkWebAppInstalls",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables app activity reporting for child user.
 // Requires |kPerAppTimeLimits| to be enabled.
 const base::Feature kAppActivityReporting{"AppActivityReporting",
@@ -89,7 +90,7 @@
 // Enables the built-in DNS resolver.
 const base::Feature kAsyncDns {
   "AsyncDns",
-#if defined(OS_CHROMEOS) || defined(OS_MAC) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_MAC) || defined(OS_ANDROID)
       base::FEATURE_ENABLED_BY_DEFAULT
 #else
       base::FEATURE_DISABLED_BY_DEFAULT
@@ -104,7 +105,7 @@
     "BackgroundModeAllowRestart", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enable Borealis on Chrome OS.
 const base::Feature kBorealis{"Borealis", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
@@ -148,7 +149,7 @@
     "CpuAffinityRestrictToLittleCores", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables or disables "usm" service in the list of user services returned by
 // userInfo Gaia message.
 const base::Feature kCrOSEnableUSMUserService{"CrOSEnableUSMUserService",
@@ -207,7 +208,7 @@
     "CryptohomeUserDataAuthKillswitch", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables parsing and enforcing Data Leak Prevention policy rules that
 // restricts usage of some system features, e.g.clipboard, screenshot, etc.
 // for confidential content.
@@ -215,7 +216,7 @@
                                               base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables passing additional user authentication in requests to DMServer
 // (policy fetch, status report upload).
 const base::Feature kDMServerOAuthForChildUser{
@@ -285,7 +286,7 @@
 // Enable DNS over HTTPS (DoH).
 const base::Feature kDnsOverHttps {
   "DnsOverHttps",
-#if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_MAC) || \
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_MAC) || \
     defined(OS_ANDROID)
       base::FEATURE_ENABLED_BY_DEFAULT
 #else
@@ -307,7 +308,7 @@
 // Sets whether the DoH setting is displayed in the settings UI.
 const base::FeatureParam<bool> kDnsOverHttpsShowUiParam {
   &kDnsOverHttps, "ShowUi",
-#if defined(OS_WIN) || defined(OS_CHROMEOS) || defined(OS_MAC) || \
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_MAC) || \
     defined(OS_ANDROID)
       true
 #else
@@ -339,14 +340,16 @@
 const base::Feature kEnableAllSystemWebApps{"EnableAllSystemWebApps",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
 
-#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || \
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_WIN) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || \
     defined(OS_MAC)
 COMPONENT_EXPORT(CHROME_FEATURES)
 // Enables ephemeral Guest profiles on desktop.
 extern const base::Feature kEnableEphemeralGuestProfilesOnDesktop{
     "EnableEphemeralGuestProfilesOnDesktop", base::FEATURE_DISABLED_BY_DEFAULT};
-#endif  // defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) ||
-        // defined(OS_MAC)
+#endif  // defined(OS_WIN) || (defined(OS_LINUX) ||
+        // BUILDFLAG(IS_CHROMEOS_LACROS)) || defined(OS_MAC)
 
 #if defined(OS_WIN)
 // Enables users to create a desktop shortcut for incognito mode.
@@ -364,13 +367,13 @@
     base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Upload enterprise cloud reporting from Chrome OS.
 const base::Feature kEnterpriseReportingInChromeOS{
     "EnterpriseReportingInChromeOS", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables event-based status reporting for child accounts in Chrome OS.
 const base::Feature kEventBasedStatusReporting{
     "EventBasedStatusReporting", base::FEATURE_ENABLED_BY_DEFAULT};
@@ -468,7 +471,7 @@
     base::FEATURE_DISABLED_BY_DEFAULT};
 #endif  // !defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables or disables the Happiness Tracking System for the device.
 const base::Feature kHappinessTrackingSystem{"HappinessTrackingSystem",
                                              base::FEATURE_DISABLED_BY_DEFAULT};
@@ -498,7 +501,7 @@
                                          base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables scraping of password-expiry information during SAML login flow, which
 // can lead to an in-session flow for changing SAML password if it has expired.
 // This is safe to enable by default since it does not cause the password-expiry
@@ -509,7 +512,7 @@
 // any unforeseen issues.
 const base::Feature kInSessionPasswordChange{"InSessionPasswordChange",
                                              base::FEATURE_ENABLED_BY_DEFAULT};
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_WIN)
 // A feature that controls whether Chrome warns about incompatible applications.
@@ -539,7 +542,7 @@
 const base::Feature kInvalidatorUniqueOwnerName{
     "InvalidatorUniqueOwnerName", base::FEATURE_DISABLED_BY_DEFAULT};
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const base::Feature kKernelnextVMs{"KernelnextVMs",
                                    base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
@@ -577,7 +580,7 @@
     "MacSystemScreenCapturePermissionCheck", base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Whether to show the Metered toggle in Settings, allowing users to toggle
 // whether to treat a WiFi or Cellular network as 'metered'.
 const base::Feature kMeteredShowToggle{"MeteredShowToggle",
@@ -593,7 +596,7 @@
 // Enables the use of native notification centers instead of using the Message
 // Center for displaying the toasts. The feature is hardcoded to enabled for
 // Chrome OS.
-#if BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS) && !defined(OS_CHROMEOS)
+#if BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS) && !BUILDFLAG(IS_CHROMEOS_ASH)
 const base::Feature kNativeNotifications{"NativeNotifications",
                                          base::FEATURE_ENABLED_BY_DEFAULT};
 #endif  // BUILDFLAG(ENABLE_NATIVE_NOTIFICATIONS)
@@ -642,7 +645,7 @@
                                      base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables usage of Parent Access Code in the login flow for reauth and add
 // user. Requires |kParentAccessCode| to be enabled.
 const base::Feature kParentAccessCodeForOnlineLogin{
@@ -657,7 +660,7 @@
 const base::Feature kPermissionPredictions{"PermissionPredictions",
                                            base::FEATURE_DISABLED_BY_DEFAULT};
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enable support for "Plugin VMs" on Chrome OS.
 const base::Feature kPluginVm{"PluginVm", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
@@ -694,7 +697,7 @@
 const base::Feature kPushMessagingBackgroundMode{
     "PushMessagingBackgroundMode", base::FEATURE_DISABLED_BY_DEFAULT};
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables or disables fingerprint quick unlock.
 const base::Feature kQuickUnlockFingerprint{"QuickUnlockFingerprint",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
@@ -709,7 +712,7 @@
     "AbusiveOriginNotificationPermissionRevocation",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables permanent removal of Legacy Supervised Users on startup.
 const base::Feature kRemoveSupervisedUsersOnStartup{
     "RemoveSupervisedUsersOnStartup", base::FEATURE_DISABLED_BY_DEFAULT};
@@ -725,11 +728,11 @@
     "SafetyCheckChromeCleanerChild", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enable support for multiple scheduler configurations.
 const base::Feature kSchedulerConfiguration{"SchedulerConfiguration",
                                             base::FEATURE_DISABLED_BY_DEFAULT};
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Controls whether SCT audit reports are queued and the rate at which they
 // should be sampled.
@@ -742,7 +745,7 @@
 const base::Feature kSecurityKeyAttestationPrompt{
     "SecurityKeyAttestationPrompt", base::FEATURE_ENABLED_BY_DEFAULT};
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const base::Feature kSharesheet{"Sharesheet", base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
@@ -769,26 +772,26 @@
 #endif
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables or disables SmartDim on Chrome OS.
 const base::Feature kSmartDim{"SmartDim", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Enables or disables using smbfs for accessing SMB file shares.
 const base::Feature kSmbFs{"SmbFs", base::FEATURE_ENABLED_BY_DEFAULT};
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Enables or disables the ability to use the sound content setting to mute a
 // website.
 const base::Feature kSoundContentSetting{"SoundContentSetting",
                                          base::FEATURE_ENABLED_BY_DEFAULT};
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables or disables chrome://sys-internals.
 const base::Feature kSysInternals{"SysInternals",
                                   base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables or disables TPM firmware update capability on Chrome OS.
 const base::Feature kTPMFirmwareUpdate{"TPMFirmwareUpdate",
                                        base::FEATURE_ENABLED_BY_DEFAULT};
@@ -819,7 +822,7 @@
 const base::Feature kTreatUnsafeDownloadsAsActive{
     "TreatUnsafeDownloadsAsActive", base::FEATURE_DISABLED_BY_DEFAULT};
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enable uploading of a zip archive of system logs instead of individual files.
 const base::Feature kUploadZippedSystemLogs{"UploadZippedSystemLogs",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
@@ -833,7 +836,7 @@
 const base::Feature kUsbguard{"USBGuard", base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables or disables user activity event logging for power management on
 // Chrome OS.
 const base::Feature kUserActivityEventLogging{"UserActivityEventLogging",
@@ -852,17 +855,17 @@
     "WebRtcRemoteEventLogGzipped", base::FEATURE_ENABLED_BY_DEFAULT};
 #endif
 
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
 // Enables Web Share (navigator.share)
 const base::Feature kWebShare{"WebShare", base::FEATURE_DISABLED_BY_DEFAULT};
 #endif
 
 // Enables setting time limit for Chrome and PWA's on child user device.
 // Requires |kPerAppTimeLimits| to be enabled.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const base::Feature kWebTimeLimits{"WebTimeLimits",
                                    base::FEATURE_DISABLED_BY_DEFAULT};
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Whether to enable "dark mode" enhancements in Mac Mojave or Windows 10 for
 // UIs implemented with web technologies.
@@ -875,7 +878,7 @@
 #endif  // defined(OS_MAC) || defined(OS_WIN) || defined(OS_ANDROID)
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Populates storage dimensions in UMA log if enabled. Requires diagnostics
 // package in the image.
 const base::Feature kUmaStorageDimensions{"UmaStorageDimensions",
@@ -901,10 +904,10 @@
     "WriteBasicSystemProfileToPersistentHistogramsFile",
     base::FEATURE_ENABLED_BY_DEFAULT};
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 bool IsParentAccessCodeForOnlineLoginEnabled() {
   return base::FeatureList::IsEnabled(kParentAccessCodeForOnlineLogin);
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace features
diff --git a/chrome/common/chrome_features.h b/chrome/common/chrome_features.h
index b96f075..375ab89d 100644
--- a/chrome/common/chrome_features.h
+++ b/chrome/common/chrome_features.h
@@ -13,6 +13,7 @@
 #include "base/metrics/field_trial_params.h"
 #include "build/build_config.h"
 #include "build/buildflag.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/buildflags.h"
 #include "device/vr/buildflags/buildflags.h"
 #include "extensions/buildflags/buildflags.h"
@@ -31,7 +32,7 @@
 extern const base::Feature kAcknowledgeNtpOverrideOnDeactivate;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kAdaptiveScreenBrightnessLogging;
 #endif
@@ -41,10 +42,10 @@
 extern const base::Feature kAddToHomescreenMessaging;
 #endif  // defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kAllowDisableMouseAcceleration;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kAlwaysReinstallSystemWebApps;
@@ -54,12 +55,12 @@
 extern const base::Feature kAndroidDarkSearch;
 #endif  // defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kApkWebAppInstalls;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kAppActivityReporting;
 #endif
@@ -87,9 +88,9 @@
 extern const base::Feature kBackgroundModeAllowRestart;
 #endif  // defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kBorealis;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if BUILDFLAG(TRIAL_COMPARISON_CERT_VERIFIER_SUPPORTED)
 COMPONENT_EXPORT(CHROME_FEATURES)
@@ -126,7 +127,7 @@
 extern const base::Feature kCpuAffinityRestrictToLittleCores;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kCrOSEnableUSMUserService;
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kCrosCompUpdates;
@@ -151,12 +152,12 @@
 extern const base::Feature kCryptohomeUserDataAuthKillswitch;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kDataLeakPreventionPolicy;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kDMServerOAuthForChildUser;
 #endif
@@ -227,11 +228,13 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kEnableAmbientAuthenticationInIncognito;
 
-#if defined(OS_WIN) || (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || \
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_WIN) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || \
     defined(OS_MAC)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kEnableEphemeralGuestProfilesOnDesktop;
-#endif  // defined(OS_WIN) || (defined(OS_LINUX) &6 !defined(OS_CHROMEOS)) ||
+#endif  // defined(OS_WIN) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) || \
         // defined(OS_MAC)
 
 #if defined(OS_WIN)
@@ -252,12 +255,12 @@
 extern const base::Feature kEnterpriseReportingApiKeychainRecreation;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kEnterpriseReportingInChromeOS;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kEventBasedStatusReporting;
 #endif
@@ -311,7 +314,7 @@
     kHappinessTrackingSurveysForDesktopDevToolsIssuesCookiesSameSite;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kHappinessTrackingSystem;
 #endif
@@ -330,7 +333,7 @@
 extern const base::Feature kImmersiveFullscreen;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kInSessionPasswordChange;
 #endif
@@ -356,7 +359,7 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kInvalidatorUniqueOwnerName;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kKernelnextVMs;
 #endif
@@ -382,7 +385,7 @@
 extern const base::Feature kMacSystemScreenCapturePermissionCheck;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kMeteredShowToggle;
 #endif
@@ -425,7 +428,7 @@
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kOomIntervention;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kParentAccessCodeForOnlineLogin;
 
@@ -436,7 +439,7 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kPermissionPredictions;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kPluginVm;
 #endif
@@ -461,7 +464,7 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kPushMessagingBackgroundMode;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kQuickUnlockFingerprint;
 #endif
@@ -472,7 +475,7 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kAbusiveNotificationPermissionRevocation;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kRemoveSupervisedUsersOnStartup;
 #endif
@@ -487,7 +490,7 @@
 extern const base::Feature kSafetyCheckChromeCleanerChild;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kSchedulerConfiguration;
 #endif
@@ -500,7 +503,7 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kSecurityKeyAttestationPrompt;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kSharesheet;
 #endif
@@ -512,7 +515,7 @@
 
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kSitePerProcess;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kSmartDim;
 
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kSmbFs;
@@ -521,12 +524,12 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kSoundContentSetting;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kSysInternals;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kTPMFirmwareUpdate;
 #endif
 
@@ -545,18 +548,18 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kTreatUnsafeDownloadsAsActive;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kUploadZippedSystemLogs;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kUsbbouncer;
 
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kUsbguard;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kUserActivityEventLogging;
 #endif
@@ -580,22 +583,22 @@
 extern const base::Feature kWebRtcRemoteEventLogGzipped;
 #endif
 
-#if defined(OS_WIN) || defined(OS_CHROMEOS)
+#if defined(OS_WIN) || BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kWebShare;
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kWebTimeLimits;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kWebUIDarkMode;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kUmaStorageDimensions;
 COMPONENT_EXPORT(CHROME_FEATURES) extern const base::Feature kWilcoDtc;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_WIN)
 COMPONENT_EXPORT(CHROME_FEATURES)
@@ -608,10 +611,10 @@
 COMPONENT_EXPORT(CHROME_FEATURES)
 extern const base::Feature kWriteBasicSystemProfileToPersistentHistogramsFile;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 COMPONENT_EXPORT(CHROME_FEATURES)
 bool IsParentAccessCodeForOnlineLoginEnabled();
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 bool PrefServiceEnabled();
 
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc
index 3528e03..959979b 100644
--- a/chrome/common/chrome_paths.cc
+++ b/chrome/common/chrome_paths.cc
@@ -15,6 +15,7 @@
 #include "base/threading/thread_restrictions.h"
 #include "base/version.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths_internal.h"
@@ -73,12 +74,12 @@
 #endif  // (defined(OS_LINUX) || defined(OS_CHROMEOS)) &&
         // BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const base::FilePath::CharType kChromeOSTPMFirmwareUpdateLocation[] =
     FILE_PATH_LITERAL("/run/tpm_firmware_update_location");
 const base::FilePath::CharType kChromeOSTPMFirmwareUpdateSRKVulnerableROCA[] =
     FILE_PATH_LITERAL("/run/tpm_firmware_update_srk_vulnerable_roca");
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 base::FilePath& GetInvalidSpecifiedUserDataDirInternal() {
   static base::NoDestructor<base::FilePath> s;
@@ -201,7 +202,7 @@
 #endif
       break;
     case chrome::DIR_CRASH_DUMPS:
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
       // ChromeOS uses a separate directory. See http://crosbug.com/25089
       cur = base::FilePath("/var/log/chrome");
 #elif defined(OS_ANDROID)
@@ -340,16 +341,16 @@
     case chrome::DIR_BUNDLED_WIDEVINE_CDM:
       if (!GetComponentDirectory(&cur))
         return false;
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
       // TODO(crbug.com/971433): Move Widevine CDM to a separate folder on
       // ChromeOS so that the manifest can be included.
       cur = cur.AppendASCII(kWidevineCdmBaseDirectory);
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
       break;
 #endif  // (defined(OS_LINUX) || defined(OS_CHROMEOS)) &&
         // BUILDFLAG(BUNDLE_WIDEVINE_CDM)
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && \
+#if (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
     BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
     case chrome::DIR_COMPONENT_UPDATED_WIDEVINE_CDM:
       if (!base::PathService::Get(chrome::DIR_USER_DATA, &cur))
@@ -362,7 +363,7 @@
         return false;
       cur = cur.Append(kComponentUpdatedWidevineCdmHint);
       break;
-#endif  // defined(OS_LINUX) && !defined(OS_CHROMEOS) &&
+#endif  // (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
         // BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
 
     case chrome::FILE_RESOURCES_PACK:  // Falls through.
@@ -390,7 +391,7 @@
 #endif
       break;
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     case chrome::DIR_CHROMEOS_WALLPAPERS:
       if (!base::PathService::Get(chrome::DIR_USER_DATA, &cur))
         return false;
@@ -459,8 +460,12 @@
       break;
     }
 #endif
-#if defined(OS_CHROMEOS) || \
-    (defined(OS_LINUX) && BUILDFLAG(CHROMIUM_BRANDING)) || defined(OS_MAC)
+// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
+// complete.
+#if defined(OS_CHROMEOS) ||                                  \
+    ((defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
+     BUILDFLAG(CHROMIUM_BRANDING)) ||                        \
+    defined(OS_MAC)
     case chrome::DIR_USER_EXTERNAL_EXTENSIONS: {
       if (!base::PathService::Get(chrome::DIR_USER_DATA, &cur))
         return false;
@@ -546,7 +551,7 @@
       cur = cur.Append(kComponentUpdatedFlashHint);
       break;
 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     case chrome::FILE_CHROME_OS_TPM_FIRMWARE_UPDATE_LOCATION:
       cur = base::FilePath(kChromeOSTPMFirmwareUpdateLocation);
       create_dir = false;
@@ -555,7 +560,7 @@
       cur = base::FilePath(kChromeOSTPMFirmwareUpdateSRKVulnerableROCA);
       create_dir = false;
       break;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
     case chrome::DIR_OPTIMIZATION_GUIDE_PREDICTION_MODELS:
       if (!base::PathService::Get(chrome::DIR_USER_DATA, &cur))
         return false;
diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h
index 4122317..e422dca 100644
--- a/chrome/common/chrome_paths.h
+++ b/chrome/common/chrome_paths.h
@@ -7,6 +7,7 @@
 
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 
 namespace base {
 class FilePath;
@@ -50,8 +51,12 @@
                      // to set policies for chrome. This directory
                      // contains subdirectories.
 #endif
-#if defined(OS_CHROMEOS) || \
-    (defined(OS_LINUX) && BUILDFLAG(CHROMIUM_BRANDING)) || defined(OS_MAC)
+// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
+// complete.
+#if defined(OS_CHROMEOS) ||                                  \
+    ((defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)) && \
+     BUILDFLAG(CHROMIUM_BRANDING)) ||                        \
+    defined(OS_MAC)
   DIR_USER_EXTERNAL_EXTENSIONS,  // Directory for per-user external extensions
                                  // on Chrome Mac and Chromium Linux.
                                  // On Chrome OS, this path is used for OEM
@@ -90,13 +95,13 @@
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
   DIR_BUNDLED_WIDEVINE_CDM,  // Full path to the directory containing the
                              // bundled Widevine CDM.
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
   DIR_COMPONENT_UPDATED_WIDEVINE_CDM,  // Base directory of the Widevine CDM
                                        // downloaded by the component
                                        // updater.
   FILE_COMPONENT_WIDEVINE_CDM_HINT,    // A file in a known location that points
-                                     // to the component updated Widevine CDM.
-#endif                                 // !defined(OS_CHROMEOS)
+                                       // to the component updated Widevine CDM.
+#endif                                 // !BUILDFLAG(IS_CHROMEOS_ASH)
 #endif                  // defined(OS_LINUX) || defined(OS_CHROMEOS)
   FILE_RESOURCES_PACK,  // Full path to the .pak file containing binary data.
                         // This includes data for internal pages (e.g., html
@@ -105,7 +110,7 @@
   FILE_DEV_UI_RESOURCES_PACK,  // Full path to the .pak file containing
                                // binary data for internal pages (e.g., html
                                // files and images).
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   DIR_CHROMEOS_WALLPAPERS,            // Directory where downloaded chromeos
                                       // wallpapers reside.
   DIR_CHROMEOS_WALLPAPER_THUMBNAILS,  // Directory where downloaded chromeos
@@ -135,14 +140,14 @@
   FILE_COMPONENT_FLASH_HINT,  // A file in a known location that points to
                               // the component updated flash plugin.
 #endif                        // defined(OS_LINUX) || defined(OS_CHROMEOS)
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // File containing the location of the updated TPM firmware binary in the file
   // system.
   FILE_CHROME_OS_TPM_FIRMWARE_UPDATE_LOCATION,
 
   // Flag file indicating SRK ROCA vulnerability status.
   FILE_CHROME_OS_TPM_FIRMWARE_UPDATE_SRK_VULNERABLE_ROCA,
-#endif  // defined(OS_CHROMEOS)
+#endif                                       // BUILDFLAG(IS_CHROMEOS_ASH)
   DIR_OPTIMIZATION_GUIDE_PREDICTION_MODELS,  // Directory where verified models
                                              // downloaded by the Optimization
                                              // Guide are stored.
diff --git a/chrome/common/chrome_paths_linux.cc b/chrome/common/chrome_paths_linux.cc
index 42d355be..fc9d67e 100644
--- a/chrome/common/chrome_paths_linux.cc
+++ b/chrome/common/chrome_paths_linux.cc
@@ -14,6 +14,7 @@
 #include "base/strings/string_util.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_paths_internal.h"
 
@@ -35,7 +36,7 @@
 bool GetUserMediaDirectory(const std::string& xdg_name,
                            const std::string& fallback_name,
                            base::FilePath* result) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   // No local media directories on CrOS.
   return false;
 #else
diff --git a/chrome/common/chrome_paths_unittest.cc b/chrome/common/chrome_paths_unittest.cc
index 6af8617..36b277c 100644
--- a/chrome/common/chrome_paths_unittest.cc
+++ b/chrome/common/chrome_paths_unittest.cc
@@ -47,7 +47,7 @@
   // Verify that a profile in the special platform-specific source
   // location ends up in the special target location. Ignore this assertion on
   // platforms that don't use a special cache directory.
-#if !defined(OS_WIN) && !BUILDFLAG(IS_LACROS)
+#if !defined(OS_WIN) && !BUILDFLAG(IS_CHROMEOS_LACROS)
   GetUserCacheDirectory(test_profile_dir, &cache_dir);
   EXPECT_EQ(expected_cache_dir.value(), cache_dir.value());
 #endif
@@ -64,7 +64,8 @@
 }
 
 // Chrome OS doesn't use any of the desktop linux configuration.
-#if defined(OS_LINUX) && !BUILDFLAG(IS_LACROS) && !BUILDFLAG(IS_ASH)
+#if defined(OS_LINUX) && !BUILDFLAG(IS_CHROMEOS_LACROS) && \
+    !BUILDFLAG(IS_CHROMEOS_ASH)
 TEST(ChromePaths, DefaultUserDataDir) {
   std::unique_ptr<base::Environment> env(base::Environment::Create());
   std::string orig_chrome_config_home;
@@ -103,7 +104,7 @@
 }
 #endif
 
-#if BUILDFLAG(IS_LACROS) || BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_LACROS) || BUILDFLAG(IS_CHROMEOS_ASH)
 TEST(ChromePaths, UserMediaDirectories) {
   base::FilePath path;
   // Chrome OS does not support custom media directories.
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 4a0793e..693541f 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -5,6 +5,7 @@
 #include "chrome/common/chrome_switches.h"
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "printing/buildflags/buildflags.h"
 
@@ -639,7 +640,7 @@
 const char kWebApkServerUrl[] = "webapk-server-url";
 #endif  // defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Custom crosh command.
 const char kCroshCommand[] = "crosh-command";
 
@@ -662,9 +663,9 @@
 // Specifies what the default scheduler configuration value is if the user does
 // not set one.
 const char kSchedulerConfigurationDefault[] = "scheduler-configuration-default";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_POSIX) && !defined(OS_MAC) && !defined(OS_CHROMEOS)
+#if defined(OS_POSIX) && !defined(OS_MAC) && !BUILDFLAG(IS_CHROMEOS_ASH)
 // These flags show the man page on Linux. They are equivalent to each
 // other.
 const char kHelp[]                          = "help";
@@ -802,7 +803,7 @@
 const char kGuest[] = "guest";
 #endif
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID)
 // Uses the system default printer as the initially selected destination in
 // print preview, instead of the most recently used destination.
 const char kUseSystemDefaultPrinter[] = "use-system-default-printer";
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 6d6a866e..8922e5d 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -9,6 +9,7 @@
 #define CHROME_COMMON_CHROME_SWITCHES_H_
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/buildflags.h"
 #include "ppapi/buildflags/buildflags.h"
 #include "printing/buildflags/buildflags.h"
@@ -195,7 +196,7 @@
 extern const char kWebApkServerUrl[];
 #endif  // defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kCroshCommand[];
 extern const char kDisableLoggingRedirect[];
 extern const char kDisableLoginScreenApps[];
@@ -204,9 +205,9 @@
 extern const char kSchedulerConfigurationConservative[];
 extern const char kSchedulerConfigurationPerformance[];
 extern const char kSchedulerConfigurationDefault[];
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
-#if defined(OS_POSIX) && !defined(OS_MAC) && !defined(OS_CHROMEOS)
+#if defined(OS_POSIX) && !defined(OS_MAC) && !BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kHelp[];
 extern const char kHelpShort[];
 extern const char kPasswordStore[];
@@ -255,7 +256,7 @@
 extern const char kGuest[];
 #endif
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID)
 extern const char kUseSystemDefaultPrinter[];
 #endif
 
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index e71c5e5..b84f727 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -11,13 +11,14 @@
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/crash/core/common/crash_key.h"
 #include "components/crash/core/common/crash_keys.h"
 #include "components/flags_ui/flags_ui_switches.h"
 #include "content/public/common/content_switches.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/common/chrome_switches.h"
 #include "components/crash/core/app/crash_switches.h"
 #include "gpu/command_buffer/service/gpu_switches.h"
@@ -38,7 +39,7 @@
     switches::kVModule,
 #if defined(OS_MAC)
     switches::kMetricsClientID,
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
     // --crash-loop-before is a "boring" switch because it is redundant;
     // crash_reporter separately informs the crash server if it is doing
     // crash-loop handling.
diff --git a/chrome/common/crash_keys_unittest.cc b/chrome/common/crash_keys_unittest.cc
index 80b1781..f4f9a71 100644
--- a/chrome/common/crash_keys_unittest.cc
+++ b/chrome/common/crash_keys_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "components/crash/core/common/crash_key.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -95,7 +96,7 @@
   command_line.AppendSwitch("--vvv");
   command_line.AppendSwitch("--enable-multi-profiles");
   command_line.AppendSwitch("--device-management-url=https://foo/bar");
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   command_line.AppendSwitch("--user-data-dir=/tmp");
   command_line.AppendSwitch("--default-wallpaper-small=test.png");
 #endif
diff --git a/chrome/common/extensions/api/BUILD.gn b/chrome/common/extensions/api/BUILD.gn
index ed80d385..4f8c653 100644
--- a/chrome/common/extensions/api/BUILD.gn
+++ b/chrome/common/extensions/api/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/features.gni")
 import("//build/config/ui.gni")
 import("//chrome/common/extensions/api/api_sources.gni")
@@ -56,7 +57,7 @@
     "tts.json",
     "tts_engine.json",
   ]
-  if (is_chromeos) {
+  if (is_chromeos_ash) {
     sources += [ "file_browser_handler.json" ]
   } else {
     # On ChromeOS, input_method_private is fully compiled (as part of
diff --git a/chrome/common/extensions/api/api_sources.gni b/chrome/common/extensions/api/api_sources.gni
index 92a50eb6..50431b22 100644
--- a/chrome/common/extensions/api/api_sources.gni
+++ b/chrome/common/extensions/api/api_sources.gni
@@ -76,18 +76,18 @@
   schema_sources_ += [ "processes.idl" ]
 }
 
-if (is_chromeos || is_mac || is_win) {
+if (is_chromeos_ash || is_mac || is_win) {
   schema_sources_ += [ "networking_cast_private.idl" ]
 }
 
-if (is_chromeos || chromeos_is_browser_only) {
+if (is_chromeos_ash || is_chromeos_lacros) {
   schema_sources_ += [
     "enterprise_platform_keys.idl",
     "enterprise_platform_keys_internal.idl",
   ]
 }
 
-if (is_chromeos) {
+if (is_chromeos_ash) {
   schema_sources_ += [
     "certificate_provider.idl",
     "certificate_provider_internal.idl",
@@ -126,11 +126,11 @@
   schema_sources_ += [ "input_ime.json" ]
 }
 
-if (!is_chromeos) {
+if (!is_chromeos_ash) {
   schema_sources_ += [ "enterprise_reporting_private.idl" ]
 }
 
-if (enable_print_preview && !is_chromeos) {
+if (enable_print_preview && !is_chromeos_ash) {
   schema_sources_ += [ "cloud_print_private.json" ]
 }
 
@@ -152,7 +152,7 @@
   "top_sites.json",
 ]
 
-if (is_chromeos) {
+if (is_chromeos_ash) {
   uncompiled_sources_ += [
     "chromeos_info_private.json",
     "media_player_private.json",
diff --git a/chrome/common/extensions/chrome_manifest_handlers.cc b/chrome/common/extensions/chrome_manifest_handlers.cc
index d0c56c6..8d2c3b5 100644
--- a/chrome/common/extensions/chrome_manifest_handlers.cc
+++ b/chrome/common/extensions/chrome_manifest_handlers.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/extensions/api/commands/commands_handler.h"
 #include "chrome/common/extensions/api/omnibox/omnibox_handler.h"
 #include "chrome/common/extensions/api/speech/tts_engine_manifest_handler.h"
@@ -29,7 +30,7 @@
 #include "extensions/common/manifest_handlers/options_page_info.h"
 #include "extensions/common/manifest_url_handlers.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h"
 #include "chrome/common/extensions/api/file_system_provider_capabilities/file_system_provider_capabilities_handler.h"
 #include "chrome/common/extensions/api/input_ime/input_components_handler.h"
@@ -66,7 +67,7 @@
   registry->RegisterHandler(std::make_unique<TtsEngineManifestHandler>());
   registry->RegisterHandler(std::make_unique<UrlHandlersParser>());
   registry->RegisterHandler(std::make_unique<URLOverridesHandler>());
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   registry->RegisterHandler(std::make_unique<FileBrowserHandlerParser>());
   registry->RegisterHandler(
       std::make_unique<FileSystemProviderCapabilitiesHandler>());
diff --git a/chrome/common/extensions/chrome_manifest_url_handlers.cc b/chrome/common/extensions/chrome_manifest_url_handlers.cc
index bdd59fcd..6b82a35 100644
--- a/chrome/common/extensions/chrome_manifest_url_handlers.cc
+++ b/chrome/common/extensions/chrome_manifest_url_handlers.cc
@@ -13,6 +13,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/url_constants.h"
 #include "extensions/common/constants.h"
@@ -25,7 +26,7 @@
 #include "extensions/common/manifest_url_handlers.h"
 #include "extensions/common/permissions/api_permission.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "ash/keyboard/ui/resources/keyboard_resource_util.h"
 #endif
 
@@ -119,7 +120,7 @@
     bool is_allowed_host = page == chrome::kChromeUINewTabHost ||
                            page == chrome::kChromeUIBookmarksHost ||
                            page == chrome::kChromeUIHistoryHost;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     is_allowed_host = is_allowed_host ||
                       page == chrome::kChromeUIActivationMessageHost ||
                       page == keyboard::kKeyboardHost;
diff --git a/chrome/common/extensions/command.cc b/chrome/common/extensions/command.cc
index 4732019..fc803ac 100644
--- a/chrome/common/extensions/command.cc
+++ b/chrome/common/extensions/command.cc
@@ -13,6 +13,7 @@
 #include "base/strings/string_util.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "extensions/common/error_utils.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest_constants.h"
@@ -31,13 +32,13 @@
 static const char kCommandKeyNotSupported[] =
     "Command key is not supported. Note: Ctrl means Command on Mac";
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // ChromeOS supports an additional modifier 'Search', which can result in longer
 // sequences.
 static const int kMaxTokenSize = 4;
 #else
 static const int kMaxTokenSize = 3;
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // TODO(devlin): Expose this on Command, since many places implicitly check
 // this.
@@ -291,9 +292,9 @@
   return values::kKeybindingPlatformWin;
 #elif defined(OS_MAC)
   return values::kKeybindingPlatformMac;
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
   return values::kKeybindingPlatformChromeOs;
-#elif defined(OS_LINUX)
+#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   return values::kKeybindingPlatformLinux;
 #else
   return "";
@@ -323,7 +324,7 @@
     shortcut += values::kKeySeparator;
 
   if (accelerator.IsCmdDown()) {
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     // Chrome OS treats the Search key like the Command key.
     shortcut += values::kKeySearch;
 #else
diff --git a/chrome/common/extensions/command_unittest.cc b/chrome/common/extensions/command_unittest.cc
index 3d6fc522..e915c4e 100644
--- a/chrome/common/extensions/command_unittest.cc
+++ b/chrome/common/extensions/command_unittest.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/values.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace extensions {
@@ -230,10 +231,10 @@
 #elif defined(OS_MAC)
   ui::Accelerator accelerator(ui::VKEY_M,
                               ui::EF_SHIFT_DOWN | ui::EF_COMMAND_DOWN);
-#elif defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_CHROMEOS_ASH)
   ui::Accelerator accelerator(ui::VKEY_C,
                               ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
-#elif defined(OS_LINUX)
+#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
   ui::Accelerator accelerator(ui::VKEY_L,
                               ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN);
 #else
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 29b16625..3ed876bd 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -6,6 +6,7 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "extensions/common/constants.h"
 
 namespace extension_urls {
@@ -68,7 +69,7 @@
     kTextEditorAppId,
     kInAppPaymentsSupportAppId,
     kCastExtensionIdRelease,
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     kAssessmentAssistantExtensionId,
     kAccessibilityCommonExtensionId,
     kSelectToSpeakExtensionId,
@@ -79,11 +80,11 @@
     kGoogleSpeechSynthesisExtensionId,
     kWallpaperManagerId,
     kZipArchiverExtensionId,
-#endif        // defined(OS_CHROMEOS)
+#endif        // BUILDFLAG(IS_CHROMEOS_ASH)
     nullptr,  // Null-terminated array.
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const char kAssessmentAssistantExtensionId[] =
     "gndmhdcefbhlchkhipcnnbkcmicncehk";
 const char kAccessibilityCommonExtensionId[] =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index 5b214230..2d4247de 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -11,6 +11,7 @@
 
 #include "base/files/file_path.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "url/gurl.h"
 
 namespace extension_urls {
@@ -182,7 +183,7 @@
   APP_LAUNCH_BUCKET_INVALID
 };
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // The extension id of the Assessment Assistant extension.
 extern const char kAssessmentAssistantExtensionId[];
 // The extension id of the Accessibility Common extension.
diff --git a/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc b/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc
index 7a45ea46..5f33931 100644
--- a/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc
+++ b/chrome/common/extensions/manifest_tests/extension_manifests_kiosk_unittest.cc
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/extensions/manifest_tests/chrome_manifest_test.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest_constants.h"
@@ -64,7 +65,7 @@
 }
 
 // 'kiosk_only' key should be set only from ChromeOS.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 TEST_F(ExtensionManifestKioskModeTest, KioskOnlyPlatformApp) {
   scoped_refptr<Extension> extension(
       LoadAndExpectSuccess("kiosk_only_platform_app.json"));
@@ -103,6 +104,6 @@
   LoadAndExpectWarning("kiosk_only_platform_app.json",
                        "'kiosk_only' is not allowed for specified platform.");
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace extensions
diff --git a/chrome/common/features.gni b/chrome/common/features.gni
index 1987da7..1b2d4f0 100644
--- a/chrome/common/features.gni
+++ b/chrome/common/features.gni
@@ -4,6 +4,7 @@
 
 import("//build/config/chrome_build.gni")
 import("//build/config/chromecast_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
 import("//build/config/compiler/compiler.gni")
 import("//build/config/dcheck_always_on.gni")
 import("//build/config/features.gni")
@@ -32,11 +33,11 @@
 
   # Enables support for background apps.
   enable_background_contents = !is_android && !is_chromecast
-  enable_background_mode = !is_android && !is_chromecast && !is_chromeos
+  enable_background_mode = !is_android && !is_chromecast && !is_chromeos_ash
 
   # Enable the printing system dialog for platforms that support printing
   # and have a system dialog.
-  enable_basic_print_dialog = enable_basic_printing && !is_chromeos
+  enable_basic_print_dialog = enable_basic_printing && !is_chromeos_ash
 
   # Enables the Click to Call feature on desktop platforms.
   enable_click_to_call = is_mac || is_win || is_linux || is_chromeos
@@ -47,10 +48,11 @@
 
   # Enables usage of the system-provided notification center.
   enable_native_notifications =
-      is_android || is_mac || is_win || (is_linux && use_dbus) || is_chromeos
+      is_android || is_mac || is_win ||
+      ((is_linux || is_chromeos_lacros) && use_dbus) || is_chromeos
 
   enable_one_click_signin =
-      is_win || is_mac || (is_linux && !is_chromeos && !is_chromecast)
+      is_win || is_mac || ((is_linux || is_chromeos_lacros) && !is_chromecast)
 
   enable_service_discovery = (enable_mdns && !is_android) || is_mac
 
@@ -58,16 +60,16 @@
   # Android stores them separately on the Java side.
   enable_session_service = !is_android && !is_chromecast
 
-  enable_supervised_users = is_chromeos || is_android
+  enable_supervised_users = is_chromeos_ash || is_android
 
   # Indicates if Wayland display server support is enabled.
-  enable_wayland_server = is_chromeos
+  enable_wayland_server = is_chromeos_ash
 
   # optimize_webui was moved to ui/base/ui_features.gni
 }
 
 # Use brlapi from brltty for braille display support.
-use_brlapi = is_chromeos
+use_brlapi = is_chromeos_ash
 
 # Every grit target in //chrome should apply these defines so that the
 # proper build flags can be set.
diff --git a/chrome/common/logging_chrome.cc b/chrome/common/logging_chrome.cc
index f85a597..c5f48b3 100644
--- a/chrome/common/logging_chrome.cc
+++ b/chrome/common/logging_chrome.cc
@@ -47,6 +47,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_switches.h"
@@ -54,7 +55,7 @@
 #include "content/public/common/content_switches.h"
 #include "ipc/ipc_logging.h"
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #include "chromeos/constants/chromeos_switches.h"
 #endif
 
@@ -157,7 +158,7 @@
   return kDefaultLoggingMode;
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 base::FilePath SetUpSymlinkIfNeeded(const base::FilePath& symlink_path,
                                     bool new_log) {
   DCHECK(!symlink_path.empty());
@@ -261,7 +262,7 @@
       .Append(GetLogFileName(command_line).BaseName());
 }
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 void InitChromeLogging(const base::CommandLine& command_line,
                        OldFileDeletionState delete_old_log_file) {
@@ -270,7 +271,7 @@
   LoggingDestination logging_dest = DetermineLoggingDestination(command_line);
   LogLockingState log_locking_state = LOCK_LOG_FILE;
   base::FilePath log_path;
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   base::FilePath target_path;
 #endif
 
@@ -279,7 +280,7 @@
   if ((logging_dest & LOG_TO_FILE) != 0) {
     log_path = GetLogFileName(command_line);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     // For BWSI (Incognito) logins, we want to put the logs in the user
     // profile directory that is created for the temporary session instead
     // of in the system log directory, for privacy reasons.
@@ -296,7 +297,7 @@
     // the link, it shouldn't remove the old file in the logging code,
     // since that will remove the newly created link instead.
     delete_old_log_file = APPEND_TO_OLD_LOG_FILE;
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
   } else {
     log_locking_state = DONT_LOCK_LOG_FILE;
   }
@@ -308,7 +309,7 @@
   settings.delete_old = delete_old_log_file;
   bool success = InitLogging(settings);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
   if (!success) {
     DPLOG(ERROR) << "Unable to initialize logging to " << log_path.value()
                 << " (which should be a link to " << target_path.value() << ")";
@@ -316,13 +317,13 @@
     chrome_logging_failed_ = true;
     return;
   }
-#else   // defined(OS_CHROMEOS)
+#else   // BUILDFLAG(IS_CHROMEOS_ASH)
   if (!success) {
     DPLOG(ERROR) << "Unable to initialize logging to " << log_path.value();
     chrome_logging_failed_ = true;
     return;
   }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
   // We call running in unattended mode "headless", and allow headless mode to
   // be configured either by the Environment Variable or by the Command Line
@@ -417,7 +418,7 @@
   return dialogs_are_suppressed_;
 }
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 base::FilePath GenerateTimestampedName(const base::FilePath& base_path,
                                        base::Time timestamp) {
   base::Time::Exploded time_deets;
@@ -431,6 +432,6 @@
                                           time_deets.second);
   return base_path.InsertBeforeExtensionASCII(suffix);
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace logging
diff --git a/chrome/common/logging_chrome.h b/chrome/common/logging_chrome.h
index f727faa5..52c8fad9 100644
--- a/chrome/common/logging_chrome.h
+++ b/chrome/common/logging_chrome.h
@@ -8,6 +8,7 @@
 #include "base/logging.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 
 namespace base {
 class CommandLine;
@@ -35,7 +36,7 @@
 LoggingDestination DetermineLoggingDestination(
     const base::CommandLine& command_line);
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Point the logging symlink to the system log or the user session log.
 base::FilePath SetUpSymlinkIfNeeded(const base::FilePath& symlink_path,
                                     bool new_log);
@@ -61,12 +62,12 @@
 // otherwise.
 bool DialogsAreSuppressed();
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Inserts timestamp before file extension (if any) in the form
 // "_yymmdd-hhmmss".
 base::FilePath GenerateTimestampedName(const base::FilePath& base_path,
                                        base::Time timestamp);
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 }  // namespace logging
 
 #endif  // CHROME_COMMON_LOGGING_CHROME_H_
diff --git a/chrome/common/media/component_widevine_cdm_hint_file_linux.h b/chrome/common/media/component_widevine_cdm_hint_file_linux.h
index 122ba44..b0568e8 100644
--- a/chrome/common/media/component_widevine_cdm_hint_file_linux.h
+++ b/chrome/common/media/component_widevine_cdm_hint_file_linux.h
@@ -7,13 +7,16 @@
 
 #include "base/compiler_specific.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "third_party/widevine/cdm/buildflags.h"
 
 #if !BUILDFLAG(ENABLE_WIDEVINE)
 #error "This file only applies when Widevine used."
 #endif
 
-#if !defined(OS_LINUX) || defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if !(defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
 #error "This file only applies to desktop Linux."
 #endif
 
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index d53a887..bcc047f6 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -7,6 +7,7 @@
 #include "base/stl_util.h"
 #include "build/branding_buildflags.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/pref_font_webkit_names.h"
 #include "extensions/buildflags/buildflags.h"
@@ -212,7 +213,7 @@
 const char kRlzPingDelaySeconds[] = "rlz_ping_delay";
 #endif  // BUILDFLAG(ENABLE_RLZ)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Locale preference of device' owner.  ChromeOS device appears in this locale
 // after startup/wakeup/signout.
 const char kOwnerLocale[] = "intl.owner_locale";
@@ -461,7 +462,7 @@
 // from the New Tab Page and app launcher.
 const char kHideWebStoreIcon[] = "hide_web_store_icon";
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // An integer preference to store the number of times the Chrome OS Account
 // Manager migration flow ran successfully.
 const char kAccountManagerNumTimesMigrationRanSuccessfully[] =
@@ -1060,7 +1061,7 @@
 const char kEduCoexistenceArcMigrationCompleted[] =
     "account_manager.edu_coexistence_arc_migration_completed";
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // A boolean pref set to true if a Home button to open the Home pages should be
 // visible on the toolbar.
@@ -1087,7 +1088,9 @@
 // only using an account that belongs to one of the domains from this pref.
 const char kAllowedDomainsForApps[] = "settings.allowed_domains_for_apps";
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 // Linux specific preference on whether we should match the system theme.
 const char kUsesSystemTheme[] = "extensions.theme.use_system";
 #endif
@@ -1204,7 +1207,7 @@
     "settings.a11y.enable_accessibility_image_labels_only_on_wifi";
 #endif
 
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 // A boolean pref which determines whether focus highlighting is enabled.
 const char kAccessibilityFocusHighlightEnabled[] =
     "settings.a11y.focus_highlight";
@@ -1244,7 +1247,9 @@
     "browser.show_update_promotion_info_bar";
 #endif
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 // Boolean that is false if we should show window manager decorations.  If
 // true, we draw a custom chrome frame (thicker title bar and blue border).
 const char kUseCustomChromeFrame[] = "browser.custom_chrome_frame";
@@ -1376,7 +1381,7 @@
 const char kPrintRasterizationMode[] = "printing.rasterization_mode";
 #endif
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID)
 // A pref that sets the default destination in Print Preview to always be the
 // OS default printer instead of the most recently used destination.
 const char kPrintPreviewUseSystemDefaultPrinter[] =
@@ -1390,7 +1395,7 @@
     "downgrade.snapshot_retention_limit";
 #endif  // !OS_CHROMEOS && !OS_ANDROID
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // List of print servers ids that are allowed in the user policy. List of
 // strings. Note that this used to be `kExternalPrintServersWhitelist`, hence
 // the difference between the variable name and the string value.
@@ -1469,7 +1474,7 @@
 // deleted.
 const char kDeletePrintJobHistoryAllowed[] =
     "printing.delete_print_job_history_allowed";
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // An integer pref specifying the fallback behavior for sites outside of content
 // packs. One of:
@@ -1777,7 +1782,7 @@
 const char kRestartLastSessionOnShutdown[] = "restart.last.session.on.shutdown";
 
 #if !defined(OS_ANDROID)
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 // Pref name for the policy controlling presentation of full-tab promotional
 // and/or educational content.
 const char kPromotionalTabsEnabled[] = "browser.promotional_tabs_enabled";
@@ -1787,7 +1792,7 @@
 // CommandLineFlagSecurityWarningsEnabled policy setting.
 const char kCommandLineFlagSecurityWarningsEnabled[] =
     "browser.command_line_flag_security_warnings_enabled";
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Boolean that specifies whether or not showing the unsupported OS warning is
 // suppressed. False by default. Controlled by the SuppressUnsupportedOSWarning
@@ -2053,7 +2058,7 @@
 const char kNtlmV2Enabled[] = "auth.ntlm_v2_enabled";
 #endif  // defined(OS_POSIX)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Boolean whether Kerberos functionality is enabled.
 const char kKerberosEnabled[] = "kerberos.enabled";
 #endif
@@ -2132,7 +2137,7 @@
 // is not allowed and API calls will fail with an error.
 const char kScreenCaptureAllowed[] = "hardware.screen_capture_enabled";
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // An integer pref that holds enum value of current demo mode configuration.
 // Values are defined by DemoSession::DemoModeConfig enum.
 const char kDemoModeConfig[] = "demo_mode.config";
@@ -2362,7 +2367,7 @@
 // set for child users only, and kept on the known user storage.
 const char kKnownUserParentAccessCodeConfig[] =
     "child_user.parent_access_code.config";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Whether there is a Flash version installed that supports clearing LSO data.
 const char kClearPluginLSODataEnabled[] = "browser.clear_lso_data_enabled";
@@ -2410,7 +2415,7 @@
 // Indicates that the user has requested that ARC APK Sideloading be enabled.
 const char kEnableAdbSideloadingRequested[] = "EnableAdbSideloadingRequested";
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // This setting controls initial device timezone that is used before user
 // session started. It is controlled by device owner.
 const char kSigninScreenTimezone[] = "settings.signin_screen_timezone";
@@ -2435,7 +2440,7 @@
 // SystemTimezoneAutomaticDetectionProto_AutomaticTimezoneDetectionType;
 const char kSystemTimezoneAutomaticDetectionPolicy[] =
     "settings.resolve_device_timezone_by_geolocation_policy";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // Pref name for the policy controlling whether to enable Media Router.
 const char kEnableMediaRouter[] = "media_router.enable_media_router";
@@ -2456,12 +2461,12 @@
     "browser.relaunch_notification_period";
 #endif  // !defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Pref name for the policy controlling the time period between the first user
 // notification about need to relaunch and the end of the
 // RelaunchNotificationPeriod. Values are in milliseconds.
 const char kRelaunchHeadsUpPeriod[] = "browser.relaunch_heads_up_period";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 // *************** SERVICE PREFS ***************
 // These are attached to the service process.
@@ -2579,7 +2584,7 @@
     "media_galleries.remembered_galleries";
 #endif  // !defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const char kPolicyPinnedLauncherApps[] = "policy_pinned_launcher_apps";
 // Keeps names of rolled default pin layouts for shelf in order not to apply
 // this twice. Names are separated by comma.
@@ -2587,7 +2592,7 @@
 // Same as kShelfDefaultPinLayoutRolls, but for tablet form factor devices.
 const char kShelfDefaultPinLayoutRollsForTabletFormFactor[] =
     "shelf_default_pin_layout_rolls_for_tablet_form_factor";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_WIN)
 // Counts how many more times the 'profile on a network share' warning should be
@@ -2603,7 +2608,7 @@
 const char kShortcutMigrationVersion[] = "browser.shortcut_migration_version";
 #endif  // defined(OS_WIN)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // The RLZ brand code, if enabled.
 const char kRLZBrand[] = "rlz.brand";
 // Whether RLZ pings are disabled.
@@ -2945,7 +2950,9 @@
 const char kBlockAutoplayEnabled[] = "media.block_autoplay";
 #endif  // !defined(OS_ANDROID)
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 // Boolean that indicates if native notifications are allowed to be used in
 // place of Chrome notifications.
 const char kAllowNativeNotifications[] = "native_notifications.allowed";
@@ -2975,7 +2982,7 @@
 // TODO(https://crbug.com/1003101): Remove this in Chrome 88.
 const char kAllowSyncXHRInPageDismissal[] = "allow_sync_xhr_in_page_dismissal";
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Enum that specifies client certificate management permissions for user. It
 // can have one of the following values.
 // 0: Users can manage all certificates.
@@ -3034,7 +3041,7 @@
     "known_interception_disclosure_infobar_last_shown";
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const char kRequiredClientCertificateForUser[] =
     "required_client_certificate_for_user";
 const char kRequiredClientCertificateForDevice[] =
@@ -3057,7 +3064,7 @@
 // TODO(enne): Remove this once AppCache has been removed.
 const char kAppCacheForceEnabled[] = "app_cache_force_enabled";
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Boolean pref indicating whether the notification informing the user that
 // adb sideloading had been disabled by their admin was shown.
 const char kAdbSideloadingDisallowedNotificationShown[] =
@@ -3086,14 +3093,14 @@
     "settings.a11y.caretbrowsing.show_dialog";
 #endif
 
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Boolean pref indicating whether the Lacros browser is allowed. This is set by
 // a policy, and the default value for managed users is false. Admins willing to
 // give rights to use Lacros can set the policy to true.
 const char kLacrosAllowed[] = "lacros_allowed";
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // String enum pref determining what should happen when a user who authenticates
 // via a security token is removing this token. "IGNORE" - nothing happens
 // (default). "LOGOUT" - The user is logged out. "LOCK" - The session is locked.
@@ -3115,6 +3122,6 @@
 // who was logged out, to be used as part of the notification message.
 const char kSecurityTokenSessionNotificationScheduledDomain[] =
     "security_token_session_notification_scheduled";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 }  // namespace prefs
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 85ffbcf..377e055 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -74,7 +74,7 @@
 // state and the user's profile.  The global property determines the locale of
 // the login screen, while the user's profile determines their personal locale
 // preference.
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kApplicationLocaleBackup[];
 extern const char kApplicationLocaleAccepted[];
 extern const char kOwnerLocale[];
@@ -181,7 +181,7 @@
 extern const char kAccessibilityImageLabelsEnabledAndroid[];
 extern const char kAccessibilityImageLabelsOnlyOnWifi[];
 #endif
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kAccessibilityFocusHighlightEnabled[];
 #endif
 extern const char kAccessibilityCaptionsTextSize[];
@@ -214,7 +214,7 @@
 extern const char kNetworkPredictionOptions[];
 extern const char kDefaultAppsInstallState[];
 extern const char kHideWebStoreIcon[];
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kAccountManagerNumTimesMigrationRanSuccessfully[];
 extern const char kAccountManagerNumTimesWelcomeScreenShown[];
 extern const char kTapToClickEnabled[];
@@ -350,14 +350,16 @@
 extern const char kUpdateRequiredWarningPeriod[];
 extern const char kSystemProxyUserTrafficHostAndPort[];
 extern const char kEduCoexistenceArcMigrationCompleted[];
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kShowHomeButton[];
 extern const char kSpeechRecognitionFilterProfanities[];
 extern const char kAllowDeletingBrowserHistory[];
 extern const char kForceGoogleSafeSearch[];
 extern const char kForceYouTubeRestrict[];
 extern const char kAllowedDomainsForApps[];
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 extern const char kUsesSystemTheme[];
 #endif
 extern const char kCurrentThemePackFilename[];
@@ -384,7 +386,9 @@
 #if defined(OS_MAC)
 extern const char kShowUpdatePromotionInfoBar[];
 #endif
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 extern const char kUseCustomChromeFrame[];
 #endif
 #if BUILDFLAG(ENABLE_PLUGINS)
@@ -440,12 +444,12 @@
 extern const char kPrintRasterizationMode[];
 #endif
 
-#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OS_ANDROID)
 extern const char kPrintPreviewUseSystemDefaultPrinter[];
 extern const char kUserDataSnapshotRetentionLimit[];
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kExternalPrintServersAllowlist[];
 extern const char kDeviceExternalPrintServersAllowlist[];
 extern const char kRecommendedPrinters[];
@@ -465,7 +469,7 @@
 extern const char kPrintJobHistoryExpirationPeriod[];
 extern const char kPrintingAPIExtensionsAllowlist[];
 extern const char kDeletePrintJobHistoryAllowed[];
-#endif  // OS_CHROMEOS
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 extern const char kDefaultSupervisedUserFilteringBehavior[];
 
@@ -523,9 +527,9 @@
 extern const char kProfilesNumCreated[];
 extern const char kGuestProfilesNumCreated[];
 extern const char kProfileInfoCache[];
-#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kLegacyProfileNamesMigrated[];
-#endif  // !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
+#endif  // !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kProfileCreatedByVersion[];
 extern const char kProfilesDeleted[];
 
@@ -591,7 +595,7 @@
 
 extern const char kRestartLastSessionOnShutdown[];
 #if !defined(OS_ANDROID)
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kPromotionalTabsEnabled[];
 extern const char kCommandLineFlagSecurityWarningsEnabled[];
 #endif
@@ -687,7 +691,7 @@
 extern const char kVideoCaptureAllowedUrls[];
 extern const char kScreenCaptureAllowed[];
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kDemoModeConfig[];
 extern const char kDemoModeCountry[];
 extern const char kDemoModeDefaultLocale[];
@@ -754,7 +758,7 @@
 extern const char kLastRsuDeviceIdUploaded[];
 extern const char kDeviceName[];
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 extern const char kClearPluginLSODataEnabled[];
 extern const char kPepperFlashSettingsEnabled[];
@@ -791,7 +795,7 @@
 extern const char kNtlmV2Enabled[];
 #endif  // defined(OS_POSIX)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kKerberosEnabled[];
 #endif
 
@@ -832,12 +836,12 @@
 extern const char kDebuggingFeaturesRequested[];
 extern const char kEnableAdbSideloadingRequested[];
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kSigninScreenTimezone[];
 extern const char kResolveDeviceTimezoneByGeolocation[];
 extern const char kResolveDeviceTimezoneByGeolocationMethod[];
 extern const char kSystemTimezoneAutomaticDetectionPolicy[];
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 extern const char kEnableMediaRouter[];
 #if !defined(OS_ANDROID)
@@ -849,9 +853,9 @@
 extern const char kRelaunchNotificationPeriod[];
 #endif  // !defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kRelaunchHeadsUpPeriod[];
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if !defined(OS_ANDROID)
 extern const char kAttemptedToEnableAutoupdate[];
@@ -860,11 +864,11 @@
 extern const char kMediaGalleriesRememberedGalleries[];
 #endif  // !defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kPolicyPinnedLauncherApps[];
 extern const char kShelfDefaultPinLayoutRolls[];
 extern const char kShelfDefaultPinLayoutRollsForTabletFormFactor[];
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_WIN)
 extern const char kNetworkProfileWarningsLeft[];
@@ -872,7 +876,7 @@
 extern const char kShortcutMigrationVersion[];
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kRLZBrand[];
 extern const char kRLZDisabled[];
 extern const char kAppListLocalState[];
@@ -1012,7 +1016,9 @@
 extern const char kBlockAutoplayEnabled[];
 #endif
 
-#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
+#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
 extern const char kAllowNativeNotifications[];
 #endif
 
@@ -1031,7 +1037,7 @@
 extern const char kUsageStatsEnabled[];
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kClientCertificateManagementAllowed[];
 extern const char kCACertificateManagementAllowed[];
 #endif
@@ -1058,7 +1064,7 @@
 extern const char kKnownInterceptionDisclosureInfobarLastShown[];
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kRequiredClientCertificateForUser[];
 extern const char kRequiredClientCertificateForDevice[];
 extern const char kCertificateProvisioningStateForUser[];
@@ -1070,7 +1076,7 @@
 
 extern const char kAppCacheForceEnabled[];
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kAdbSideloadingDisallowedNotificationShown[];
 extern const char kAdbSideloadingPowerwashPlannedNotificationShownTime[];
 extern const char kAdbSideloadingPowerwashOnNextRebootNotificationShown[];
@@ -1081,11 +1087,11 @@
 extern const char kShowCaretBrowsingDialog[];
 #endif
 
-#if BUILDFLAG(IS_ASH)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kLacrosAllowed[];
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kSecurityTokenSessionBehavior[];
 extern const char kSecurityTokenSessionNotificationSeconds[];
 extern const char kSecurityTokenSessionNotificationDisplayed[];
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc
index 3607f95..95a580d 100644
--- a/chrome/common/url_constants.cc
+++ b/chrome/common/url_constants.cc
@@ -7,6 +7,8 @@
 #include "build/branding_buildflags.h"
 #include "chrome/common/webui_url_constants.h"
 
+#include "build/chromeos_buildflags.h"
+
 namespace chrome {
 
 const char kAccessibilityLabelsLearnMoreURL[] =
@@ -44,7 +46,7 @@
     "https://www.google.com/chromebook/whatsnew/embedded/";
 
 const char kChromeHelpViaKeyboardURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     "chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html";
 #else
@@ -52,10 +54,10 @@
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #else
     "https://support.google.com/chrome/?p=help&ctx=keyboard";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 const char kChromeHelpViaMenuURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     "chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html";
 #else
@@ -63,18 +65,18 @@
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
 #else
     "https://support.google.com/chrome/?p=help&ctx=menu";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 const char kChromeHelpViaWebUIURL[] =
     "https://support.google.com/chrome/?p=help&ctx=settings";
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const char kChromeOsHelpViaWebUIURL[] =
 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
     "chrome-extension://honijodknafkokifofgiaalefdiedpko/main.html";
 #else
     "https://support.google.com/chromebook/?p=help&ctx=settings";
 #endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 const char kChromeNativeScheme[] = "chrome-native";
 
@@ -99,7 +101,7 @@
 const char kChromiumProjectURL[] = "https://www.chromium.org/";
 
 const char kCloudPrintCertificateErrorLearnMoreURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook?p=cloudprint_error_troubleshoot";
 #elif defined(OS_MAC)
     "https://support.google.com/cloudprint?p=cloudprint_error_offline_mac";
@@ -121,21 +123,21 @@
     "https://support.google.com/chrome/?p=chrome_update_sse3";
 
 const char kCrashReasonURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=e_awsnap";
 #else
     "https://support.google.com/chrome/?p=e_awsnap";
 #endif
 
 const char kCrashReasonFeedbackDisplayedURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=e_awsnap_rl";
 #else
     "https://support.google.com/chrome/?p=e_awsnap_rl";
 #endif
 
 const char kDoNotTrackLearnMoreURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=settings_do_not_track";
 #else
     "https://support.google.com/chrome/?p=settings_do_not_track";
@@ -174,7 +176,7 @@
     "www.chrome.com/manage";
 
 const char kManagedUiLearnMoreUrl[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=is_chrome_managed";
 #else
     "https://support.google.com/chrome/?p=is_chrome_managed";
@@ -187,21 +189,21 @@
     "https://myactivity.google.com/myactivity/?utm_source=chrome_cbd";
 
 const char kOmniboxLearnMoreURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=settings_omnibox";
 #else
     "https://support.google.com/chrome/?p=settings_omnibox";
 #endif
 
 const char kPageInfoHelpCenterURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=ui_security_indicator";
 #else
     "https://support.google.com/chrome/?p=ui_security_indicator";
 #endif
 
 const char kPasswordCheckLearnMoreURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/"
     "?p=settings_password#leak_detection_privacy";
 #else
@@ -213,7 +215,7 @@
     "https://support.google.com/chrome/answer/7570435";
 
 const char kPasswordManagerLearnMoreURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=settings_password";
 #else
     "https://support.google.com/chrome/?p=settings_password";
@@ -225,7 +227,7 @@
     "paymentMethods";
 
 const char kPaymentMethodsLearnMoreURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/answer/"
     "142893?visit_id=636857416902558798-696405304&p=settings_autofill&rd=1";
 #else
@@ -234,7 +236,7 @@
 #endif
 
 const char kPrivacyLearnMoreURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=settings_privacy";
 #else
     "https://support.google.com/chrome/?p=settings_privacy";
@@ -262,7 +264,7 @@
     "https://support.google.com/chrome?p=syncgoogleservices";
 
 const char kSyncEncryptionHelpURL[] =
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=settings_encryption";
 #else
     "https://support.google.com/chrome/?p=settings_encryption";
@@ -290,17 +292,17 @@
 const char kAndroidAppScheme[] = "android-app";
 #endif
 
-#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_ANDROID)
 const char kEnhancedPlaybackNotificationLearnMoreURL[] =
 #endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     "https://support.google.com/chromebook/?p=enhanced_playback";
 #elif defined(OS_ANDROID)
 // Keep in sync with chrome/android/java/strings/android_chrome_strings.grd
     "https://support.google.com/chrome/?p=mobile_protected_content";
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 const char kAccountManagerLearnMoreURL[] =
     "https://support.google.com/chromebook/?p=google_accounts";
 
@@ -422,7 +424,7 @@
 
 const char kWifiSyncLearnMoreURL[] =
     "https://support.google.com/chromebook/?p=wifisync";
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_MAC)
 const char kChromeEnterpriseSignInLearnMoreURL[] =
diff --git a/chrome/common/url_constants.h b/chrome/common/url_constants.h
index a84adcb..ec2c7b60 100644
--- a/chrome/common/url_constants.h
+++ b/chrome/common/url_constants.h
@@ -19,6 +19,7 @@
 #include <stddef.h>
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/buildflags.h"
 #include "chrome/common/webui_url_constants.h"
 #include "content/public/common/url_constants.h"
@@ -66,7 +67,7 @@
 extern const char kChromeHelpViaKeyboardURL[];
 extern const char kChromeHelpViaMenuURL[];
 extern const char kChromeHelpViaWebUIURL[];
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 extern const char kChromeOsHelpViaWebUIURL[];
 #endif
 
@@ -254,12 +255,12 @@
 extern const char kAndroidAppScheme[];
 #endif
 
-#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
+#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH)
 // "Learn more" URL for the enhanced playback notification dialog.
 extern const char kEnhancedPlaybackNotificationLearnMoreURL[];
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Help center URL for Chrome OS Account Manager.
 extern const char kAccountManagerLearnMoreURL[];
 
@@ -386,7 +387,7 @@
 
 // The URL for the help center article about Wi-Fi sync.
 extern const char kWifiSyncLearnMoreURL[];
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_MAC)
 // "Learn more" URL for the enterprise sign-in confirmation dialog.
diff --git a/chrome/common/webui_url_constants.cc b/chrome/common/webui_url_constants.cc
index 7ca2aee..12dfe7b 100644
--- a/chrome/common/webui_url_constants.cc
+++ b/chrome/common/webui_url_constants.cc
@@ -6,6 +6,7 @@
 
 #include "base/stl_util.h"
 #include "base/strings/string_piece.h"
+#include "build/chromeos_buildflags.h"
 #include "components/nacl/common/buildflags.h"
 #include "components/safe_browsing/core/web_ui/constants.h"
 #include "extensions/buildflags/buildflags.h"
@@ -207,7 +208,7 @@
 const char kChromeUIReadLaterURL[] = "chrome://read-later/";
 #endif
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // Keep alphabetized.
 const char kChromeUIAccountManagerErrorHost[] = "account-manager-error";
 const char kChromeUIAccountManagerErrorURL[] = "chrome://account-manager-error";
@@ -335,7 +336,7 @@
   }
   return false;
 }
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
 const char kChromeUIWebUIJsErrorHost[] = "webuijserror";
@@ -364,8 +365,10 @@
 const char kChromeUISandboxHost[] = "sandbox";
 #endif
 
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
 #if defined(OS_WIN) || defined(OS_MAC) || \
-    (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+    (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
 const char kChromeUIBrowserSwitchHost[] = "browser-switch";
 const char kChromeUIBrowserSwitchURL[] = "chrome://browser-switch/";
 const char kChromeUIProfileCustomizationHost[] = "profile-customization";
@@ -456,7 +459,7 @@
     kChromeUIComponentsHost,
     kChromeUICrashesHost,
     kChromeUICreditsHost,
-#if defined(OS_CHROMEOS) && !defined(OFFICIAL_BUILD)
+#if BUILDFLAG(IS_CHROMEOS_ASH) && !defined(OFFICIAL_BUILD)
     kChromeUIDeviceEmulatorHost,
 #endif
     kChromeUIDeviceLogHost,
@@ -514,7 +517,7 @@
     content::kChromeUIUkmHost,
     content::kChromeUIWebRTCInternalsHost,
 #if !defined(OS_ANDROID)
-#if !defined(OS_CHROMEOS)
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
     kChromeUIAppLauncherPageHost,
 #endif
     kChromeUIBookmarksHost,
@@ -531,7 +534,7 @@
     kChromeUISnippetsInternalsHost,
     kChromeUIWebApksHost,
 #endif
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
     kChromeUICertificateManagerHost,
     kChromeUICrostiniCreditsHost,
     kChromeUICryptohomeHost,
diff --git a/chrome/common/webui_url_constants.h b/chrome/common/webui_url_constants.h
index 47cfcf1..8dfef70b 100644
--- a/chrome/common/webui_url_constants.h
+++ b/chrome/common/webui_url_constants.h
@@ -13,6 +13,7 @@
 
 #include "base/strings/string_piece_forward.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/common/buildflags.h"
 #include "content/public/common/url_constants.h"
 #include "media/media_buildflags.h"
@@ -203,7 +204,7 @@
 extern const char kChromeUIReadLaterURL[];
 #endif  // defined(OS_ANDROID)
 
-#if defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 // NOTE: If you add a URL/host please check if it should be added to
 // IsSystemWebUIHost().
 extern const char kChromeUIAccountManagerErrorHost[];
@@ -289,7 +290,7 @@
 // systems would be considered part of the OS or window manager.
 bool IsSystemWebUIHost(base::StringPiece host);
 
-#endif  // defined(OS_CHROMEOS)
+#endif  // BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
 extern const char kChromeUIWebUIJsErrorHost[];
@@ -307,7 +308,7 @@
 #if !defined(OS_ANDROID)
 extern const char kChromeUINearbyShareHost[];
 extern const char kChromeUINearbyShareURL[];
-#endif  // !defined(OS_CHROMEOS)
+#endif  // !BUILDFLAG(IS_CHROMEOS_ASH)
 
 #if defined(OS_POSIX) && !defined(OS_MAC) && !defined(OS_ANDROID)
 extern const char kChromeUILinuxProxyConfigHost[];
@@ -318,8 +319,10 @@
 extern const char kChromeUISandboxHost[];
 #endif
 
+// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
+// of lacros-chrome is complete.
 #if defined(OS_WIN) || defined(OS_MAC) || \
-    (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+    (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
 extern const char kChromeUIBrowserSwitchHost[];
 extern const char kChromeUIBrowserSwitchURL[];
 extern const char kChromeUIProfileCustomizationHost[];
diff --git a/chrome/credential_provider/gaiacp/associated_user_validator.cc b/chrome/credential_provider/gaiacp/associated_user_validator.cc
index ddeb49f..ad851d0 100644
--- a/chrome/credential_provider/gaiacp/associated_user_validator.cc
+++ b/chrome/credential_provider/gaiacp/associated_user_validator.cc
@@ -547,6 +547,15 @@
     return AssociatedUserValidator::EnforceAuthReason::ONLINE_LOGIN_STALE;
   }
 
+  // Force user to login when policies are missing or stale. This check should
+  // be done before MDM enrollment to have the correct MDM enrollment policy for
+  // user.
+  if (UserPoliciesManager::Get()->CloudPoliciesEnabled() &&
+      UserPoliciesManager::Get()->IsUserPolicyStaleOrMissing(sid)) {
+    return AssociatedUserValidator::EnforceAuthReason::
+        MISSING_OR_STALE_USER_POLICIES;
+  }
+
   // Force a reauth only for this user if mdm enrollment is needed, so that they
   // enroll.
   if (NeedsToEnrollWithMdm(sid))
@@ -572,13 +581,6 @@
         UPLOAD_DEVICE_DETAILS_FAILED;
   }
 
-  // Force user to login when policies are missing or stale.
-  if (UserPoliciesManager::Get()->CloudPoliciesEnabled() &&
-      UserPoliciesManager::Get()->IsUserPolicyStaleOrMissing(sid)) {
-    return AssociatedUserValidator::EnforceAuthReason::
-        MISSING_OR_STALE_USER_POLICIES;
-  }
-
   return AssociatedUserValidator::EnforceAuthReason::NOT_ENFORCED;
 }
 
diff --git a/chrome/credential_provider/gaiacp/associated_user_validator_unittests.cc b/chrome/credential_provider/gaiacp/associated_user_validator_unittests.cc
index cf0b433..42d8eb65 100644
--- a/chrome/credential_provider/gaiacp/associated_user_validator_unittests.cc
+++ b/chrome/credential_provider/gaiacp/associated_user_validator_unittests.cc
@@ -672,10 +672,12 @@
 // 4. int : 0 - Cloud policies disabled.
 //          1 - Cloud policies enabled but user policies are missing.
 //          2 - Cloud policies enabled and user policies are up to date.
+// 5. bool : Whether user is enrolled with MDM.
 class AssociatedUserValidatorCloudPolicyLoginEnforcedTest
     : public AssociatedUserValidatorTest,
       public ::testing::WithParamInterface<
-          std::tuple<CREDENTIAL_PROVIDER_USAGE_SCENARIO, bool, int, int>> {
+          std::
+              tuple<CREDENTIAL_PROVIDER_USAGE_SCENARIO, bool, int, int, bool>> {
  private:
   FakeScopedLsaPolicyFactory fake_scoped_lsa_policy_factory_;
 };
@@ -686,8 +688,9 @@
   const bool is_user_associated = std::get<1>(GetParam());
   const int upload_device_details_state = std::get<2>(GetParam());
   const int cloud_policies_state = std::get<3>(GetParam());
+  const bool mdm_enrolled = std::get<4>(GetParam());
 
-  GoogleMdmEnrolledStatusForTesting forced_status(true);
+  GoogleMdmEnrolledStatusForTesting forced_status(mdm_enrolled);
   FakeUserPoliciesManager fake_user_policies_manager(cloud_policies_state != 0);
   FakeTokenGenerator fake_token_generator;
 
@@ -766,8 +769,9 @@
     }
   }
 
-  bool is_get_auth_enforced = is_user_associated && (!uploaded_device_details ||
-                                                     reauth_for_missing_policy);
+  bool is_get_auth_enforced =
+      is_user_associated &&
+      (!uploaded_device_details || reauth_for_missing_policy || !mdm_enrolled);
 
   bool should_user_be_blocked =
       should_user_locking_be_enabled && is_get_auth_enforced;
@@ -776,6 +780,12 @@
             validator.IsUserAccessBlockedForTesting(OLE2W(sid)));  // IN-TEST
   EXPECT_EQ(is_get_auth_enforced, validator.IsAuthEnforcedForUser(OLE2W(sid)));
 
+  if (is_get_auth_enforced && reauth_for_missing_policy) {
+    ASSERT_EQ(AssociatedUserValidator::EnforceAuthReason::
+                  MISSING_OR_STALE_USER_POLICIES,
+              validator.GetAuthEnforceReason((BSTR)sid));
+  }
+
   // Unlock the user.
   validator.AllowSigninForUsersWithInvalidTokenHandles();
 
@@ -795,7 +805,8 @@
                                          CPUS_CREDUI),
                        ::testing::Bool(),
                        ::testing::Values(0, 1, 2),
-                       ::testing::Values(0, 1, 2)));
+                       ::testing::Values(0, 1, 2),
+                       ::testing::Bool()));
 
 // Tests auth enforcement when multiple number of device details uploads fail
 // consecutively.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 91c02e1..be5fd37 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2746,6 +2746,7 @@
         "../browser/resources/chromeos/zip_archiver/test/zip_archiver_jstest.cc",
         "../browser/signin/chromeos_mirror_account_consistency_browsertest.cc",
         "../browser/ui/app_list/app_list_client_impl_browsertest.cc",
+        "../browser/ui/app_list/app_service/app_service_app_item_browsertest.cc",
         "../browser/ui/app_list/arc/arc_usb_host_permission_browsertest.cc",
         "../browser/ui/app_list/chrome_app_list_model_updater_browsertest.cc",
         "../browser/ui/app_list/search/app_list_search_browsertest.cc",
@@ -6526,6 +6527,7 @@
     deps = [
       ":test_support",
       ":test_support_ui",
+      "//build:chromeos_buildflags",
       "//chrome:packed_resources",
       "//chrome:resources",
       "//chrome:strings",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
index be13b4b..ec2abf63 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeActivityTestRule.java
@@ -5,30 +5,31 @@
 package org.chromium.chrome.test;
 
 import android.app.Activity;
-import android.app.Instrumentation;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.internal.runner.listener.InstrumentationResultPrinter;
-import android.support.test.rule.ActivityTestRule;
 import android.view.Menu;
 
+import androidx.annotation.NonNull;
+
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.runner.Description;
 import org.junit.runners.model.Statement;
 
-import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
-import org.chromium.base.ApplicationStatus.ActivityStateListener;
 import org.chromium.base.CommandLine;
-import org.chromium.base.Log;
+import org.chromium.base.ThreadUtils;
+import org.chromium.base.test.BaseActivityTestRule;
 import org.chromium.base.test.util.CallbackHelper;
 import org.chromium.base.test.util.Criteria;
 import org.chromium.base.test.util.CriteriaHelper;
+import org.chromium.base.test.util.ScalableTimeout;
+import org.chromium.chrome.browser.DeferredStartupHandler;
 import org.chromium.chrome.browser.app.ChromeActivity;
 import org.chromium.chrome.browser.document.ChromeLauncherActivity;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
@@ -41,7 +42,9 @@
 import org.chromium.chrome.browser.ui.appmenu.AppMenuTestSupport;
 import org.chromium.chrome.test.util.ChromeApplicationTestUtils;
 import org.chromium.chrome.test.util.ChromeTabUtils;
+import org.chromium.chrome.test.util.NewTabPageTestUtils;
 import org.chromium.chrome.test.util.browser.Features;
+import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.components.infobars.InfoBar;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
@@ -59,14 +62,13 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
 
 /**
  * Custom  {@link ActivityTestRule} for test using  {@link ChromeActivity}.
  *
  * @param <T> The {@link Activity} class under test.
  */
-public class ChromeActivityTestRule<T extends ChromeActivity> extends ActivityTestRule<T> {
+public class ChromeActivityTestRule<T extends ChromeActivity> extends BaseActivityTestRule<T> {
     private static final String TAG = "ChromeATR";
 
     // The number of ms to wait for the rendering activity to be started.
@@ -75,20 +77,13 @@
     private static final long OMNIBOX_FIND_SUGGESTION_TIMEOUT_MS = 10 * 1000;
 
     private Thread.UncaughtExceptionHandler mDefaultUncaughtExceptionHandler;
-    private Class<T> mChromeActivityClass;
-    private T mSetActivity;
     private String mCurrentTestName;
 
     @Rule
     private EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
 
     protected ChromeActivityTestRule(Class<T> activityClass) {
-        this(activityClass, false);
-    }
-
-    protected ChromeActivityTestRule(Class<T> activityClass, boolean initialTouchMode) {
-        super(activityClass, initialTouchMode, false);
-        mChromeActivityClass = activityClass;
+        super(activityClass);
     }
 
     @Override
@@ -135,13 +130,11 @@
         return ACTIVITY_START_TIMEOUT_MS;
     }
 
-    // TODO(yolandyan): remove this once startActivityCompletely is refactored out of
-    // ChromeActivityTestRule
+    // This has to be here or getActivity will return a T that extends Activity, not a T that
+    // extends ChromeActivity.
     @Override
+    @SuppressWarnings("RedundantOverride")
     public T getActivity() {
-        if (mSetActivity != null) {
-            return mSetActivity;
-        }
         return super.getActivity();
     }
 
@@ -152,6 +145,14 @@
     }
 
     /**
+     * TODO(https://crbug.com/1146574): This only exists here because legacy ActivityTestRule
+     * inherited from UiThreadTestRule. This function should be removed.
+     */
+    public void runOnUiThread(Runnable r) {
+        ThreadUtils.runOnUiThreadBlocking(r);
+    }
+
+    /**
      * @return The {@link AppMenuCoordinator} for the activity.
      */
     public AppMenuCoordinator getAppMenuCoordinator() {
@@ -196,49 +197,37 @@
     }
 
     /**
-     * Invokes {@link Instrumentation#startActivitySync(Intent)} and sets the
-     * test case's activity to the result. See the documentation for
-     * {@link Instrumentation#startActivitySync(Intent)} on the timing of the
-     * return, but generally speaking the activity's "onCreate" has completed
-     * and the activity's main looper has become idle.
-     *
-     * TODO(yolandyan): very similar to ActivityTestRule#launchActivity(Intent),
-     * yet small differences remains (e.g. launchActivity() uses FLAG_ACTIVITY_NEW_TASK while
-     * startActivityCompletely doesn't), need to refactor and use only launchActivity
-     * after the JUnit4 migration
+     * Similar to #launchActivity(Intent), but waits for the Activity tab to be initialized.
      */
     public void startActivityCompletely(Intent intent) {
-        Features.ensureCommandLineIsUpToDate();
+        DeferredStartupHandler.setExpectingActivityStartupForTesting();
+        launchActivity(intent);
+        waitForActivityNativeInitializationComplete();
 
-        final CallbackHelper activityCallback = new CallbackHelper();
-        final AtomicReference<T> activityRef = new AtomicReference<>();
-        ActivityStateListener stateListener = new ActivityStateListener() {
-            @SuppressWarnings("unchecked")
-            @Override
-            public void onActivityStateChange(Activity activity, int newState) {
-                if (newState == ActivityState.RESUMED) {
-                    if (!mChromeActivityClass.isAssignableFrom(activity.getClass())) return;
+        CriteriaHelper.pollUiThread(
+                () -> getActivity().getActivityTab() != null, "Tab never selected/initialized.");
+        Tab tab = getActivity().getActivityTab();
 
-                    activityRef.set((T) activity);
-                    activityCallback.notifyCalled();
-                    ApplicationStatus.unregisterActivityStateListener(this);
-                }
-            }
-        };
-        ApplicationStatus.registerStateListenerForAllActivities(stateListener);
+        ChromeTabUtils.waitForTabPageLoaded(tab, (String) null);
 
-        try {
-            InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
-            activityCallback.waitForCallback("Activity did not start as expected", 0);
-            T activity = activityRef.get();
-            Assert.assertNotNull("Activity reference is null.", activity);
-            setActivity(activity);
-            Log.d(TAG, "startActivityCompletely <<");
-        } catch (TimeoutException e) {
-            throw new RuntimeException(e);
-        } finally {
-            ApplicationStatus.unregisterActivityStateListener(stateListener);
+        if (tab != null && UrlUtilities.isNTPUrl(ChromeTabUtils.getUrlStringOnUiThread(tab))
+                && !getActivity().isInOverviewMode()) {
+            NewTabPageTestUtils.waitForNtpLoaded(tab);
         }
+
+        Assert.assertTrue("Deferred startup never completed. Did you try to start an Activity "
+                        + "that was already started?",
+                DeferredStartupHandler.waitForDeferredStartupCompleteForTesting(
+                        ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL)));
+
+        Assert.assertNotNull(tab);
+        Assert.assertNotNull(tab.getView());
+    }
+
+    @Override
+    public void launchActivity(@NonNull Intent startIntent) {
+        Features.ensureCommandLineIsUpToDate();
+        super.launchActivity(startIntent);
     }
 
     /**
@@ -472,10 +461,6 @@
         return getActivity().getWindowAndroid().getKeyboardDelegate();
     }
 
-    public void setActivity(T chromeActivity) {
-        mSetActivity = chromeActivity;
-    }
-
     /**
      * Waits for an Activity of the given class to be started.
      * @return The Activity.
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java
index cc708d7..65e683d2 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/ChromeTabbedActivityTestRule.java
@@ -20,11 +20,8 @@
 import org.chromium.base.Log;
 import org.chromium.base.test.util.ApplicationTestUtils;
 import org.chromium.base.test.util.CallbackHelper;
-import org.chromium.base.test.util.CriteriaHelper;
-import org.chromium.base.test.util.ScalableTimeout;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeTabbedActivity;
-import org.chromium.chrome.browser.DeferredStartupHandler;
 import org.chromium.chrome.browser.omnibox.UrlBar;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabCreationState;
@@ -36,7 +33,6 @@
 import org.chromium.chrome.test.util.MenuUtils;
 import org.chromium.chrome.test.util.NewTabPageTestUtils;
 import org.chromium.chrome.test.util.WaitForFocusHelper;
-import org.chromium.components.embedder_support.util.UrlUtilities;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
 import java.util.concurrent.TimeoutException;
@@ -113,31 +109,7 @@
      */
     public void startMainActivityFromIntent(Intent intent, String url) {
         prepareUrlIntent(intent, url);
-
-        DeferredStartupHandler.setExpectingActivityStartupForTesting();
         startActivityCompletely(intent);
-        waitForActivityNativeInitializationComplete();
-
-        CriteriaHelper.pollUiThread(
-                () -> getActivity().getActivityTab() != null, "Tab never selected/initialized.");
-        Tab tab = getActivity().getActivityTab();
-
-        ChromeTabUtils.waitForTabPageLoaded(tab, (String) null);
-
-        if (tab != null && UrlUtilities.isNTPUrl(ChromeTabUtils.getUrlStringOnUiThread(tab))
-                && !getActivity().isInOverviewMode()) {
-            NewTabPageTestUtils.waitForNtpLoaded(tab);
-        }
-
-        Assert.assertTrue("Deferred startup never completed. Did you try to start an Activity "
-                        + "that was already started?",
-                DeferredStartupHandler.waitForDeferredStartupCompleteForTesting(
-                        ScalableTimeout.scaleTimeout(CriteriaHelper.DEFAULT_MAX_TIME_TO_POLL)));
-
-        Assert.assertNotNull(tab);
-        Assert.assertNotNull(tab.getView());
-
-        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     }
 
     /**
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java
index e401694..dba985d0 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/batch/BlankCTATabInitialStateRule.java
@@ -39,6 +39,7 @@
         super();
         mActivityTestRule = activityTestRule;
         mClearAllTabState = clearAllTabState;
+        mActivityTestRule.setFinishActivity(false);
     }
 
     @Override
diff --git a/chrome/test/base/browser_with_test_window_test.cc b/chrome/test/base/browser_with_test_window_test.cc
index a9e02e51..921b072 100644
--- a/chrome/test/base/browser_with_test_window_test.cc
+++ b/chrome/test/base/browser_with_test_window_test.cc
@@ -47,6 +47,10 @@
   ash_test_helper_.SetUp();
 #endif
 
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+  tablet_state_ = std::make_unique<chromeos::TabletState>();
+#endif
+
   // This must be created after |ash_test_helper_| is set up so that it doesn't
   // create a DeviceDataManager.
   rvh_test_enabler_ = std::make_unique<content::RenderViewHostTestEnabler>();
@@ -95,6 +99,10 @@
 
   profile_manager_.reset();
 
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+  tablet_state_.reset();
+#endif
+
 #if defined(OS_CHROMEOS)
   // If initialized, the KioskAppManager will register an observer to
   // CrosSettings and will need to be destroyed before it. Having it destroyed
diff --git a/chrome/test/base/browser_with_test_window_test.h b/chrome/test/base/browser_with_test_window_test.h
index f8050c2..23638d3d 100644
--- a/chrome/test/base/browser_with_test_window_test.h
+++ b/chrome/test/base/browser_with_test_window_test.h
@@ -9,6 +9,7 @@
 
 #include "base/compiler_specific.h"
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/test/base/test_browser_window.h"
 #include "chrome/test/base/testing_profile.h"
@@ -31,6 +32,10 @@
 #endif
 #endif
 
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chromeos/ui/base/tablet_state.h"
+#endif
+
 #if defined(OS_WIN)
 #include "ui/base/win/scoped_ole_initializer.h"
 #endif
@@ -233,6 +238,10 @@
           std::make_unique<ChromeTestViewsDelegate<>>());
 #endif
 
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+  std::unique_ptr<chromeos::TabletState> tablet_state_;
+#endif
+
   // The existence of this object enables tests via RenderViewHostTester.
   std::unique_ptr<content::RenderViewHostTestEnabler> rvh_test_enabler_;
 
diff --git a/chrome/test/data/extensions/signin_screen_managed_storage/extension.crx b/chrome/test/data/extensions/signin_screen_managed_storage/extension.crx
new file mode 100644
index 0000000..aa027c9
--- /dev/null
+++ b/chrome/test/data/extensions/signin_screen_managed_storage/extension.crx
Binary files differ
diff --git a/chrome/test/data/webui/chromeos/diagnostics/BUILD.gn b/chrome/test/data/webui/chromeos/diagnostics/BUILD.gn
index 991573f..f2b4819a 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/BUILD.gn
+++ b/chrome/test/data/webui/chromeos/diagnostics/BUILD.gn
@@ -42,6 +42,7 @@
     "//chromeos/components/diagnostics_ui/resources:battery_status_card",
     "//chromeos/components/diagnostics_ui/resources:diagnostics_types",
     "//chromeos/components/diagnostics_ui/resources:fake_data",
+    "//ui/webui/resources/js:load_time_data.m",
   ]
   externs_list = [ "$externs_path/mocha-2.5.js" ]
 }
@@ -53,6 +54,7 @@
     "//chromeos/components/diagnostics_ui/resources:cpu_card",
     "//chromeos/components/diagnostics_ui/resources:diagnostics_types",
     "//chromeos/components/diagnostics_ui/resources:routine_section",
+    "//ui/webui/resources/js:load_time_data.m",
   ]
   externs_list = [ "$externs_path/mocha-2.5.js" ]
 }
diff --git a/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js b/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js
index 8bbc135..70bf8d7 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/battery_status_card_test.js
@@ -9,6 +9,7 @@
 import {FakeSystemDataProvider} from 'chrome://diagnostics/fake_system_data_provider.js';
 import {getSystemDataProvider, setSystemDataProviderForTesting} from 'chrome://diagnostics/mojo_interface_provider.js';
 import {mojoString16ToString} from 'chrome://diagnostics/mojo_utils.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 
 import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
 import {flushTasks, isChildVisible} from '../../test_util.m.js';
@@ -102,14 +103,22 @@
           dx_utils.assertTextContains(
               dataPoints[0].value,
               `${fakeBatteryHealth[0].batteryWearPercentage}`);
+          dx_utils.assertTextContains(
+              dataPoints[0].tooltipText,
+              loadTimeData.getString('batteryHealthTooltipText'));
           assertEquals(fakeBatteryHealth[0].cycleCount, dataPoints[1].value);
           dx_utils.assertTextContains(
+              dataPoints[1].tooltipText,
+              loadTimeData.getString('cycleCountTooltipText'));
+          dx_utils.assertTextContains(
               dataPoints[2].value,
               `${fakeBatteryChargeStatus[0].currentNowMilliamps}`);
+          dx_utils.assertTextContains(
+              dataPoints[2].tooltipText,
+              loadTimeData.getString('currentNowTooltipText'));
           dx_utils.assertElementContainsText(
               batteryStatusElement.$$('#batteryStatusChipInfo'),
               `${fakeBatteryHealth[0].chargeFullDesignMilliampHours}`);
-
           const barChart =
               dx_utils.getPercentBarChartElement(batteryStatusElement);
           assertEquals(
diff --git a/chrome/test/data/webui/chromeos/diagnostics/cpu_card_test.js b/chrome/test/data/webui/chromeos/diagnostics/cpu_card_test.js
index 32b5676..92dcfbd 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/cpu_card_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/cpu_card_test.js
@@ -8,6 +8,7 @@
 import {fakeCpuUsage, fakeSystemInfo} from 'chrome://diagnostics/fake_data.js';
 import {FakeSystemDataProvider} from 'chrome://diagnostics/fake_system_data_provider.js';
 import {getSystemDataProvider, setSystemDataProviderForTesting} from 'chrome://diagnostics/mojo_interface_provider.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
 
 import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
 import {flushTasks, isChildVisible} from '../../test_util.m.js';
@@ -98,6 +99,9 @@
               fakeCpuUsage[0].percentUsageUser +
               fakeCpuUsage[0].percentUsageSystem}`);
       dx_utils.assertTextContains(
+          dataPoints[0].tooltipText,
+          loadTimeData.getStringF('cpuUsageTooltipText', 4));
+      dx_utils.assertTextContains(
           dataPoints[1].value, `${fakeCpuUsage[0].averageCpuTempCelsius}`);
       // TODO(michaelcheco): Replace with value for CPU speed.
       assertEquals('', dataPoints[2].value);
diff --git a/chrome/test/data/webui/chromeos/diagnostics/data_point_test.js b/chrome/test/data/webui/chromeos/diagnostics/data_point_test.js
index aee4c86..1d7a3bebb 100644
--- a/chrome/test/data/webui/chromeos/diagnostics/data_point_test.js
+++ b/chrome/test/data/webui/chromeos/diagnostics/data_point_test.js
@@ -3,9 +3,10 @@
 // found in the LICENSE file.
 
 import 'chrome://diagnostics/data_point.js';
-
 import {assertEquals, assertFalse, assertTrue} from '../../chai_assert.js';
-import {flushTasks} from '../../test_util.m.js';
+import {flushTasks, isVisible} from '../../test_util.m.js';
+
+import * as dx_utils from './diagnostics_test_utils.js';
 
 export function dataPointTestSuite() {
   /** @type {?DataPointElement} */
@@ -25,8 +26,9 @@
   /**
    * @param {string} header
    * @param {string} value
+   * @param {string=} tooltipText
    */
-  function initializeDataPoint(header, value) {
+  function initializeDataPoint(header, value, tooltipText = '') {
     assertFalse(!!dataPointElement);
 
     // Add the data point to the DOM.
@@ -35,6 +37,7 @@
     assertTrue(!!dataPointElement);
     dataPointElement.header = header;
     dataPointElement.value = value;
+    dataPointElement.tooltipText = tooltipText;
     document.body.appendChild(dataPointElement);
 
     return flushTasks();
@@ -43,9 +46,25 @@
   test('InitializeDataPoint', () => {
     const header = 'Test header';
     const value = 'Test value';
+    const tooltipText = 'Test tooltip';
+    return initializeDataPoint(header, value, tooltipText).then(() => {
+      dx_utils.assertElementContainsText(
+          dataPointElement.$$('.header > span'), header);
+      dx_utils.assertElementContainsText(dataPointElement.$$('.value'), value);
+      assertTrue(isVisible(
+          /**@type {!HTMLElement} */ (dataPointElement.$$('#infoIcon'))));
+      dx_utils.assertElementContainsText(
+          dataPointElement.$$('paper-tooltip'), tooltipText);
+    });
+  });
+
+  test('InitializeDataPointWithoutTooltip', () => {
+    const header = 'Test header';
+    const value = 'Test value';
     return initializeDataPoint(header, value).then(() => {
-      assertEquals(header, dataPointElement.$$('.header').textContent.trim());
-      assertEquals(value, dataPointElement.$$('.value').textContent.trim());
+      // Icon should be hidden when tooltip text is not provided.
+      assertFalse(isVisible(
+          /**@type {!HTMLElement} */ (dataPointElement.$$('#infoIcon'))));
     });
   });
 }
diff --git a/chrome/test/data/webui/new_tab_page/realbox_test.js b/chrome/test/data/webui/new_tab_page/realbox_test.js
index 56966a9..c74d972f 100644
--- a/chrome/test/data/webui/new_tab_page/realbox_test.js
+++ b/chrome/test/data/webui/new_tab_page/realbox_test.js
@@ -901,6 +901,8 @@
 
         // Matches are hidden.
         assertFalse(areMatchesShowing());
+        // Force a synchronous render.
+        realbox.$.matches.$.groups.render();
         // First match is still selected.
         matchEls =
             realbox.$.matches.shadowRoot.querySelectorAll('ntp-realbox-match');
@@ -1015,11 +1017,12 @@
 
         // Matches are hidden.
         assertFalse(areMatchesShowing());
-        // First match is no longer selected (zero-prefix case).
+        // Force a synchronous render.
+        realbox.$.matches.$.groups.render();
+        // Matches are cleared.
         matchEls =
             realbox.$.matches.shadowRoot.querySelectorAll('ntp-realbox-match');
-        assertEquals(2, matchEls.length);
-        assertFalse(matchEls[0].classList.contains(CLASSES.SELECTED));
+        assertEquals(0, matchEls.length);
         // Input is cleared (zero-prefix case).
         assertEquals('', realbox.$.input.value);
         // Icon is restored (zero-prefix case).
@@ -1579,13 +1582,16 @@
     realbox.$.input.dispatchEvent(escapeEvent);
     assertTrue(escapeEvent.defaultPrevented);
 
-    // Matches are hidden and input gets cleared.
+    // Matches are hidden.
     assertFalse(areMatchesShowing());
-    assertEquals('', realbox.$.input.value);
-    realbox.$.matches.$.selector.forceSynchronousItemUpdate();
+    // Force a synchronous render.
+    realbox.$.matches.$.groups.render();
+    // Matches are cleared.
     matchEls =
         realbox.$.matches.shadowRoot.querySelectorAll('ntp-realbox-match');
-    assertEquals(2, matchEls.length);
+    assertEquals(0, matchEls.length);
+    // Input is cleared.
+    assertEquals('', realbox.$.input.value);
   });
 
   test('arrow up/down moves selection / focus', async () => {
diff --git a/chromeos/assistant/ambient.gni b/chromeos/assistant/ambient.gni
index ddd43f35..17ca5ef 100644
--- a/chromeos/assistant/ambient.gni
+++ b/chromeos/assistant/ambient.gni
@@ -1,7 +1,8 @@
 import("//build/config/chrome_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
 
 declare_args() {
   # Enable ambient mode backend controller implementation based on
   # is_chrome_branded.
-  enable_cros_ambient_mode_backend = is_chromeos && is_chrome_branded
+  enable_cros_ambient_mode_backend = is_chromeos_ash && is_chrome_branded
 }
diff --git a/chromeos/assistant/assistant.gni b/chromeos/assistant/assistant.gni
index 231b5b2..c28a144 100644
--- a/chromeos/assistant/assistant.gni
+++ b/chromeos/assistant/assistant.gni
@@ -1,8 +1,9 @@
 import("//build/config/chrome_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
 
 declare_args() {
   # Enable assistant implementation based on libassistant.
-  enable_cros_libassistant = is_chromeos && is_chrome_branded
+  enable_cros_libassistant = is_chromeos_ash && is_chrome_branded
   enable_cros_on_device_assistant = false
 
   # Enable a fake microphone, which can replay audio files as microphone input.
diff --git a/chromeos/chromeos_strings.grd b/chromeos/chromeos_strings.grd
index 83ec365f..be52428da 100644
--- a/chromeos/chromeos_strings.grd
+++ b/chromeos/chromeos_strings.grd
@@ -669,6 +669,18 @@
       <message name="IDS_DIAGNOSTICS_DEVICE_INFO_TEXT" desc="The text that displays the device's name and milestone version." translateable="true">
         (<ph name="BOARD_NAME">$1<ex>Atlas</ex></ph>, version <ph name="MILESTONE_VERSION">$2<ex>88</ex></ph>)
       </message>
+      <message name="IDS_DIAGNOSTICS_BATTERY_HEALTH_TOOLTIP_TEXT" desc="The tooltip that states that battery capacity declines with usage." translateable="true">
+        Batteries capacity declines with usage
+      </message>
+      <message name="IDS_DIAGNOSTICS_CYCLE_COUNT_TOOLTIP_TEXT" desc="The tooltip that states that a battery is considered consumed once it reaches its cycle count limit." translateable="true">
+        The battery is considered consumed once it reaches the limit
+      </message>
+      <message name="IDS_DIAGNOSTICS_CURRENT_NOW_TOOLTIP_TEXT" desc="The tooltip that states the current rate at which a user's device is charging or discharging." translateable="true">
+        The rate at which the device is currently charging or discharging
+      </message>
+      <message name="IDS_DIAGNOSTICS_CPU_USAGE_TOOLTIP_TEXT" desc="The tooltip for CPU usage." translateable="true">
+        This measures the CPU usage, and is an aggregation of all cores
+      </message>
 
       <!-- Quick Answers -->
       <message name="IDS_QUICK_ANSWERS_DEFINITION_TITLE_TEXT" desc="The title text format string used for Quick Answers definition result card. The first placeholder contains the source query text and the second placeholder contains the phonetics.">
diff --git a/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_BATTERY_HEALTH_TOOLTIP_TEXT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_BATTERY_HEALTH_TOOLTIP_TEXT.png.sha1
new file mode 100644
index 0000000..87d582c
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_BATTERY_HEALTH_TOOLTIP_TEXT.png.sha1
@@ -0,0 +1 @@
+5bf8d3ccc96e6aa72e5f778900e1e6614fd65f89
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_CPU_USAGE_TOOLTIP_TEXT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_CPU_USAGE_TOOLTIP_TEXT.png.sha1
new file mode 100644
index 0000000..25a3aed2
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_CPU_USAGE_TOOLTIP_TEXT.png.sha1
@@ -0,0 +1 @@
+69bd525a2d92a2aaa05b509a16c986e6af3fec5e
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_CURRENT_NOW_TOOLTIP_TEXT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_CURRENT_NOW_TOOLTIP_TEXT.png.sha1
new file mode 100644
index 0000000..a1c1ab7
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_CURRENT_NOW_TOOLTIP_TEXT.png.sha1
@@ -0,0 +1 @@
+97385214bc5a2626fb840781f965e47b4753368f
\ No newline at end of file
diff --git a/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_CYCLE_COUNT_TOOLTIP_TEXT.png.sha1 b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_CYCLE_COUNT_TOOLTIP_TEXT.png.sha1
new file mode 100644
index 0000000..a9ba379b
--- /dev/null
+++ b/chromeos/chromeos_strings_grd/IDS_DIAGNOSTICS_CYCLE_COUNT_TOOLTIP_TEXT.png.sha1
@@ -0,0 +1 @@
+d422ae5dda85b755dad9345a132e29b0e1f7f66b
\ No newline at end of file
diff --git a/chromeos/components/diagnostics_ui/backend/system_routine_controller.cc b/chromeos/components/diagnostics_ui/backend/system_routine_controller.cc
index 91b57120..7d7e0279 100644
--- a/chromeos/components/diagnostics_ui/backend/system_routine_controller.cc
+++ b/chromeos/components/diagnostics_ui/backend/system_routine_controller.cc
@@ -116,6 +116,79 @@
   return std::string(contents.begin(), contents.end());
 }
 
+bool IsKnownRoutine(healthd::DiagnosticRoutineEnum routine_enum) {
+  switch (routine_enum) {
+    case healthd::DiagnosticRoutineEnum::kBatteryCharge:
+    case healthd::DiagnosticRoutineEnum::kBatteryDischarge:
+    case healthd::DiagnosticRoutineEnum::kCpuCache:
+    case healthd::DiagnosticRoutineEnum::kCpuStress:
+    case healthd::DiagnosticRoutineEnum::kFloatingPointAccuracy:
+    case healthd::DiagnosticRoutineEnum::kMemory:
+    case healthd::DiagnosticRoutineEnum::kPrimeSearch:
+      return true;
+    case healthd::DiagnosticRoutineEnum::kAcPower:
+    case healthd::DiagnosticRoutineEnum::kBatteryCapacity:
+    case healthd::DiagnosticRoutineEnum::kBatteryHealth:
+    case healthd::DiagnosticRoutineEnum::kCaptivePortal:
+    case healthd::DiagnosticRoutineEnum::kDiskRead:
+    case healthd::DiagnosticRoutineEnum::kDnsLatency:
+    case healthd::DiagnosticRoutineEnum::kDnsResolution:
+    case healthd::DiagnosticRoutineEnum::kDnsResolverPresent:
+    case healthd::DiagnosticRoutineEnum::kGatewayCanBePinged:
+    case healthd::DiagnosticRoutineEnum::kHasSecureWiFiConnection:
+    case healthd::DiagnosticRoutineEnum::kHttpFirewall:
+    case healthd::DiagnosticRoutineEnum::kHttpsFirewall:
+    case healthd::DiagnosticRoutineEnum::kLanConnectivity:
+    case healthd::DiagnosticRoutineEnum::kNvmeSelfTest:
+    case healthd::DiagnosticRoutineEnum::kNvmeWearLevel:
+    case healthd::DiagnosticRoutineEnum::kSignalStrength:
+    case healthd::DiagnosticRoutineEnum::kSmartctlCheck:
+    case healthd::DiagnosticRoutineEnum::kUrandom:
+      return false;
+  }
+}
+
+mojom::RoutineType DiagnosticRoutineEnumToRoutineType(
+    healthd::DiagnosticRoutineEnum routine_enum) {
+  switch (routine_enum) {
+    case healthd::DiagnosticRoutineEnum::kBatteryCharge:
+      return mojom::RoutineType::kBatteryCharge;
+    case healthd::DiagnosticRoutineEnum::kBatteryDischarge:
+      return mojom::RoutineType::kBatteryDischarge;
+    case healthd::DiagnosticRoutineEnum::kCpuCache:
+      return mojom::RoutineType::kCpuCache;
+    case healthd::DiagnosticRoutineEnum::kCpuStress:
+      return mojom::RoutineType::kCpuStress;
+    case healthd::DiagnosticRoutineEnum::kFloatingPointAccuracy:
+      return mojom::RoutineType::kCpuFloatingPoint;
+    case healthd::DiagnosticRoutineEnum::kMemory:
+      return mojom::RoutineType::kMemory;
+    case healthd::DiagnosticRoutineEnum::kPrimeSearch:
+      return mojom::RoutineType::kCpuPrime;
+    case healthd::DiagnosticRoutineEnum::kAcPower:
+    case healthd::DiagnosticRoutineEnum::kBatteryCapacity:
+    case healthd::DiagnosticRoutineEnum::kBatteryHealth:
+    case healthd::DiagnosticRoutineEnum::kCaptivePortal:
+    case healthd::DiagnosticRoutineEnum::kDiskRead:
+    case healthd::DiagnosticRoutineEnum::kDnsLatency:
+    case healthd::DiagnosticRoutineEnum::kDnsResolution:
+    case healthd::DiagnosticRoutineEnum::kDnsResolverPresent:
+    case healthd::DiagnosticRoutineEnum::kGatewayCanBePinged:
+    case healthd::DiagnosticRoutineEnum::kHasSecureWiFiConnection:
+    case healthd::DiagnosticRoutineEnum::kHttpFirewall:
+    case healthd::DiagnosticRoutineEnum::kHttpsFirewall:
+    case healthd::DiagnosticRoutineEnum::kLanConnectivity:
+    case healthd::DiagnosticRoutineEnum::kNvmeSelfTest:
+    case healthd::DiagnosticRoutineEnum::kNvmeWearLevel:
+    case healthd::DiagnosticRoutineEnum::kSignalStrength:
+    case healthd::DiagnosticRoutineEnum::kSmartctlCheck:
+    case healthd::DiagnosticRoutineEnum::kUrandom:
+      NOTREACHED() << "DiagnosticRoutineEnumToRoutineType called with "
+                      "unsupported routine.";
+      return mojom::RoutineType::kBatteryCharge;
+  }
+}
+
 }  // namespace
 
 SystemRoutineController::SystemRoutineController() {
@@ -142,11 +215,31 @@
   ExecuteRoutine(type);
 }
 
+void SystemRoutineController::GetSupportedRoutines(
+    GetSupportedRoutinesCallback callback) {
+  BindCrosHealthdDiagnosticsServiceIfNeccessary();
+  diagnostics_service_->GetAvailableRoutines(
+      base::BindOnce(&SystemRoutineController::OnAvailableRoutinesFetched,
+                     base::Unretained(this), std::move(callback)));
+}
+
 void SystemRoutineController::BindInterface(
     mojo::PendingReceiver<mojom::SystemRoutineController> pending_receiver) {
   receiver_.Bind(std::move(pending_receiver));
 }
 
+void SystemRoutineController::OnAvailableRoutinesFetched(
+    GetSupportedRoutinesCallback callback,
+    const std::vector<healthd::DiagnosticRoutineEnum>& available_routines) {
+  std::vector<mojom::RoutineType> supported_routines;
+  for (const auto& routine : available_routines) {
+    if (IsKnownRoutine(routine)) {
+      supported_routines.push_back(DiagnosticRoutineEnumToRoutineType(routine));
+    }
+  }
+  std::move(callback).Run(supported_routines);
+}
+
 void SystemRoutineController::ExecuteRoutine(mojom::RoutineType routine_type) {
   BindCrosHealthdDiagnosticsServiceIfNeccessary();
 
diff --git a/chromeos/components/diagnostics_ui/backend/system_routine_controller.h b/chromeos/components/diagnostics_ui/backend/system_routine_controller.h
index 593ad23..2ee9792d 100644
--- a/chromeos/components/diagnostics_ui/backend/system_routine_controller.h
+++ b/chromeos/components/diagnostics_ui/backend/system_routine_controller.h
@@ -41,6 +41,7 @@
   SystemRoutineController& operator=(const SystemRoutineController&) = delete;
 
   // mojom::SystemRoutineController:
+  void GetSupportedRoutines(GetSupportedRoutinesCallback callback) override;
   void RunRoutine(mojom::RoutineType type,
                   mojo::PendingRemote<mojom::RoutineRunner> runner) override;
 
@@ -48,6 +49,11 @@
       mojo::PendingReceiver<mojom::SystemRoutineController> pending_receiver);
 
  private:
+  void OnAvailableRoutinesFetched(
+      GetSupportedRoutinesCallback callback,
+      const std::vector<cros_healthd::mojom::DiagnosticRoutineEnum>&
+          supported_routines);
+
   void ExecuteRoutine(mojom::RoutineType routine_type);
 
   void OnRoutineStarted(
diff --git a/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc b/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc
index 3a85dfe8..7d16ff4a 100644
--- a/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc
+++ b/chromeos/components/diagnostics_ui/backend/system_routine_controller_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/json/json_writer.h"
 #include "base/run_loop.h"
+#include "base/stl_util.h"
 #include "base/test/bind.h"
 #include "base/test/task_environment.h"
 #include "chromeos/dbus/cros_healthd/fake_cros_healthd_client.h"
@@ -108,6 +109,12 @@
   return json;
 }
 
+void SetAvailableRoutines(
+    const std::vector<healthd::DiagnosticRoutineEnum>& routines) {
+  cros_healthd::FakeCrosHealthdClient::Get()->SetAvailableRoutinesForTesting(
+      routines);
+}
+
 }  // namespace
 
 struct FakeRoutineRunner : public mojom::RoutineRunner {
@@ -426,5 +433,36 @@
                                   expected_time_elapsed_seconds));
 }
 
+TEST_F(SystemRoutineControllerTest, AvailableRoutines) {
+  SetAvailableRoutines({healthd::DiagnosticRoutineEnum::kFloatingPointAccuracy,
+                        healthd::DiagnosticRoutineEnum::kMemory,
+                        healthd::DiagnosticRoutineEnum::kPrimeSearch,
+                        healthd::DiagnosticRoutineEnum::kAcPower,
+                        healthd::DiagnosticRoutineEnum::kBatteryCapacity,
+                        healthd::DiagnosticRoutineEnum::kBatteryHealth});
+
+  base::RunLoop run_loop;
+  system_routine_controller_->GetSupportedRoutines(base::BindLambdaForTesting(
+      [&](const std::vector<mojom::RoutineType>& supported_routines) {
+        EXPECT_EQ(3u, supported_routines.size());
+        EXPECT_FALSE(base::Contains(supported_routines,
+                                    mojom::RoutineType::kBatteryCharge));
+        EXPECT_FALSE(base::Contains(supported_routines,
+                                    mojom::RoutineType::kBatteryDischarge));
+        EXPECT_FALSE(
+            base::Contains(supported_routines, mojom::RoutineType::kCpuCache));
+        EXPECT_FALSE(
+            base::Contains(supported_routines, mojom::RoutineType::kCpuStress));
+        EXPECT_TRUE(base::Contains(supported_routines,
+                                   mojom::RoutineType::kCpuFloatingPoint));
+        EXPECT_TRUE(
+            base::Contains(supported_routines, mojom::RoutineType::kCpuPrime));
+        EXPECT_TRUE(
+            base::Contains(supported_routines, mojom::RoutineType::kMemory));
+        run_loop.Quit();
+      }));
+  run_loop.Run();
+}
+
 }  // namespace diagnostics
 }  // namespace chromeos
diff --git a/chromeos/components/diagnostics_ui/diagnostics_ui.cc b/chromeos/components/diagnostics_ui/diagnostics_ui.cc
index f3ac2ae..32ecd2f 100644
--- a/chromeos/components/diagnostics_ui/diagnostics_ui.cc
+++ b/chromeos/components/diagnostics_ui/diagnostics_ui.cc
@@ -37,6 +37,7 @@
       {"batteryChipText", IDS_DIAGNOSTICS_BATTERY_CHIP_TEXT},
       {"batteryHealthLabel", IDS_DIAGNOSTICS_BATTERY_HEALTH_LABEL},
       {"batteryHealthText", IDS_DIAGNOSTICS_BATTERY_HEALTH_TEXT},
+      {"batteryHealthTooltipText", IDS_DIAGNOSTICS_BATTERY_HEALTH_TOOLTIP_TEXT},
       {"batteryTitle", IDS_DIAGNOSTICS_BATTERY_TITLE},
       {"chargeFullDesign", IDS_DIAGNOSTICS_DESIGNED_FULL_CHARGE_LABEL},
       {"chargeFullNow", IDS_DIAGNOSTICS_NOW_FULL_CHARGE_LABEL},
@@ -48,11 +49,14 @@
       {"cpuTitle", IDS_DIAGNOSTICS_CPU_TITLE},
       {"cpuUsageLabel", IDS_DIAGNOSTICS_CPU_USAGE_LABEL},
       {"cpuUsageText", IDS_DIAGNOSTICS_CPU_USAGE_TEXT},
+      {"cpuUsageTooltipText", IDS_DIAGNOSTICS_CPU_USAGE_TOOLTIP_TEXT},
       {"cpuUsageSystem", IDS_DIAGNOSTICS_CPU_USAGE_SYSTEM_LABEL},
       {"cpuUsageUser", IDS_DIAGNOSTICS_CPU_USAGE_USER_LABEL},
       {"currentNowLabel", IDS_DIAGNOSTICS_CURRENT_NOW_LABEL},
       {"currentNowText", IDS_DIAGNOSTICS_CURRENT_NOW_TEXT},
+      {"currentNowTooltipText", IDS_DIAGNOSTICS_CURRENT_NOW_TOOLTIP_TEXT},
       {"cycleCount", IDS_DIAGNOSTICS_CYCLE_COUNT_LABEL},
+      {"cycleCountTooltipText", IDS_DIAGNOSTICS_CYCLE_COUNT_TOOLTIP_TEXT},
       {"deviceInfo", IDS_DIAGNOSTICS_DEVICE_INFO_TEXT},
       {"diagnosticsTitle", IDS_DIAGNOSTICS_TITLE},
       {"learnMore", IDS_DIANOSTICS_LEARN_MORE_LABEL},
diff --git a/chromeos/components/diagnostics_ui/mojom/system_routine_controller.mojom b/chromeos/components/diagnostics_ui/mojom/system_routine_controller.mojom
index 5fb53c4..b722dd6 100644
--- a/chromeos/components/diagnostics_ui/mojom/system_routine_controller.mojom
+++ b/chromeos/components/diagnostics_ui/mojom/system_routine_controller.mojom
@@ -47,6 +47,9 @@
 // Enables clients to run diagnostic routines to test the status of various
 // components on the system. This API is exposed to the Diagnostics SWA.
 interface SystemRoutineController {
+  // Gets the list of supported routines on the device.
+  GetSupportedRoutines() => (array<RoutineType> routines);
+
   // Runs routine |type|. The result is returned via the RoutineRunner |runner|.
   // If the client closes the |remote|, cancellation of the associated routine
   // is attempted.
diff --git a/chromeos/components/diagnostics_ui/resources/battery_status_card.html b/chromeos/components/diagnostics_ui/resources/battery_status_card.html
index 95a9595..2dfc092a 100644
--- a/chromeos/components/diagnostics_ui/resources/battery_status_card.html
+++ b/chromeos/components/diagnostics_ui/resources/battery_status_card.html
@@ -13,15 +13,18 @@
   </percent-bar-chart>
   <data-point slot="body" id="batteryHealth"
     header="[[i18n('batteryHealthLabel')]]"
-    value="[[getBatteryHealth_(batteryHealth_.batteryWearPercentage)]]">
+    value="[[getBatteryHealth_(batteryHealth_.batteryWearPercentage)]]"
+    tooltip-text="[[i18n('batteryHealthTooltipText')]]">
   </data-point>
   <div slot="body" class="divider"></div>
   <data-point slot="body" id="cycleCount" header="[[i18n('cycleCount')]]"
-    value="[[batteryHealth_.cycleCount]]">
+    value="[[batteryHealth_.cycleCount]]"
+    tooltip-text="[[i18n('cycleCountTooltipText')]]">
   </data-point>
   <div slot="body" class="divider"></div>
   <data-point slot="body" id="currentNow" header="[[i18n('currentNowLabel')]]"
-    value="[[getCurrentNow_(batteryChargeStatus_.currentNowMilliamps)]]">
+    value="[[getCurrentNow_(batteryChargeStatus_.currentNowMilliamps)]]"
+    tooltip-text="[[i18n('currentNowTooltipText')]]">
   </data-point>
 
   <routine-section slot="routines" routines="[[routines_]]"
diff --git a/chromeos/components/diagnostics_ui/resources/cpu_card.html b/chromeos/components/diagnostics_ui/resources/cpu_card.html
index 3fa7ca8..cf12f48 100644
--- a/chromeos/components/diagnostics_ui/resources/cpu_card.html
+++ b/chromeos/components/diagnostics_ui/resources/cpu_card.html
@@ -13,7 +13,8 @@
   <data-point slot="body" id="cpuUsageUser"
     header="[[i18n('cpuUsageLabel')]]"
     value="[[getCurrentlyUsing_(cpuUsage_.percentUsageSystem,
-        cpuUsage_.percentUsageUser)]]">
+        cpuUsage_.percentUsageUser)]]"
+    tooltip-text="[[getCpuUsageTooltipText_()]]">
   </data-point>
   <div slot="body" class="divider"></div>
   <data-point slot="body" id="cpuTemp" header="[[i18n('cpuTempLabel')]]"
diff --git a/chromeos/components/diagnostics_ui/resources/cpu_card.js b/chromeos/components/diagnostics_ui/resources/cpu_card.js
index 184d75d1..f778ff2 100644
--- a/chromeos/components/diagnostics_ui/resources/cpu_card.js
+++ b/chromeos/components/diagnostics_ui/resources/cpu_card.js
@@ -135,4 +135,10 @@
     return loadTimeData.getStringF(
         'cpuTempText', this.cpuUsage_.averageCpuTempCelsius);
   },
+
+  /** @protected */
+  getCpuUsageTooltipText_() {
+    // TODO(michaelcheco): Update when number of cores is added to the api.
+    return loadTimeData.getString('cpuUsageTooltipText');
+  },
 });
diff --git a/chromeos/components/diagnostics_ui/resources/data_point.html b/chromeos/components/diagnostics_ui/resources/data_point.html
index 6126bda..7df986b 100644
--- a/chromeos/components/diagnostics_ui/resources/data_point.html
+++ b/chromeos/components/diagnostics_ui/resources/data_point.html
@@ -11,11 +11,24 @@
     color: var(--diagnostics-overview-text-color);
   }
 
+  #infoIcon {
+    fill:  var(--google-grey-600);
+    height: 18px;
+    left: 4px;
+    width: 18px;
+  }
+
   .value {
     @apply --diagnostics-data-point-subtitle-font;
   }
 </style>
 <div class="data-point">
-  <div class="header">[[header]]</div>
+  <div class="header">
+    <span>[[header]]</span>
+    <iron-icon slot="icon" icon="cr:info-outline" id="infoIcon"
+      hidden$="[[!tooltipText]]">
+    </iron-icon>
+    <paper-tooltip for="infoIcon">[[tooltipText]]</paper-tooltip>
+  </div>
   <div class="value">[[value]]</div>
 </div>
\ No newline at end of file
diff --git a/chromeos/components/diagnostics_ui/resources/data_point.js b/chromeos/components/diagnostics_ui/resources/data_point.js
index 0adde60..2de65a9 100644
--- a/chromeos/components/diagnostics_ui/resources/data_point.js
+++ b/chromeos/components/diagnostics_ui/resources/data_point.js
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'chrome://resources/cr_elements/icons.m.js';
+import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
+import 'chrome://resources/polymer/v3_0/paper-tooltip/paper-tooltip.js';
 import './diagnostics_fonts_css.js';
 import './diagnostics_shared_css.js';
 
@@ -10,7 +13,8 @@
 /**
  * @fileoverview
  * 'data-point' shows a single piece of information related to a component. It
- *  consists of a header and value.
+ *  consists of a header, value, and tooltip that provides context about the
+ *  item.
  */
 Polymer({
   is: 'data-point',
@@ -28,5 +32,11 @@
       type: String,
       value: '',
     },
+
+    /** @type {string} */
+    tooltipText: {
+      type: String,
+      value: '',
+    },
   },
 });
diff --git a/chromeos/components/help_app_ui/help_app_ui.gni b/chromeos/components/help_app_ui/help_app_ui.gni
index 8c29b691..af4f850 100644
--- a/chromeos/components/help_app_ui/help_app_ui.gni
+++ b/chromeos/components/help_app_ui/help_app_ui.gni
@@ -1,7 +1,8 @@
 import("//build/config/chrome_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
 
 declare_args() {
   # Whether to enable the "real" ChromeOS Help App. When false, a mock app is
   # bundled for testing integration points.
-  enable_cros_help_app = is_chromeos && is_chrome_branded
+  enable_cros_help_app = is_chromeos_ash && is_chrome_branded
 }
diff --git a/chromeos/components/media_app_ui/media_app_ui.gni b/chromeos/components/media_app_ui/media_app_ui.gni
index 0f17b6f..f3ad756 100644
--- a/chromeos/components/media_app_ui/media_app_ui.gni
+++ b/chromeos/components/media_app_ui/media_app_ui.gni
@@ -1,7 +1,8 @@
 import("//build/config/chrome_build.gni")
+import("//build/config/chromeos/ui_mode.gni")
 
 declare_args() {
   # Whether to enable the "real" ChromeOS Media App. When false, a mock app is
   # bundled for testing integration points.
-  enable_cros_media_app = is_chromeos && is_chrome_branded
+  enable_cros_media_app = is_chromeos_ash && is_chrome_branded
 }
diff --git a/chromeos/constants/chromeos_features.cc b/chromeos/constants/chromeos_features.cc
index 704ac2f..c0f56da 100644
--- a/chromeos/constants/chromeos_features.cc
+++ b/chromeos/constants/chromeos_features.cc
@@ -660,7 +660,7 @@
 
 // Enable or disable bordered key for virtual keyboard on Chrome OS.
 const base::Feature kVirtualKeyboardBorderedKey{
-    "VirtualKeyboardBorderedKey", base::FEATURE_ENABLED_BY_DEFAULT};
+    "VirtualKeyboardBorderedKey", base::FEATURE_DISABLED_BY_DEFAULT};
 
 // Enable or disable the camera/mic indicators/notifications for VMs.
 const base::Feature kVmCameraMicIndicatorsAndNotifications{
diff --git a/chromeos/ime/gen_input_methods.py b/chromeos/ime/gen_input_methods.py
index 17e6a50..edaf562 100755
--- a/chromeos/ime/gen_input_methods.py
+++ b/chromeos/ime/gen_input_methods.py
@@ -9,8 +9,6 @@
 available input methods.  It parses input_methods.txt, and then generates a
 static array definition from the information extracted. The input and output
 file names are specified on the command line.
-The header input_methods.h is used in input_method_allowlist.cc which is for
-testing purpose.
 
 Run it like:
   gen_input_methods.py input_methods.txt input_methods.h
diff --git a/chromeos/lacros/BUILD.gn b/chromeos/lacros/BUILD.gn
index 4e3f0c7..517dfea 100644
--- a/chromeos/lacros/BUILD.gn
+++ b/chromeos/lacros/BUILD.gn
@@ -7,7 +7,7 @@
 import("//build/lacros/lacros_resource_sizes.gni")
 
 # Code lives in the lacros-chrome browser only, not ash-chrome.
-assert(chromeos_is_browser_only)
+assert(is_chromeos_lacros)
 assert(!use_gtk)
 
 component("lacros") {
diff --git a/chromeos/services/assistant/BUILD.gn b/chromeos/services/assistant/BUILD.gn
index 55fa4269..087ca4d 100644
--- a/chromeos/services/assistant/BUILD.gn
+++ b/chromeos/services/assistant/BUILD.gn
@@ -3,9 +3,10 @@
 # found in the LICENSE file.
 
 import("//build/buildflag_header.gni")
+import("//build/config/chromeos/ui_mode.gni")
 import("//chromeos/assistant/assistant.gni")
 
-assert(is_chromeos)
+assert(is_chromeos_ash)
 
 component("lib") {
   output_name = "assistant_service"
diff --git a/chromeos/services/assistant/proxy/BUILD.gn b/chromeos/services/assistant/proxy/BUILD.gn
index 71ab9cd..a4d361b 100644
--- a/chromeos/services/assistant/proxy/BUILD.gn
+++ b/chromeos/services/assistant/proxy/BUILD.gn
@@ -2,9 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE fil
 import("//build/buildflag_header.gni")
+import("//build/config/chromeos/ui_mode.gni")
 import("//chromeos/assistant/assistant.gni")
 
-assert(is_chromeos)
+assert(is_chromeos_ash)
 
 source_set("proxy") {
   sources = [
diff --git a/chromeos/services/nearby/public/mojom/BUILD.gn b/chromeos/services/nearby/public/mojom/BUILD.gn
index 413f8689..46031d3 100644
--- a/chromeos/services/nearby/public/mojom/BUILD.gn
+++ b/chromeos/services/nearby/public/mojom/BUILD.gn
@@ -1,6 +1,7 @@
+import("//build/config/chromeos/ui_mode.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 
-assert(is_chromeos)
+assert(is_chromeos_ash)
 
 mojom("nearby_share_target_types") {
   sources = [ "nearby_share_target_types.mojom" ]
diff --git a/chromeos/ui/base/BUILD.gn b/chromeos/ui/base/BUILD.gn
index a508945a..6a04c40 100644
--- a/chromeos/ui/base/BUILD.gn
+++ b/chromeos/ui/base/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//build/config/chromeos/ui_mode.gni")
 
-assert(is_chromeos || is_lacros,
+assert(is_chromeos_ash || is_chromeos_lacros,
        "Non-Chrome-OS or Lacros builds must not depend on //chromeos")
 
 # C++ headers and sources that can be used by both ash and lacros builds.
@@ -31,5 +31,9 @@
     "//ui/base",
     "//ui/display",
     "//ui/gfx/geometry",
+
+    # TODO(https://crbug.com/1113900): Remove this dependency when resize-shadow
+    # is integrated to lacros.
+    "//build:chromeos_buildflags",
   ]
 }
diff --git a/chromeos/ui/base/chromeos_ui_constants.h b/chromeos/ui/base/chromeos_ui_constants.h
index 4828fd8..c66a2d8 100644
--- a/chromeos/ui/base/chromeos_ui_constants.h
+++ b/chromeos/ui/base/chromeos_ui_constants.h
@@ -5,6 +5,7 @@
 #ifndef CHROMEOS_UI_BASE_CHROMEOS_UI_CONSTANTS_H_
 #define CHROMEOS_UI_BASE_CHROMEOS_UI_CONSTANTS_H_
 
+#include "build/chromeos_buildflags.h"
 #include "third_party/skia/include/core/SkColor.h"
 
 namespace chromeos {
@@ -22,7 +23,14 @@
 // "non-client" area and use it for resizing.
 constexpr int kResizeOutsideBoundsSize = 6;
 constexpr int kResizeOutsideBoundsScaleForTouch = 5;
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
 constexpr int kResizeInsideBoundsSize = 1;
+#else
+// TODO(https://crbug.com/1113900): Remove this if-check when resize-shadow
+// works in lacros/chrome.
+constexpr int kResizeInsideBoundsSize = 2;
+#endif
 
 // The default frame color.
 constexpr SkColor kDefaultFrameColor = SkColorSetRGB(0xFD, 0xFE, 0xFF);
diff --git a/chromeos/ui/frame/BUILD.gn b/chromeos/ui/frame/BUILD.gn
index 1ca1851..992939e 100644
--- a/chromeos/ui/frame/BUILD.gn
+++ b/chromeos/ui/frame/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//build/config/chromeos/ui_mode.gni")
 
-assert(is_chromeos || is_lacros,
+assert(is_chromeos_ash || is_chromeos_lacros,
        "Non-Chrome-OS or Lacros builds must not depend on //chromeos")
 
 # C++ headers and sources that can be used by both ash and lacros builds.
diff --git a/chromeos/ui/frame/interior_resize_handler_targeter.h b/chromeos/ui/frame/interior_resize_handler_targeter.h
index d514c76..0fa9621 100644
--- a/chromeos/ui/frame/interior_resize_handler_targeter.h
+++ b/chromeos/ui/frame/interior_resize_handler_targeter.h
@@ -19,7 +19,7 @@
       delete;
   ~InteriorResizeHandleTargeter() override;
 
-  // aura::WindowTargeter
+  // aura::WindowTargeter:
   bool GetHitTestRects(aura::Window* target,
                        gfx::Rect* hit_test_rect_mouse,
                        gfx::Rect* hit_test_rect_touch) const override;
@@ -28,4 +28,4 @@
 
 }  // namespace chromeos
 
-#endif  // CHROMEOS_UI_BASE_WINDOW_PROPERTIES_H_
+#endif  // CHROMEOS_UI_FRAME_INTERIOR_RESIZE_HANDLER_TARGETER_H_
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc
index 44cb0c51..8aa3499 100644
--- a/components/arc/ime/arc_ime_service.cc
+++ b/components/arc/ime/arc_ime_service.cc
@@ -626,10 +626,11 @@
   return gfx::Rect();
 }
 
-bool ArcImeService::SetAutocorrectRange(const base::string16& autocorrect_text,
-                                        const gfx::Range& range) {
-  base::UmaHistogramEnumeration("InputMethod.Assistive.Autocorrect.Count",
-                                TextInputClient::SubClass::kArcImeService);
+bool ArcImeService::SetAutocorrectRange(const gfx::Range& range) {
+  if (!range.is_empty()) {
+    base::UmaHistogramEnumeration("InputMethod.Assistive.Autocorrect.Count",
+                                  TextInputClient::SubClass::kArcImeService);
+  }
   // TODO(https:://crbug.com/1091088): Implement this method.
   NOTIMPLEMENTED_LOG_ONCE();
   return false;
@@ -642,11 +643,6 @@
   }
 }
 
-void ArcImeService::ClearAutocorrectRange() {
-  // TODO(https:://crbug.com/1091088): Implement this method.
-  NOTIMPLEMENTED_LOG_ONCE();
-}
-
 // static
 void ArcImeService::SetOverrideDefaultDeviceScaleFactorForTesting(
     base::Optional<double> scale_factor) {
diff --git a/components/arc/ime/arc_ime_service.h b/components/arc/ime/arc_ime_service.h
index 36a31c0..2e745d7 100644
--- a/components/arc/ime/arc_ime_service.h
+++ b/components/arc/ime/arc_ime_service.h
@@ -152,10 +152,8 @@
       const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
   gfx::Range GetAutocorrectRange() const override;
   gfx::Rect GetAutocorrectCharacterBounds() const override;
-  bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                           const gfx::Range& range) override;
+  bool SetAutocorrectRange(const gfx::Range& range) override;
   void OnDispatchingKeyEventPostIME(ui::KeyEvent* event) override;
-  void ClearAutocorrectRange() override;
 
   // Normally, the default device scale factor is used to convert from DPI to
   // physical pixels. This method provides a way to override it for testing.
diff --git a/components/arc/mojom/arc_bridge.mojom b/components/arc/mojom/arc_bridge.mojom
index 3ed01bd..9566def 100644
--- a/components/arc/mojom/arc_bridge.mojom
+++ b/components/arc/mojom/arc_bridge.mojom
@@ -228,7 +228,7 @@
       pending_remote<SensorInstance> instance_ptr);
 
   // Notifies Chrome that the SharesheetInstance interface is ready.
-  [MinVersion=53] OnSharesheetInstanceReady@158(
+  [MinVersion=52] OnSharesheetInstanceReady@158(
                       pending_remote<SharesheetInstance> instance_remote);
 
   // Notifies Chrome that the SmartCardManagerInstance interface is ready.
diff --git a/components/download/internal/common/download_utils.cc b/components/download/internal/common/download_utils.cc
index f75993e5..452f1e1f 100644
--- a/components/download/internal/common/download_utils.cc
+++ b/components/download/internal/common/download_utils.cc
@@ -51,6 +51,9 @@
 // downloads will be deleted after expiration.
 const int kDefaultDownloadExpiredTimeInDays = 90;
 
+// Default time for an overwritten download to be removed from the history.
+const int kDefaultOverwrittenDownloadExpiredTimeInDays = 90;
+
 #if defined(OS_ANDROID)
 // Default maximum length of a downloaded file name on Android.
 const int kDefaultMaxFileNameLengthOnAndroid = 127;
@@ -638,4 +641,12 @@
   return base::TimeDelta::FromDays(expired_days);
 }
 
+base::TimeDelta GetOverwrittenDownloadDeleteTime() {
+  int expired_days = base::GetFieldTrialParamByFeatureAsInt(
+      features::kDeleteOverwrittenDownloads,
+      kOverwrittenDownloadDeleteTimeFinchKey,
+      kDefaultOverwrittenDownloadExpiredTimeInDays);
+  return base::TimeDelta::FromDays(expired_days);
+}
+
 }  // namespace download
diff --git a/components/download/public/common/download_features.cc b/components/download/public/common/download_features.cc
index 38ed21f0..5e31fa8a 100644
--- a/components/download/public/common/download_features.cc
+++ b/components/download/public/common/download_features.cc
@@ -67,6 +67,9 @@
 const base::Feature kDeleteExpiredDownloads{"DeleteExpiredDownloads",
                                             base::FEATURE_ENABLED_BY_DEFAULT};
 
+const base::Feature kDeleteOverwrittenDownloads{
+    "DeleteOverwrittenDownloads", base::FEATURE_DISABLED_BY_DEFAULT};
+
 }  // namespace features
 
 namespace switches {
diff --git a/components/download/public/common/download_features.h b/components/download/public/common/download_features.h
index 1a29aab..8713b77b 100644
--- a/components/download/public/common/download_features.h
+++ b/components/download/public/common/download_features.h
@@ -68,6 +68,10 @@
 // Whether to delete expired download.
 COMPONENTS_DOWNLOAD_EXPORT extern const base::Feature kDeleteExpiredDownloads;
 
+// Whether to delete downloads that are overwritten by others.
+COMPONENTS_DOWNLOAD_EXPORT extern const base::Feature
+    kDeleteOverwrittenDownloads;
+
 }  // namespace features
 
 namespace switches {
diff --git a/components/download/public/common/download_utils.h b/components/download/public/common/download_utils.h
index 737c193..97373c2 100644
--- a/components/download/public/common/download_utils.h
+++ b/components/download/public/common/download_utils.h
@@ -117,9 +117,15 @@
 constexpr char kExpiredDownloadDeleteTimeFinchKey[] =
     "expired_download_delete_days";
 
+// Finch parameter key value for the time to delete expired downloads in days.
+constexpr char kOverwrittenDownloadDeleteTimeFinchKey[] =
+    "overwritten_download_delete_days";
+
 // Returns the time to delete expired downloads.
 COMPONENTS_DOWNLOAD_EXPORT base::TimeDelta GetExpiredDownloadDeleteTime();
 
+// Returns the time in days to delete download that is overwritten by others.
+COMPONENTS_DOWNLOAD_EXPORT base::TimeDelta GetOverwrittenDownloadDeleteTime();
 }  // namespace download
 
 #endif  // COMPONENTS_DOWNLOAD_PUBLIC_COMMON_DOWNLOAD_UTILS_H_
diff --git a/components/embedder_support/android/BUILD.gn b/components/embedder_support/android/BUILD.gn
index eae62fb..5a781488 100644
--- a/components/embedder_support/android/BUILD.gn
+++ b/components/embedder_support/android/BUILD.gn
@@ -196,6 +196,7 @@
     "//content/public/android:content_java",
     "//third_party/android_deps:androidx_annotation_annotation_java",
     "//third_party/android_deps:androidx_core_core_java",
+    "//third_party/blink/public/mojom:mojom_platform_java",
     "//ui/android:ui_no_recycler_view_java",
   ]
   resources_package = "org.chromium.components.embedder_support.delegate"
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
index 420803e..c0e854d 100644
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.cc
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.cc
@@ -394,4 +394,16 @@
   return contents->GetNativeView()->ControlsResizeView();
 }
 
+blink::mojom::DisplayMode WebContentsDelegateAndroid::GetDisplayMode(
+    const content::WebContents* web_contents) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+
+  ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
+  if (obj.is_null())
+    return blink::mojom::DisplayMode::kUndefined;
+
+  return static_cast<blink::mojom::DisplayMode>(
+      Java_WebContentsDelegateAndroid_getDisplayModeChecked(env, obj));
+}
+
 }  // namespace web_contents_delegate_android
diff --git a/components/embedder_support/android/delegate/web_contents_delegate_android.h b/components/embedder_support/android/delegate/web_contents_delegate_android.h
index fdd6866f..7f8f856 100644
--- a/components/embedder_support/android/delegate/web_contents_delegate_android.h
+++ b/components/embedder_support/android/delegate/web_contents_delegate_android.h
@@ -113,6 +113,8 @@
   bool ShouldAnimateBrowserControlsHeightChanges() override;
   bool DoBrowserControlsShrinkRendererSize(
       content::WebContents* contents) override;
+  blink::mojom::DisplayMode GetDisplayMode(
+      const content::WebContents* web_contents) override;
 
  protected:
   base::android::ScopedJavaLocalRef<jobject> GetJavaDelegate(JNIEnv* env) const;
diff --git a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java
index b5cf1ed..9dd36fc 100644
--- a/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java
+++ b/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/WebContentsDelegateAndroid.java
@@ -8,6 +8,7 @@
 
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.blink.mojom.DisplayMode;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.common.ResourceRequestBody;
 
@@ -167,4 +168,23 @@
     public boolean shouldAnimateBrowserControlsHeightChanges() {
         return false;
     }
+
+    /**
+     * Check and return the {@link DisplayMode} value.
+     *
+     * @return The {@link DisplayMode} value.
+     */
+    @CalledByNative
+    protected final int getDisplayModeChecked() {
+        int displayMode = getDisplayMode();
+        assert DisplayMode.isKnownValue(displayMode);
+        return displayMode;
+    }
+
+    /**
+     * @return The {@link DisplayMode} value.
+     */
+    public int getDisplayMode() {
+        return DisplayMode.UNDEFINED;
+    }
 }
diff --git a/components/exo/text_input.cc b/components/exo/text_input.cc
index f2d5343..d0f632a 100644
--- a/components/exo/text_input.cc
+++ b/components/exo/text_input.cc
@@ -348,17 +348,11 @@
 }
 
 // TODO(crbug.com/1091088) Implement setAutocorrectRange
-bool TextInput::SetAutocorrectRange(const base::string16& autocorrect_text,
-                                    const gfx::Range& range) {
+bool TextInput::SetAutocorrectRange(const gfx::Range& range) {
   NOTIMPLEMENTED_LOG_ONCE();
   return false;
 }
 
-// TODO(crbug.com/1091088) Implement ClearAutocorrectRange
-void TextInput::ClearAutocorrectRange() {
-  NOTIMPLEMENTED_LOG_ONCE();
-}
-
 void TextInput::OnKeyboardVisibilityChanged(bool is_visible) {
   delegate_->OnVirtualKeyboardVisibilityChanged(is_visible);
 }
diff --git a/components/exo/text_input.h b/components/exo/text_input.h
index ebe88ff1..aa5e00d 100644
--- a/components/exo/text_input.h
+++ b/components/exo/text_input.h
@@ -139,9 +139,7 @@
       const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
   gfx::Range GetAutocorrectRange() const override;
   gfx::Rect GetAutocorrectCharacterBounds() const override;
-  bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                           const gfx::Range& range) override;
-  void ClearAutocorrectRange() override;
+  bool SetAutocorrectRange(const gfx::Range& range) override;
 
   // ash::KeyboardControllerObserver:
   void OnKeyboardVisibilityChanged(bool is_visible) override;
diff --git a/components/language_usage_metrics/BUILD.gn b/components/language_usage_metrics/BUILD.gn
index 960319f..26155ef 100644
--- a/components/language_usage_metrics/BUILD.gn
+++ b/components/language_usage_metrics/BUILD.gn
@@ -8,7 +8,10 @@
     "language_usage_metrics.h",
   ]
 
-  deps = [ "//base" ]
+  deps = [
+    "//base",
+    "//components/language/core/browser:browser",
+  ]
 }
 
 source_set("unit_tests") {
@@ -17,6 +20,9 @@
 
   deps = [
     ":language_usage_metrics",
+    "//base",
+    "//components/language/core/browser:browser",
+    "//components/prefs:test_support",
     "//testing/gtest",
   ]
 }
diff --git a/components/language_usage_metrics/DEPS b/components/language_usage_metrics/DEPS
new file mode 100644
index 0000000..27895b9
--- /dev/null
+++ b/components/language_usage_metrics/DEPS
@@ -0,0 +1,9 @@
+include_rules = [
+  "+components/language",
+]
+
+specific_include_rules = {
+  ".*unittest.cc": [
+    "+components/prefs",
+  ],
+}
diff --git a/components/language_usage_metrics/language_usage_metrics.cc b/components/language_usage_metrics/language_usage_metrics.cc
index b123be3..4f9dd2f 100644
--- a/components/language_usage_metrics/language_usage_metrics.cc
+++ b/components/language_usage_metrics/language_usage_metrics.cc
@@ -9,6 +9,7 @@
 #include "base/metrics/histogram_functions.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/string_tokenizer.h"
+#include "components/language/core/browser/url_language_histogram.h"
 
 namespace language_usage_metrics {
 
@@ -26,6 +27,27 @@
 }
 
 // static
+void LanguageUsageMetrics::RecordPageLanguages(
+    const language::UrlLanguageHistogram& language_counts) {
+  const float kMinLanguageFrequency = 0.05;
+  std::vector<language::UrlLanguageHistogram::LanguageInfo> top_languages =
+      language_counts.GetTopLanguages();
+
+  for (const language::UrlLanguageHistogram::LanguageInfo& language_info :
+       top_languages) {
+    if (language_info.frequency < kMinLanguageFrequency) {
+      continue;
+    }
+
+    const int language_code = ToLanguageCode(language_info.language_code);
+    if (language_code != 0) {
+      base::UmaHistogramSparse("LanguageUsage.MostFrequentPageLanguages",
+                               language_code);
+    }
+  }
+}
+
+// static
 void LanguageUsageMetrics::RecordApplicationLanguage(
     base::StringPiece application_locale) {
   const int language_code = ToLanguageCode(application_locale);
diff --git a/components/language_usage_metrics/language_usage_metrics.h b/components/language_usage_metrics/language_usage_metrics.h
index 7cea6f6..f350bec 100644
--- a/components/language_usage_metrics/language_usage_metrics.h
+++ b/components/language_usage_metrics/language_usage_metrics.h
@@ -11,6 +11,10 @@
 #include "base/macros.h"
 #include "base/strings/string_piece.h"
 
+namespace language {
+class UrlLanguageHistogram;
+}
+
 namespace language_usage_metrics {
 
 // Methods to record language usage as UMA histograms.
@@ -23,6 +27,13 @@
   // identical and recorded once.
   static void RecordAcceptLanguages(base::StringPiece accept_languages);
 
+  // Records detected page language history as a UMA histogram.
+  // |UrlLanguageHistogram| is a mapping of page language to frequency. Country
+  // codes are ignored for page language. Each language is counted once
+  // regardless of frequency. Languages with a frequency below 0.05 are ignored.
+  static void RecordPageLanguages(
+      const language::UrlLanguageHistogram& language_counts);
+
   // Records the application language as a UMA histogram. |application_locale|
   // is a case-insensitive locale string of either xx, xx-YY, or xx_YY format.
   // Only the language part (xx in the example) is considered.
diff --git a/components/language_usage_metrics/language_usage_metrics_unittest.cc b/components/language_usage_metrics/language_usage_metrics_unittest.cc
index 74344eb..03195fc1 100644
--- a/components/language_usage_metrics/language_usage_metrics_unittest.cc
+++ b/components/language_usage_metrics/language_usage_metrics_unittest.cc
@@ -4,10 +4,188 @@
 
 #include "components/language_usage_metrics/language_usage_metrics.h"
 
+#include "base/macros.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "components/language/core/browser/url_language_histogram.h"
+#include "components/prefs/testing_pref_service.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+using base::HistogramBase;
+using base::HistogramSamples;
+using base::SampleCountIterator;
+using base::StatisticsRecorder;
+using language::UrlLanguageHistogram;
+
 namespace language_usage_metrics {
 
+namespace {
+
+class MetricsRecorder {
+ public:
+  explicit MetricsRecorder(const char* key) : key_(key) {
+    HistogramBase* histogram = StatisticsRecorder::FindHistogram(key_);
+    if (histogram)
+      base_samples_ = histogram->SnapshotSamples();
+  }
+
+  void CheckTotalCount(int count) {
+    Snapshot();
+    EXPECT_EQ(count, GetTotalCount());
+  }
+
+  void CheckValueCount(HistogramBase::Sample value, int count) {
+    Snapshot();
+    EXPECT_EQ(count, GetCountWithoutSnapshot(value));
+  }
+
+ private:
+  void Snapshot() {
+    HistogramBase* histogram = StatisticsRecorder::FindHistogram(key_);
+    if (!histogram)
+      return;
+    samples_ = histogram->SnapshotSamples();
+  }
+
+  HistogramBase::Count GetCountWithoutSnapshot(HistogramBase::Sample value) {
+    if (!samples_)
+      return 0;
+    HistogramBase::Count count = samples_->GetCount(value);
+    if (!base_samples_)
+      return count;
+    return count - base_samples_->GetCount(value);
+  }
+
+  HistogramBase::Count GetTotalCount() {
+    if (!samples_)
+      return 0;
+    HistogramBase::Count count = samples_->TotalCount();
+    if (!base_samples_)
+      return count;
+    return count - base_samples_->TotalCount();
+  }
+
+  std::string key_;
+  std::unique_ptr<HistogramSamples> base_samples_;
+  std::unique_ptr<HistogramSamples> samples_;
+
+  DISALLOW_COPY_AND_ASSIGN(MetricsRecorder);
+};
+
+void RecordPageLanguageVisits(UrlLanguageHistogram& language_histogram,
+                              std::string language,
+                              int count) {
+  for (int i = 0; i < count; i++) {
+    language_histogram.OnPageVisited(language);
+  }
+}
+
+struct LanguageCodeHash {
+  LanguageCodeHash() = default;
+  LanguageCodeHash(const std::string& code, int hash)
+      : code(code), hash(hash) {}
+  std::string code;
+  int hash;
+};
+
+}  // namespace
+
+TEST(LanguageUsageMetricsTest, RecordPageLanguageCounts) {
+  const LanguageCodeHash EN("en", 25966);
+  const LanguageCodeHash ES("es", 25971);
+  const LanguageCodeHash JP("ja", 27233);
+
+  TestingPrefServiceSimple prefs;
+  UrlLanguageHistogram::RegisterProfilePrefs(prefs.registry());
+  UrlLanguageHistogram url_hist(&prefs);
+
+  // Initialize recorder
+  MetricsRecorder recorder("LanguageUsage.MostFrequentPageLanguages");
+  recorder.CheckTotalCount(0);
+
+  // Check that nothing is recorded if less than 10 page visits.
+  RecordPageLanguageVisits(url_hist, EN.code, 8);
+  RecordPageLanguageVisits(url_hist, ES.code, 1);
+  LanguageUsageMetrics::RecordPageLanguages(url_hist);
+  recorder.CheckTotalCount(0);
+
+  // Check that recording works at 10 page visits.
+  RecordPageLanguageVisits(url_hist, EN.code, 1);
+  LanguageUsageMetrics::RecordPageLanguages(url_hist);
+  recorder.CheckTotalCount(2);
+  recorder.CheckValueCount(EN.hash, 1);
+  recorder.CheckValueCount(ES.hash, 1);
+
+  // Check that languages with frequency below 0.05 are not recorded.
+  RecordPageLanguageVisits(url_hist, EN.code, 28);  // 37/40
+  RecordPageLanguageVisits(url_hist, ES.code, 1);   //  2/40 -> exactly 0.05
+  RecordPageLanguageVisits(url_hist, JP.code, 1);   //  1/40 -> below 0.05
+  LanguageUsageMetrics::RecordPageLanguages(url_hist);
+  recorder.CheckTotalCount(4);
+  recorder.CheckValueCount(EN.hash, 2);
+  recorder.CheckValueCount(ES.hash, 2);
+  recorder.CheckValueCount(JP.hash, 0);
+}
+
+TEST(LanguageUsageMetricsTest, RecordAcceptLanguages) {
+  const LanguageCodeHash EN("en", 25966);
+  const LanguageCodeHash ES("es", 25971);
+  const LanguageCodeHash JP("ja", 27233);
+
+  // Initialize recorders
+  MetricsRecorder recorder("LanguageUsage.AcceptLanguage");
+  MetricsRecorder recorder_count("LanguageUsage.AcceptLanguage.Count");
+  recorder.CheckTotalCount(0);
+  recorder_count.CheckTotalCount(0);
+
+  LanguageUsageMetrics::RecordAcceptLanguages("en");
+  LanguageUsageMetrics::RecordAcceptLanguages("en");
+  recorder.CheckTotalCount(2);
+  recorder.CheckValueCount(EN.hash, 2);
+  recorder_count.CheckTotalCount(2);
+  recorder_count.CheckValueCount(1, 2);
+
+  LanguageUsageMetrics::RecordAcceptLanguages("en,es");
+  recorder.CheckTotalCount(4);
+  recorder.CheckValueCount(EN.hash, 3);
+  recorder.CheckValueCount(ES.hash, 1);
+  recorder_count.CheckTotalCount(3);
+  recorder_count.CheckValueCount(1, 2);
+  recorder_count.CheckValueCount(2, 1);
+
+  LanguageUsageMetrics::RecordAcceptLanguages("en,es,ja-JP");
+  recorder.CheckTotalCount(7);
+  recorder.CheckTotalCount(7);
+  recorder.CheckValueCount(EN.hash, 4);
+  recorder.CheckValueCount(ES.hash, 2);
+  recorder.CheckValueCount(JP.hash, 1);
+  recorder_count.CheckTotalCount(4);
+  recorder_count.CheckValueCount(1, 2);
+  recorder_count.CheckValueCount(2, 1);
+  recorder_count.CheckValueCount(3, 1);
+}
+
+TEST(LanguageUsageMetricsTest, RecordApplicationLanguage) {
+  const LanguageCodeHash EN("en", 25966);
+  const LanguageCodeHash ES("es", 25971);
+
+  // Initialize recorder
+  MetricsRecorder recorder("LanguageUsage.ApplicationLanguage");
+
+  LanguageUsageMetrics::RecordApplicationLanguage("en");
+  LanguageUsageMetrics::RecordApplicationLanguage("en-US");
+  LanguageUsageMetrics::RecordApplicationLanguage("en-UK");
+  recorder.CheckTotalCount(3);
+  recorder.CheckValueCount(EN.hash, 3);
+
+  LanguageUsageMetrics::RecordApplicationLanguage("es");
+  LanguageUsageMetrics::RecordApplicationLanguage("es-ES");
+  LanguageUsageMetrics::RecordApplicationLanguage("es-419");
+  recorder.CheckTotalCount(6);
+  recorder.CheckValueCount(ES.hash, 3);
+}
+
 TEST(LanguageUsageMetricsTest, ParseAcceptLanguages) {
   std::set<int> language_set;
   std::set<int>::const_iterator it;
diff --git a/components/metrics/structured/structured_metrics_provider_unittest.cc b/components/metrics/structured/structured_metrics_provider_unittest.cc
index 07ddc2a9..44ec9ab 100644
--- a/components/metrics/structured/structured_metrics_provider_unittest.cc
+++ b/components/metrics/structured/structured_metrics_provider_unittest.cc
@@ -182,7 +182,7 @@
 TEST_F(StructuredMetricsProviderTest, EventsNotReportedWhenRecordingDisabled) {
   Init();
   OnRecordingDisabled();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
   EXPECT_EQ(GetProvidedEvents().structured_event_size(), 0);
   ExpectOnlyFileReadError();
 }
@@ -224,15 +224,15 @@
 TEST_F(StructuredMetricsProviderTest, RecordedEventAppearsInReport) {
   Init();
 
-  events::TestEventOne()
+  events::test_project_one::TestEventOne()
       .SetTestMetricOne("a string")
       .SetTestMetricTwo(12345)
       .Record();
-  events::TestEventOne()
+  events::test_project_one::TestEventOne()
       .SetTestMetricOne("a string")
       .SetTestMetricTwo(12345)
       .Record();
-  events::TestEventOne()
+  events::test_project_one::TestEventOne()
       .SetTestMetricOne("a string")
       .SetTestMetricTwo(12345)
       .Record();
@@ -245,11 +245,13 @@
   WriteTestingKeys();
   Init();
 
-  events::TestEventOne()
+  events::test_project_one::TestEventOne()
       .SetTestMetricOne(kValueOne)
       .SetTestMetricTwo(12345)
       .Record();
-  events::TestEventTwo().SetTestMetricThree(kValueTwo).Record();
+  events::test_project_two::TestEventTwo()
+      .SetTestMetricThree(kValueTwo)
+      .Record();
 
   const auto uma = GetProvidedEvents();
   ASSERT_EQ(uma.structured_event_size(), 2);
@@ -300,9 +302,9 @@
   WriteTestingKeys();
   Init();
 
-  events::TestEventOne().Record();
-  events::TestEventTwo().Record();
-  events::TestEventThree().Record();
+  events::test_project_one::TestEventOne().Record();
+  events::test_project_two::TestEventTwo().Record();
+  events::test_project_two::TestEventThree().Record();
 
   const auto uma = GetProvidedEvents();
   ASSERT_EQ(uma.structured_event_size(), 3);
@@ -331,15 +333,15 @@
 TEST_F(StructuredMetricsProviderTest, EventsClearedAfterReport) {
   Init();
 
-  events::TestEventOne().SetTestMetricTwo(1).Record();
-  events::TestEventOne().SetTestMetricTwo(2).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(2).Record();
   // Should provide both the previous events.
   EXPECT_EQ(GetProvidedEvents().structured_event_size(), 2);
 
   // But the previous events shouldn't appear in the second report.
   EXPECT_EQ(GetProvidedEvents().structured_event_size(), 0);
 
-  events::TestEventOne().SetTestMetricTwo(3).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(3).Record();
   // The third request should only contain the third event.
   EXPECT_EQ(GetProvidedEvents().structured_event_size(), 1);
 
@@ -351,7 +353,7 @@
 TEST_F(StructuredMetricsProviderTest, EventsFromPreviousSessionAreReported) {
   // Start first session and record one event.
   Init();
-  events::TestEventOne().SetTestMetricTwo(1234).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1234).Record();
 
   // Write events to disk, then destroy the provider.
   CommitPendingWrite();
@@ -372,15 +374,15 @@
 TEST_F(StructuredMetricsProviderTest, EventsNotRecordedBeforeInitialization) {
   // Manually create and initialize the provider, adding recording calls between
   // each step. All of these events should be ignored.
-  events::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
   provider_ = std::make_unique<StructuredMetricsProvider>();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
   OnRecordingEnabled();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
   OnProfileAdded(TempDirPath());
   // This one should still fail even though all of the initialization calls are
   // done, because the provider hasn't finished loading the keys from disk.
-  events::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
   Wait();
   EXPECT_EQ(GetProvidedEvents().structured_event_size(), 0);
 
@@ -393,10 +395,10 @@
 TEST_F(StructuredMetricsProviderTest,
        ExistingEventsClearedWhenRecordingDisabled) {
   Init();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
   OnRecordingDisabled();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
   EXPECT_EQ(GetProvidedEvents().structured_event_size(), 0);
 
   ExpectOnlyFileReadError();
@@ -406,14 +408,14 @@
 // and then enabled again.
 TEST_F(StructuredMetricsProviderTest, ReportingResumesWhenEnabled) {
   Init();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
   OnRecordingDisabled();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
 
   OnRecordingEnabled();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
   EXPECT_EQ(GetProvidedEvents().structured_event_size(), 2);
 
   ExpectOnlyFileReadError();
@@ -450,7 +452,7 @@
 
   // Initialize and trigger a migration by recording an event.
   Init();
-  events::TestEventOne().SetTestMetricTwo(1).Record();
+  events::test_project_one::TestEventOne().SetTestMetricTwo(1).Record();
   CommitPendingWrite();
 
   // Check that the new format has the structure:
diff --git a/components/omnibox/browser/autocomplete_match_android.cc b/components/omnibox/browser/autocomplete_match_android.cc
index 839376b0..48670edc 100644
--- a/components/omnibox/browser/autocomplete_match_android.cc
+++ b/components/omnibox/browser/autocomplete_match_android.cc
@@ -71,9 +71,10 @@
   ScopedJavaLocalRef<jobject> j_query_tiles =
       query_tiles::TileConversionBridge::CreateJavaTiles(env, query_tiles);
 
-  std::vector<base::string16> navsuggest_titles(navsuggest_tiles.size());
-  std::vector<base::android::ScopedJavaLocalRef<jobject>> navsuggest_urls(
-      navsuggest_tiles.size());
+  std::vector<base::string16> navsuggest_titles;
+  navsuggest_titles.reserve(navsuggest_tiles.size());
+  std::vector<base::android::ScopedJavaLocalRef<jobject>> navsuggest_urls;
+  navsuggest_urls.reserve(navsuggest_tiles.size());
   for (const auto& tile : navsuggest_tiles) {
     navsuggest_titles.push_back(tile.title);
     navsuggest_urls.push_back(url::GURLAndroid::FromNativeGURL(env, tile.url));
diff --git a/components/omnibox/browser/autocomplete_result_android.cc b/components/omnibox/browser/autocomplete_result_android.cc
index abe1667..7840eaba 100644
--- a/components/omnibox/browser/autocomplete_result_android.cc
+++ b/components/omnibox/browser/autocomplete_result_android.cc
@@ -33,8 +33,8 @@
 
   size_t index = 0;
   for (const auto& group_header : headers_map_) {
-    group_ids.push_back(group_header.first);
-    group_names.push_back(group_header.second);
+    group_ids[index] = group_header.first;
+    group_names[index] = group_header.second;
     group_collapsed_states[index] =
         base::Contains(hidden_group_ids_, group_header.first);
     ++index;
diff --git a/components/payments/content/payment_request.cc b/components/payments/content/payment_request.cc
index 86d0702..c5c8598 100644
--- a/components/payments/content/payment_request.cc
+++ b/components/payments/content/payment_request.cc
@@ -494,7 +494,7 @@
   // Failed transactions show an error. Successful and unknown-state
   // transactions don't show an error.
   if (result == mojom::PaymentComplete::FAIL) {
-    delegate_->ShowErrorMessage();
+    ShowErrorMessageAndAbortPayment();
   } else {
     DCHECK(!has_recorded_completion_);
     journey_logger_.SetCompleted();
@@ -768,9 +768,7 @@
   RecordFirstAbortReason(JourneyLogger::ABORT_REASON_INSTRUMENT_DETAILS_ERROR);
 
   reject_show_error_message_ = error_message;
-  delegate_->ShowErrorMessage();
-  // When the user dismisses the error message, UserCancelled() will reject
-  // PaymentRequest.show() with |reject_show_error_message_|.
+  ShowErrorMessageAndAbortPayment();
 }
 
 void PaymentRequest::OnShippingOptionIdSelected(
@@ -787,7 +785,7 @@
   client_->OnPayerDetailChange(std::move(payer_info));
 }
 
-void PaymentRequest::UserCancelled() {
+void PaymentRequest::OnUserCancelled() {
   // If |client_| is not bound, then the object is already being destroyed as
   // a result of a renderer event.
   if (!client_.is_bound())
@@ -827,8 +825,8 @@
   RecordFirstAbortReason(JourneyLogger::ABORT_REASON_ABORTED_BY_USER);
   // But don't bother sending errors to |client_| because the mojo pipe will be
   // torn down anyways when RenderFrameHost is destroyed. It's not safe to call
-  // UserCancelled() here because it is not re-entrant.
-  // TODO(crbug.com/1121841) Make UserCancelled re-entrant.
+  // OnUserCancelled() here because it is not re-entrant.
+  // TODO(crbug.com/1121841) Make OnUserCancelled re-entrant.
   TerminateConnection();
 }
 
@@ -969,4 +967,18 @@
   }
 }
 
+void PaymentRequest::ShowErrorMessageAndAbortPayment() {
+  // Note that both branches of the if-else will invoke the OnUserCancelled()
+  // method.
+  if (display_handle_ && display_handle_->was_shown()) {
+    // Will invoke OnUserCancelled() asynchronously when the user closes the
+    // error message UI.
+    delegate_->ShowErrorMessage();
+  } else {
+    // Only app store billing apps do not display any browser payment UI.
+    DCHECK(spec_->IsAppStoreBillingAlsoRequested());
+    OnUserCancelled();
+  }
+}
+
 }  // namespace payments
diff --git a/components/payments/content/payment_request.h b/components/payments/content/payment_request.h
index e218b69d7..cb2230b1 100644
--- a/components/payments/content/payment_request.h
+++ b/components/payments/content/payment_request.h
@@ -106,7 +106,7 @@
   // Called when the user explicitly cancelled the flow. Will send a message
   // to the renderer which will indirectly destroy this object (through
   // TerminateConnection).
-  void UserCancelled();
+  void OnUserCancelled();
 
   // Called when the main frame attached to this PaymentRequest is navigating to
   // another document, but before the PaymentRequest is destroyed.
@@ -204,6 +204,9 @@
 
   void OnAbortResult(bool aborted);
 
+  // Show an error message in the UI (if available) and abort payment.
+  void ShowErrorMessageAndAbortPayment();
+
   const content::GlobalFrameRoutingId initiator_frame_routing_id_;
   DeveloperConsoleLogger log_;
   std::unique_ptr<ContentPaymentRequestDelegate> delegate_;
diff --git a/components/payments/content/secure_payment_confirmation_controller.cc b/components/payments/content/secure_payment_confirmation_controller.cc
index 2b96947a..c84508a 100644
--- a/components/payments/content/secure_payment_confirmation_controller.cc
+++ b/components/payments/content/secure_payment_confirmation_controller.cc
@@ -182,7 +182,7 @@
     return;
 
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&PaymentRequest::UserCancelled, request_));
+      FROM_HERE, base::BindOnce(&PaymentRequest::OnUserCancelled, request_));
 }
 
 void SecurePaymentConfirmationController::OnConfirm() {
diff --git a/components/safe_browsing/content/password_protection/mock_password_protection_service.h b/components/safe_browsing/content/password_protection/mock_password_protection_service.h
index fe58918..2ebf3f1 100644
--- a/components/safe_browsing/content/password_protection/mock_password_protection_service.h
+++ b/components/safe_browsing/content/password_protection/mock_password_protection_service.h
@@ -52,7 +52,8 @@
   MOCK_METHOD0(IsUnderAdvancedProtection, bool());
   MOCK_METHOD0(IsInExcludedCountry, bool());
   MOCK_METHOD0(ReportPasswordChanged, void());
-  MOCK_METHOD1(UserClickedThroughSBInterstitial, bool(content::WebContents*));
+  MOCK_METHOD1(UserClickedThroughSBInterstitial,
+               bool(PasswordProtectionRequest*));
   MOCK_METHOD1(MaybeLogPasswordReuseDetectedEvent, void(content::WebContents*));
   MOCK_METHOD1(SanitizeReferrerChain, void(ReferrerChain*));
   MOCK_METHOD2(ShowInterstitial,
diff --git a/components/safe_browsing/content/password_protection/password_protection_request.cc b/components/safe_browsing/content/password_protection/password_protection_request.cc
index 538b0ea..3f637f6e 100644
--- a/components/safe_browsing/content/password_protection/password_protection_request.cc
+++ b/components/safe_browsing/content/password_protection/password_protection_request.cc
@@ -255,8 +255,7 @@
       password_protection_service_->GetStoredVerdictCount(trigger_type_));
 
   bool clicked_through_interstitial =
-      password_protection_service_->UserClickedThroughSBInterstitial(
-          web_contents_);
+      password_protection_service_->UserClickedThroughSBInterstitial(this);
   request_proto_->set_clicked_through_interstitial(
       clicked_through_interstitial);
   request_proto_->set_content_type(web_contents_->GetContentsMimeType());
diff --git a/components/safe_browsing/content/password_protection/password_protection_service.h b/components/safe_browsing/content/password_protection/password_protection_service.h
index 216823e..6a12835 100644
--- a/components/safe_browsing/content/password_protection/password_protection_service.h
+++ b/components/safe_browsing/content/password_protection/password_protection_service.h
@@ -181,10 +181,10 @@
   // (6) Its hostname is a dotless domain.
   static bool CanGetReputationOfURL(const GURL& url);
 
-  // If user has clicked through any Safe Browsing interstitial on this given
-  // |web_contents|.
+  // If user has clicked through any Safe Browsing interstitial for |request|'s
+  // web contents.
   virtual bool UserClickedThroughSBInterstitial(
-      content::WebContents* web_contents) = 0;
+      PasswordProtectionRequest* request) = 0;
 
   // Called when a new navigation is starting. Create throttle if there is a
   // pending sync password reuse ping or if there is a modal warning dialog
diff --git a/components/storage_monitor/storage_monitor_linux.h b/components/storage_monitor/storage_monitor_linux.h
index d6748153c..02ac626 100644
--- a/components/storage_monitor/storage_monitor_linux.h
+++ b/components/storage_monitor/storage_monitor_linux.h
@@ -20,7 +20,6 @@
 
 #include "base/compiler_specific.h"
 #include "base/files/file_path.h"
-#include "base/files/file_path_watcher.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index db2f628..ea1395c 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1488,8 +1488,6 @@
     "renderer_host/render_frame_host_impl.h",
     "renderer_host/render_frame_host_manager.cc",
     "renderer_host/render_frame_host_manager.h",
-    "renderer_host/render_frame_message_filter.cc",
-    "renderer_host/render_frame_message_filter.h",
     "renderer_host/render_frame_metadata_provider_impl.cc",
     "renderer_host/render_frame_metadata_provider_impl.h",
     "renderer_host/render_frame_proxy_host.cc",
@@ -2369,6 +2367,8 @@
       "renderer_host/pepper/quota_reservation.h",
       "renderer_host/plugin_registry_impl.cc",
       "renderer_host/plugin_registry_impl.h",
+      "renderer_host/render_frame_message_filter.cc",
+      "renderer_host/render_frame_message_filter.h",
     ]
     deps += [
       "//ppapi/host",
diff --git a/content/browser/accessibility/accessibility_win_browsertest.cc b/content/browser/accessibility/accessibility_win_browsertest.cc
index 5765295c..d4ede28 100644
--- a/content/browser/accessibility/accessibility_win_browsertest.cc
+++ b/content/browser/accessibility/accessibility_win_browsertest.cc
@@ -913,7 +913,7 @@
   // the "kLoadComplete" event, and the "kFocus" and "kLoadComplete" events are
   // not guaranteed to be sent in the same order every time, neither do we need
   // to enforce such an ordering. However, we do need to ensure that at the
-  // point when the "kFocus" event is sent, the document is fully loaded.
+  // point when the "kFocus" event is sent, the root object is present.
   AccessibilityNotificationWaiter waiter(
       shell()->web_contents(), ui::kAXModeComplete,
       ui::AXEventGenerator::Event::FOCUS_CHANGED);
@@ -921,14 +921,15 @@
   ASSERT_TRUE(NavigateToURL(shell(), html_data_url));
   waiter.WaitForNotification();
 
-  // Check that the page has indeed loaded.
-  AccessibleChecker document_checker(L"", ROLE_SYSTEM_DOCUMENT, L"");
-  AccessibleChecker paragraph_checker(L"", ROLE_SYSTEM_GROUPING,
-                                      IA2_ROLE_PARAGRAPH, L"");
-  document_checker.AppendExpectedChild(&paragraph_checker);
-  AccessibleChecker text_checker(L"Hello world.", ROLE_SYSTEM_STATICTEXT, L"");
-  paragraph_checker.AppendExpectedChild(&text_checker);
-  document_checker.CheckAccessible(GetRendererAccessible());
+  // Check that at least the root of the page has indeed loaded and that it is
+  // focused.
+  Microsoft::WRL::ComPtr<IAccessible> document(GetRendererAccessible());
+  ASSERT_TRUE(document);
+  base::win::ScopedVariant focus;
+  base::win::ScopedVariant childid_self(CHILDID_SELF);
+  ASSERT_HRESULT_SUCCEEDED(document->get_accFocus(focus.Receive()));
+  EXPECT_EQ(VT_I4, focus.type());
+  EXPECT_EQ(CHILDID_SELF, V_I4(focus.ptr()));
 }
 
 IN_PROC_BROWSER_TEST_F(AccessibilityWinBrowserTest, TestBusyAccessibilityTree) {
diff --git a/content/browser/accessibility/browser_accessibility_cocoa.mm b/content/browser/accessibility/browser_accessibility_cocoa.mm
index 89064cb408..8d2b44c 100644
--- a/content/browser/accessibility/browser_accessibility_cocoa.mm
+++ b/content/browser/accessibility/browser_accessibility_cocoa.mm
@@ -3798,6 +3798,16 @@
   }
 }
 
+- (id)accessibilityFocusedUIElement {
+  TRACE_EVENT1("accessibility",
+               "BrowserAccessibilityCocoa::accessibilityFocusedUIElement",
+               "role=", ui::ToString([self internalRole]));
+  if (![self instanceActive])
+    return nil;
+
+  return ToBrowserAccessibilityCocoa(_owner->manager()->GetFocus());
+}
+
 // Returns the deepest accessibility child that should not be ignored.
 // It is assumed that the hit test has been narrowed down to this object
 // or one of its children, so this will never return nil unless this
diff --git a/content/browser/accessibility/browser_accessibility_manager.cc b/content/browser/accessibility/browser_accessibility_manager.cc
index 05cec91..296773e 100644
--- a/content/browser/accessibility/browser_accessibility_manager.cc
+++ b/content/browser/accessibility/browser_accessibility_manager.cc
@@ -274,19 +274,6 @@
       return;
   }
 
-  // Don't allow the top document to be focused if it has no children and hasn't
-  // finished loading yet. Wait for at least a tiny bit of content, or for the
-  // document to actually finish loading.
-  // Even after the document has loaded, we shouldn't fire a focus event if the
-  // document is completely empty, otherwise the user will be placed inside an
-  // empty container. This would result in user confusion, since none of the
-  // screen reader commands will read anything.
-  if (focus == focus->manager()->GetRoot() &&
-      (focus->PlatformChildCount() == 0 ||
-       !focus->manager()->GetTreeData().loaded)) {
-    return;
-  }
-
   // Wait until navigation is complete or stopped, before attempting to move the
   // accessibility focus.
   if (user_is_navigating_away_)
diff --git a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
index 790d1a2..bbbbda31 100644
--- a/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
+++ b/content/browser/accessibility/dump_accessibility_tree_browsertest.cc
@@ -1359,12 +1359,12 @@
   RunHtmlTest(FILE_PATH_LITERAL("bounds-absolute.html"));
 }
 
-IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessiblitiyBoundsFixed) {
+IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest, AccessibilityBoundsFixed) {
   RunHtmlTest(FILE_PATH_LITERAL("bounds-fixed.html"));
 }
 
 IN_PROC_BROWSER_TEST_P(DumpAccessibilityTreeTest,
-                       AccessiblitiyBoundsFixedScrolling) {
+                       AccessibilityBoundsFixedScrolling) {
   RunHtmlTest(FILE_PATH_LITERAL("bounds-fixed-scrolling.html"));
 }
 
diff --git a/content/browser/network_service_restart_browsertest.cc b/content/browser/network_service_restart_browsertest.cc
index 412cbcc..58458bf2 100644
--- a/content/browser/network_service_restart_browsertest.cc
+++ b/content/browser/network_service_restart_browsertest.cc
@@ -19,7 +19,6 @@
 #include "build/build_config.h"
 #include "content/browser/network_service_instance_impl.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
-#include "content/browser/renderer_host/render_frame_message_filter.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
 #include "content/browser/service_worker/embedded_worker_instance.h"
 #include "content/browser/service_worker/embedded_worker_status.h"
diff --git a/content/browser/renderer_host/cookie_browsertest.cc b/content/browser/renderer_host/cookie_browsertest.cc
index f80f027..3f80eb0 100644
--- a/content/browser/renderer_host/cookie_browsertest.cc
+++ b/content/browser/renderer_host/cookie_browsertest.cc
@@ -15,7 +15,6 @@
 #include "base/test/scoped_feature_list.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/renderer_host/frame_tree.h"
-#include "content/browser/renderer_host/render_frame_message_filter.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/public/browser/browser_context.h"
diff --git a/content/browser/renderer_host/navigation_controller_impl.cc b/content/browser/renderer_host/navigation_controller_impl.cc
index 9eb91c2..1d8a595 100644
--- a/content/browser/renderer_host/navigation_controller_impl.cc
+++ b/content/browser/renderer_host/navigation_controller_impl.cc
@@ -1070,7 +1070,8 @@
   // Set the replacement bit here and ClassifyNavigation will identify this
   // case and return NEW_PAGE.
   if (!rfh->GetParent() && pending_entry_ &&
-      pending_entry_->GetUniqueID() == params.nav_entry_id &&
+      pending_entry_->GetUniqueID() ==
+          navigation_request->commit_params().nav_entry_id &&
       pending_entry_->site_instance() &&
       pending_entry_->site_instance() != rfh->GetSiteInstance()) {
     DCHECK_NE(-1, pending_entry_index_);
@@ -1086,7 +1087,7 @@
   }
 
   // Do navigation-type specific actions. These will make and commit an entry.
-  details->type = ClassifyNavigation(rfh, params);
+  details->type = ClassifyNavigation(rfh, params, navigation_request);
 
   // is_same_document must be computed before the entry gets committed.
   details->is_same_document = is_same_document_navigation;
@@ -1242,7 +1243,8 @@
 
 NavigationType NavigationControllerImpl::ClassifyNavigation(
     RenderFrameHostImpl* rfh,
-    const mojom::DidCommitProvisionalLoadParams& params) {
+    const mojom::DidCommitProvisionalLoadParams& params,
+    NavigationRequest* navigation_request) {
   TraceReturnReason<tracing_category::kNavigation> trace_return(
       "ClassifyNavigation");
 
@@ -1286,7 +1288,8 @@
     return NAVIGATION_TYPE_NAV_IGNORE;
   }
 
-  if (params.nav_entry_id == 0) {
+  const int nav_entry_id = navigation_request->commit_params().nav_entry_id;
+  if (nav_entry_id == 0) {
     // This is a renderer-initiated navigation (nav_entry_id == 0), but didn't
     // create a new page.
 
@@ -1309,7 +1312,7 @@
     return NAVIGATION_TYPE_EXISTING_PAGE;
   }
 
-  if (pending_entry_ && pending_entry_->GetUniqueID() == params.nav_entry_id) {
+  if (pending_entry_ && pending_entry_->GetUniqueID() == nav_entry_id) {
     // If the SiteInstance of the |pending_entry_| does not match the
     // SiteInstance that got committed, treat this as a new navigation with
     // replacement. This can happen if back/forward/reload encounters a server
@@ -1361,7 +1364,7 @@
   }
 
   if (params.url_is_unreachable && failed_pending_entry_id_ != 0 &&
-      params.nav_entry_id == failed_pending_entry_id_) {
+      nav_entry_id == failed_pending_entry_id_) {
     // If the renderer was going to a new pending entry that got cleared because
     // of an error, this is the case of the user trying to retry a failed load
     // by pressing return. Classify as EXISTING_PAGE because we probably don't
@@ -1372,7 +1375,7 @@
   }
 
   // Now we know that the notification is for an existing page. Find that entry.
-  int existing_entry_index = GetEntryIndexWithUniqueID(params.nav_entry_id);
+  int existing_entry_index = GetEntryIndexWithUniqueID(nav_entry_id);
   trace_return.traced_value()->SetInteger("existing_entry_index",
                                           existing_entry_index);
   if (existing_entry_index == -1) {
@@ -1562,7 +1565,7 @@
   // process, then it should be the one replaced, so update the
   // last_committed_entry_index_ to use it.
   if (replace_entry && pending_entry_index_ != -1 &&
-      pending_entry_->GetUniqueID() == params.nav_entry_id) {
+      pending_entry_->GetUniqueID() == request->commit_params().nav_entry_id) {
     last_committed_entry_index_ = pending_entry_index_;
   }
 
@@ -1614,9 +1617,9 @@
             has_cert);
       }
     }
-  } else if (params.nav_entry_id) {
+  } else if (const int nav_entry_id = request->commit_params().nav_entry_id) {
     // This is a browser-initiated navigation (back/forward/reload).
-    entry = GetEntryWithUniqueID(params.nav_entry_id);
+    entry = GetEntryWithUniqueID(nav_entry_id);
 
     if (is_same_document) {
       // There's no SSLStatus in the NavigationRequest for same document
@@ -1769,7 +1772,8 @@
   // We assign the entry's unique ID to be that of the new one. Since this is
   // always the result of a user action, we want to dismiss infobars, etc. like
   // a regular user-initiated navigation.
-  DCHECK_EQ(pending_entry_->GetUniqueID(), params.nav_entry_id);
+  DCHECK_EQ(pending_entry_->GetUniqueID(),
+            request->commit_params().nav_entry_id);
   existing_entry->set_unique_id(pending_entry_->GetUniqueID());
 
   // The URL may have changed due to redirects.
@@ -1886,12 +1890,12 @@
   // This is only necessary for history navigations in subframes.
   bool send_commit_notification = false;
 
-  // If the |nav_entry_id| is non-zero and matches an existing entry, this is
-  // a history navigation.  Update the last committed index accordingly.
-  // If we don't recognize the |nav_entry_id|, it might be a recently pruned
-  // entry.  We'll handle it below.
-  if (params.nav_entry_id) {
-    int entry_index = GetEntryIndexWithUniqueID(params.nav_entry_id);
+  // If |nav_entry_id| is non-zero and matches an existing entry, this
+  // is a history navigation.  Update the last committed index accordingly. If
+  // we don't recognize the |nav_entry_id|, it might be a recently
+  // pruned entry.  We'll handle it below.
+  if (const int nav_entry_id = request->commit_params().nav_entry_id) {
+    int entry_index = GetEntryIndexWithUniqueID(nav_entry_id);
     if (entry_index != -1 && entry_index != last_committed_entry_index_) {
       // Make sure that a subframe commit isn't changing the main frame's
       // origin. Otherwise the renderer process may be confused, leading to a
diff --git a/content/browser/renderer_host/navigation_controller_impl.h b/content/browser/renderer_host/navigation_controller_impl.h
index 296375f5..97bf101ba 100644
--- a/content/browser/renderer_host/navigation_controller_impl.h
+++ b/content/browser/renderer_host/navigation_controller_impl.h
@@ -476,7 +476,8 @@
   // Classifies the given renderer navigation (see the NavigationType enum).
   NavigationType ClassifyNavigation(
       RenderFrameHostImpl* rfh,
-      const mojom::DidCommitProvisionalLoadParams& params);
+      const mojom::DidCommitProvisionalLoadParams& params,
+      NavigationRequest* navigation_request);
 
   // Handlers for the different types of navigation types. They will actually
   // handle the navigations corresponding to the different NavClasses above.
diff --git a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
index fc3a55a..b98f4eb2 100644
--- a/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_browsertest.cc
@@ -4226,8 +4226,8 @@
   NavigationControllerImpl& new_controller =
       static_cast<NavigationControllerImpl&>(
           new_shell->web_contents()->GetController());
-  new_controller.Restore(entries.size() - 1,
-                         RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  new_controller.Restore(entries.size() - 1, RestoreType::LAST_SESSION,
+                         &entries);
   ASSERT_EQ(0u, entries.size());
   {
     TestNavigationObserver restore_observer(new_shell->web_contents());
@@ -4281,8 +4281,7 @@
   // content injected into it.
   std::vector<std::unique_ptr<NavigationEntry>> entries;
   entries.push_back(std::move(restored_entry));
-  controller.Restore(entries.size() - 1,
-                     RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  controller.Restore(entries.size() - 1, RestoreType::LAST_SESSION, &entries);
   ASSERT_EQ(0u, entries.size());
   {
     TestNavigationObserver restore_observer(shell()->web_contents());
@@ -5236,8 +5235,8 @@
   NavigationControllerImpl& new_controller =
       static_cast<NavigationControllerImpl&>(
           new_shell->web_contents()->GetController());
-  new_controller.Restore(entries.size() - 1,
-                         RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  new_controller.Restore(entries.size() - 1, RestoreType::LAST_SESSION,
+                         &entries);
   ASSERT_EQ(0u, entries.size());
   {
     TestNavigationObserver restore_observer(new_shell->web_contents());
@@ -8709,7 +8708,6 @@
   // call. The browser doesn't know about the navigation at all previously.
   GURL bad_url(embedded_test_server()->GetURL("/title2.html"));
   auto params = mojom::DidCommitProvisionalLoadParams::New();
-  params->nav_entry_id = 0;
   params->did_create_new_entry = true;
   params->url = bad_url;
   params->referrer = blink::mojom::Referrer::New();
diff --git a/content/browser/renderer_host/navigation_controller_impl_unittest.cc b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
index ebf56c7..1f9185a6 100644
--- a/content/browser/renderer_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_controller_impl_unittest.cc
@@ -2273,7 +2273,6 @@
   // First navigation (using location.replace).
   const GURL url2("http://foo#a");
   auto params = mojom::DidCommitProvisionalLoadParams::New();
-  params->nav_entry_id = 0;
   params->did_create_new_entry = false;
   params->should_replace_current_entry = true;
   params->url = url2;
@@ -2298,7 +2297,6 @@
   ASSERT_FALSE(controller_impl().GetLastCommittedEntry());
   GURL url("http://foo");
   auto params = mojom::DidCommitProvisionalLoadParams::New();
-  params->nav_entry_id = 0;
   params->did_create_new_entry = true;
   params->url = url;
   params->referrer = blink::mojom::Referrer::New();
@@ -2375,13 +2373,13 @@
   WebContentsImpl* raw_our_contents =
       static_cast<WebContentsImpl*>(our_contents.get());
   NavigationControllerImpl& our_controller = raw_our_contents->GetController();
-  our_controller.Restore(0, RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  our_controller.Restore(0, RestoreType::LAST_SESSION, &entries);
   ASSERT_EQ(0u, entries.size());
 
   // Before navigating to the restored entry, it should have a restore_type
   // and no SiteInstance.
   ASSERT_EQ(1, our_controller.GetEntryCount());
-  EXPECT_EQ(RestoreType::LAST_SESSION_EXITED_CLEANLY,
+  EXPECT_EQ(RestoreType::LAST_SESSION,
             our_controller.GetEntryAtIndex(0)->restore_type());
   EXPECT_FALSE(our_controller.GetEntryAtIndex(0)->site_instance());
 
@@ -2441,7 +2439,7 @@
   WebContentsImpl* raw_our_contents =
       static_cast<WebContentsImpl*>(our_contents.get());
   NavigationControllerImpl& our_controller = raw_our_contents->GetController();
-  our_controller.Restore(0, RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  our_controller.Restore(0, RestoreType::LAST_SESSION, &entries);
   ASSERT_EQ(0u, entries.size());
 
   // Ensure the RenderFrame is initialized before simulating events coming from
@@ -2450,7 +2448,7 @@
 
   // Before navigating to the restored entry, it should have a restore_type
   // and no SiteInstance.
-  EXPECT_EQ(RestoreType::LAST_SESSION_EXITED_CLEANLY,
+  EXPECT_EQ(RestoreType::LAST_SESSION,
             our_controller.GetEntryAtIndex(0)->restore_type());
   EXPECT_FALSE(our_controller.GetEntryAtIndex(0)->site_instance());
 
@@ -2998,7 +2996,6 @@
 
   // Doing a replaceState to a cross-origin URL is thus allowed.
   auto params = mojom::DidCommitProvisionalLoadParams::New();
-  params->nav_entry_id = 1;
   params->did_create_new_entry = false;
   params->url = different_origin_url;
   params->referrer = blink::mojom::Referrer::New();
@@ -3494,8 +3491,8 @@
   EXPECT_EQ(url2b, other_controller.GetPendingEntry()->GetURL());
 
   // Let the pending entry commit.
-  other_contents->TestDidNavigate(other_contents->GetMainFrame(), 0, false,
-                                  url2b, ui::PAGE_TRANSITION_LINK);
+  other_contents->TestDidNavigate(other_contents->GetMainFrame(), false, url2b,
+                                  ui::PAGE_TRANSITION_LINK);
 }
 
 // Test CopyStateFromAndPrune with 2 urls, a back navigation pending in the
@@ -3733,8 +3730,8 @@
       static_cast<TestWebContents*>(CreateTestWebContents().release()));
   NavigationControllerImpl& source_controller =
       source_contents->GetController();
-  source_controller.Restore(entries.size() - 1,
-                            RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  source_controller.Restore(entries.size() - 1, RestoreType::LAST_SESSION,
+                            &entries);
   ASSERT_EQ(0u, entries.size());
   source_controller.LoadIfNecessary();
   source_contents->CommitPendingNavigation();
@@ -4049,7 +4046,6 @@
   // history.pushState() is called.
   auto params = mojom::DidCommitProvisionalLoadParams::New();
   GURL kUrl2("http://foo#foo");
-  params->nav_entry_id = 0;
   params->did_create_new_entry = true;
   params->url = kUrl2;
   params->referrer = blink::mojom::Referrer::New();
diff --git a/content/browser/renderer_host/navigation_entry_impl_unittest.cc b/content/browser/renderer_host/navigation_entry_impl_unittest.cc
index 80a7cd5..3d4e6f8 100644
--- a/content/browser/renderer_host/navigation_entry_impl_unittest.cc
+++ b/content/browser/renderer_host/navigation_entry_impl_unittest.cc
@@ -272,8 +272,8 @@
   EXPECT_FALSE(entry1_->IsRestored());
   EXPECT_EQ(RestoreType::NONE, entry2_->restore_type());
   EXPECT_FALSE(entry2_->IsRestored());
-  entry2_->set_restore_type(RestoreType::LAST_SESSION_EXITED_CLEANLY);
-  EXPECT_EQ(RestoreType::LAST_SESSION_EXITED_CLEANLY, entry2_->restore_type());
+  entry2_->set_restore_type(RestoreType::LAST_SESSION);
+  EXPECT_EQ(RestoreType::LAST_SESSION, entry2_->restore_type());
   EXPECT_TRUE(entry2_->IsRestored());
 
   // Original URL
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index 3c02c38..04873f3a 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -4648,7 +4648,6 @@
   params->should_replace_current_entry =
       common_params().should_replace_current_entry;
   DCHECK_EQ(params->post_id, -1);
-  params->nav_entry_id = commit_params().nav_entry_id;
   params->navigation_token = commit_params().navigation_token;
   params->did_create_new_entry = false;
   DCHECK_EQ(params->origin, commit_params().origin_to_commit.value());
diff --git a/content/browser/renderer_host/navigator.cc b/content/browser/renderer_host/navigator.cc
index bddf1891..969037c 100644
--- a/content/browser/renderer_host/navigator.cc
+++ b/content/browser/renderer_host/navigator.cc
@@ -68,8 +68,7 @@
         is_browser_initiated_before_unload_(
             is_browser_initiated_before_unload) {
     is_restoring_from_last_session_ =
-        (restore_type == RestoreType::LAST_SESSION_EXITED_CLEANLY ||
-         restore_type == RestoreType::LAST_SESSION_CRASHED);
+        (restore_type == RestoreType::LAST_SESSION);
   }
 
   base::TimeTicks start_time_;
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 9cefacd..d2ca1f6 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -8867,7 +8867,6 @@
           ->GetProcessLock(agent_scheduling_group_.GetProcess()->GetID())
           .ToString());
 
-  value->SetInteger("nav_entry_id", params.nav_entry_id);
   value->SetInteger("item_sequence_number", params.item_sequence_number);
   value->SetInteger("document_sequence_number",
                     params.document_sequence_number);
diff --git a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
index ffd8470..1526222 100644
--- a/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_browsertest.cc
@@ -3004,8 +3004,8 @@
   NavigationControllerImpl& new_controller =
       static_cast<NavigationControllerImpl&>(
           new_shell->web_contents()->GetController());
-  new_controller.Restore(entries.size() - 1,
-                         RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  new_controller.Restore(entries.size() - 1, RestoreType::LAST_SESSION,
+                         &entries);
   ASSERT_EQ(0u, entries.size());
   {
     TestNavigationObserver restore_observer(new_shell->web_contents());
diff --git a/content/browser/renderer_host/render_frame_host_manager_unittest.cc b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
index ad091b1..11ec2e8 100644
--- a/content/browser/renderer_host/render_frame_host_manager_unittest.cc
+++ b/content/browser/renderer_host/render_frame_host_manager_unittest.cc
@@ -2544,7 +2544,7 @@
           std::string(), browser_context(),
           nullptr /* blob_url_loader_factory */);
   entries.push_back(std::move(new_entry));
-  controller.Restore(0, RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  controller.Restore(0, RestoreType::LAST_SESSION, &entries);
   ASSERT_EQ(0u, entries.size());
   ASSERT_EQ(1, controller.GetEntryCount());
 
@@ -2558,7 +2558,7 @@
       nullptr /* instance */, kInitUrl, Referrer(), base::nullopt,
       base::string16() /* title */, ui::PAGE_TRANSITION_RELOAD,
       false /* is_renderer_init */, nullptr /* blob_url_loader_factory */);
-  entry.set_restore_type(RestoreType::LAST_SESSION_EXITED_CLEANLY);
+  entry.set_restore_type(RestoreType::LAST_SESSION);
   NavigateToEntry(manager, &entry);
 
   // As the initial renderer was not live, the new RenderFrameHost should be
diff --git a/content/browser/renderer_host/render_frame_message_filter.cc b/content/browser/renderer_host/render_frame_message_filter.cc
index 69a2f4b..9cc3d07 100644
--- a/content/browser/renderer_host/render_frame_message_filter.cc
+++ b/content/browser/renderer_host/render_frame_message_filter.cc
@@ -13,22 +13,22 @@
 #include "build/build_config.h"
 #include "content/browser/bad_message.h"
 #include "content/browser/child_process_security_policy_impl.h"
-#include "content/browser/renderer_host/render_widget_helper.h"
+#include "content/browser/plugin_service_impl.h"
+#include "content/browser/ppapi_plugin_process_host.h"
 #include "content/common/frame_messages.h"
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/plugin_service_filter.h"
 #include "content/public/browser/resource_context.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_constants.h"
-#include "ppapi/buildflags/buildflags.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
-#if BUILDFLAG(ENABLE_PLUGINS)
-#include "content/browser/plugin_service_impl.h"
-#include "content/browser/ppapi_plugin_process_host.h"
-#include "content/public/browser/plugin_service_filter.h"
+#if !BUILDFLAG(ENABLE_PLUGINS)
+#error "RenderFrameMessageFilter is only used for plugin builds."
 #endif
 
 namespace content {
@@ -70,8 +70,6 @@
 
 }  // namespace
 
-#if BUILDFLAG(ENABLE_PLUGINS)
-
 class RenderFrameMessageFilter::OpenChannelToPpapiPluginCallback
     : public RenderMessageCompletionCallback,
       public PpapiPluginProcessHost::PluginClient {
@@ -100,38 +98,25 @@
   bool Incognito() override { return filter()->incognito_; }
 };
 
-#endif  // ENABLE_PLUGINS
-
 RenderFrameMessageFilter::RenderFrameMessageFilter(
     int render_process_id,
     PluginServiceImpl* plugin_service,
     BrowserContext* browser_context,
-    StoragePartition* storage_partition,
-    RenderWidgetHelper* render_widget_helper)
+    StoragePartition* storage_partition)
     : BrowserMessageFilter(FrameMsgStart),
-#if BUILDFLAG(ENABLE_PLUGINS)
       plugin_service_(plugin_service),
       profile_data_directory_(storage_partition->GetPath()),
-#endif  // ENABLE_PLUGINS
-      resource_context_(browser_context->GetResourceContext()),
-      render_widget_helper_(render_widget_helper),
       incognito_(browser_context->IsOffTheRecord()),
-      render_process_id_(render_process_id) {
-}
+      render_process_id_(render_process_id) {}
 
 RenderFrameMessageFilter::~RenderFrameMessageFilter() {
   // This function should be called on the IO thread.
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 }
 
-void RenderFrameMessageFilter::ClearResourceContext() {
-  resource_context_ = nullptr;
-}
-
 bool RenderFrameMessageFilter::OnMessageReceived(const IPC::Message& message) {
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(RenderFrameMessageFilter, message)
-#if BUILDFLAG(ENABLE_PLUGINS)
     IPC_MESSAGE_HANDLER(FrameHostMsg_GetPluginInfo, OnGetPluginInfo)
     IPC_MESSAGE_HANDLER_DELAY_REPLY(FrameHostMsg_OpenChannelToPepperPlugin,
                                     OnOpenChannelToPepperPlugin)
@@ -139,7 +124,6 @@
                         OnDidCreateOutOfProcessPepperInstance)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidDeleteOutOfProcessPepperInstance,
                         OnDidDeleteOutOfProcessPepperInstance)
-#endif  // ENABLE_PLUGINS
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
 
@@ -153,14 +137,10 @@
 void RenderFrameMessageFilter::OverrideThreadForMessage(
     const IPC::Message& message,
     BrowserThread::ID* thread) {
-#if BUILDFLAG(ENABLE_PLUGINS)
   if (message.type() == FrameHostMsg_GetPluginInfo::ID)
     *thread = BrowserThread::UI;
-#endif  // ENABLE_PLUGINS
 }
 
-#if BUILDFLAG(ENABLE_PLUGINS)
-
 void RenderFrameMessageFilter::OnGetPluginInfo(
     int render_frame_id,
     const GURL& url,
@@ -238,6 +218,4 @@
   }
 }
 
-#endif  // ENABLE_PLUGINS
-
 }  // namespace content
diff --git a/content/browser/renderer_host/render_frame_message_filter.h b/content/browser/renderer_host/render_frame_message_filter.h
index ff2ee230..100c3936 100644
--- a/content/browser/renderer_host/render_frame_message_filter.h
+++ b/content/browser/renderer_host/render_frame_message_filter.h
@@ -12,6 +12,7 @@
 
 #include "base/optional.h"
 #include "content/common/frame_replication_state.h"
+#include "content/common/pepper_renderer_instance_data.h"
 #include "content/public/browser/browser_associated_interface.h"
 #include "content/public/browser/browser_message_filter.h"
 #include "ppapi/buildflags/buildflags.h"
@@ -20,8 +21,8 @@
 #include "third_party/blink/public/mojom/frame/tree_scope_type.mojom.h"
 #include "url/origin.h"
 
-#if BUILDFLAG(ENABLE_PLUGINS)
-#include "content/common/pepper_renderer_instance_data.h"
+#if !BUILDFLAG(ENABLE_PLUGINS)
+#error "RenderFrameMessageFilter is only used for plugin builds."
 #endif
 
 class GURL;
@@ -33,8 +34,6 @@
 namespace content {
 class BrowserContext;
 class PluginServiceImpl;
-class RenderWidgetHelper;
-class ResourceContext;
 class StoragePartition;
 struct WebPluginInfo;
 
@@ -49,8 +48,7 @@
   RenderFrameMessageFilter(int render_process_id,
                            PluginServiceImpl* plugin_service,
                            BrowserContext* browser_context,
-                           StoragePartition* storage_partition,
-                           RenderWidgetHelper* render_widget_helper);
+                           StoragePartition* storage_partition);
 
   // BrowserMessageFilter methods:
   bool OnMessageReceived(const IPC::Message& message) override;
@@ -58,21 +56,14 @@
   void OverrideThreadForMessage(const IPC::Message& message,
                                 BrowserThread::ID* thread) override;
 
-  // Clears |resource_context_| to prevent accessing it after deletion.
-  void ClearResourceContext();
-
  private:
   friend class BrowserThread;
   friend class base::DeleteHelper<RenderFrameMessageFilter>;
 
   class OpenChannelToPpapiPluginCallback;
-  class OpenChannelToPpapiBrokerCallback;
 
   ~RenderFrameMessageFilter() override;
 
-  void OnRenderProcessGone();
-
-#if BUILDFLAG(ENABLE_PLUGINS)
   void OnGetPluginInfo(int render_frame_id,
                        const GURL& url,
                        const url::Origin& main_frame_origin,
@@ -94,24 +85,15 @@
                                              int32_t pp_instance,
                                              bool is_external);
   void OnOpenChannelToPpapiBroker(int routing_id, const base::FilePath& path);
-#endif  // ENABLE_PLUGINS
 
-#if BUILDFLAG(ENABLE_PLUGINS)
   PluginServiceImpl* plugin_service_;
   base::FilePath profile_data_directory_;
 
   // Initialized to 0, accessed on FILE thread only.
   base::TimeTicks last_plugin_refresh_time_;
-#endif  // ENABLE_PLUGINS
-
-  // The ResourceContext which is to be used on the IO thread.
-  ResourceContext* resource_context_;
-
-  // Needed for issuing routing ids and surface ids.
-  scoped_refptr<RenderWidgetHelper> render_widget_helper_;
 
   // Whether this process is used for incognito contents.
-  bool incognito_;
+  const bool incognito_;
 
   const int render_process_id_;
 };
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 460905c8..d1795ffb 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -125,7 +125,6 @@
 #include "content/browser/renderer_host/pepper/pepper_message_filter.h"
 #include "content/browser/renderer_host/pepper/pepper_renderer_connection.h"
 #include "content/browser/renderer_host/plugin_registry_impl.h"
-#include "content/browser/renderer_host/render_frame_message_filter.h"
 #include "content/browser/renderer_host/render_message_filter.h"
 #include "content/browser/renderer_host/render_widget_helper.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -266,6 +265,7 @@
 
 #if BUILDFLAG(ENABLE_PLUGINS)
 #include "content/browser/plugin_service_impl.h"
+#include "content/browser/renderer_host/render_frame_message_filter.h"
 #include "ppapi/shared_impl/ppapi_switches.h"  // nogncheck
 #endif
 
@@ -1948,17 +1948,11 @@
           GetID(), GetBrowserContext(), widget_helper_.get(), media_internals);
   AddFilter(render_message_filter.get());
 
-  render_frame_message_filter_ = new RenderFrameMessageFilter(
-      GetID(),
 #if BUILDFLAG(ENABLE_PLUGINS)
-      PluginServiceImpl::GetInstance(),
-#else
-      nullptr,
-#endif
-      GetBrowserContext(), storage_partition_impl_, widget_helper_.get());
-  AddFilter(render_frame_message_filter_.get());
+  AddFilter(new RenderFrameMessageFilter(
+      GetID(), PluginServiceImpl::GetInstance(), GetBrowserContext(),
+      storage_partition_impl_));
 
-#if BUILDFLAG(ENABLE_PLUGINS)
   AddFilter(new PepperRendererConnection(GetID()));
 #endif
 
@@ -3809,19 +3803,6 @@
   base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
   deleting_soon_ = true;
 
-  if (render_frame_message_filter_) {
-    // RenderFrameMessageFilter is refcounted and can outlive the
-    // ResourceContext. If the BrowserContext is shutting down, after
-    // RenderProcessHostImpl cleanup a task will be posted to the IO thread
-    // that destroys the ResourceContext. Therefore the ClearResourceContext
-    // task must be posted now to ensure it gets ahead of the destruction of
-    // the ResourceContext in the IOThread sequence.
-    GetIOThreadTaskRunner({})->PostTask(
-        FROM_HERE,
-        base::BindOnce(&RenderFrameMessageFilter::ClearResourceContext,
-                       render_frame_message_filter_));
-  }
-
   // Destroy all mojo bindings and IPC channels that can cause calls to this
   // object, to avoid method invocations that trigger usages of profile.
   ResetIPC();
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 379f466..1f2f101e 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -120,7 +120,6 @@
 class PluginRegistryImpl;
 class ProcessLock;
 class PushMessagingManager;
-class RenderFrameMessageFilter;
 class RenderProcessHostCreationObserver;
 class RenderProcessHostFactory;
 class RenderProcessHostTest;
@@ -468,10 +467,6 @@
   static void SetCodeCacheHostReceiverHandlerForTesting(
       CodeCacheHostReceiverHandler handler);
 
-  RenderFrameMessageFilter* render_frame_message_filter_for_testing() const {
-    return render_frame_message_filter_.get();
-  }
-
   void set_is_for_guests_only_for_testing(bool is_for_guests_only) {
     is_for_guests_only_ = is_for_guests_only;
   }
@@ -1034,8 +1029,6 @@
   // IO thread.
   scoped_refptr<RenderWidgetHelper> widget_helper_;
 
-  scoped_refptr<RenderFrameMessageFilter> render_frame_message_filter_;
-
   // Used in single-process mode.
   std::unique_ptr<base::Thread> in_process_renderer_;
 
diff --git a/content/browser/renderer_host/render_view_host_unittest.cc b/content/browser/renderer_host/render_view_host_unittest.cc
index 93bfa6f..eaf40a1 100644
--- a/content/browser/renderer_host/render_view_host_unittest.cc
+++ b/content/browser/renderer_host/render_view_host_unittest.cc
@@ -11,7 +11,6 @@
 #include "base/strings/utf_string_conversions.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/renderer_host/render_frame_host_impl.h"
-#include "content/browser/renderer_host/render_frame_message_filter.h"
 #include "content/browser/renderer_host/render_view_host_delegate_view.h"
 #include "content/browser/renderer_host/render_widget_helper.h"
 #include "content/common/frame_messages.h"
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index d64dd44..433f4d50 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1507,23 +1507,28 @@
 }
 
 bool RenderWidgetHostViewAura::SetAutocorrectRange(
-    const base::string16& autocorrect_text,
     const gfx::Range& range) {
-  if (autocorrect_text.empty() || range.is_empty())
-    return false;
-
-  base::UmaHistogramEnumeration(
-      "InputMethod.Assistive.Autocorrect.Count",
-      TextInputClient::SubClass::kRenderWidgetHostViewAura);
+  if (!range.is_empty()) {
+    base::UmaHistogramEnumeration(
+        "InputMethod.Assistive.Autocorrect.Count",
+        TextInputClient::SubClass::kRenderWidgetHostViewAura);
+  }
 
   auto* input_handler = GetFrameWidgetInputHandlerForFocusedWidget();
   if (!input_handler)
     return false;
 
+  input_handler->ClearImeTextSpansByType(0,
+                                         std::numeric_limits<uint32_t>::max(),
+                                         ui::ImeTextSpan::Type::kAutocorrect);
+
+  if (range.is_empty())
+    return true;
+
   ui::ImeTextSpan ui_ime_text_span;
   ui_ime_text_span.type = ui::ImeTextSpan::Type::kAutocorrect;
   ui_ime_text_span.start_offset = 0;
-  ui_ime_text_span.end_offset = autocorrect_text.length();
+  ui_ime_text_span.end_offset = range.length();
   ui_ime_text_span.underline_style = ui::ImeTextSpan::UnderlineStyle::kDot;
   ui_ime_text_span.underline_color = gfx::kGoogleGrey700;
 
@@ -1531,16 +1536,6 @@
                                                {ui_ime_text_span});
   return true;
 }
-
-void RenderWidgetHostViewAura::ClearAutocorrectRange() {
-  // TODO(crbug/1108170): Once we have a FrameWidgetInputHandlerMock, add a test
-  // to verify that the ClearImeTextSpansByType function has been called.
-  auto* input_handler = GetFrameWidgetInputHandlerForFocusedWidget();
-  if (!input_handler)
-    return;
-  input_handler->ClearImeTextSpansByType(0, UINT32_MAX,
-                                         ui::ImeTextSpan::Type::kAutocorrect);
-}
 #endif
 
 #if defined(OS_WIN)
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 3ed4409..0f7426de 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -231,9 +231,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   gfx::Range GetAutocorrectRange() const override;
   gfx::Rect GetAutocorrectCharacterBounds() const override;
-  bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                           const gfx::Range& range) override;
-  void ClearAutocorrectRange() override;
+  bool SetAutocorrectRange(const gfx::Range& range) override;
 #endif
 
 #if defined(OS_WIN)
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 4df92ef..b4f92985 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -7804,8 +7804,8 @@
   NavigationControllerImpl& new_controller =
       static_cast<NavigationControllerImpl&>(
           new_shell->web_contents()->GetController());
-  new_controller.Restore(entries.size() - 1,
-                         RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  new_controller.Restore(entries.size() - 1, RestoreType::LAST_SESSION,
+                         &entries);
   ASSERT_EQ(0u, entries.size());
   {
     TestNavigationObserver restore_observer(new_shell->web_contents());
@@ -7911,8 +7911,8 @@
   NavigationControllerImpl& new_controller =
       static_cast<NavigationControllerImpl&>(
           new_shell->web_contents()->GetController());
-  new_controller.Restore(entries.size() - 1,
-                         RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  new_controller.Restore(entries.size() - 1, RestoreType::LAST_SESSION,
+                         &entries);
   ASSERT_EQ(0u, entries.size());
   {
     TestNavigationObserver restore_observer(new_shell->web_contents());
@@ -8014,8 +8014,8 @@
   NavigationControllerImpl& new_controller =
       static_cast<NavigationControllerImpl&>(
           new_shell->web_contents()->GetController());
-  new_controller.Restore(entries.size() - 1,
-                         RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  new_controller.Restore(entries.size() - 1, RestoreType::LAST_SESSION,
+                         &entries);
   ASSERT_EQ(0u, entries.size());
   {
     TestNavigationObserver restore_observer(new_shell->web_contents());
@@ -15346,7 +15346,6 @@
   // Create commit params with the same URL as the start one, so URL checks
   // pass, but use a different origin than the origin lock of the process.
   auto params = mojom::DidCommitProvisionalLoadParams::New();
-  params->nav_entry_id = 0;
   params->did_create_new_entry = false;
   params->url = start_url;
   params->referrer = blink::mojom::Referrer::New();
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 835e5159..1e4fa98 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -264,7 +264,6 @@
                std::string());
 
   auto params = mojom::DidCommitProvisionalLoadParams::New();
-  params->nav_entry_id = 0;
   params->url = GURL(url::kAboutBlankURL);
   params->origin = url::Origin::Create(params->url);
   params->referrer = blink::mojom::Referrer::New();
@@ -792,16 +791,15 @@
           false, std::string(), browser_context(),
           nullptr /* blob_url_loader_factory */);
   entries.push_back(std::move(new_entry));
-  controller().Restore(0, RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  controller().Restore(0, RestoreType::LAST_SESSION, &entries);
   ASSERT_EQ(0u, entries.size());
   ASSERT_EQ(1, controller().GetEntryCount());
 
   EXPECT_TRUE(controller().NeedsReload());
   controller().LoadIfNecessary();
-  NavigationEntry* entry = controller().GetPendingEntry();
   orig_rfh->PrepareForCommit();
-  contents()->TestDidNavigate(orig_rfh, entry->GetUniqueID(), false,
-                              native_url, ui::PAGE_TRANSITION_RELOAD);
+  contents()->TestDidNavigate(orig_rfh, false, native_url,
+                              ui::PAGE_TRANSITION_RELOAD);
   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
   EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
   EXPECT_FALSE(orig_instance->HasSite());
@@ -835,16 +833,15 @@
           false, std::string(), browser_context(),
           nullptr /* blob_url_loader_factory */);
   entries.push_back(std::move(new_entry));
-  controller().Restore(0, RestoreType::LAST_SESSION_EXITED_CLEANLY, &entries);
+  controller().Restore(0, RestoreType::LAST_SESSION, &entries);
   ASSERT_EQ(0u, entries.size());
 
   ASSERT_EQ(1, controller().GetEntryCount());
   EXPECT_TRUE(controller().NeedsReload());
   controller().LoadIfNecessary();
-  NavigationEntry* entry = controller().GetPendingEntry();
   orig_rfh->PrepareForCommit();
-  contents()->TestDidNavigate(orig_rfh, entry->GetUniqueID(), false,
-                              regular_url, ui::PAGE_TRANSITION_RELOAD);
+  contents()->TestDidNavigate(orig_rfh, false, regular_url,
+                              ui::PAGE_TRANSITION_RELOAD);
   EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
   EXPECT_TRUE(orig_instance->HasSite());
   EXPECT_EQ(AreDefaultSiteInstancesEnabled(),
@@ -1273,7 +1270,7 @@
   EXPECT_EQ(entry1, controller().GetLastCommittedEntry());
 
   // When the second back commits, it should be ignored.
-  contents()->TestDidNavigate(google_rfh, entry2->GetUniqueID(), false, url2,
+  contents()->TestDidNavigate(google_rfh, false, url2,
                               ui::PAGE_TRANSITION_TYPED);
   EXPECT_EQ(entry1, controller().GetLastCommittedEntry());
 
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc
index 0143e0f2..e832a04 100644
--- a/content/child/runtime_features.cc
+++ b/content/child/runtime_features.cc
@@ -128,6 +128,14 @@
   WebRuntimeFeatures::EnableMediaControlsExpandGesture(
       base::FeatureList::IsEnabled(media::kMediaControlsExpandGesture));
 #endif
+
+#if defined(OS_ANDROID)
+  WebRuntimeFeatures::EnableCSSColorSchemeUARendering(
+      // Combining form-controls-refresh and form-controls-dark-mode
+      // to be launched together on Android. Only one about flags
+      // for both features.
+      base::FeatureList::IsEnabled(features::kFormControlsRefresh));
+#endif
 }
 
 enum RuntimeFeatureEnableOptions {
diff --git a/content/common/navigation_client.mojom b/content/common/navigation_client.mojom
index e8286dce..13eb0ea 100644
--- a/content/common/navigation_client.mojom
+++ b/content/common/navigation_client.mojom
@@ -37,12 +37,6 @@
 // - NavigationClient.CommitNavigationCallback
 // - NavigationClient.CommitFailedNavigationCallback
 struct DidCommitProvisionalLoadParams {
-  // The unique ID of the NavigationEntry for browser-initiated navigations.
-  // This value was given to the render process in the HistoryNavigationParams
-  // and is being returned by the renderer without it having any idea what it
-  // means. If the navigation was renderer-initiated, this value is 0.
-  int32 nav_entry_id = 0;
-
   // The item sequence number identifies each stop in the session history.  It
   // is unique within the renderer process and makes a best effort to be unique
   // across browser sessions (using a renderer process timestamp).
@@ -227,4 +221,3 @@
       => (DidCommitProvisionalLoadParams params,
           DidCommitProvisionalLoadInterfaceParams? interface_params);
 };
-
diff --git a/content/public/browser/restore_type.h b/content/public/browser/restore_type.h
index 5aae159..4736da47 100644
--- a/content/public/browser/restore_type.h
+++ b/content/public/browser/restore_type.h
@@ -10,8 +10,7 @@
 // Enumerations of the possible restore types.
 enum class RestoreType {
   // Restore from the previous session.
-  LAST_SESSION_EXITED_CLEANLY,
-  LAST_SESSION_CRASHED,
+  LAST_SESSION,
 
   // The entry has been restored from the current session. This is used when
   // the user issues 'reopen closed tab'.
diff --git a/content/public/test/web_contents_tester.h b/content/public/test/web_contents_tester.h
index 8f5471b..eafb0e1 100644
--- a/content/public/test/web_contents_tester.h
+++ b/content/public/test/web_contents_tester.h
@@ -96,14 +96,10 @@
   // Simulates a navigation with the given information.
   //
   // Guidance for calling these:
-  // - nav_entry_id should be 0 if simulating a renderer-initiated navigation;
-  //   if simulating a browser-initiated one, pass the GetUniqueID() value of
-  //   the NavigationController's PendingEntry.
   // - did_create_new_entry should be true if simulating a navigation that
   //   created a new navigation entry; false for history navigations, reloads,
   //   and other navigations that don't affect the history list.
   virtual void TestDidNavigate(RenderFrameHost* render_frame_host,
-                               int nav_entry_id,
                                bool did_create_new_entry,
                                const GURL& url,
                                ui::PageTransition transition) = 0;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index dcf84d9..ae7e1fa 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4990,7 +4990,6 @@
   params->should_replace_current_entry =
       document_loader->ReplacesCurrentHistoryItem();
   params->post_id = -1;
-  params->nav_entry_id = navigation_state->commit_params().nav_entry_id;
   params->embedding_token = embedding_token;
 
   // Pass the navigation token back to the browser process, or generate a new
diff --git a/content/test/data/accessibility/event/tabindex-added-on-aria-hidden-expected-auralinux.txt b/content/test/data/accessibility/event/tabindex-added-on-aria-hidden-expected-auralinux.txt
index 5c86d85..98e3aa2c 100644
--- a/content/test/data/accessibility/event/tabindex-added-on-aria-hidden-expected-auralinux.txt
+++ b/content/test/data/accessibility/event/tabindex-added-on-aria-hidden-expected-auralinux.txt
@@ -1,3 +1 @@
 CHILDREN-CHANGED:ADD index:0 CHILD:(role=ROLE_SECTION) role=ROLE_DOCUMENT_WEB ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
-FOCUS-EVENT:TRUE role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
-STATE-CHANGE:FOCUSED:TRUE role=ROLE_DOCUMENT_WEB name='(null)' ENABLED,FOCUSABLE,FOCUSED,SENSITIVE,SHOWING,VISIBLE
diff --git a/content/test/data/accessibility/event/tabindex-added-on-aria-hidden.html b/content/test/data/accessibility/event/tabindex-added-on-aria-hidden.html
index fc6b085e..262938ec 100644
--- a/content/test/data/accessibility/event/tabindex-added-on-aria-hidden.html
+++ b/content/test/data/accessibility/event/tabindex-added-on-aria-hidden.html
@@ -4,7 +4,7 @@
 <div id="d" aria-hidden="true"></div>
 <script>
   function go() {
-    document.querySelector('#d').tabIndex = '-1';
+    document.querySelector('#d').tabIndex = -1;
   }
 </script>
 </body>
diff --git a/content/test/data/accessibility/html/bounds-fixed-scrolling.html b/content/test/data/accessibility/html/bounds-fixed-scrolling.html
index 2ece330..fe03eb2 100644
--- a/content/test/data/accessibility/html/bounds-fixed-scrolling.html
+++ b/content/test/data/accessibility/html/bounds-fixed-scrolling.html
@@ -36,14 +36,16 @@
 <div id="statusDiv"></div>
 <script>
 function onLoad() {
-  window.setTimeout(() => {
+  window.requestAnimationFrame(() => {
     window.onscroll = function() {
       window.requestAnimationFrame(() => {
         statusDiv.innerText = "done";
       });
     };
-    document.querySelector('button').click();
-  }, 100);
+    window.requestAnimationFrame(() => {
+      document.querySelector('button').click();
+    });
+  });
 }
 
 function clicked() {
diff --git a/content/test/navigation_simulator_impl.cc b/content/test/navigation_simulator_impl.cc
index c6a3810..ea4cc339 100644
--- a/content/test/navigation_simulator_impl.cc
+++ b/content/test/navigation_simulator_impl.cc
@@ -1327,7 +1327,6 @@
   }
 
   CHECK(same_document || request_);
-  params->nav_entry_id = request_ ? request_->nav_entry_id() : 0;
 
   // Simulate Blink assigning a item sequence number and document sequence
   // number to the navigation.
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index e80c1e5..4a14c76 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -264,8 +264,8 @@
        url.ReplaceComponents(replacements) ==
            GetLastCommittedURL().ReplaceComponents(replacements));
 
-  auto params = BuildDidCommitParams(nav_entry_id, did_create_new_entry, url,
-                                     transition, response_code);
+  auto params = BuildDidCommitParams(did_create_new_entry, url, transition,
+                                     response_code);
   if (!was_within_same_document)
     params->embedding_token = base::UnguessableToken::Create();
 
@@ -431,7 +431,6 @@
         browser_interface_broker_receiver,
     bool same_document) {
   CHECK(params);
-
   if (!same_document) {
     // Note: Although the code does not prohibit the running of multiple
     // callbacks, no more than 1 callback will ever run, because navigation_id
@@ -521,13 +520,11 @@
 }
 
 mojom::DidCommitProvisionalLoadParamsPtr
-TestRenderFrameHost::BuildDidCommitParams(int nav_entry_id,
-                                          bool did_create_new_entry,
+TestRenderFrameHost::BuildDidCommitParams(bool did_create_new_entry,
                                           const GURL& url,
                                           ui::PageTransition transition,
                                           int response_code) {
   auto params = mojom::DidCommitProvisionalLoadParams::New();
-  params->nav_entry_id = nav_entry_id;
   params->url = url;
   params->referrer = blink::mojom::Referrer::New();
   params->transition = transition;
diff --git a/content/test/test_render_frame_host.h b/content/test/test_render_frame_host.h
index 17f6916..a6a5671d 100644
--- a/content/test/test_render_frame_host.h
+++ b/content/test/test_render_frame_host.h
@@ -253,7 +253,6 @@
   int32_t ComputeNextPageID();
 
   mojom::DidCommitProvisionalLoadParamsPtr BuildDidCommitParams(
-      int nav_entry_id,
       bool did_create_new_entry,
       const GURL& url,
       ui::PageTransition transition,
diff --git a/content/test/test_web_contents.cc b/content/test/test_web_contents.cc
index 385b85d..462e6ab 100644
--- a/content/test/test_web_contents.cc
+++ b/content/test/test_web_contents.cc
@@ -129,18 +129,15 @@
 }
 
 void TestWebContents::TestDidNavigate(RenderFrameHost* render_frame_host,
-                                      int nav_entry_id,
                                       bool did_create_new_entry,
                                       const GURL& url,
                                       ui::PageTransition transition) {
-  TestDidNavigateWithSequenceNumber(render_frame_host, nav_entry_id,
-                                    did_create_new_entry, url, Referrer(),
-                                    transition, false, -1, -1);
+  TestDidNavigateWithSequenceNumber(render_frame_host, did_create_new_entry,
+                                    url, Referrer(), transition, false, -1, -1);
 }
 
 void TestWebContents::TestDidNavigateWithSequenceNumber(
     RenderFrameHost* render_frame_host,
-    int nav_entry_id,
     bool did_create_new_entry,
     const GURL& url,
     const Referrer& referrer,
@@ -156,7 +153,6 @@
     rfh->SimulateNavigationStart(url);
 
   auto params = mojom::DidCommitProvisionalLoadParams::New();
-  params->nav_entry_id = nav_entry_id;
   params->item_sequence_number = item_sequence_number;
   params->document_sequence_number = document_sequence_number;
   params->url = url;
diff --git a/content/test/test_web_contents.h b/content/test/test_web_contents.h
index a3df6e05..cc0fadc 100644
--- a/content/test/test_web_contents.h
+++ b/content/test/test_web_contents.h
@@ -75,12 +75,10 @@
   void NavigateAndFail(const GURL& url, int error_code) override;
   void TestSetIsLoading(bool value) override;
   void TestDidNavigate(RenderFrameHost* render_frame_host,
-                       int nav_entry_id,
                        bool did_create_new_entry,
                        const GURL& url,
                        ui::PageTransition transition) override;
   void TestDidNavigateWithSequenceNumber(RenderFrameHost* render_frame_host,
-                                         int nav_entry_id,
                                          bool did_create_new_entry,
                                          const GURL& url,
                                          const Referrer& referrer,
diff --git a/device/bluetooth/bluetooth_adapter_mac_unittest.mm b/device/bluetooth/bluetooth_adapter_mac_unittest.mm
index 6540c03..7d210bf 100644
--- a/device/bluetooth/bluetooth_adapter_mac_unittest.mm
+++ b/device/bluetooth/bluetooth_adapter_mac_unittest.mm
@@ -10,7 +10,6 @@
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
-#include "base/files/file_path_watcher.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/memory/ptr_util.h"
diff --git a/device/fido/cros/authenticator.cc b/device/fido/cros/authenticator.cc
index 66c43cc3a..b1fbef43 100644
--- a/device/fido/cros/authenticator.cc
+++ b/device/fido/cros/authenticator.cc
@@ -167,6 +167,7 @@
     FIDO_LOG(ERROR) << "Attestation statement is not a CBOR map.";
     std::move(callback).Run(CtapDeviceResponseCode::kCtap2ErrOther,
                             base::nullopt);
+    return;
   }
   auto statement = std::make_unique<OpaqueAttestationStatement>(
       resp.attestation_format(), std::move(*statement_map));
diff --git a/infra/config/generated/cr-buildbucket.cfg b/infra/config/generated/cr-buildbucket.cfg
index 0b8ba065..be75742 100644
--- a/infra/config/generated/cr-buildbucket.cfg
+++ b/infra/config/generated/cr-buildbucket.cfg
@@ -19077,6 +19077,53 @@
       }
     }
     builders {
+      name: "mac-arm64-updater-tester-rel"
+      swarming_host: "chromium-swarm.appspot.com"
+      swarming_tags: "vpython:native-python-wrapper"
+      dimensions: "builderless:1"
+      dimensions: "cores:8"
+      dimensions: "cpu:x86-64"
+      dimensions: "os:Ubuntu-16.04"
+      dimensions: "pool:luci.chromium.ci"
+      dimensions: "ssd:0"
+      exe {
+        cipd_package: "infra/recipe_bundles/chromium.googlesource.com/chromium/tools/build"
+        cipd_version: "refs/heads/master"
+        cmd: "recipes"
+      }
+      properties: "{\"$build/goma\":{\"enable_ats\":true,\"rpc_extra_params\":\"?prod\",\"server_host\":\"goma.chromium.org\",\"use_luci_auth\":true},\"$kitchen\":{\"devshell\":true,\"git_auth\":true},\"$recipe_engine/isolated\":{\"server\":\"https://isolateserver.appspot.com\"},\"builder_group\":\"chromium.updater\",\"recipe\":\"chromium\"}"
+      execution_timeout_secs: 10800
+      build_numbers: YES
+      service_account: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+      experiments {
+        key: "chromium.resultdb.result_sink"
+        value: 100
+      }
+      experiments {
+        key: "luci.use_realms"
+        value: 100
+      }
+      resultdb {
+        enable: true
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "ci_test_results"
+          test_results {}
+        }
+        bq_exports {
+          project: "luci-resultdb"
+          dataset: "chromium"
+          table: "gpu_ci_test_results"
+          test_results {
+            predicate {
+              test_id_regexp: "ninja://(chrome/test:|content/test:fuchsia_)telemetry_gpu_integration_test/.+"
+            }
+          }
+        }
+      }
+    }
+    builders {
       name: "mac-code-coverage"
       swarming_host: "chromium-swarm.appspot.com"
       swarming_tags: "vpython:native-python-wrapper"
diff --git a/infra/config/generated/luci-milo.cfg b/infra/config/generated/luci-milo.cfg
index 535b367..d12720bb 100644
--- a/infra/config/generated/luci-milo.cfg
+++ b/infra/config/generated/luci-milo.cfg
@@ -9399,6 +9399,11 @@
     short_name: "11.0"
   }
   builders {
+    name: "buildbucket/luci.chromium.ci/mac-arm64-updater-tester-rel"
+    category: "release|mac"
+    short_name: "11.0 arm64"
+  }
+  builders {
     name: "buildbucket/luci.chromium.ci/mac-updater-builder-rel"
     category: "release|mac"
     short_name: "bld"
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg
index 6c30f1ef..40d4a9e 100644
--- a/infra/config/generated/luci-scheduler.cfg
+++ b/infra/config/generated/luci-scheduler.cfg
@@ -5756,6 +5756,20 @@
   }
 }
 job {
+  id: "mac-arm64-updater-tester-rel"
+  realm: "ci"
+  acls {
+    role: TRIGGERER
+    granted_to: "chromium-ci-builder@chops-service-accounts.iam.gserviceaccount.com"
+  }
+  acl_sets: "ci"
+  buildbucket {
+    server: "cr-buildbucket.appspot.com"
+    bucket: "luci.chromium.ci"
+    builder: "mac-arm64-updater-tester-rel"
+  }
+}
+job {
   id: "mac-code-coverage"
   realm: "ci"
   acl_sets: "ci"
diff --git a/infra/config/subprojects/chromium/ci.star b/infra/config/subprojects/chromium/ci.star
index ed518a69..95b576b2 100644
--- a/infra/config/subprojects/chromium/ci.star
+++ b/infra/config/subprojects/chromium/ci.star
@@ -2719,6 +2719,15 @@
 )
 
 ci.updater_builder(
+    name = "mac-arm64-updater-tester-rel",
+    console_view_entry = ci.console_view_entry(
+        category = "release|mac",
+        short_name = "11.0 arm64",
+    ),
+    triggered_by = ["mac-updater-builder-rel"],
+)
+
+ci.updater_builder(
     name = "win-updater-builder-dbg",
     console_view_entry = ci.console_view_entry(
         category = "debug|win",
diff --git a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
index 2fd0de3..b582011f 100644
--- a/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/clear_browsing_data/clear_browsing_data_table_view_controller.mm
@@ -43,7 +43,8 @@
 
 @interface ClearBrowsingDataTableViewController () <
     TableViewTextLinkCellDelegate,
-    ClearBrowsingDataConsumer>
+    ClearBrowsingDataConsumer,
+    UIGestureRecognizerDelegate>
 
 // TODO(crbug.com/850699): remove direct dependency and replace with
 // delegate.
@@ -191,6 +192,24 @@
     [self.alertCoordinator stop];
     self.alertCoordinator = nil;
   }
+  if (self.overlayCoordinator.started) {
+    [self.overlayCoordinator stop];
+    self.navigationController.interactivePopGestureRecognizer.delegate = nil;
+    self.overlayCoordinator = nil;
+  }
+}
+
+#pragma mark - UIGestureRecognizerDelegate
+
+- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer {
+  if (gestureRecognizer ==
+      self.navigationController.interactivePopGestureRecognizer) {
+    // This view controller should only be observing gestures when the activity
+    // overlay is showing (e.g. when Clear Browsing Data is in progress and the
+    // user should not be able to swipe away from this view).
+    return NO;
+  }
+  return YES;
 }
 
 #pragma mark - UITableViewDataSource
@@ -322,6 +341,9 @@
 
   self.overlayCoordinator.blockAllWindows = YES;
 
+  // Observe Gestures while overlay is visible to prevent user from swiping away
+  // from this view during the process of clear browsing data.
+  self.navigationController.interactivePopGestureRecognizer.delegate = self;
   [self.overlayCoordinator start];
 
   __weak ClearBrowsingDataTableViewController* weakSelf = self;
@@ -337,6 +359,7 @@
     // least 1 second instead of looking like a glitch.
     dispatch_after(timeOneSecondLater, dispatch_get_main_queue(), ^{
       [self.overlayCoordinator stop];
+      self.navigationController.interactivePopGestureRecognizer.delegate = nil;
       if (completionBlock)
         completionBlock();
     });
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
index 6ccb6cdd..8798143 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-3b30330efdd827bc6864631913443204d8029957
\ No newline at end of file
+5f401a2d7f24069036a13d2c31b8e5fddde3d5a7
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
index 7850f07e..0142622 100644
--- a/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-524a06279f8ba5466dde18e50079114e98fb4e65
\ No newline at end of file
+f71c498d92a9035f1c9db31094ce300d8be4e6f1
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
index 7612efd7..caf27f8 100644
--- a/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/chrome_sso_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-e69977602fc7a4ac9a5dafc43dab0c8f29760f45
\ No newline at end of file
+b9404c6de81585b24625b55dc5b278ea4d59292f
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
index 8a2f93a..538826c6 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-92abcfdaba129659273cb204346e292a36f63258
\ No newline at end of file
+030efabe9b40c94b70b7d2744929fb98cd1299c0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
index 7a8119ac..c5b275b 100644
--- a/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_dogfood_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-243b08a84b4b9f90b666971692c0a2492bb78634
\ No newline at end of file
+8fb34dcb825f96c215ac32dc3993342f8fbb5423
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
index e316176..02bc5a5 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-a71d94f18037cf1329664ef7458157e792c821db
\ No newline at end of file
+c3083629c1b1cbec5a3dca37df09e0803e72e76a
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
index b333b55..059ce07 100644
--- a/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/remoting_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-857da30be20b9bc960f13032be282849ee17b2dc
\ No newline at end of file
+e1a98658a4bb87db8e01fb16b37e8e2207d303c0
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
index 36c3cb3..997f546 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.arm64.zip.sha1
@@ -1 +1 @@
-35155c392319b4dd20f5adf5f87f83516cc622ec
\ No newline at end of file
+a21e29ea67c207149ae38649dd5d1f58715ff0d6
\ No newline at end of file
diff --git a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1 b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
index fcdee64..f78adc3 100644
--- a/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
+++ b/ios/google_internal/frameworks/web_view_shell_internal_dynamic_framework.x64.zip.sha1
@@ -1 +1 @@
-414f0f90a5831f1d902b283df871f918a7fe7c3b
\ No newline at end of file
+567fa443c2274d441e0d0955fdabb51fc6e1a25f
\ No newline at end of file
diff --git a/media/base/video_encoder.h b/media/base/video_encoder.h
index 50087ca6..1513367 100644
--- a/media/base/video_encoder.h
+++ b/media/base/video_encoder.h
@@ -41,8 +41,7 @@
     base::Optional<uint64_t> bitrate;
     base::Optional<double> framerate;
 
-    int width = 0;
-    int height = 0;
+    gfx::Size frame_size;
 
     base::Optional<int> keyframe_interval = 10000;
   };
diff --git a/media/base/video_util.cc b/media/base/video_util.cc
index 3daa1cb..595e947 100644
--- a/media/base/video_util.cc
+++ b/media/base/video_util.cc
@@ -13,6 +13,7 @@
 #include "base/numerics/safe_math.h"
 #include "media/base/video_frame.h"
 #include "third_party/libyuv/include/libyuv.h"
+#include "ui/gfx/gpu_memory_buffer.h"
 
 namespace media {
 
@@ -424,15 +425,53 @@
                      region_in_frame.width(), region_in_frame.height());
 }
 
+scoped_refptr<VideoFrame> ConvertToMemoryMappedFrame(
+    scoped_refptr<VideoFrame> video_frame) {
+  DCHECK(video_frame);
+  DCHECK_EQ(video_frame->storage_type(),
+            VideoFrame::StorageType::STORAGE_GPU_MEMORY_BUFFER);
+
+  auto* gmb = video_frame->GetGpuMemoryBuffer();
+  DCHECK(gmb);
+
+  if (!gmb->Map())
+    return nullptr;
+
+  const size_t num_planes = VideoFrame::NumPlanes(video_frame->format());
+  uint8_t* plane_addrs[VideoFrame::kMaxPlanes] = {};
+  for (size_t i = 0; i < num_planes; i++)
+    plane_addrs[i] = static_cast<uint8_t*>(gmb->memory(i));
+
+  auto mapped_frame = VideoFrame::WrapExternalYuvDataWithLayout(
+      video_frame->layout(), video_frame->visible_rect(),
+      video_frame->natural_size(), plane_addrs[0], plane_addrs[1],
+      plane_addrs[2], video_frame->timestamp());
+
+  if (!mapped_frame) {
+    gmb->Unmap();
+    return nullptr;
+  }
+
+  mapped_frame->set_color_space(video_frame->ColorSpace());
+
+  // Pass |video_frame| so that it outlives |mapped_frame| and the mapped buffer
+  // is unmapped on destruction.
+  mapped_frame->AddDestructionObserver(base::BindOnce(
+      [](scoped_refptr<VideoFrame> frame) {
+        DCHECK(frame->HasGpuMemoryBuffer());
+        frame->GetGpuMemoryBuffer()->Unmap();
+      },
+      std::move(video_frame)));
+  return mapped_frame;
+}
+
 scoped_refptr<VideoFrame> WrapAsI420VideoFrame(
     scoped_refptr<VideoFrame> frame) {
   DCHECK_EQ(VideoFrame::STORAGE_OWNED_MEMORY, frame->storage_type());
   DCHECK_EQ(PIXEL_FORMAT_I420A, frame->format());
 
-  scoped_refptr<media::VideoFrame> wrapped_frame =
-      media::VideoFrame::WrapVideoFrame(frame, PIXEL_FORMAT_I420,
-                                        frame->visible_rect(),
-                                        frame->natural_size());
+  scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame(
+      frame, PIXEL_FORMAT_I420, frame->visible_rect(), frame->natural_size());
   if (!wrapped_frame)
     return nullptr;
   return wrapped_frame;
diff --git a/media/base/video_util.h b/media/base/video_util.h
index 42e060a2..d0652ae0 100644
--- a/media/base/video_util.h
+++ b/media/base/video_util.h
@@ -141,6 +141,12 @@
                                       const gfx::Rect& region_in_frame,
                                       VideoFrame* frame);
 
+// A helper function to map GpuMemoryBuffer-based VideoFrame. This function
+// maps the given GpuMemoryBuffer of |frame| as-is without converting pixel
+// format. The returned VideoFrame owns the |frame|.
+MEDIA_EXPORT scoped_refptr<VideoFrame> ConvertToMemoryMappedFrame(
+    scoped_refptr<VideoFrame> frame);
+
 // Converts a frame with YV12A format into I420 by dropping alpha channel.
 MEDIA_EXPORT scoped_refptr<VideoFrame> WrapAsI420VideoFrame(
     scoped_refptr<VideoFrame> frame);
diff --git a/media/video/openh264_video_encoder.cc b/media/video/openh264_video_encoder.cc
index 8c15b00..05abf97 100644
--- a/media/video/openh264_video_encoder.cc
+++ b/media/video/openh264_video_encoder.cc
@@ -29,8 +29,8 @@
   params->iMultipleThreadIdc = 1;
   if (options.framerate.has_value())
     params->fMaxFrameRate = options.framerate.value();
-  params->iPicHeight = options.height;
-  params->iPicWidth = options.width;
+  params->iPicHeight = options.frame_size.height();
+  params->iPicWidth = options.frame_size.width();
 
   if (options.keyframe_interval.has_value())
     params->uiIntraPeriod = options.keyframe_interval.value();
diff --git a/media/video/video_encode_accelerator_adapter.cc b/media/video/video_encode_accelerator_adapter.cc
index 8753a14..bdfa80b 100644
--- a/media/video/video_encode_accelerator_adapter.cc
+++ b/media/video/video_encode_accelerator_adapter.cc
@@ -36,8 +36,8 @@
     VideoPixelFormat format,
     VideoFrame::StorageType storage_type) {
   auto config = VideoEncodeAccelerator::Config(
-      format, gfx::Size(opts.width, opts.height), profile,
-      opts.bitrate.value_or(opts.width * opts.height *
+      format, opts.frame_size, profile,
+      opts.bitrate.value_or(opts.frame_size.width() * opts.frame_size.height() *
                             kVEADefaultBitratePerPixel));
 
 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
@@ -180,9 +180,16 @@
     return;
   }
 
-  if (options.width <= 0 || options.height <= 0) {
+  if (options.frame_size.width() <= 0 || options.frame_size.height() <= 0) {
     auto status = Status(StatusCode::kEncoderUnsupportedConfig,
-                         "Negative width or height values");
+                         "Negative width or height values.");
+    std::move(done_cb).Run(status);
+    return;
+  }
+
+  if (!options.frame_size.GetCheckedArea().IsValid()) {
+    auto status =
+        Status(StatusCode::kEncoderUnsupportedConfig, "Frame is too large.");
     std::move(done_cb).Run(status);
     return;
   }
@@ -367,7 +374,7 @@
   DCHECK(pending_encodes_.empty());
   DCHECK_EQ(state_, State::kReadyToEncode);
 
-  if (options.width != options_.width || options.height != options_.height) {
+  if (options.frame_size != options_.frame_size) {
     auto status = Status(StatusCode::kEncoderInitializationError,
                          "Resolution change is not supported.");
     std::move(done_cb).Run(status);
@@ -375,7 +382,8 @@
   }
 
   uint32_t bitrate =
-      std::min(options.bitrate.value_or(options.width * options.height *
+      std::min(options.bitrate.value_or(options.frame_size.width() *
+                                        options.frame_size.height() *
                                         kVEADefaultBitratePerPixel),
                uint64_t{std::numeric_limits<uint32_t>::max()});
 
diff --git a/media/video/vpx_video_encoder.cc b/media/video/vpx_video_encoder.cc
index 3fe5e35..7e23a78 100644
--- a/media/video/vpx_video_encoder.cc
+++ b/media/video/vpx_video_encoder.cc
@@ -4,12 +4,14 @@
 
 #include "media/video/vpx_video_encoder.h"
 
+#include "base/numerics/checked_math.h"
 #include "base/numerics/ranges.h"
 #include "base/strings/stringprintf.h"
 #include "base/system/sys_info.h"
 #include "base/time/time.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/video_frame.h"
+#include "media/base/video_util.h"
 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
 #include "third_party/libyuv/include/libyuv/convert.h"
 
@@ -40,9 +42,12 @@
 
 Status SetUpVpxConfig(const VideoEncoder::Options& opts,
                       vpx_codec_enc_cfg_t* config) {
-  if (opts.width <= 0 || opts.height <= 0)
+  if (opts.frame_size.width() <= 0 || opts.frame_size.height() <= 0)
     return Status(StatusCode::kEncoderUnsupportedConfig,
-                  "Negative width or height values");
+                  "Negative width or height values.");
+
+  if (!opts.frame_size.GetCheckedArea().IsValid())
+    return Status(StatusCode::kEncoderUnsupportedConfig, "Frame is too large.");
 
   config->g_pass = VPX_RC_ONE_PASS;
   config->g_lag_in_frames = 0;
@@ -52,7 +57,7 @@
   config->g_timebase.den = base::Time::kMicrosecondsPerSecond;
 
   // Set the number of threads based on the image width and num of cores.
-  config->g_threads = GetNumberOfThreads(opts.width);
+  config->g_threads = GetNumberOfThreads(opts.frame_size.width());
 
   // Insert keyframes at will with a given max interval
   if (opts.keyframe_interval.has_value()) {
@@ -66,17 +71,32 @@
     config->rc_target_bitrate = opts.bitrate.value() / 1000;
   } else {
     config->rc_end_usage = VPX_VBR;
-    config->rc_target_bitrate = double{opts.width} * double{opts.height} /
-                                config->g_w / config->g_h *
-                                config->rc_target_bitrate;
+    config->rc_target_bitrate =
+        double{opts.frame_size.GetCheckedArea().ValueOrDie()} / config->g_w /
+        config->g_h * config->rc_target_bitrate;
   }
 
-  config->g_w = opts.width;
-  config->g_h = opts.height;
+  config->g_w = opts.frame_size.width();
+  config->g_h = opts.frame_size.height();
 
   return Status();
 }
 
+Status MaybeRewrapImageWithFormat(vpx_image_t* vpx_image,
+                                  const vpx_img_fmt fmt,
+                                  int width,
+                                  int height) {
+  if (vpx_image->fmt != fmt) {
+    vpx_img_free(vpx_image);
+    if (vpx_image != vpx_img_wrap(vpx_image, fmt, width, height, 1, nullptr)) {
+      return Status(StatusCode::kEncoderFailedEncode,
+                    "Invalid format or frame size.");
+    }
+  }
+  // else no-op since the image don't need to change format.
+  return Status();
+}
+
 void FreeCodecCtx(vpx_codec_ctx_t* codec_ctx) {
   if (codec_ctx->name) {
     // Codec has been initialized, we need to destroy it.
@@ -185,8 +205,9 @@
     return;
   }
 
-  if (&vpx_image_ != vpx_img_wrap(&vpx_image_, img_fmt, options.width,
-                                  options.height, 1, nullptr)) {
+  if (&vpx_image_ != vpx_img_wrap(&vpx_image_, img_fmt,
+                                  options.frame_size.width(),
+                                  options.frame_size.height(), 1, nullptr)) {
     status = Status(StatusCode::kEncoderInitializationError,
                     "Invalid format or frame size.");
     std::move(done_cb).Run(status);
@@ -227,7 +248,7 @@
                                   "No frame provided for encoding."));
     return;
   }
-  if (!frame->IsMappable() || frame->format() != PIXEL_FORMAT_I420) {
+  if (!frame->IsMappable() && !frame->HasGpuMemoryBuffer()) {
     status =
         Status(StatusCode::kEncoderFailedEncode, "Unexpected frame format.")
             .WithData("IsMappable", frame->IsMappable())
@@ -236,6 +257,16 @@
     return;
   }
 
+  if (frame->format() == PIXEL_FORMAT_NV12 &&
+      frame->storage_type() == VideoFrame::STORAGE_GPU_MEMORY_BUFFER)
+    frame = ConvertToMemoryMappedFrame(frame);
+  if (!frame) {
+    std::move(done_cb).Run(
+        Status(StatusCode::kEncoderFailedEncode,
+               "Convert GMB frame to MemoryMappedFrame failed."));
+    return;
+  }
+
   switch (profile_) {
     case VP9PROFILE_PROFILE1:
       NOTREACHED();
@@ -260,15 +291,37 @@
       NOTREACHED();
       break;
     default:
-      vpx_image_.planes[VPX_PLANE_Y] =
-          const_cast<uint8_t*>(frame->visible_data(VideoFrame::kYPlane));
-      vpx_image_.planes[VPX_PLANE_U] =
-          const_cast<uint8_t*>(frame->visible_data(VideoFrame::kUPlane));
-      vpx_image_.planes[VPX_PLANE_V] =
-          const_cast<uint8_t*>(frame->visible_data(VideoFrame::kVPlane));
-      vpx_image_.stride[VPX_PLANE_Y] = frame->stride(VideoFrame::kYPlane);
-      vpx_image_.stride[VPX_PLANE_U] = frame->stride(VideoFrame::kUPlane);
-      vpx_image_.stride[VPX_PLANE_V] = frame->stride(VideoFrame::kVPlane);
+      vpx_img_fmt_t fmt = frame->format() == PIXEL_FORMAT_NV12
+                              ? VPX_IMG_FMT_NV12
+                              : VPX_IMG_FMT_I420;
+      Status status = MaybeRewrapImageWithFormat(
+          &vpx_image_, fmt, codec_config_.g_w, codec_config_.g_h);
+      if (!status.is_ok()) {
+        std::move(done_cb).Run(status);
+        return;
+      }
+      if (fmt == VPX_IMG_FMT_NV12) {
+        vpx_image_.planes[VPX_PLANE_Y] =
+            const_cast<uint8_t*>(frame->visible_data(VideoFrame::kYPlane));
+        vpx_image_.planes[VPX_PLANE_U] =
+            const_cast<uint8_t*>(frame->visible_data(VideoFrame::kUVPlane));
+        // For NV12,the V plane address is set to U plane address + 1, see
+        // vpx_image.c: img->planes[VPX_PLANE_V] = img->planes[VPX_PLANE_U] + 1.
+        vpx_image_.planes[VPX_PLANE_V] = vpx_image_.planes[VPX_PLANE_U] + 1;
+        vpx_image_.stride[VPX_PLANE_Y] = frame->stride(VideoFrame::kYPlane);
+        vpx_image_.stride[VPX_PLANE_U] = frame->stride(VideoFrame::kUVPlane);
+        vpx_image_.stride[VPX_PLANE_V] = frame->stride(VideoFrame::kUVPlane);
+      } else {
+        vpx_image_.planes[VPX_PLANE_Y] =
+            const_cast<uint8_t*>(frame->visible_data(VideoFrame::kYPlane));
+        vpx_image_.planes[VPX_PLANE_U] =
+            const_cast<uint8_t*>(frame->visible_data(VideoFrame::kUPlane));
+        vpx_image_.planes[VPX_PLANE_V] =
+            const_cast<uint8_t*>(frame->visible_data(VideoFrame::kVPlane));
+        vpx_image_.stride[VPX_PLANE_Y] = frame->stride(VideoFrame::kYPlane);
+        vpx_image_.stride[VPX_PLANE_U] = frame->stride(VideoFrame::kUPlane);
+        vpx_image_.stride[VPX_PLANE_V] = frame->stride(VideoFrame::kVPlane);
+      }
       break;
   }
 
@@ -303,6 +356,20 @@
     return;
   }
 
+  auto old_area = options_.frame_size.GetCheckedArea();
+  auto new_area = options.frame_size.GetCheckedArea();
+  DCHECK(old_area.IsValid());
+
+  // Libvpx doesn't support reconfiguring in a way that enlarges frame area.
+  // https://bugs.chromium.org/p/webm/issues/detail?id=1642
+  if (!new_area.IsValid() || new_area.ValueOrDie() > old_area.ValueOrDie()) {
+    auto status =
+        Status(StatusCode::kEncoderUnsupportedConfig,
+               "libvpx doesn't support dynamically increasing frame area");
+    std::move(done_cb).Run(std::move(status));
+    return;
+  }
+
   vpx_codec_enc_cfg_t new_config = codec_config_;
   auto status = SetUpVpxConfig(options, &new_config);
   if (!status.is_ok()) {
@@ -310,13 +377,14 @@
     return;
   }
 
-  if (options_.width != options.width || options_.height != options.height) {
+  if (options_.frame_size != options.frame_size) {
     // Need to re-allocate |vpx_image_| because the size has changed.
     auto img_fmt = vpx_image_.fmt;
     auto bit_depth = vpx_image_.bit_depth;
     vpx_img_free(&vpx_image_);
-    if (&vpx_image_ != vpx_img_wrap(&vpx_image_, img_fmt, options.width,
-                                    options.height, 1, nullptr)) {
+    if (&vpx_image_ != vpx_img_wrap(&vpx_image_, img_fmt,
+                                    options.frame_size.width(),
+                                    options.frame_size.height(), 1, nullptr)) {
       status = Status(StatusCode::kEncoderInitializationError,
                       "Invalid format or frame size.");
       std::move(done_cb).Run(status);
diff --git a/net/cookies/cookie_monster.cc b/net/cookies/cookie_monster.cc
index 16ea90e..ab82526 100644
--- a/net/cookies/cookie_monster.cc
+++ b/net/cookies/cookie_monster.cc
@@ -1011,6 +1011,13 @@
                                           (*it)->SourceScheme()));
     }
 
+    if ((*it)->IsDomainCookie()) {
+      UMA_HISTOGRAM_ENUMERATION(
+          "Cookie.Port.ReadDiffersFromSet.DomainSet",
+          IsCookieSentToSamePortThatSetIt(url, (*it)->SourcePort(),
+                                          (*it)->SourceScheme()));
+    }
+
     included_cookies->push_back({**it, access_result});
   }
 }
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc
index 95eef42..259a8ab 100644
--- a/net/cookies/cookie_monster_unittest.cc
+++ b/net/cookies/cookie_monster_unittest.cc
@@ -4447,6 +4447,8 @@
   base::HistogramTester histograms;
   const char kHistogramName[] = "Cookie.Port.ReadDiffersFromSet.RemoteHost";
   const char kHistogramNameLocal[] = "Cookie.Port.ReadDiffersFromSet.Localhost";
+  const char kHistogramNameDomainSet[] =
+      "Cookie.Port.ReadDiffersFromSet.DomainSet";
 
   scoped_refptr<MockPersistentCookieStore> store(new MockPersistentCookieStore);
   std::unique_ptr<CookieMonster> cm(new CookieMonster(store.get(), &net_log_));
@@ -4522,6 +4524,23 @@
   histograms.ExpectTotalCount(kHistogramNameLocal, 1);
   histograms.ExpectBucketCount(kHistogramNameLocal,
                                CookieMonster::CookieSentToSamePort::kYes, 1);
+
+  // Make sure the Domain set version works.
+  EXPECT_TRUE(SetCookie(cm.get(), GURL("https://www.foo.com/withDomain"),
+                        "W=D; Domain=foo.com; Path=/withDomain"));
+
+  histograms.ExpectTotalCount(kHistogramNameDomainSet, 0);
+
+  EXPECT_EQ(GetCookies(cm.get(), GURL("https://www.foo.com/withDomain")),
+            "W=D");
+  histograms.ExpectTotalCount(kHistogramNameDomainSet, 1);
+  histograms.ExpectBucketCount(kHistogramNameDomainSet,
+                               CookieMonster::CookieSentToSamePort::kYes, 1);
+  // The RemoteHost histogram should also increase with this cookie. Domain
+  // cookies aren't special insofar as this metric is concerned.
+  histograms.ExpectTotalCount(kHistogramName, 6);
+  histograms.ExpectBucketCount(kHistogramName,
+                               CookieMonster::CookieSentToSamePort::kYes, 2);
 }
 
 }  // namespace net
diff --git a/ppapi/shared_impl/BUILD.gn b/ppapi/shared_impl/BUILD.gn
index 24e5734..0422393 100644
--- a/ppapi/shared_impl/BUILD.gn
+++ b/ppapi/shared_impl/BUILD.gn
@@ -166,6 +166,7 @@
   ]
 
   deps = [
+    "//build:chromeos_buildflags",
     "//gpu/command_buffer/client",
     "//gpu/command_buffer/client:gles2_cmd_helper",
     "//gpu/command_buffer/client:gles2_implementation",
diff --git a/ppapi/shared_impl/ppb_audio_config_shared.cc b/ppapi/shared_impl/ppb_audio_config_shared.cc
index 74a0b32..4b912d6 100644
--- a/ppapi/shared_impl/ppb_audio_config_shared.cc
+++ b/ppapi/shared_impl/ppb_audio_config_shared.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
 #include "ppapi/thunk/enter.h"
 #include "ppapi/thunk/ppb_instance_api.h"
 
@@ -84,7 +85,7 @@
 
   // Should track the value reported by XP and ALSA backends.
   const uint32_t kHighLatencySampleFrameCount = 2048;
-#if defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
+#if BUILDFLAG(IS_CHROMEOS_ASH) && defined(ARCH_CPU_ARM_FAMILY)
   // TODO(ihf): Remove this once ARM Chromebooks support low latency audio. For
   // now we classify them as high latency. See crbug.com/289770. Note that
   // Adobe Flash is affected but not HTML5, WebRTC and WebAudio (they are using
diff --git a/remoting/codec/webrtc_video_encoder_vpx.cc b/remoting/codec/webrtc_video_encoder_vpx.cc
index efe6af7..78074da 100644
--- a/remoting/codec/webrtc_video_encoder_vpx.cc
+++ b/remoting/codec/webrtc_video_encoder_vpx.cc
@@ -4,6 +4,7 @@
 
 #include "remoting/codec/webrtc_video_encoder_vpx.h"
 
+#include <algorithm>
 #include <utility>
 
 #include "base/bind.h"
@@ -11,6 +12,7 @@
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
 #include "base/system/sys_info.h"
+#include "build/build_config.h"
 #include "remoting/base/util.h"
 #include "remoting/proto/video.pb.h"
 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
@@ -82,6 +84,12 @@
                            const webrtc::DesktopSize& size) {
   SetCommonCodecParameters(config, size);
 
+#if defined(OS_LINUX)
+  // On Linux, using too many threads for VP8 encoding has been linked to high
+  // CPU usage on machines that are under stress. See http://crbug.com/1151148.
+  config->g_threads = std::min(config->g_threads, 2U);
+#endif  // defined(OS_LINUX)
+
   // Value of 2 means using the real time profile. This is basically a
   // redundant option since we explicitly select real time mode when doing
   // encoding.
diff --git a/services/network/BUILD.gn b/services/network/BUILD.gn
index 78d70dc..1a72112 100644
--- a/services/network/BUILD.gn
+++ b/services/network/BUILD.gn
@@ -181,6 +181,8 @@
     "url_request_context_builder_mojo.h",
     "url_request_context_owner.cc",
     "url_request_context_owner.h",
+    "web_bundle_url_loader_factory.cc",
+    "web_bundle_url_loader_factory.h",
   ]
 
   if (enable_mdns) {
@@ -232,6 +234,7 @@
     "//components/network_session_configurator/common",
     "//components/os_crypt",
     "//components/prefs",
+    "//components/web_package",
     "//jingle:fake_ssl_socket",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
@@ -342,6 +345,7 @@
     "udp_socket_unittest.cc",
     "upload_progress_tracker_unittest.cc",
     "url_loader_unittest.cc",
+    "web_bundle_url_loader_factory_unittest.cc",
   ]
 
   if (enable_mdns) {
@@ -382,6 +386,7 @@
     "//components/network_session_configurator/browser",
     "//components/prefs:test_support",
     "//components/variations:test_support",
+    "//components/web_package:test_support",
     "//crypto:test_support",
     "//jingle:fake_ssl_socket",
     "//mojo/public/cpp/bindings",
diff --git a/services/network/DEPS b/services/network/DEPS
index 0d167b8..f0c4b947 100644
--- a/services/network/DEPS
+++ b/services/network/DEPS
@@ -9,6 +9,7 @@
   # store for networking-related data (Like which servers support QUIC), rather
   # than to store user preferences.
   "+components/prefs",
+  "+components/web_package",
   "+crypto",
   "+ipc",
   # FakeSSLClientSocket
diff --git a/services/network/public/mojom/BUILD.gn b/services/network/public/mojom/BUILD.gn
index e95eb1e..5de301a5 100644
--- a/services/network/public/mojom/BUILD.gn
+++ b/services/network/public/mojom/BUILD.gn
@@ -165,6 +165,7 @@
     "mutable_network_traffic_annotation_tag.mojom",
     "mutable_partial_network_traffic_annotation_tag.mojom",
     "trust_tokens.mojom",
+    "web_bundle_handle.mojom",
   ]
 
   public_deps = [
diff --git a/services/network/public/mojom/web_bundle_handle.mojom b/services/network/public/mojom/web_bundle_handle.mojom
new file mode 100644
index 0000000..a12c6872
--- /dev/null
+++ b/services/network/public/mojom/web_bundle_handle.mojom
@@ -0,0 +1,23 @@
+// Copyright 2020 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.
+
+module network.mojom;
+
+enum WebBundleErrorType {
+  kMetadataParseError,
+  kResponseParseError,
+  kResourceNotFound,
+};
+
+// A handle to a WebBundle instance in the Network Service. Created by a
+// renderer, and its remote endpoint is passed to the Network Service. The
+// receiving endpoint is held in the renderer and closed to tell the Network
+// Service that the Bundle is no longer needed.
+interface WebBundleHandle {
+  // Used to create a copy of this handle.
+  Clone(pending_receiver<WebBundleHandle> receiver);
+
+  // Report errors to the renderer.
+  OnWebBundleError(WebBundleErrorType type, string message);
+};
diff --git a/services/network/web_bundle_url_loader_factory.cc b/services/network/web_bundle_url_loader_factory.cc
new file mode 100644
index 0000000..3264c29
--- /dev/null
+++ b/services/network/web_bundle_url_loader_factory.cc
@@ -0,0 +1,387 @@
+// Copyright 2020 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 "services/network/web_bundle_url_loader_factory.h"
+
+#include "components/web_package/web_bundle_parser.h"
+#include "components/web_package/web_bundle_utils.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/data_pipe_drainer.h"
+#include "mojo/public/cpp/system/data_pipe_producer.h"
+#include "net/http/http_status_code.h"
+
+namespace network {
+
+namespace {
+
+class PipeDataSource : public mojo::DataPipeProducer::DataSource {
+ public:
+  explicit PipeDataSource(std::vector<uint8_t> data) : data_(std::move(data)) {}
+  uint64_t GetLength() const override { return data_.size(); }
+
+  ReadResult Read(uint64_t uint64_offset, base::span<char> buffer) override {
+    ReadResult result;
+    if (uint64_offset > data_.size()) {
+      result.result = MOJO_RESULT_OUT_OF_RANGE;
+      return result;
+    }
+    size_t offset = base::checked_cast<size_t>(uint64_offset);
+    size_t len = std::min(data_.size() - offset, buffer.size());
+    if (len > 0) {
+      DCHECK_LT(offset, data_.size());
+      memcpy(buffer.data(), &data_[offset], len);
+    }
+    result.bytes_read = len;
+    return result;
+  }
+
+ private:
+  // Since mojo::DataPipeProducer runs in its own sequence, we can't just have
+  // a reference to the buffer in BundleDataSource.
+  std::vector<uint8_t> data_;
+};
+
+void DeleteProducerAndRunCallback(
+    std::unique_ptr<mojo::DataPipeProducer> producer,
+    base::OnceCallback<void(MojoResult result)> callback,
+    MojoResult result) {
+  std::move(callback).Run(result);
+}
+
+}  // namespace
+
+class WebBundleURLLoaderFactory::URLLoader : public mojom::URLLoader {
+ public:
+  URLLoader(mojo::PendingReceiver<mojom::URLLoader> loader,
+            const ResourceRequest& request,
+            mojo::PendingRemote<mojom::URLLoaderClient> client)
+      : url_(request.url),
+        receiver_(this, std::move(loader)),
+        client_(std::move(client)) {
+    receiver_.set_disconnect_handler(
+        base::BindOnce(&URLLoader::OnMojoDisconnect, GetWeakPtr()));
+  }
+  URLLoader(const URLLoader&) = delete;
+  URLLoader& operator=(const URLLoader&) = delete;
+
+  const GURL& url() const { return url_; }
+
+  base::WeakPtr<URLLoader> GetWeakPtr() {
+    return weak_ptr_factory_.GetWeakPtr();
+  }
+
+  void OnResponse(mojom::URLResponseHeadPtr response) {
+    client_->OnReceiveResponse(std::move(response));
+  }
+
+  void OnData(mojo::ScopedDataPipeConsumerHandle consumer) {
+    client_->OnStartLoadingResponseBody(std::move(consumer));
+  }
+
+  void OnFail(net::Error error) {
+    client_->OnComplete(URLLoaderCompletionStatus(error));
+    delete this;
+  }
+
+  void OnWriteCompleted(MojoResult result) {
+    URLLoaderCompletionStatus status(
+        result == MOJO_RESULT_OK ? net::OK : net::ERR_INVALID_WEB_BUNDLE);
+    client_->OnComplete(status);
+    delete this;
+  }
+
+ private:
+  // mojom::URLLoader
+  void FollowRedirect(
+      const std::vector<std::string>& removed_headers,
+      const net::HttpRequestHeaders& modified_headers,
+      const net::HttpRequestHeaders& modified_cors_exempt_headers,
+      const base::Optional<GURL>& new_url) override {
+    NOTREACHED();
+  }
+
+  void SetPriority(net::RequestPriority priority,
+                   int32_t intra_priority_value) override {
+    // Not supported (do nothing).
+  }
+
+  void PauseReadingBodyFromNet() override {}
+  void ResumeReadingBodyFromNet() override {}
+
+  void OnMojoDisconnect() { delete this; }
+
+  const GURL url_;
+  mojo::Receiver<mojom::URLLoader> receiver_;
+  mojo::Remote<mojom::URLLoaderClient> client_;
+  base::WeakPtrFactory<URLLoader> weak_ptr_factory_{this};
+};
+
+class WebBundleURLLoaderFactory::BundleDataSource
+    : public web_package::mojom::BundleDataSource,
+      public mojo::DataPipeDrainer::Client {
+ public:
+  using ReadToDataPipeCallback = base::OnceCallback<void(MojoResult result)>;
+
+  BundleDataSource(mojo::PendingReceiver<web_package::mojom::BundleDataSource>
+                       data_source_receiver,
+                   mojo::ScopedDataPipeConsumerHandle bundle_body)
+      : data_source_receiver_(this, std::move(data_source_receiver)),
+        pipe_drainer_(
+            std::make_unique<mojo::DataPipeDrainer>(this,
+                                                    std::move(bundle_body))) {}
+
+  ~BundleDataSource() override {
+    // The receiver must be closed before destructing pending callbacks in
+    // |pending_reads_| / |pending_reads_to_data_pipe_|.
+    data_source_receiver_.reset();
+  }
+
+  BundleDataSource(const BundleDataSource&) = delete;
+  BundleDataSource& operator=(const BundleDataSource&) = delete;
+
+  void ReadToDataPipe(mojo::ScopedDataPipeProducerHandle producer,
+                      uint64_t offset,
+                      uint64_t length,
+                      ReadToDataPipeCallback callback) {
+    TRACE_EVENT0("loading", "BundleDataSource::ReadToDataPipe");
+    if (!finished_loading_ && offset + length > data_.size()) {
+      // Current implementation does not support progressive loading of inner
+      // response body.
+      PendingReadToDataPipe pending;
+      pending.producer = std::move(producer);
+      pending.offset = offset;
+      pending.length = length;
+      pending.callback = std::move(callback);
+      pending_reads_to_data_pipe_.push_back(std::move(pending));
+      return;
+    }
+
+    auto writer = std::make_unique<mojo::DataPipeProducer>(std::move(producer));
+    mojo::DataPipeProducer* raw_writer = writer.get();
+    raw_writer->Write(std::make_unique<PipeDataSource>(GetData(offset, length)),
+                      base::BindOnce(&DeleteProducerAndRunCallback,
+                                     std::move(writer), std::move(callback)));
+  }
+
+  // mojom::BundleDataSource
+  void Read(uint64_t offset, uint64_t length, ReadCallback callback) override {
+    TRACE_EVENT0("loading", "BundleDataSource::Read");
+    if (!finished_loading_ && offset + length > data_.size()) {
+      PendingRead pending;
+      pending.offset = offset;
+      pending.length = length;
+      pending.callback = std::move(callback);
+      pending_reads_.push_back(std::move(pending));
+      return;
+    }
+    std::move(callback).Run(GetData(offset, length));
+  }
+
+  // mojo::DataPipeDrainer::Client
+  void OnDataAvailable(const void* data, size_t num_bytes) override {
+    DCHECK(!finished_loading_);
+    const uint8_t* data_uint8 = reinterpret_cast<const uint8_t*>(data);
+    // TODO(crbug.com/1082020): Set a threshold for buffer size, so that Network
+    // Service does not use memory indefinitely.
+    data_.insert(data_.end(), data_uint8, data_uint8 + num_bytes);
+    ProcessPendingReads();
+  }
+
+  void OnDataComplete() override {
+    DCHECK(!finished_loading_);
+    finished_loading_ = true;
+    ProcessPendingReads();
+  }
+
+ private:
+  void ProcessPendingReads() {
+    std::vector<PendingRead> pendings;
+    pendings.swap(pending_reads_);
+    for (auto& pending : pendings)
+      Read(pending.offset, pending.length, std::move(pending.callback));
+
+    std::vector<PendingReadToDataPipe> pipe_pendings;
+    pipe_pendings.swap(pending_reads_to_data_pipe_);
+    for (auto& pending : pipe_pendings) {
+      ReadToDataPipe(std::move(pending.producer), pending.offset,
+                     pending.length, std::move(pending.callback));
+    }
+  }
+
+  std::vector<uint8_t> GetData(uint64_t uint64_offset, uint64_t uint64_length) {
+    size_t offset = base::checked_cast<size_t>(uint64_offset);
+    size_t length = base::checked_cast<size_t>(uint64_length);
+    if (offset >= data_.size())
+      return {};
+    if (length > data_.size() - offset)
+      length = data_.size() - offset;
+
+    std::vector<uint8_t> output(length);
+    memcpy(output.data(), data_.data() + offset, length);
+    return output;
+  }
+
+  struct PendingRead {
+    uint64_t offset;
+    uint64_t length;
+    ReadCallback callback;
+  };
+  struct PendingReadToDataPipe {
+    mojo::ScopedDataPipeProducerHandle producer;
+    uint64_t offset;
+    uint64_t length;
+    ReadToDataPipeCallback callback;
+  };
+
+  mojo::Receiver<web_package::mojom::BundleDataSource> data_source_receiver_;
+  std::vector<uint8_t> data_;
+  std::vector<PendingRead> pending_reads_;
+  std::vector<PendingReadToDataPipe> pending_reads_to_data_pipe_;
+  bool finished_loading_ = false;
+  std::unique_ptr<mojo::DataPipeDrainer> pipe_drainer_;
+};
+
+WebBundleURLLoaderFactory::WebBundleURLLoaderFactory(
+    mojo::Remote<mojom::WebBundleHandle> web_bundle_handle)
+    : web_bundle_handle_(std::move(web_bundle_handle)) {}
+
+WebBundleURLLoaderFactory::~WebBundleURLLoaderFactory() {
+  for (auto loader : pending_loaders_) {
+    if (loader)
+      loader->OnFail(net::ERR_FAILED);
+  }
+}
+
+base::WeakPtr<WebBundleURLLoaderFactory> WebBundleURLLoaderFactory::GetWeakPtr()
+    const {
+  return weak_ptr_factory_.GetWeakPtr();
+}
+
+void WebBundleURLLoaderFactory::SetBundleStream(
+    mojo::ScopedDataPipeConsumerHandle body) {
+  mojo::PendingRemote<web_package::mojom::BundleDataSource> data_source;
+  source_ = std::make_unique<BundleDataSource>(
+      data_source.InitWithNewPipeAndPassReceiver(), std::move(body));
+  // WebBundleParser will self-destruct on remote mojo ends' disconnection.
+  new web_package::WebBundleParser(parser_.BindNewPipeAndPassReceiver(),
+                                   std::move(data_source));
+
+  parser_->ParseMetadata(
+      base::BindOnce(&WebBundleURLLoaderFactory::OnMetadataParsed,
+                     weak_ptr_factory_.GetWeakPtr()));
+}
+
+void WebBundleURLLoaderFactory::CreateLoaderAndStart(
+    mojo::PendingReceiver<mojom::URLLoader> receiver,
+    int32_t routing_id,
+    int32_t request_id,
+    uint32_t options,
+    const ResourceRequest& url_request,
+    mojo::PendingRemote<mojom::URLLoaderClient> client,
+    const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+  TRACE_EVENT0("loading", "WebBundleURLLoaderFactory::CreateLoaderAndStart");
+  URLLoader* loader =
+      new URLLoader(std::move(receiver), url_request, std::move(client));
+  if (metadata_error_) {
+    loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
+    return;
+  }
+  if (!metadata_) {
+    pending_loaders_.push_back(loader->GetWeakPtr());
+    return;
+  }
+  StartLoad(loader);
+}
+
+void WebBundleURLLoaderFactory::Clone(
+    mojo::PendingReceiver<mojom::URLLoaderFactory> receiver) {
+  NOTREACHED();
+}
+
+void WebBundleURLLoaderFactory::StartLoad(URLLoader* loader) {
+  DCHECK(metadata_);
+  if (!loader)
+    return;
+  auto it = metadata_->requests.find(loader->url());
+  if (it == metadata_->requests.end()) {
+    web_bundle_handle_->OnWebBundleError(
+        mojom::WebBundleErrorType::kResourceNotFound,
+        loader->url().possibly_invalid_spec() +
+            " is not found in the WebBundle.");
+    loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
+    return;
+  }
+  // Currently, we just return the first response for the URL.
+  // TODO(crbug.com/1082020): Support variant matching.
+  auto& location = it->second->response_locations[0];
+
+  parser_->ParseResponse(
+      location->offset, location->length,
+      base::BindOnce(&WebBundleURLLoaderFactory::OnResponseParsed,
+                     weak_ptr_factory_.GetWeakPtr(), loader->GetWeakPtr()));
+}
+
+void WebBundleURLLoaderFactory::OnMetadataParsed(
+    web_package::mojom::BundleMetadataPtr metadata,
+    web_package::mojom::BundleMetadataParseErrorPtr error) {
+  TRACE_EVENT0("loading", "WebBundleURLLoaderFactory::OnMetadataParsed");
+  if (error) {
+    metadata_error_ = std::move(error);
+    web_bundle_handle_->OnWebBundleError(
+        mojom::WebBundleErrorType::kMetadataParseError,
+        metadata_error_->message);
+    for (auto loader : pending_loaders_) {
+      if (loader)
+        loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
+    }
+    pending_loaders_.clear();
+    return;
+  }
+
+  metadata_ = std::move(metadata);
+  for (auto loader : pending_loaders_)
+    StartLoad(loader.get());
+  pending_loaders_.clear();
+}
+
+void WebBundleURLLoaderFactory::OnResponseParsed(
+    base::WeakPtr<URLLoader> loader,
+    web_package::mojom::BundleResponsePtr response,
+    web_package::mojom::BundleResponseParseErrorPtr error) {
+  TRACE_EVENT0("loading", "WebBundleURLLoaderFactory::OnResponseParsed");
+  if (!loader)
+    return;
+  if (error) {
+    web_bundle_handle_->OnWebBundleError(
+        mojom::WebBundleErrorType::kResponseParseError, error->message);
+    loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
+    return;
+  }
+  // Currently we allow only net::HTTP_OK responses in bundles.
+  // TODO(crbug.com/990733): Revisit this once
+  // https://github.com/WICG/webpackage/issues/478 is resolved.
+  if (response->response_code != net::HTTP_OK) {
+    web_bundle_handle_->OnWebBundleError(
+        mojom::WebBundleErrorType::kResponseParseError,
+        "Invalid response code " +
+            base::NumberToString(response->response_code));
+    loader->OnFail(net::ERR_INVALID_WEB_BUNDLE);
+    return;
+  }
+
+  loader->OnResponse(web_package::CreateResourceResponse(response));
+
+  mojo::ScopedDataPipeProducerHandle producer;
+  mojo::ScopedDataPipeConsumerHandle consumer;
+  if (CreateDataPipe(nullptr, &producer, &consumer) != MOJO_RESULT_OK) {
+    loader->OnFail(net::ERR_INSUFFICIENT_RESOURCES);
+    return;
+  }
+  loader->OnData(std::move(consumer));
+  source_->ReadToDataPipe(
+      std::move(producer), response->payload_offset, response->payload_length,
+      base::BindOnce(&URLLoader::OnWriteCompleted, loader->GetWeakPtr()));
+}
+
+}  // namespace network
diff --git a/services/network/web_bundle_url_loader_factory.h b/services/network/web_bundle_url_loader_factory.h
new file mode 100644
index 0000000..6e4669a
--- /dev/null
+++ b/services/network/web_bundle_url_loader_factory.h
@@ -0,0 +1,67 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_NETWORK_WEB_BUNDLE_URL_LOADER_FACTORY_H_
+#define SERVICES_NETWORK_WEB_BUNDLE_URL_LOADER_FACTORY_H_
+
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/memory/weak_ptr.h"
+#include "components/web_package/mojom/web_bundle_parser.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/public/mojom/web_bundle_handle.mojom.h"
+
+namespace network {
+
+class COMPONENT_EXPORT(NETWORK_SERVICE) WebBundleURLLoaderFactory
+    : public mojom::URLLoaderFactory {
+ public:
+  explicit WebBundleURLLoaderFactory(
+      mojo::Remote<mojom::WebBundleHandle> web_bundle_handle);
+  ~WebBundleURLLoaderFactory() override;
+  WebBundleURLLoaderFactory(const WebBundleURLLoaderFactory&) = delete;
+  WebBundleURLLoaderFactory& operator=(const WebBundleURLLoaderFactory&) =
+      delete;
+
+  base::WeakPtr<WebBundleURLLoaderFactory> GetWeakPtr() const;
+
+  void SetBundleStream(mojo::ScopedDataPipeConsumerHandle body);
+
+  // mojom::URLLoaderFactory implementation.
+  void CreateLoaderAndStart(mojo::PendingReceiver<mojom::URLLoader> receiver,
+                            int32_t routing_id,
+                            int32_t request_id,
+                            uint32_t options,
+                            const ResourceRequest& url_request,
+                            mojo::PendingRemote<mojom::URLLoaderClient> client,
+                            const net::MutableNetworkTrafficAnnotationTag&
+                                traffic_annotation) override;
+
+  void Clone(mojo::PendingReceiver<mojom::URLLoaderFactory> receiver) override;
+
+ private:
+  class BundleDataSource;
+  class URLLoader;
+
+  void StartLoad(URLLoader* loader);
+  void OnMetadataParsed(web_package::mojom::BundleMetadataPtr metadata,
+                        web_package::mojom::BundleMetadataParseErrorPtr error);
+  void OnResponseParsed(base::WeakPtr<URLLoader> loader,
+                        web_package::mojom::BundleResponsePtr response,
+                        web_package::mojom::BundleResponseParseErrorPtr error);
+
+  mojo::Remote<mojom::WebBundleHandle> web_bundle_handle_;
+  std::unique_ptr<BundleDataSource> source_;
+  mojo::Remote<web_package::mojom::WebBundleParser> parser_;
+  web_package::mojom::BundleMetadataPtr metadata_;
+  web_package::mojom::BundleMetadataParseErrorPtr metadata_error_;
+  std::vector<base::WeakPtr<URLLoader>> pending_loaders_;
+
+  base::WeakPtrFactory<WebBundleURLLoaderFactory> weak_ptr_factory_{this};
+};
+
+}  // namespace network
+
+#endif  // SERVICES_NETWORK_WEB_BUNDLE_URL_LOADER_FACTORY_H_
diff --git a/services/network/web_bundle_url_loader_factory_unittest.cc b/services/network/web_bundle_url_loader_factory_unittest.cc
new file mode 100644
index 0000000..1758676
--- /dev/null
+++ b/services/network/web_bundle_url_loader_factory_unittest.cc
@@ -0,0 +1,340 @@
+// Copyright 2020 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 "services/network/web_bundle_url_loader_factory.h"
+
+#include "base/test/task_environment.h"
+#include "components/web_package/test_support/web_bundle_builder.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "mojo/public/cpp/system/data_pipe_utils.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/test/test_url_loader_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace {
+
+const char kResourceUrl[] = "https://example.com/";
+const char kResourceUrl2[] = "https://example.com/another";
+const char kResourceUrl3[] = "https://example.com/yetanother";
+
+std::vector<uint8_t> CreateSmallBundle() {
+  web_package::test::WebBundleBuilder builder(kResourceUrl,
+                                              "" /* manifest_url */);
+  builder.AddExchange(kResourceUrl,
+                      {{":status", "200"}, {"content-type", "text/plain"}},
+                      "body");
+  return builder.CreateBundle();
+}
+
+std::vector<uint8_t> CreateLargeBundle() {
+  web_package::test::WebBundleBuilder builder(kResourceUrl,
+                                              "" /* manifest_url */);
+  builder.AddExchange(kResourceUrl,
+                      {{":status", "200"}, {"content-type", "text/plain"}},
+                      "body");
+  builder.AddExchange(kResourceUrl2,
+                      {{":status", "200"}, {"content-type", "text/plain"}},
+                      std::string(10000, 'a'));
+  builder.AddExchange(kResourceUrl3,
+                      {{":status", "200"}, {"content-type", "text/plain"}},
+                      "body");
+  return builder.CreateBundle();
+}
+
+class TestWebBundleHandle : public mojom::WebBundleHandle {
+ public:
+  explicit TestWebBundleHandle(
+      mojo::PendingReceiver<mojom::WebBundleHandle> receiver)
+      : receiver_(this, std::move(receiver)) {}
+
+  const base::Optional<std::pair<mojom::WebBundleErrorType, std::string>>&
+  last_bundle_error() const {
+    return last_bundle_error_;
+  }
+
+  void RunUntilBundleError() {
+    if (last_bundle_error_.has_value())
+      return;
+    base::RunLoop run_loop;
+    quit_closure_for_bundle_error_ = run_loop.QuitClosure();
+    run_loop.Run();
+  }
+
+  // mojom::WebBundleHandle
+  void Clone(mojo::PendingReceiver<mojom::WebBundleHandle> receiver) override {
+    NOTREACHED();
+  }
+
+  void OnWebBundleError(mojom::WebBundleErrorType type,
+                        const std::string& message) override {
+    last_bundle_error_ = std::make_pair(type, message);
+    if (quit_closure_for_bundle_error_)
+      std::move(quit_closure_for_bundle_error_).Run();
+  }
+
+ private:
+  mojo::Receiver<mojom::WebBundleHandle> receiver_;
+  base::Optional<std::pair<mojom::WebBundleErrorType, std::string>>
+      last_bundle_error_;
+  base::OnceClosure quit_closure_for_bundle_error_;
+};
+
+}  // namespace
+
+class WebBundleURLLoaderFactoryTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    mojo::ScopedDataPipeConsumerHandle consumer;
+    ASSERT_EQ(CreateDataPipe(nullptr, &bundle_data_destination_, &consumer),
+              MOJO_RESULT_OK);
+    mojo::Remote<mojom::WebBundleHandle> handle;
+    handle_ = std::make_unique<TestWebBundleHandle>(
+        handle.BindNewPipeAndPassReceiver());
+    factory_ = std::make_unique<WebBundleURLLoaderFactory>(std::move(handle));
+    factory_->SetBundleStream(std::move(consumer));
+  }
+
+  void WriteBundle(base::span<const uint8_t> data) {
+    mojo::BlockingCopyFromString(
+        std::string(reinterpret_cast<const char*>(data.data()), data.size()),
+        bundle_data_destination_);
+  }
+
+  void FinishWritingBundle() { bundle_data_destination_.reset(); }
+
+  struct StartRequestResult {
+    mojo::Remote<network::mojom::URLLoader> loader;
+    std::unique_ptr<network::TestURLLoaderClient> client;
+  };
+
+  StartRequestResult StartRequest(const GURL& url) {
+    network::ResourceRequest request;
+    request.url = url;
+    request.method = "GET";
+    StartRequestResult result;
+    result.client = std::make_unique<network::TestURLLoaderClient>();
+    factory_->CreateLoaderAndStart(
+        result.loader.BindNewPipeAndPassReceiver(), 0 /* routing_id */,
+        0 /* request_id */, 0 /* options */, request,
+        result.client->CreateRemote(),
+        net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+    return result;
+  }
+
+  void RunUntilBundleError() { handle_->RunUntilBundleError(); }
+
+  const base::Optional<std::pair<mojom::WebBundleErrorType, std::string>>&
+  last_bundle_error() const {
+    return handle_->last_bundle_error();
+  }
+
+ protected:
+  std::unique_ptr<WebBundleURLLoaderFactory> factory_;
+
+ private:
+  std::unique_ptr<TestWebBundleHandle> handle_;
+  mojo::ScopedDataPipeProducerHandle bundle_data_destination_;
+  base::test::TaskEnvironment task_environment;
+};
+
+TEST_F(WebBundleURLLoaderFactoryTest, Basic) {
+  WriteBundle(CreateSmallBundle());
+  FinishWritingBundle();
+
+  auto request = StartRequest(GURL(kResourceUrl));
+  request.client->RunUntilComplete();
+
+  EXPECT_EQ(net::OK, request.client->completion_status().error_code);
+  EXPECT_FALSE(last_bundle_error().has_value());
+  std::string body;
+  EXPECT_TRUE(mojo::BlockingCopyToString(
+      request.client->response_body_release(), &body));
+  EXPECT_EQ("body", body);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, MetadataParseError) {
+  auto request = StartRequest(GURL(kResourceUrl));
+
+  std::vector<uint8_t> bundle = CreateSmallBundle();
+  bundle[4] ^= 1;  // Mutate magic bytes.
+  WriteBundle(bundle);
+  FinishWritingBundle();
+
+  request.client->RunUntilComplete();
+  RunUntilBundleError();
+
+  EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+            request.client->completion_status().error_code);
+  EXPECT_EQ(last_bundle_error()->first,
+            mojom::WebBundleErrorType::kMetadataParseError);
+  EXPECT_EQ(last_bundle_error()->second, "Wrong magic bytes.");
+
+  // Requests made after metadata parse error should also fail.
+  auto request2 = StartRequest(GURL(kResourceUrl));
+  request2.client->RunUntilComplete();
+
+  EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+            request2.client->completion_status().error_code);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, ResponseParseError) {
+  web_package::test::WebBundleBuilder builder(kResourceUrl,
+                                              "" /* manifest_url */);
+  // An invalid response.
+  builder.AddExchange(kResourceUrl, {{":status", "0"}}, "body");
+  WriteBundle(builder.CreateBundle());
+  FinishWritingBundle();
+
+  auto request = StartRequest(GURL(kResourceUrl));
+  request.client->RunUntilComplete();
+  RunUntilBundleError();
+
+  EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+            request.client->completion_status().error_code);
+  EXPECT_EQ(last_bundle_error()->first,
+            mojom::WebBundleErrorType::kResponseParseError);
+  EXPECT_EQ(last_bundle_error()->second,
+            ":status must be 3 ASCII decimal digits.");
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, ResourceNotFoundInBundle) {
+  WriteBundle(CreateSmallBundle());
+  FinishWritingBundle();
+
+  auto request = StartRequest(GURL("https://example.com/no-such-resource"));
+  request.client->RunUntilComplete();
+  RunUntilBundleError();
+
+  EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+            request.client->completion_status().error_code);
+  EXPECT_EQ(last_bundle_error()->first,
+            mojom::WebBundleErrorType::kResourceNotFound);
+  EXPECT_EQ(
+      last_bundle_error()->second,
+      "https://example.com/no-such-resource is not found in the WebBundle.");
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, RedirectResponseIsNotAllowed) {
+  web_package::test::WebBundleBuilder builder(kResourceUrl,
+                                              "" /* manifest_url */);
+  builder.AddExchange(kResourceUrl,
+                      {{":status", "301"}, {"location", kResourceUrl2}}, "");
+  builder.AddExchange(kResourceUrl2,
+                      {{":status", "200"}, {"content-type", "text/plain"}},
+                      "body");
+  WriteBundle(builder.CreateBundle());
+  FinishWritingBundle();
+
+  auto request = StartRequest(GURL(kResourceUrl));
+  request.client->RunUntilComplete();
+  RunUntilBundleError();
+
+  EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+            request.client->completion_status().error_code);
+  EXPECT_EQ(last_bundle_error()->first,
+            mojom::WebBundleErrorType::kResponseParseError);
+  EXPECT_EQ(last_bundle_error()->second, "Invalid response code 301");
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, StartRequestBeforeReadingBundle) {
+  auto request = StartRequest(GURL(kResourceUrl));
+
+  WriteBundle(CreateSmallBundle());
+  FinishWritingBundle();
+  request.client->RunUntilComplete();
+
+  EXPECT_EQ(net::OK, request.client->completion_status().error_code);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, MultipleRequests) {
+  auto request1 = StartRequest(GURL(kResourceUrl));
+  auto request2 = StartRequest(GURL(kResourceUrl2));
+
+  std::vector<uint8_t> bundle = CreateLargeBundle();
+  // Write the first 10kB of the bundle in which the bundle's metadata and the
+  // response for kResourceUrl are included.
+  ASSERT_GT(bundle.size(), 10000U);
+  WriteBundle(base::make_span(bundle).subspan(0, 10000));
+  request1.client->RunUntilComplete();
+
+  EXPECT_EQ(net::OK, request1.client->completion_status().error_code);
+  EXPECT_FALSE(request2.client->has_received_completion());
+
+  // Write the rest of the data.
+  WriteBundle(base::make_span(bundle).subspan(10000));
+  FinishWritingBundle();
+  request2.client->RunUntilComplete();
+
+  EXPECT_EQ(net::OK, request2.client->completion_status().error_code);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, CancelRequest) {
+  auto request_to_complete1 = StartRequest(GURL(kResourceUrl));
+  auto request_to_complete2 = StartRequest(GURL(kResourceUrl2));
+  auto request_to_cancel1 = StartRequest(GURL(kResourceUrl));
+  auto request_to_cancel2 = StartRequest(GURL(kResourceUrl2));
+  auto request_to_cancel3 = StartRequest(GURL(kResourceUrl3));
+
+  // Cancel request before getting metadata.
+  request_to_cancel1.loader.reset();
+
+  std::vector<uint8_t> bundle = CreateLargeBundle();
+  // Write the first 10kB of the bundle in which the bundle's metadata, response
+  // for kResourceUrl, and response header for kResourceUrl2 are included.
+  ASSERT_GT(bundle.size(), 10000U);
+  WriteBundle(base::make_span(bundle).subspan(0, 10000));
+
+  // This makes sure the bytes written above are consumed by WebBundle parser.
+  request_to_complete1.client->RunUntilComplete();
+
+  // Cancel request after reading response header, but before reading body.
+  request_to_cancel2.loader.reset();
+
+  // Cancel request after getting metadata, but before reading response header.
+  request_to_cancel3.loader.reset();
+
+  // Write the rest of the data.
+  WriteBundle(base::make_span(bundle).subspan(10000));
+  FinishWritingBundle();
+  request_to_complete2.client->RunUntilComplete();
+  EXPECT_EQ(net::OK,
+            request_to_complete2.client->completion_status().error_code);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest,
+       FactoryDestructionCancelsInflightRequests) {
+  auto request = StartRequest(GURL(kResourceUrl));
+
+  factory_ = nullptr;
+
+  WriteBundle(CreateSmallBundle());
+  FinishWritingBundle();
+  request.client->RunUntilComplete();
+
+  EXPECT_EQ(net::ERR_FAILED, request.client->completion_status().error_code);
+}
+
+TEST_F(WebBundleURLLoaderFactoryTest, TruncatedBundle) {
+  std::vector<uint8_t> bundle = CreateSmallBundle();
+  // Truncate in the middle of responses section.
+  bundle.resize(bundle.size() - 10);
+  WriteBundle(std::move(bundle));
+  FinishWritingBundle();
+
+  auto request = StartRequest(GURL(kResourceUrl));
+  request.client->RunUntilComplete();
+  RunUntilBundleError();
+
+  EXPECT_EQ(net::ERR_INVALID_WEB_BUNDLE,
+            request.client->completion_status().error_code);
+  EXPECT_EQ(last_bundle_error()->first,
+            mojom::WebBundleErrorType::kResponseParseError);
+  EXPECT_EQ(last_bundle_error()->second, "Error reading response header.");
+}
+
+}  // namespace network
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index d829e1f..27e4668 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -233,6 +233,10 @@
 #define SK_SUPPORT_LEGACY_ADJUSTHQHEURISTIC
 #endif
 
+#ifndef SK_SUPPORT_LEGACY_SCALEPIXELS_PARAM
+#define SK_SUPPORT_LEGACY_SCALEPIXELS_PARAM
+#endif
+
 // Staging for lowp::bilerp_clamp_8888, and for planned misc. others.
 #define SK_DISABLE_LOWP_BILERP_CLAMP_CLAMP_STAGE
 
diff --git a/testing/buildbot/chromium.updater.json b/testing/buildbot/chromium.updater.json
index aa21cd7f7..cfe90c462 100644
--- a/testing/buildbot/chromium.updater.json
+++ b/testing/buildbot/chromium.updater.json
@@ -1,6 +1,51 @@
 {
   "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {},
   "AAAAA2 See generate_buildbot_json.py to make changes": {},
+  "mac-arm64-updater-tester-rel": {
+    "gtest_tests": [
+      {
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_gtest_merge.py"
+        },
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "os": "Mac-11.0|Mac-10.16",
+              "pool": "chromium.tests.mac-arm64"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test": "updater_tests",
+        "test_id_prefix": "ninja://chrome/updater:updater_tests/"
+      }
+    ],
+    "isolated_scripts": [
+      {
+        "isolate_name": "updater_integration_tests",
+        "merge": {
+          "args": [],
+          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
+        },
+        "name": "updater_integration_tests",
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "cpu": "arm64",
+              "os": "Mac-11.0|Mac-10.16",
+              "pool": "chromium.tests.mac-arm64"
+            }
+          ],
+          "service_account": "chromium-tester@chops-service-accounts.iam.gserviceaccount.com"
+        },
+        "test_id_prefix": "ninja://chrome/updater:updater_integration_tests/"
+      }
+    ]
+  },
   "mac10.11-updater-tester-rel": {
     "gtest_tests": [
       {
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index a5bba2be..63cd9dd 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -5261,6 +5261,15 @@
     'name': 'chromium.updater',
     'mixins': ['chromium-tester-service-account'],
     'machines': {
+      'mac-arm64-updater-tester-rel': {
+        'mixins': [
+            'mac_arm64_apple_dtk_experimental',
+        ],
+        'test_suites': {
+          'gtest_tests': 'updater_gtests',
+          'isolated_scripts': 'updater_isolated_scripts',
+        },
+      },
       'mac10.11-updater-tester-rel': {
         'mixins': [
             'mac_10.11',
diff --git a/third_party/android_build_tools/bundletool/README.chromium b/third_party/android_build_tools/bundletool/README.chromium
index cc0241db..b50bf12c 100644
--- a/third_party/android_build_tools/bundletool/README.chromium
+++ b/third_party/android_build_tools/bundletool/README.chromium
@@ -1,6 +1,6 @@
 Name: Android SDK bundletool
 Short Name:  bundletool
-Version: 1.4.0
+Version: 1.2.0
 License: Apache Version 2.0
 License File: NOT_SHIPPED
 Security Critical: No
diff --git a/third_party/android_build_tools/bundletool/cipd.yaml b/third_party/android_build_tools/bundletool/cipd.yaml
index 0b69dda2..a59d7ee 100644
--- a/third_party/android_build_tools/bundletool/cipd.yaml
+++ b/third_party/android_build_tools/bundletool/cipd.yaml
@@ -10,4 +10,4 @@
 # swarming isolation works properly with symlinks.
 install_mode: copy
 data:
-  - file: bundletool-all-1.4.0.jar
+  - file: bundletool-all-1.2.0.jar
diff --git a/third_party/blink/public/platform/web_runtime_features.h b/third_party/blink/public/platform/web_runtime_features.h
index e68a6b99..a13c6fc 100644
--- a/third_party/blink/public/platform/web_runtime_features.h
+++ b/third_party/blink/public/platform/web_runtime_features.h
@@ -233,6 +233,8 @@
 
   BLINK_PLATFORM_EXPORT static void EnableParseUrlProtocolHandler(bool);
 
+  BLINK_PLATFORM_EXPORT static void EnableCSSColorSchemeUARendering(bool);
+
  private:
   WebRuntimeFeatures();
 };
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc
index a34e695d..b159a2a6 100644
--- a/third_party/blink/renderer/core/dom/document.cc
+++ b/third_party/blink/renderer/core/dom/document.cc
@@ -1934,6 +1934,13 @@
 }
 
 void Document::DidChangeVisibilityState() {
+  if (load_event_progress_ >= kUnloadVisibilityChangeInProgress) {
+    // It's possible to get here even after we've started unloading the document
+    // and dispatched the visibilitychange event, e.g. when we're closing a tab,
+    // where we would first try to dispatch unload events, and then close the
+    // tab and update the visibility state.
+    return;
+  }
   DispatchEvent(*Event::CreateBubble(event_type_names::kVisibilitychange));
   // Also send out the deprecated version until it can be removed.
   DispatchEvent(
diff --git a/third_party/blink/renderer/core/editing/iterators/text_iterator.h b/third_party/blink/renderer/core/editing/iterators/text_iterator.h
index 18b0418..1d26a33 100644
--- a/third_party/blink/renderer/core/editing/iterators/text_iterator.h
+++ b/third_party/blink/renderer/core/editing/iterators/text_iterator.h
@@ -42,8 +42,9 @@
 PlainText(const EphemeralRange&,
           const TextIteratorBehavior& = TextIteratorBehavior());
 
-String PlainText(const EphemeralRangeInFlatTree&,
-                 const TextIteratorBehavior& = TextIteratorBehavior());
+CORE_EXPORT String
+PlainText(const EphemeralRangeInFlatTree&,
+          const TextIteratorBehavior& = TextIteratorBehavior());
 
 // Iterates through the DOM range, returning all the text, and 0-length
 // boundaries at points where replaced elements break up the text flow.  The
diff --git a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
index 5489b87..7b500a5 100644
--- a/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
+++ b/third_party/blink/renderer/core/frame/web_frame_widget_base.cc
@@ -57,6 +57,7 @@
 #include "third_party/blink/renderer/core/layout/layout_box.h"
 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
 #include "third_party/blink/renderer/core/loader/document_loader.h"
 #include "third_party/blink/renderer/core/loader/interactive_detector.h"
 #include "third_party/blink/renderer/core/page/context_menu_controller.h"
@@ -1884,6 +1885,13 @@
   if (largest_contentful_paint >= start)
     metrics->largest_contentful_paint = largest_contentful_paint - start;
 
+  double layout_shift = LocalRootImpl()
+                            ->GetFrame()
+                            ->View()
+                            ->GetLayoutShiftTracker()
+                            .WeightedScore();
+  if (layout_shift > 0.f)
+    metrics->layout_shift = layout_shift;
   return metrics;
 }
 
diff --git a/third_party/blink/renderer/core/layout/hit_test_result.cc b/third_party/blink/renderer/core/layout/hit_test_result.cc
index 774e1a9..2dbc8d2 100644
--- a/third_party/blink/renderer/core/layout/hit_test_result.cc
+++ b/third_party/blink/renderer/core/layout/hit_test_result.cc
@@ -151,6 +151,19 @@
   SetNodeAndPosition(node, position);
 }
 
+void HitTestResult::OverrideNodeAndPosition(Node* node,
+                                            PhysicalOffset position) {
+  // We are replacing the inner node. Reset any box fragment previously found.
+  box_fragment_.reset();
+
+  // The new inner node needs to be monolithic.
+  DCHECK(!node->GetLayoutBox() ||
+         node->GetLayoutBox()->PhysicalFragmentCount() <= 1);
+
+  local_point_ = position;
+  SetInnerNode(node);
+}
+
 void HitTestResult::SetBoxFragment(
     scoped_refptr<const NGPhysicalBoxFragment> box_fragment) {
   DCHECK(!box_fragment || !box_fragment->IsInlineBox());
@@ -215,11 +228,13 @@
           IsA<SVGUseElement>(containing_shadow_root->host()))) {
     shadow_host = &containing_shadow_root->host();
     containing_shadow_root = shadow_host->ContainingShadowRoot();
-    SetInnerNode(node->OwnerShadowHost());
+    // TODO(layout-dev): Not updating local_point_ here seems like a mistake?
+    OverrideNodeAndPosition(node->OwnerShadowHost(), local_point_);
   }
 
+  // TODO(layout-dev): Not updating local_point_ here seems like a mistake?
   if (shadow_host)
-    SetInnerNode(shadow_host);
+    OverrideNodeAndPosition(shadow_host, local_point_);
 }
 
 CompositorElementId HitTestResult::GetScrollableContainer() const {
diff --git a/third_party/blink/renderer/core/layout/hit_test_result.h b/third_party/blink/renderer/core/layout/hit_test_result.h
index b7af941..e6b267f 100644
--- a/third_party/blink/renderer/core/layout/hit_test_result.h
+++ b/third_party/blink/renderer/core/layout/hit_test_result.h
@@ -124,6 +124,13 @@
                           scoped_refptr<const NGPhysicalBoxFragment>,
                           const PhysicalOffset&);
 
+  // Override an inner node previously set. The new node needs to be monolithic
+  // (or at least only consist of one fragment).
+  //
+  // TODO(layout-dev): Figure out if we really need this. Why can't we just
+  // hit-test correctly in the first place instead?
+  void OverrideNodeAndPosition(Node*, PhysicalOffset);
+
   // Set the box fragment to be associated with the inner node. If the inner
   // node is text or non-atomic inline content, this will be a fragment
   // generated by the containing block of the inner node. In all other cases, it
diff --git a/third_party/blink/renderer/core/layout/layout_text_control.cc b/third_party/blink/renderer/core/layout/layout_text_control.cc
index 63d356f..4dd232e 100644
--- a/third_party/blink/renderer/core/layout/layout_text_control.cc
+++ b/third_party/blink/renderer/core/layout/layout_text_control.cc
@@ -109,7 +109,7 @@
       hit_test_location.Point() - accumulated_offset -
       inner_editor.GetLayoutObject()->LocalToAncestorPoint(PhysicalOffset(),
                                                            &box);
-  result.SetNodeAndPosition(&inner_editor, local_point);
+  result.OverrideNodeAndPosition(&inner_editor, local_point);
 }
 
 static const char* const kFontFamiliesWithInvalidCharWidth[] = {
diff --git a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index 82e850b..431aa4f7 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -755,8 +755,14 @@
     return layout_object_->CreatePositionWithAffinity(0);
   }
 
+  if (!RuntimeEnabledFeatures::LayoutNGFullPositionForPointEnabled()) {
+    DCHECK(layout_object_->ChildrenInline());
+    return layout_object_->CreatePositionWithAffinity(0);
+  }
+
   NGLink closest_child = {nullptr};
   LayoutUnit shortest_distance = LayoutUnit::Max();
+  bool found_hit_test_candidate = false;
   const PhysicalSize pixel_size(LayoutUnit(1), LayoutUnit(1));
   PhysicalRect point_rect(point, pixel_size);
 
@@ -771,8 +777,18 @@
   // direction (column rows and spanners).
   for (const NGLink& child : Children()) {
     const auto& box_fragment = To<NGPhysicalBoxFragment>(*child.fragment);
-    if (!IsHitTestCandidate(box_fragment))
-      continue;
+    bool is_hit_test_candidate = IsHitTestCandidate(box_fragment);
+    if (!is_hit_test_candidate) {
+      if (found_hit_test_candidate)
+        continue;
+      // We prefer valid hit-test candidates, but if there are no such children,
+      // we'll lower our requirements somewhat. The exact reasoning behind the
+      // details here is unknown, but it is something that evolved during
+      // WebKit's early years.
+      if (box_fragment.Style().Visibility() != EVisibility::kVisible ||
+          (box_fragment.Children().empty() && !box_fragment.IsBlockFlow()))
+        continue;
+    }
 
     PhysicalRect child_rect(child.offset, child->Size());
     LayoutUnit horizontal_distance;
@@ -795,10 +811,13 @@
     const LayoutUnit distance = horizontal_distance * horizontal_distance +
                                 vertical_distance * vertical_distance;
 
-    if (shortest_distance > distance) {
-      // This child is closer to the point than any previous child.
+    if (shortest_distance > distance ||
+        (is_hit_test_candidate && !found_hit_test_candidate)) {
+      // This child is either closer to the point than any previous child, or
+      // this is the first child that is an actual hit-test candidate.
       shortest_distance = distance;
       closest_child = child;
+      found_hit_test_candidate = is_hit_test_candidate;
     }
   }
 
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
index f95ef3f..97ee6d7 100644
--- a/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_layout_algorithm.cc
@@ -871,21 +871,24 @@
   }
 
   // Section setup.
-  const LogicalSize section_available_size{table_inline_size -
-                                               border_padding.InlineSum() -
-                                               border_spacing.inline_size * 2,
-                                           kIndefiniteSize};
-  DCHECK_GE(section_available_size.inline_size, LayoutUnit());
+  const LayoutUnit section_available_inline_size =
+      table_inline_size - border_padding.InlineSum() -
+      border_spacing.inline_size * 2;
+
+  DCHECK_GE(section_available_inline_size, LayoutUnit());
   auto CreateSectionConstraintSpace = [&table_writing_direction,
-                                       &section_available_size,
-                                       &constraint_space_data](
-                                          wtf_size_t section_index) {
+                                       &section_available_inline_size,
+                                       &constraint_space_data,
+                                       &sections](wtf_size_t section_index) {
     NGConstraintSpaceBuilder section_space_builder(
         table_writing_direction.GetWritingMode(), table_writing_direction,
         /* is_new_fc */ true);
-    section_space_builder.SetAvailableSize(section_available_size);
+    section_space_builder.SetAvailableSize(
+        {section_available_inline_size, sections[section_index].block_size});
     section_space_builder.SetIsFixedInlineSize(true);
-    section_space_builder.SetPercentageResolutionSize(section_available_size);
+    section_space_builder.SetIsFixedBlockSize(true);
+    section_space_builder.SetPercentageResolutionSize(
+        {section_available_inline_size, kIndefiniteSize});
     section_space_builder.SetTableSectionData(constraint_space_data,
                                               section_index);
     return section_space_builder.ToConstraintSpace();
diff --git a/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc b/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc
index b14310e5..461640a0 100644
--- a/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc
+++ b/third_party/blink/renderer/core/layout/ng/table/ng_table_section_layout_algorithm.cc
@@ -50,9 +50,10 @@
         table_data.table_writing_direction.GetWritingMode(),
         table_data.table_writing_direction,
         /* is_new_fc */ true);
-    row_space_builder.SetAvailableSize(
-        {container_builder_.InlineSize(), kIndefiniteSize});
+    row_space_builder.SetAvailableSize({container_builder_.InlineSize(),
+                                        table_data.rows[row_index].block_size});
     row_space_builder.SetIsFixedInlineSize(true);
+    row_space_builder.SetIsFixedBlockSize(true);
     row_space_builder.SetPercentageResolutionSize(
         {container_builder_.InlineSize(), kIndefiniteSize});
     row_space_builder.SetTableRowData(&table_data, row_index);
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc
index 9631282..2f5a71d 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.cc
@@ -153,6 +153,10 @@
                            TRACE_EVENT_SCOPE_THREAD, "end_text_length",
                            match.selector.End().length());
 
+      base::UmaHistogramBoolean(
+          base::StrCat({uma_prefix, "SpansMultipleBlocks"}),
+          match.spans_multiple_blocks);
+
       // We only record ListItemMatch and TableCellMatch for exact matches
       DCHECK(!match.is_list_item && !match.is_table_cell);
     }
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h
index 18117f0..b6f8d7c6 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics.h
@@ -24,6 +24,7 @@
     TextFragmentSelector selector;
     bool is_list_item = false;
     bool is_table_cell = false;
+    bool spans_multiple_blocks = false;
   };
 
   // An enum to indicate which parameters were specified in the text fragment.
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc
index 08ed28f..d311586 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_metrics_test.cc
@@ -1460,6 +1460,79 @@
       WebFeature::kV8Document_FragmentDirective_AttributeGetter));
 }
 
+// Test recording of the SpansMultipleBlocks metric. Records true because the
+// range crosses an intervening block element.
+TEST_F(TextFragmentAnchorMetricsTest, SpansMultipleBlocksInterveningBlock) {
+  SimRequest request("https://example.com/test.html#:~:text=start,end",
+                     "text/html");
+  LoadURL("https://example.com/test.html#:~:text=start,end");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <div>
+      start of text
+      <div>block</div>
+      text end
+    </div>
+  )HTML");
+  RunAsyncMatchingTasks();
+
+  BeginEmptyFrame();
+  BeginEmptyFrame();
+
+  histogram_tester_.ExpectTotalCount(
+      "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 1);
+  histogram_tester_.ExpectUniqueSample(
+      "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 1, 1);
+}
+
+// Test recording of the SpansMultipleBlocks metric. Records true because the
+// range start and end are in different block elements.
+TEST_F(TextFragmentAnchorMetricsTest, SpansMultipleBlocks) {
+  SimRequest request("https://example.com/test.html#:~:text=start,end",
+                     "text/html");
+  LoadURL("https://example.com/test.html#:~:text=start,end");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <div>
+      <div>start of text</div>
+      text end
+    </div>
+  )HTML");
+  RunAsyncMatchingTasks();
+
+  BeginEmptyFrame();
+  BeginEmptyFrame();
+
+  histogram_tester_.ExpectTotalCount(
+      "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 1);
+  histogram_tester_.ExpectUniqueSample(
+      "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 1, 1);
+}
+
+// Test recording of the SpansMultipleBlocks metric. Records false because the
+// range start and end are in the same block element with no intervening block.
+TEST_F(TextFragmentAnchorMetricsTest, SpansMultipleBlocksSingleBlock) {
+  SimRequest request("https://example.com/test.html#:~:text=start,end",
+                     "text/html");
+  LoadURL("https://example.com/test.html#:~:text=start,end");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <div>
+      start of <i>text</i>
+      text end
+    </div>
+  )HTML");
+  RunAsyncMatchingTasks();
+
+  BeginEmptyFrame();
+  BeginEmptyFrame();
+
+  histogram_tester_.ExpectTotalCount(
+      "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 1);
+  histogram_tester_.ExpectUniqueSample(
+      "TextFragmentAnchor.Unknown.SpansMultipleBlocks", 0, 1);
+}
+
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
index 93ffc2e..aba1fa1 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_anchor_test.cc
@@ -6,6 +6,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
 #include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -16,6 +17,7 @@
 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
 #include "third_party/blink/renderer/core/input/event_handler.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/scroll/scrollable_area.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
@@ -2040,6 +2042,61 @@
   EXPECT_EQ(2u, GetDocument().Markers().Markers().size());
 }
 
+// Checks that selection in the same text node is considerered uninterrupted.
+TEST_F(TextFragmentAnchorTest, IsInSameUninterruptedBlock_OneTextNode) {
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <div id='first'>First paragraph text</div>
+  )HTML");
+  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+  const auto& start = PositionInFlatTree(first_paragraph, 0);
+  const auto& end = PositionInFlatTree(first_paragraph, 15);
+  ASSERT_EQ("First paragraph", PlainText(EphemeralRangeInFlatTree(start, end)));
+
+  EXPECT_TRUE(TextFragmentFinder::IsInSameUninterruptedBlock(start, end));
+}
+
+// Checks that selection in the same text node with nested non-block element is
+// considerered uninterrupted.
+TEST_F(TextFragmentAnchorTest,
+       IsInSameUninterruptedBlock_NonBlockInterruption) {
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <div id='first'>First <i>styled text</i> paragraph text</div>
+  )HTML");
+  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+  const auto& start = PositionInFlatTree(first_paragraph, 0);
+  const auto& end =
+      PositionInFlatTree(first_paragraph->nextSibling()->nextSibling(), 10);
+  ASSERT_EQ("First styled text paragraph",
+            PlainText(EphemeralRangeInFlatTree(start, end)));
+
+  EXPECT_TRUE(TextFragmentFinder::IsInSameUninterruptedBlock(start, end));
+}
+
+// Checks that selection in the same text node with nested block element is
+// considerered interrupted.
+TEST_F(TextFragmentAnchorTest, IsInSameUninterruptedBlock_BlockInterruption) {
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+    <!DOCTYPE html>
+    <div id='first'>First <div>block text</div> paragraph text</div>
+  )HTML");
+  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
+  const auto& start = PositionInFlatTree(first_paragraph, 0);
+  const auto& end =
+      PositionInFlatTree(first_paragraph->nextSibling()->nextSibling(), 10);
+  ASSERT_EQ("First\nblock text\nparagraph",
+            PlainText(EphemeralRangeInFlatTree(start, end)));
+
+  EXPECT_FALSE(TextFragmentFinder::IsInSameUninterruptedBlock(start, end));
+}
+
 }  // namespace
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc
index 24470c3..3b7ad04 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.cc
@@ -254,6 +254,33 @@
 
 }  // namespace
 
+// static
+bool TextFragmentFinder::IsInSameUninterruptedBlock(
+    const PositionInFlatTree& start,
+    const PositionInFlatTree& end) {
+  Node* start_node = start.ComputeContainerNode();
+  Node* end_node = end.ComputeContainerNode();
+
+  if (start_node->isSameNode(end_node))
+    return true;
+
+  Node& start_ancestor =
+      FindBuffer::GetFirstBlockLevelAncestorInclusive(*start_node);
+  Node& end_ancestor =
+      FindBuffer::GetFirstBlockLevelAncestorInclusive(*end_node);
+
+  if (!start_ancestor.isSameNode(&end_ancestor))
+    return false;
+
+  Node* node = start_node;
+  while (!node->isSameNode(end_node)) {
+    if (FindBuffer::IsNodeBlockLevel(*node))
+      return false;
+    node = FlatTreeTraversal::Next(*node);
+  }
+  return true;
+}
+
 TextFragmentFinder::TextFragmentFinder(Client& client,
                                        const TextFragmentSelector& selector)
     : client_(client), selector_(selector) {
@@ -289,6 +316,8 @@
       }
     } else if (selector_.Type() == TextFragmentSelector::SelectorType::kRange) {
       match_metrics.text = PlainText(match);
+      match_metrics.spans_multiple_blocks = !IsInSameUninterruptedBlock(
+          match.StartPosition(), match.EndPosition());
     }
 
     // Continue searching to see if we have an ambiguous selector.
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h
index 31051b2e..51e18caf 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_finder.h
@@ -29,6 +29,11 @@
     virtual void NoMatchFound() = 0;
   };
 
+  // Returns true if start and end positions are in the same block and there are
+  // no other blocks between them. Otherwise, returns false.
+  static bool IsInSameUninterruptedBlock(const PositionInFlatTree& start,
+                                         const PositionInFlatTree& end);
+
   // Client must outlive the finder.
   TextFragmentFinder(Client& client, const TextFragmentSelector& selector);
   ~TextFragmentFinder() = default;
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
index 8fcc799b..acfc46a 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.cc
@@ -407,16 +407,12 @@
   EphemeralRangeInFlatTree ephemeral_range(selection_range_);
 
   // If not in same node, should use ranges.
-  if (!IsInSameUninterruptedBlock(selection_range_->StartPosition(),
-                                  selection_range_->EndPosition())) {
+  if (!TextFragmentFinder::IsInSameUninterruptedBlock(
+          ephemeral_range.StartPosition(), ephemeral_range.EndPosition())) {
     step_ = kRange;
     return;
   }
 
-  // TODO(gayane): If same node, need to check if start and end are interrupted
-  // by a block. Example: <div>start of the selection <div> sub block </div>end
-  // of the selection</div>.
-
   String selected_text = PlainText(ephemeral_range).StripWhiteSpace();
   if (selected_text.IsEmpty()) {
     UMA_HISTOGRAM_ENUMERATION("SharedHighlights.LinkGenerated.Error",
@@ -460,8 +456,8 @@
 
     // If selection starts and ends in the same block, then split selected text
     // roughly in the middle.
-    if (IsInSameUninterruptedBlock(selection_range_->StartPosition(),
-                                   selection_range_->EndPosition())) {
+    if (TextFragmentFinder::IsInSameUninterruptedBlock(
+            ephemeral_range.StartPosition(), ephemeral_range.EndPosition())) {
       String selection_text = PlainText(ephemeral_range);
       selection_text.Ensure16Bit();
       int selection_length = selection_text.length();
@@ -605,30 +601,4 @@
   auto range_end = Position(suffix_end, suffix_end->textContent().length());
   return PlainText(EphemeralRange(range_start, range_end)).StripWhiteSpace();
 }
-
-bool TextFragmentSelectorGenerator::IsInSameUninterruptedBlock(
-    const Position& start,
-    const Position& end) {
-  Node* start_node = start.ComputeContainerNode();
-  Node* end_node = end.ComputeContainerNode();
-
-  if (start_node->isSameNode(end_node))
-    return true;
-
-  Node& start_ancestor =
-      FindBuffer::GetFirstBlockLevelAncestorInclusive(*start_node);
-  Node& end_ancestor =
-      FindBuffer::GetFirstBlockLevelAncestorInclusive(*end_node);
-
-  if (!start_ancestor.isSameNode(&end_ancestor))
-    return false;
-
-  Node* node = start_node;
-  while (!node->isSameNode(end_node)) {
-    if (FindBuffer::IsNodeBlockLevel(*node))
-      return false;
-    node = FlatTreeTraversal::Next(*node);
-  }
-  return true;
-}
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h
index 996ba70..9fd3b111 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator.h
@@ -88,10 +88,6 @@
   String GetNextTextBlockForTesting(const Position& position) {
     return GetNextTextBlock(position);
   }
-  bool IsInSameUninterruptedBlockForTesting(const Position& start,
-                                            const Position& end) {
-    return IsInSameUninterruptedBlock(start, end);
-  }
 
   // Releases members if necessary.
   void ClearSelection();
@@ -132,10 +128,6 @@
   // boundaries.
   String GetNextTextBlock(const Position& position);
 
-  // Returns true if start and end positions are in the same block and there are
-  // no other blocks between them. Otherwise, returns false.
-  bool IsInSameUninterruptedBlock(const Position& start, const Position& end);
-
   void GenerateExactSelector();
   void ExtendRangeSelector();
   void ExtendContext();
diff --git a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc
index f1ca0ec..60aacea 100644
--- a/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc
+++ b/third_party/blink/renderer/core/page/scrolling/text_fragment_selector_generator_test.cc
@@ -1359,68 +1359,4 @@
                                          ->GetNextTextBlockForTesting(end));
 }
 
-// Checks that selection in the same text node is considerered uninterrupted.
-TEST_F(TextFragmentSelectorGeneratorTest,
-       IsInSameUninterruptedBlock_OneTextNode) {
-  SimRequest request("https://example.com/test.html", "text/html");
-  LoadURL("https://example.com/test.html");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <div id='first'>First paragraph text</div>
-  )HTML");
-  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
-  const auto& start = Position(first_paragraph, 0);
-  const auto& end = Position(first_paragraph, 15);
-  ASSERT_EQ("First paragraph", PlainText(EphemeralRange(start, end)));
-
-  EXPECT_TRUE(GetDocument()
-                  .GetFrame()
-                  ->GetTextFragmentSelectorGenerator()
-                  ->IsInSameUninterruptedBlockForTesting(start, end));
-}
-
-// Checks that selection in the same text node with nested non-block element is
-// considerered uninterrupted.
-TEST_F(TextFragmentSelectorGeneratorTest,
-       IsInSameUninterruptedBlock_NonBlockInterruption) {
-  SimRequest request("https://example.com/test.html", "text/html");
-  LoadURL("https://example.com/test.html");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <div id='first'>First <i>styled text</i> paragraph text</div>
-  )HTML");
-  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
-  const auto& start = Position(first_paragraph, 0);
-  const auto& end = Position(first_paragraph->nextSibling()->nextSibling(), 10);
-  ASSERT_EQ("First styled text paragraph",
-            PlainText(EphemeralRange(start, end)));
-
-  EXPECT_TRUE(GetDocument()
-                  .GetFrame()
-                  ->GetTextFragmentSelectorGenerator()
-                  ->IsInSameUninterruptedBlockForTesting(start, end));
-}
-
-// Checks that selection in the same text node with nested block element is
-// considerered interrupted.
-TEST_F(TextFragmentSelectorGeneratorTest,
-       IsInSameUninterruptedBlock_BlockInterruption) {
-  SimRequest request("https://example.com/test.html", "text/html");
-  LoadURL("https://example.com/test.html");
-  request.Complete(R"HTML(
-    <!DOCTYPE html>
-    <div id='first'>First <div>block text</div> paragraph text</div>
-  )HTML");
-  Node* first_paragraph = GetDocument().getElementById("first")->firstChild();
-  const auto& start = Position(first_paragraph, 0);
-  const auto& end = Position(first_paragraph->nextSibling()->nextSibling(), 10);
-  ASSERT_EQ("First\nblock text\nparagraph",
-            PlainText(EphemeralRange(start, end)));
-
-  EXPECT_FALSE(GetDocument()
-                   .GetFrame()
-                   ->GetTextFragmentSelectorGenerator()
-                   ->IsInSameUninterruptedBlockForTesting(start, end));
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
index fbbde2db..7a6602e 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.cc
@@ -70,13 +70,15 @@
     if (supported_profile.profile != profile)
       continue;
 
-    if (supported_profile.min_resolution.width() > options.width ||
-        supported_profile.min_resolution.height() > options.height) {
+    if (supported_profile.min_resolution.width() > options.frame_size.width() ||
+        supported_profile.min_resolution.height() >
+            options.frame_size.height()) {
       continue;
     }
 
-    if (supported_profile.max_resolution.width() < options.width ||
-        supported_profile.max_resolution.height() < options.height) {
+    if (supported_profile.max_resolution.width() < options.frame_size.width() ||
+        supported_profile.max_resolution.height() <
+            options.frame_size.height()) {
       continue;
     }
 
@@ -207,16 +209,16 @@
   constexpr int kMaxSupportedFrameSize = 8000;
   auto* parsed = MakeGarbageCollected<ParsedConfig>();
 
-  parsed->options.height = config->height();
-  if (parsed->options.height == 0 ||
-      parsed->options.height > kMaxSupportedFrameSize) {
+  parsed->options.frame_size.set_height(config->height());
+  if (parsed->options.frame_size.height() == 0 ||
+      parsed->options.frame_size.height() > kMaxSupportedFrameSize) {
     exception_state.ThrowTypeError("Invalid height.");
     return nullptr;
   }
 
-  parsed->options.width = config->width();
-  if (parsed->options.width == 0 ||
-      parsed->options.width > kMaxSupportedFrameSize) {
+  parsed->options.frame_size.set_width(config->width());
+  if (parsed->options.frame_size.width() == 0 ||
+      parsed->options.frame_size.width() > kMaxSupportedFrameSize) {
     exception_state.ThrowTypeError("Invalid width.");
     return nullptr;
   }
@@ -366,7 +368,7 @@
     case AccelerationPreference::kRequire: {
       auto result =
           CreateAcceleratedVideoEncoder(config.profile, config.options);
-      is_hw_accelerated_ = !!result;
+      support_nv12_ = !!result;
       if (result)
         UpdateEncoderLog("AcceleratedVideoEncoder", true);
       return result;
@@ -374,7 +376,7 @@
     case AccelerationPreference::kAllow:
       if (auto result =
               CreateAcceleratedVideoEncoder(config.profile, config.options)) {
-        is_hw_accelerated_ = true;
+        support_nv12_ = true;
         UpdateEncoderLog("AcceleratedVideoEncoder", true);
         return result;
       }
@@ -384,17 +386,19 @@
       switch (config.codec) {
         case media::kCodecVP8:
         case media::kCodecVP9:
+          support_nv12_ = true;
           result = CreateVpxVideoEncoder();
           UpdateEncoderLog("VpxVideoEncoder", false);
           break;
         case media::kCodecH264:
+          // TODO: support NV12 format in OpenH264 encoder.
+          support_nv12_ = false;
           result = CreateOpenH264VideoEncoder();
           UpdateEncoderLog("OpenH264VideoEncoder", false);
           break;
         default:
           return nullptr;
       }
-      is_hw_accelerated_ = false;
       if (!result)
         return nullptr;
       return std::make_unique<media::OffloadingVideoEncoder>(std::move(result));
@@ -472,9 +476,8 @@
   }
 
   DCHECK(active_config_);
-  if (internal_frame->cropWidth() != uint32_t{active_config_->options.width} ||
-      internal_frame->cropHeight() !=
-          uint32_t{active_config_->options.height}) {
+  if (internal_frame->frame()->coded_size() !=
+      active_config_->options.frame_size) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kOperationError,
         "Frame size doesn't match initial encoder parameters.");
@@ -627,7 +630,7 @@
   };
 
   scoped_refptr<media::VideoFrame> frame = request->frame->frame();
-  if (frame->HasGpuMemoryBuffer() && !is_hw_accelerated_) {
+  if (frame->HasGpuMemoryBuffer() && !support_nv12_) {
     frame = ConvertToI420Frame(frame);
     if (!frame) {
       HandleError("Unexpected frame format.",
@@ -790,8 +793,8 @@
   VideoDecoderConfig* decoder_config =
       MakeGarbageCollected<VideoDecoderConfig>();
   decoder_config->setCodec(active_config->codec_string);
-  decoder_config->setCodedHeight(active_config->options.height);
-  decoder_config->setCodedWidth(active_config->options.width);
+  decoder_config->setCodedHeight(active_config->options.frame_size.height());
+  decoder_config->setCodedWidth(active_config->options.frame_size.width());
   if (codec_desc.has_value()) {
     auto* desc_array_buf = DOMArrayBuffer::Create(codec_desc.value().data(),
                                                   codec_desc.value().size());
diff --git a/third_party/blink/renderer/modules/webcodecs/video_encoder.h b/third_party/blink/renderer/modules/webcodecs/video_encoder.h
index 317b079d..7b0185c 100644
--- a/third_party/blink/renderer/modules/webcodecs/video_encoder.h
+++ b/third_party/blink/renderer/modules/webcodecs/video_encoder.h
@@ -141,7 +141,8 @@
   bool CanReconfigure(ParsedConfig& original_config, ParsedConfig& new_config);
 
   std::unique_ptr<media::VideoEncoder> media_encoder_;
-  bool is_hw_accelerated_ = false;
+  // This flag maybe removed when all encoders can handle NV12 frame.
+  bool support_nv12_ = false;
 
   // |parent_media_log_| must be destroyed if ever the ExecutionContext is
   // destroyed, since the blink::MediaInspectorContext* pointer given to
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
index 44be1715..5eaf6cf 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
+++ b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.cc
@@ -110,7 +110,7 @@
 
 WGPUBufferCopyView ValidateAndConvertBufferCopyView(
     const GPUBufferCopyView* webgpu_view,
-    ExceptionState& exception_state) {
+    const char** error) {
   DCHECK(webgpu_view);
   DCHECK(webgpu_view->buffer());
 
@@ -118,17 +118,7 @@
   dawn_view.nextInChain = nullptr;
   dawn_view.buffer = webgpu_view->buffer()->GetHandle();
 
-  {
-    const char* error =
-        ValidateTextureDataLayout(webgpu_view, &dawn_view.layout);
-    if (error) {
-      // TODO(crbug.com/dawn/566): This error needs to be injected into the
-      // encoder, instead of thrown as an exception.
-      exception_state.ThrowDOMException(DOMExceptionCode::kOperationError,
-                                        error);
-    }
-  }
-
+  *error = ValidateTextureDataLayout(webgpu_view, &dawn_view.layout);
   return dawn_view;
 }
 
@@ -262,14 +252,15 @@
 void GPUCommandEncoder::copyBufferToTexture(
     GPUBufferCopyView* source,
     GPUTextureCopyView* destination,
-    UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
-    ExceptionState& exception_state) {
+    UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size) {
   WGPUExtent3D dawn_copy_size = AsDawnType(&copy_size);
   WGPUTextureCopyView dawn_destination = AsDawnType(destination, device_);
 
+  const char* error = nullptr;
   WGPUBufferCopyView dawn_source =
-      ValidateAndConvertBufferCopyView(source, exception_state);
-  if (exception_state.HadException()) {
+      ValidateAndConvertBufferCopyView(source, &error);
+  if (error) {
+    GetProcs().commandEncoderInjectValidationError(GetHandle(), error);
     return;
   }
 
@@ -280,14 +271,15 @@
 void GPUCommandEncoder::copyTextureToBuffer(
     GPUTextureCopyView* source,
     GPUBufferCopyView* destination,
-    UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
-    ExceptionState& exception_state) {
+    UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size) {
   WGPUExtent3D dawn_copy_size = AsDawnType(&copy_size);
   WGPUTextureCopyView dawn_source = AsDawnType(source, device_);
 
+  const char* error = nullptr;
   WGPUBufferCopyView dawn_destination =
-      ValidateAndConvertBufferCopyView(destination, exception_state);
-  if (exception_state.HadException()) {
+      ValidateAndConvertBufferCopyView(destination, &error);
+  if (error) {
+    GetProcs().commandEncoderInjectValidationError(GetHandle(), error);
     return;
   }
 
@@ -298,8 +290,7 @@
 void GPUCommandEncoder::copyTextureToTexture(
     GPUTextureCopyView* source,
     GPUTextureCopyView* destination,
-    UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
-    ExceptionState& exception_state) {
+    UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size) {
   WGPUTextureCopyView dawn_source = AsDawnType(source, device_);
   WGPUTextureCopyView dawn_destination = AsDawnType(destination, device_);
   WGPUExtent3D dawn_copy_size = AsDawnType(&copy_size);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h
index 92d221f..915a75f7 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h
+++ b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.h
@@ -49,18 +49,15 @@
   void copyBufferToTexture(
       GPUBufferCopyView* source,
       GPUTextureCopyView* destination,
-      UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
-      ExceptionState& exception_state);
+      UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size);
   void copyTextureToBuffer(
       GPUTextureCopyView* source,
       GPUBufferCopyView* destination,
-      UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
-      ExceptionState& exception_state);
+      UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size);
   void copyTextureToTexture(
       GPUTextureCopyView* source,
       GPUTextureCopyView* destination,
-      UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size,
-      ExceptionState& exception_state);
+      UnsignedLongEnforceRangeSequenceOrGPUExtent3DDict& copy_size);
   void pushDebugGroup(String groupLabel);
   void popDebugGroup();
   void insertDebugMarker(String markerLabel);
diff --git a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl
index d054757..bb3bb7a7 100644
--- a/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl
+++ b/third_party/blink/renderer/modules/webgpu/gpu_command_encoder.idl
@@ -17,17 +17,17 @@
         GPUSize64 dstOffset,
         GPUSize64 size);
 
-    [RaisesException] void copyBufferToTexture(
+    void copyBufferToTexture(
         GPUBufferCopyView source,
         GPUTextureCopyView destination,
         GPUExtent3D copySize);
 
-    [RaisesException] void copyTextureToBuffer(
+    void copyTextureToBuffer(
         GPUTextureCopyView source,
         GPUBufferCopyView destination,
         GPUExtent3D copySize);
 
-    [RaisesException] void copyTextureToTexture(
+    void copyTextureToTexture(
         GPUTextureCopyView source,
         GPUTextureCopyView destination,
         GPUExtent3D copySize);
diff --git a/third_party/blink/renderer/platform/exported/web_runtime_features.cc b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
index 132a297..6a4ba38 100644
--- a/third_party/blink/renderer/platform/exported/web_runtime_features.cc
+++ b/third_party/blink/renderer/platform/exported/web_runtime_features.cc
@@ -651,4 +651,8 @@
   RuntimeEnabledFeatures::SetTargetBlankImpliesNoOpenerEnabled(enable);
 }
 
+void WebRuntimeFeatures::EnableCSSColorSchemeUARendering(bool enable) {
+  RuntimeEnabledFeatures::SetCSSColorSchemeUARenderingEnabled(enable);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc b/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
index 25f4095..008619a 100644
--- a/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
+++ b/third_party/blink/renderer/platform/widget/compositing/layer_tree_settings.cc
@@ -361,6 +361,9 @@
   settings.initial_debug_state.show_web_vital_metrics =
       base::FeatureList::IsEnabled(
           ::features::kHudDisplayForPerformanceMetrics);
+  settings.initial_debug_state.show_smoothness_metrics =
+      base::FeatureList::IsEnabled(
+          ::features::kHudDisplayForPerformanceMetrics);
 
   settings.initial_debug_state.SetRecordRenderingStats(
       cmd.HasSwitch(cc::switches::kEnableGpuBenchmarking));
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index c2309c5..26ea61a9b 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -1531,9 +1531,11 @@
 crbug.com/552494 virtual/prefer_compositing_to_lcd_text/scrollbars/overflow-scrollbar-combinations.html [ Pass Failure ]
 
 crbug.com/1146486 [ Fuchsia ] virtual/text-antialias/international/bidi-neutral-directionality-paragraph-start.html [ Skip ]
+crbug.com/1146486 [ Fuchsia ] virtual/text-antialias/international/bidi-LDB-2-formatting-characters.html [ Skip ]
 crbug.com/1057339 [ Fuchsia ] virtual/text-antialias/international/rtl-mark.html [ Skip ]
 crbug.com/1056027 [ Fuchsia ] virtual/text-antialias/small-caps-aat.html [ Skip ]
 crbug.com/1146486 [ Fuchsia ] virtual/text-antialias/stroking-decorations.html [ Skip ]
+crbug.com/1146486 [ Fuchsia ] virtual/text-antialias/whitespace/whitespace-and-margin-wrap-after-list-marker-crash.html [ Skip ]
 
 crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-018.html [ Failure ]
 crbug.com/305376 external/wpt/css/css-overflow/webkit-line-clamp-024.html [ Failure ]
diff --git a/third_party/blink/web_tests/WebGPUExpectations b/third_party/blink/web_tests/WebGPUExpectations
index 9c29059b..8e238e2 100644
--- a/third_party/blink/web_tests/WebGPUExpectations
+++ b/third_party/blink/web_tests/WebGPUExpectations
@@ -38,15 +38,32 @@
 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,copyBufferToBuffer:copy_with_invalid_buffer: [ Failure ]
 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,encoding,cmds,compute_pass:* [ Failure ]
 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,render_pass,storeOp:* [ Failure ]
-wpt_internal/webgpu/cts.html?q=webgpu:api,operation,render_pipeline,primitive_topology:* [ Failure ]
+# Crash with validation layer
+wpt_internal/webgpu/cts.html?q=webgpu:api,operation,render_pipeline,primitive_topology:* [ Failure Crash ]
 
-wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer_mapping:mapAsync,invalidBuffer:* [ Failure ]
-wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer_mapping:mapAsync,offsetAndSizeAlignment,* [ Failure ]
-wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer_mapping:mapAsync,offsetAndSizeOOB,* [ Failure ]
-wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer_mapping:mapAsync,sizeUnspecifiedOOB,* [ Failure ]
-wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer_mapping:mapAsync,state,* [ Failure ]
-wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer_mapping:mapAsync,usage,* [ Failure ]
-wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer_mapping:mapAsync_,* [ Failure ]
+wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer,mapping:mapAsync,invalidBuffer:* [ Failure ]
+wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer,mapping:mapAsync,offsetAndSizeAlignment,* [ Failure ]
+wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer,mapping:mapAsync,offsetAndSizeOOB,* [ Failure ]
+wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer,mapping:mapAsync,sizeUnspecifiedOOB,* [ Failure ]
+wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer,mapping:mapAsync,state,* [ Failure ]
+wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer,mapping:mapAsync,usage,* [ Failure ]
+wpt_internal/webgpu/cts.html?q=webgpu:api,validation,buffer,mapping:mapAsync_,* [ Failure ]
+
+wpt_internal/webgpu/cts.html?q=webgpu:util,texture,texelData:unorm_texel_data_in_shader:format="rgba8unorm-srgb";* [ Failure ]
+wpt_internal/webgpu/cts.html?q=webgpu:util,texture,texelData:unorm_texel_data_in_shader:format="bgra8unorm-srgb";* [ Failure ]
+wpt_internal/webgpu/cts.html?q=webgpu:util,texture,texelData:ufloat_texel_data_in_shader:format="rg11b10ufloat";* [ Failure ]
+wpt_internal/webgpu/cts.html?q=webgpu:util,texture,texelData:ufloat_texel_data_in_shader:format="rgb9e5ufloat";* [ Failure ]
+
+# Many formats failing on Mac. Crash with validation layer on Linux. Also slow.
+# TODO: Split, once failures are cleaned up.
+wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="Sample";* [ Slow Failure Crash ]
+
+# All failing, crash with validation layer. Seems also slow.
+wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="DepthTest";* [ Slow Failure Crash ]
+
+# Failing on Mac in a few cases (same as CopyToBuffer).
+# Many cases failing on Windows. May also be slow.
+wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";* [ Slow Failure ]
 
 # Fails or crashes on numerous combinations of backends, hardware, and validation layers
 wpt_internal/webgpu/cts.html?q=webgpu:api,operation,render_pass,resolve:* [ Failure Crash ]
@@ -58,7 +75,7 @@
 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,copy_between_linear_data_and_texture,copyBetweenLinearDataAndTexture_dataRelated:* [ Skip ]
 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,copy_between_linear_data_and_texture,copyBetweenLinearDataAndTexture_textureRelated:* [ Skip ]
 wpt_internal/webgpu/cts.html?q=webgpu:shader,execution,robust_access_vertex:* [ Skip ]
-wpt_internal/webgpu/cts.html?q=webgpu:web-platform,copyImageBitmapToTexture:from_ImageData:* [ Skip ]
+wpt_internal/webgpu/cts.html?q=webgpu:web_platform,copyImageBitmapToTexture:from_ImageData:* [ Skip ]
 wpt_internal/webgpu/cts.html?q=webgpu:api,operation,copyBetweenLinearDataAndTexture:* [ Skip ]
 
 # Has many failures but also is very long, will need splitting
@@ -71,15 +88,11 @@
 # These tests aren't working on CQ, unclear whether the test or harness (or Chrome) is broken.
 # Mac: mostly works
 # Linux: actual is white/blank - is actually crashing silently
-crbug.com/1083478 [ Linux ] wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_clear.html [ Skip ]
-crbug.com/1083478 [ Linux ] wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_complex_bgra8unorm.html [ Skip ]
+crbug.com/1083478 [ Linux ] wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_clear.html [ Skip ]
+crbug.com/1083478 [ Linux ] wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_complex_bgra8unorm.html [ Skip ]
 # Win: takeScreenshot crashes
-crbug.com/1083478 [ Win ] wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_clear.html [ Skip ]
-crbug.com/1083478 [ Win ] wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_complex_bgra8unorm.html [ Skip ]
-
-# These tests were written before the validation rules where settled upon.
-crbug.com/dawn/542 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,setViewport:* [ Failure ]
-crbug.com/dawn/542 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,setScissorRect:* [ Failure ]
+crbug.com/1083478 [ Win ] wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_clear.html [ Skip ]
+crbug.com/1083478 [ Win ] wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_complex_bgra8unorm.html [ Skip ]
 
 #
 # Platform-independent failures
@@ -88,17 +101,6 @@
 # This test runs first, and is often slow due to some browser startup not being complete.
 crbug.com/953991 wpt_internal/webgpu/000_run_me_first.html [ Slow ]
 
-# Many bugs are contained here.
-# - One of them is crbug.com/dawn/424
-# - Mac: Timeout on worker seen at least once.
-# - Win: Crash seen for r8snorm, rg11b10float, rg8snorm, rgba8snorm.
-# - General: Test takes too long to run, needs to be split up.
-#   (Not really worth implementing until there are fewer actual failures.)
-# - Possibly also slower or hanging with validation layers.
-wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,copied_texture_clear:* [ Skip ]
-crbug.com/dawn/431 wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,sampled_texture_clear:* [ Skip ]
-wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,depth_stencil_attachment_clear:* [ Skip ]
-
 crbug.com/dawn/375 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,createBindGroup:buffer_offset_and_size_for_bind_groups_match:offset=0;size=0 [ Failure ]
 crbug.com/dawn/375 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,createBindGroup:buffer_offset_and_size_for_bind_groups_match:offset=256;size=0 [ Failure ]
 crbug.com/dawn/375 wpt_internal/webgpu/cts.html?q=webgpu:api,validation,createBindGroup:buffer_offset_and_size_for_bind_groups_match:offset=1024;size=0 [ Failure ]
@@ -125,7 +127,17 @@
 #
 
 # Rendering differs slightly from ref.
-crbug.com/1083478 [ Mac ] wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_complex_bgra8unorm.html [ Failure ]
+crbug.com/1083478 [ Mac ] wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_complex_bgra8unorm.html [ Failure ]
+
+[ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:util,texture,texelData:unorm_texel_data_in_shader:format="rgb10a2unorm";* [ Failure ]
+
+# Widespread failures with depth32float
+[ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="depth32float";* [ Failure ]
+[ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="depth32float";* [ Failure ]
+
+# Only ...;aspect="all";mipLevelCount=5;sampleCount=1;uninitializeMethod="_StoreOpClear;dimension="2d";sliceCount=1;nonPowerOfTwo=false
+[ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="r8unorm";* [ Failure ]
+[ Mac ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg8unorm";* [ Failure ]
 
 #
 # Linux (Vulkan) specific
@@ -137,9 +149,15 @@
 # Nvidia only, worker only, very flaky
 [ Linux ] wpt_internal/webgpu/cts.html?worker=1&q=webgpu:api,operation,command_buffer,render,storeop:* [ Failure ]
 
+# Crash with backend validation.
+[ Linux ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,memory_sync,buffer,ww:* [ Failure Crash ]
+
 #
 # Windows (D3D12) specific
 #
 
 # Very flaky on Windows/Linux, especially (but not exclusively!) with backend validation
 crbug.com/1087130 [ Win ] wpt_internal/webgpu/cts.html?q=webgpu:api,validation,createView:* [ RetryOnFailure ]
+
+# Crash with validation layer. May also be slow.
+[ Win ] wpt_internal/webgpu/cts.html?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="StencilTest";* [ Slow Failure Crash ]
diff --git a/third_party/blink/web_tests/webcodecs/reconfiguring_encooder.html b/third_party/blink/web_tests/webcodecs/reconfiguring_encooder.html
index db9afcf..ee00013 100644
--- a/third_party/blink/web_tests/webcodecs/reconfiguring_encooder.html
+++ b/third_party/blink/web_tests/webcodecs/reconfiguring_encooder.html
@@ -99,6 +99,7 @@
       let encoder = new VideoEncoder(init);
       encoder.configure(params);
 
+      // Encode |frames_to_encode| frames with original settings
       for (let i = 0; i < frames_to_encode; i++) {
         var frame = await createFrame(original_w, original_h, next_ts++);
         encoder.encode(frame, {});
@@ -109,6 +110,7 @@
       params.height = new_h;
       params.bitrate = new_bitrate;
 
+      // Reconfigure encoder and run |frames_to_encode| frames with new settings
       encoder.configure(params);
       reconf_ts = next_ts;
 
@@ -119,6 +121,14 @@
       }
 
       await encoder.flush();
+
+      // Configure back to original config
+      params.width = original_w;
+      params.height = original_h;
+      params.bitrate = original_bitrate;
+      encoder.configure(params);
+      await encoder.flush();
+
       encoder.close();
       assert_equals(before_reconf_frames, frames_to_encode);
       assert_equals(after_reconf_frames, frames_to_encode);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/test_group.js b/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/test_group.js
index dbbb821..6fe5284 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/test_group.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/test_group.js
@@ -86,6 +86,10 @@
 
   unimplemented() {
     assert(this.testFn === undefined);
+
+    this.description =
+      (this.description ? this.description + '\n\n' : '') + 'TODO: .unimplemented()';
+
     this.testFn = () => {
       throw new SkipTestCase('test unimplemented');
     };
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/tree.js b/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/tree.js
index 3bbd0092..8a2b5ee 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/tree.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/tree.js
@@ -69,9 +69,16 @@
 
   static *iterateSubtreeCollapsedQueries(subtree) {
     for (const [, child] of subtree.children) {
-      if ('children' in child && !child.collapsible) {
-        yield* TestTree.iterateSubtreeCollapsedQueries(child);
+      if ('children' in child) {
+        // Is a subtree
+        if (!child.collapsible) {
+          yield* TestTree.iterateSubtreeCollapsedQueries(child);
+        } else if (child.children.size) {
+          // Don't yield empty subtrees (e.g. files with no tests)
+          yield child.query;
+        }
       } else {
+        // Is a leaf
         yield child.query;
       }
     }
@@ -203,8 +210,8 @@
     const seen = seenSubqueriesToExpand[i];
     assert(
       seen,
-      `subqueriesToExpand entry did not match anything \
-(can happen due to overlap with another subquery): ${sq.toString()}`
+      `subqueriesToExpand entry did not match anything (can happen if the subquery was larger \
+than one file, or due to overlap with another subquery): ${sq.toString()}`
     );
   }
   assert(foundCase, 'Query does not match any cases');
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/version.js b/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/version.js
index 5695779..8411958 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/version.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/common/framework/version.js
@@ -1,3 +1,3 @@
 // AUTO-GENERATED - DO NOT EDIT. See tools/gen_version.
 
-export const version = '7518ac184c13bc1d7d68309d03234c834682428e-dirty';
+export const version = 'a8196844ac6228fea3560b82d29e01fed2fbf13a';
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/cts.html b/third_party/blink/web_tests/wpt_internal/webgpu/cts.html
index 86dff35..56679f9 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/cts.html
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/cts.html
@@ -46,22 +46,99 @@
 <meta name=variant content='?q=webgpu:api,operation,command_buffer,render,storeop:*'>
 <meta name=variant content='?q=webgpu:api,operation,copyBetweenLinearDataAndTexture:*'>
 <meta name=variant content='?q=webgpu:api,operation,fences:*'>
+<meta name=variant content='?q=webgpu:api,operation,memory_sync,buffer,ww:*'>
 <meta name=variant content='?q=webgpu:api,operation,render_pass,resolve:*'>
 <meta name=variant content='?q=webgpu:api,operation,render_pass,storeOp:*'>
 <meta name=variant content='?q=webgpu:api,operation,render_pipeline,culling_tests:*'>
 <meta name=variant content='?q=webgpu:api,operation,render_pipeline,primitive_topology:*'>
-<meta name=variant content='?q=webgpu:api,operation,resource_init,copied_texture_clear:*'>
-<meta name=variant content='?q=webgpu:api,operation,resource_init,depth_stencil_attachment_clear:*'>
-<meta name=variant content='?q=webgpu:api,operation,resource_init,sampled_texture_clear:*'>
-<meta name=variant content='?q=webgpu:api,validation,buffer_mapping:mapAsync,usage,*'>
-<meta name=variant content='?q=webgpu:api,validation,buffer_mapping:mapAsync,invalidBuffer:*'>
-<meta name=variant content='?q=webgpu:api,validation,buffer_mapping:mapAsync,state,*'>
-<meta name=variant content='?q=webgpu:api,validation,buffer_mapping:mapAsync,sizeUnspecifiedOOB,*'>
-<meta name=variant content='?q=webgpu:api,validation,buffer_mapping:mapAsync,offsetAndSizeAlignment,*'>
-<meta name=variant content='?q=webgpu:api,validation,buffer_mapping:mapAsync,offsetAndSizeOOB,*'>
-<meta name=variant content='?q=webgpu:api,validation,buffer_mapping:mapAsync_,*'>
-<meta name=variant content='?q=webgpu:api,validation,buffer_mapping:getMappedRange,*'>
-<meta name=variant content='?q=webgpu:api,validation,buffer_mapping:unmap,*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="r8unorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="r8snorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="r8uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="r8sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="r16uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="r16sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="r16float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg8unorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg8snorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg8uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg8sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="r32uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="r32sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="r32float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg16uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg16sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg16float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgba8unorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgba8unorm-srgb";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgba8snorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgba8uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgba8sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="bgra8unorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="bgra8unorm-srgb";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgb10a2unorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg11b10ufloat";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgb9e5ufloat";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg32uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg32sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rg32float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgba16uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgba16sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgba16float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgba32uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgba32sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="rgba32float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToBuffer";format="depth32float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="r8unorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="r8snorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="r8uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="r8sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="r16uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="r16sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="r16float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rg8unorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rg8snorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rg8uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rg8sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="r32uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="r32sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="r32float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rg16uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rg16sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rg16float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgba8unorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgba8unorm-srgb";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgba8snorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgba8uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgba8sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="bgra8unorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="bgra8unorm-srgb";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgb10a2unorm";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rg11b10ufloat";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgb9e5ufloat";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rg32uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rg32sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rg32float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgba16uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgba16sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgba16float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgba32uint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgba32sint";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="rgba32float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="CopyToTexture";format="depth32float";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="Sample";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="DepthTest";*'>
+<meta name=variant content='?q=webgpu:api,operation,resource_init,texture_zero_init:uninitialized_texture_is_zero:readMethod="StencilTest";*'>
+<meta name=variant content='?q=webgpu:api,validation,buffer,create:*'>
+<meta name=variant content='?q=webgpu:api,validation,buffer,destroy:*'>
+<meta name=variant content='?q=webgpu:api,validation,buffer,mapping:mapAsync,usage,*'>
+<meta name=variant content='?q=webgpu:api,validation,buffer,mapping:mapAsync,invalidBuffer:*'>
+<meta name=variant content='?q=webgpu:api,validation,buffer,mapping:mapAsync,state,*'>
+<meta name=variant content='?q=webgpu:api,validation,buffer,mapping:mapAsync,sizeUnspecifiedOOB,*'>
+<meta name=variant content='?q=webgpu:api,validation,buffer,mapping:mapAsync,offsetAndSizeAlignment,*'>
+<meta name=variant content='?q=webgpu:api,validation,buffer,mapping:mapAsync,offsetAndSizeOOB,*'>
+<meta name=variant content='?q=webgpu:api,validation,buffer,mapping:mapAsync_,*'>
+<meta name=variant content='?q=webgpu:api,validation,buffer,mapping:getMappedRange,*'>
+<meta name=variant content='?q=webgpu:api,validation,buffer,mapping:unmap,*'>
 <meta name=variant content='?q=webgpu:api,validation,copyBufferToBuffer:copy_with_invalid_buffer:'>
 <meta name=variant content='?q=webgpu:api,validation,copyBufferToBuffer:buffer_usage,*'>
 <meta name=variant content='?q=webgpu:api,validation,copyBufferToBuffer:copy_size_alignment,*'>
@@ -116,9 +193,12 @@
 <meta name=variant content='?q=webgpu:api,validation,createView:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,compute_pass:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,debug:*'>
+<meta name=variant content='?q=webgpu:api,validation,encoding,cmds,dynamic_render_state:*'>
 <meta name=variant content='?q=webgpu:api,validation,encoding,cmds,index_access:*'>
 <meta name=variant content='?q=webgpu:api,validation,error_scope:*'>
 <meta name=variant content='?q=webgpu:api,validation,fences:*'>
+<meta name=variant content='?q=webgpu:api,validation,initialization,requestDevice:*'>
+<meta name=variant content='?q=webgpu:api,validation,query_set,destroy:*'>
 <meta name=variant content='?q=webgpu:api,validation,queue,copyImageBitmapToTexture:*'>
 <meta name=variant content='?q=webgpu:api,validation,queue_submit:*'>
 <meta name=variant content='?q=webgpu:api,validation,render_pass:*'>
@@ -127,16 +207,26 @@
 <meta name=variant content='?q=webgpu:api,validation,render_pass_descriptor:*'>
 <meta name=variant content='?q=webgpu:api,validation,resource_usages,textureUsageInPassEncoder:*'>
 <meta name=variant content='?q=webgpu:api,validation,setBindGroup:*'>
-<meta name=variant content='?q=webgpu:api,validation,setBlendColor:*'>
-<meta name=variant content='?q=webgpu:api,validation,setScissorRect:*'>
-<meta name=variant content='?q=webgpu:api,validation,setStencilReference:*'>
 <meta name=variant content='?q=webgpu:api,validation,setVertexBuffer:*'>
-<meta name=variant content='?q=webgpu:api,validation,setViewport:*'>
+<meta name=variant content='?q=webgpu:api,validation,texture,destroy:*'>
 <meta name=variant content='?q=webgpu:api,validation,vertex_state:*'>
 <meta name=variant content='?q=webgpu:examples:*'>
 <meta name=variant content='?q=webgpu:idl,constants,flags:*'>
 <meta name=variant content='?q=webgpu:shader,execution,robust_access:*'>
 <meta name=variant content='?q=webgpu:shader,execution,robust_access_vertex:*'>
-<meta name=variant content='?q=webgpu:web-platform,canvas,context_creation:*'>
-<meta name=variant content='?q=webgpu:web-platform,copyImageBitmapToTexture:from_ImageData:*'>
-<meta name=variant content='?q=webgpu:web-platform,copyImageBitmapToTexture:from_canvas,*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:unorm_texel_data_in_shader:format="r8unorm";*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:unorm_texel_data_in_shader:format="rg8unorm";*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:unorm_texel_data_in_shader:format="rgba8unorm";*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:unorm_texel_data_in_shader:format="rgba8unorm-srgb";*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:unorm_texel_data_in_shader:format="bgra8unorm";*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:unorm_texel_data_in_shader:format="bgra8unorm-srgb";*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:unorm_texel_data_in_shader:format="rgb10a2unorm";*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:snorm_texel_data_in_shader,*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:uint_texel_data_in_shader,*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:sint_texel_data_in_shader,*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:float_texel_data_in_shader,*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:ufloat_texel_data_in_shader:format="rg11b10ufloat";*'>
+<meta name=variant content='?q=webgpu:util,texture,texelData:ufloat_texel_data_in_shader:format="rgb9e5ufloat";*'>
+<meta name=variant content='?q=webgpu:web_platform,canvas,context_creation:*'>
+<meta name=variant content='?q=webgpu:web_platform,copyImageBitmapToTexture:from_ImageData:*'>
+<meta name=variant content='?q=webgpu:web_platform,copyImageBitmapToTexture:from_canvas,*'>
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/compute/basic.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/compute/basic.spec.js
index 230e8920..8717b49a 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/compute/basic.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/compute/basic.spec.js
@@ -25,11 +25,26 @@
     usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.STORAGE,
   });
 
-  const bgl = t.device.createBindGroupLayout({
-    entries: [
-      { binding: 0, visibility: 4, type: 'storage-buffer' },
-      { binding: 1, visibility: 4, type: 'storage-buffer' },
-    ],
+  const pipeline = t.device.createComputePipeline({
+    computeStage: {
+      module: t.device.createShaderModule({
+        code: `
+          [[block]] struct Data {
+              [[offset(0)]] value : u32;
+          };
+
+          [[set(0), binding(0)]] var<storage_buffer> src : Data;
+          [[set(0), binding(1)]] var<storage_buffer> dst : Data;
+
+          [[stage(compute)]] fn main() -> void {
+            dst.value = src.value;
+            return;
+          }
+        `,
+      }),
+
+      entryPoint: 'main',
+    },
   });
 
   const bg = t.device.createBindGroup({
@@ -38,36 +53,14 @@
       { binding: 1, resource: { buffer: dst, offset: 0, size: 4 } },
     ],
 
-    layout: bgl,
-  });
-
-  const module = t.makeShaderModule('compute', {
-    glsl: `
-      #version 310 es
-      layout(std140, set = 0, binding = 0) buffer Src {
-        int value;
-      } src;
-      layout(std140, set = 0, binding = 1) buffer Dst {
-        int value;
-      } dst;
-
-      void main() {
-        dst.value = src.value;
-      }
-    `,
-  });
-
-  const pl = t.device.createPipelineLayout({ bindGroupLayouts: [bgl] });
-  const pipeline = t.device.createComputePipeline({
-    computeStage: { module, entryPoint: 'main' },
-    layout: pl,
+    layout: pipeline.getBindGroupLayout(0),
   });
 
   const encoder = t.device.createCommandEncoder();
   const pass = encoder.beginComputePass();
   pass.setPipeline(pipeline);
   pass.setBindGroup(0, bg);
-  pass.dispatch(1, 1, 1);
+  pass.dispatch(1);
   pass.endPass();
   t.device.defaultQueue.submit([encoder.finish()]);
 
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/render/rendering.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/render/rendering.spec.js
index 60e843a..2b2effd0e 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/render/rendering.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/render/rendering.spec.js
@@ -20,43 +20,43 @@
 
   const colorAttachmentView = colorAttachment.createView();
 
-  const vertexModule = t.makeShaderModule('vertex', {
-    glsl: `
-      #version 310 es
-      void main() {
-        const vec2 pos[3] = vec2[3](
-            vec2(-1.f, -3.f), vec2(3.f, 1.f), vec2(-1.f, 1.f));
-        gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f);
-      }
-    `,
-  });
-
-  const fragmentModule = t.makeShaderModule('fragment', {
-    glsl: `
-      #version 310 es
-      precision mediump float;
-      layout(location = 0) out vec4 fragColor;
-      void main() {
-        fragColor = vec4(0.0, 1.0, 0.0, 1.0);
-      }
-    `,
-  });
-
-  const pl = t.device.createPipelineLayout({ bindGroupLayouts: [] });
   const pipeline = t.device.createRenderPipeline({
-    vertexStage: { module: vertexModule, entryPoint: 'main' },
-    fragmentStage: { module: fragmentModule, entryPoint: 'main' },
-    layout: pl,
-    primitiveTopology: 'triangle-list',
-    rasterizationState: {
-      frontFace: 'ccw',
+    vertexStage: {
+      module: t.device.createShaderModule({
+        code: `
+          [[builtin(position)]] var<out> Position : vec4<f32>;
+          [[builtin(vertex_idx)]] var<in> VertexIndex : i32;
+
+          [[stage(vertex)]] fn main() -> void {
+            const pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
+                vec2<f32>(-1.0, -3.0),
+                vec2<f32>(3.0, 1.0),
+                vec2<f32>(-1.0, 1.0));
+            Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
+            return;
+          }
+          `,
+      }),
+
+      entryPoint: 'main',
     },
 
-    colorStates: [{ format: 'rgba8unorm', alphaBlend: {}, colorBlend: {} }],
-    vertexState: {
-      indexFormat: 'uint16',
-      vertexBuffers: [],
+    fragmentStage: {
+      module: t.device.createShaderModule({
+        code: `
+          [[location(0)]] var<out> fragColor : vec4<f32>;
+          [[stage(fragment)]] fn main() -> void {
+            fragColor = vec4<f32>(0.0, 1.0, 0.0, 1.0);
+            return;
+          }
+          `,
+      }),
+
+      entryPoint: 'main',
     },
+
+    primitiveTopology: 'triangle-list',
+    colorStates: [{ format: 'rgba8unorm' }],
   });
 
   const encoder = t.device.createCommandEncoder();
@@ -71,7 +71,7 @@
   });
 
   pass.setPipeline(pipeline);
-  pass.draw(3, 1, 0, 0);
+  pass.draw(3);
   pass.endPass();
   encoder.copyTextureToBuffer(
     { texture: colorAttachment, mipLevel: 0, origin: { x: 0, y: 0, z: 0 } },
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/render/storeop.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/render/storeop.spec.js
index cd0c9d6..f3a3ac29 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/render/storeop.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/command_buffer/render/storeop.spec.js
@@ -20,35 +20,41 @@
     });
 
     // create render pipeline
-    const vertexModule = t.makeShaderModule('vertex', {
-      glsl: `
-        #version 450
-        const vec2 pos[3] = vec2[3](
-                                vec2( 1.0f, -1.0f),
-                                vec2( 1.0f,  1.0f),
-                                vec2(-1.0f,  1.0f)
-                                );
-
-        void main() {
-            gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
-        }
-      `,
-    });
-
-    const fragmentModule = t.makeShaderModule('fragment', {
-      glsl: `
-      #version 450
-      layout(location = 0) out vec4 fragColor;
-      void main() {
-          fragColor = vec4(1.0, 0.0, 0.0, 1.0);
-      }
-    `,
-    });
-
     const renderPipeline = t.device.createRenderPipeline({
-      vertexStage: { module: vertexModule, entryPoint: 'main' },
-      fragmentStage: { module: fragmentModule, entryPoint: 'main' },
-      layout: t.device.createPipelineLayout({ bindGroupLayouts: [] }),
+      vertexStage: {
+        module: t.device.createShaderModule({
+          code: `
+            [[builtin(position)]] var<out> Position : vec4<f32>;
+            [[builtin(vertex_idx)]] var<in> VertexIndex : i32;
+
+            [[stage(vertex)]] fn main() -> void {
+              const pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
+                  vec2<f32>( 1.0, -1.0),
+                  vec2<f32>( 1.0,  1.0),
+                  vec2<f32>(-1.0,  1.0));
+              Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
+              return;
+            }
+            `,
+        }),
+
+        entryPoint: 'main',
+      },
+
+      fragmentStage: {
+        module: t.device.createShaderModule({
+          code: `
+            [[location(0)]] var<out> fragColor : vec4<f32>;
+            [[stage(fragment)]] fn main() -> void {
+              fragColor = vec4<f32>(1.0, 0.0, 0.0, 1.0);
+              return;
+            }
+            `,
+        }),
+
+        entryPoint: 'main',
+      },
+
       primitiveTopology: 'triangle-list',
       colorStates: [{ format: 'r8unorm' }],
     });
@@ -66,7 +72,7 @@
     });
 
     pass.setPipeline(renderPipeline);
-    pass.draw(3, 1, 0, 0);
+    pass.draw(3);
     pass.endPass();
     t.device.defaultQueue.submit([encoder.finish()]);
 
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/copyBetweenLinearDataAndTexture.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/copyBetweenLinearDataAndTexture.spec.js
index d2b8918..379dd8f 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/copyBetweenLinearDataAndTexture.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/copyBetweenLinearDataAndTexture.spec.js
@@ -27,7 +27,7 @@
 
 * TODO:
   - add another initMethod which renders the texture
-  - because of expectContests 4-bytes alignment we don't test CopyT2B with buffer size not divisible by 4
+  - test copyT2B with buffer size not divisible by 4 (not done because expectContents 4-byte alignment)
   - add tests for 1d / 3d textures
 `;
 import { params, poptions } from '../../../common/framework/params_builder.js';
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/labels.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/labels.spec.js
new file mode 100644
index 0000000..b872b5c
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/labels.spec.js
@@ -0,0 +1,11 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+For every create function, the descriptor.label is carried over to the object.label.
+
+TODO: implement
+`;
+import { makeTestGroup } from '../../../common/framework/test_group.js';
+import { GPUTest } from '../../gpu_test.js';
+
+export const g = makeTestGroup(GPUTest);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/memory_sync/buffer/buffer_sync_test.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/memory_sync/buffer/buffer_sync_test.js
new file mode 100644
index 0000000..14498657
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/memory_sync/buffer/buffer_sync_test.js
@@ -0,0 +1,246 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ import { assert } from '../../../../../common/framework/util/util.js';
+import { GPUTest } from '../../../../gpu_test.js';
+const kSize = 4;
+
+export const kAllWriteOps = ['render', 'render-via-bundle', 'compute', 'b2b-copy', 't2b-copy'];
+
+// Note: If it would be useful to have any of these helpers be separate from the fixture,
+// they can be refactored into standalone functions.
+export class BufferSyncTest extends GPUTest {
+  // Create a buffer, and initialize it to a specified value for all elements.
+  async createBufferWithValue(initValue) {
+    const fence = this.queue.createFence();
+    const buffer = this.device.createBuffer({
+      mappedAtCreation: true,
+      size: kSize,
+      usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST | GPUBufferUsage.STORAGE,
+    });
+
+    new Uint32Array(buffer.getMappedRange()).fill(initValue);
+    buffer.unmap();
+    this.queue.signal(fence, 1);
+    await fence.onCompletion(1);
+    return buffer;
+  }
+
+  // Create a texture, and initialize it to a specified value for all elements.
+  async createTextureWithValue(initValue) {
+    const fence = this.queue.createFence();
+    const data = new Uint32Array(kSize / 4).fill(initValue);
+    const texture = this.device.createTexture({
+      size: { width: kSize / 4, height: 1, depth: 1 },
+      format: 'r32uint',
+      usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
+    });
+
+    this.device.defaultQueue.writeTexture(
+      { texture, mipLevel: 0, origin: { x: 0, y: 0, z: 0 } },
+      data,
+      { offset: 0, bytesPerRow: kSize, rowsPerImage: 1 },
+      { width: kSize / 4, height: 1, depth: 1 }
+    );
+
+    this.queue.signal(fence, 1);
+    await fence.onCompletion(1);
+    return texture;
+  }
+
+  createBindGroup(pipeline, buffer) {
+    return this.device.createBindGroup({
+      layout: pipeline.getBindGroupLayout(0),
+      entries: [{ binding: 0, resource: { buffer } }],
+    });
+  }
+
+  // Create a compute pipeline and write given data into storage buffer.
+  createStorageWriteComputePipeline(value) {
+    const wgslCompute = `
+      [[block]] struct Data {
+        [[offset(0)]] a : i32;
+      };
+
+      [[binding(0), set(0)]] var<storage_buffer> data : Data;
+      [[stage(compute)]] fn main() -> void {
+        data.a = ${value};
+        return;
+      }
+    `;
+
+    return this.device.createComputePipeline({
+      computeStage: {
+        module: this.device.createShaderModule({
+          code: wgslCompute,
+        }),
+
+        entryPoint: 'main',
+      },
+    });
+  }
+
+  // Create a render pipeline and write given data into storage buffer at fragment stage.
+  createStorageWriteRenderPipeline(value) {
+    const wgslShaders = {
+      vertex: `
+      [[builtin(position)]] var<out> Position : vec4<f32>;
+      [[stage(vertex)]] fn vert_main() -> void {
+        Position = vec4<f32>(0.5, 0.5, 0.0, 1.0);
+        return;
+      }
+    `,
+
+      fragment: `
+      [[location(0)]] var<out> outColor : vec4<f32>;
+      [[block]] struct Data {
+        [[offset(0)]] a : i32;
+      };
+
+      [[binding(0), set(0)]] var<storage_buffer> data : Data;
+      [[stage(fragment)]] fn frag_main() -> void {
+        data.a = ${value};
+        outColor = vec4<f32>(1.0, 0.0, 0.0, 1.0);
+        return;
+      }
+    `,
+    };
+
+    return this.device.createRenderPipeline({
+      vertexStage: {
+        module: this.device.createShaderModule({
+          code: wgslShaders.vertex,
+        }),
+
+        entryPoint: 'vert_main',
+      },
+
+      fragmentStage: {
+        module: this.device.createShaderModule({
+          code: wgslShaders.fragment,
+        }),
+
+        entryPoint: 'frag_main',
+      },
+
+      primitiveTopology: 'point-list',
+      colorStates: [{ format: 'rgba8unorm' }],
+    });
+  }
+
+  beginSimpleRenderPass(encoder) {
+    const view = this.device
+      .createTexture({
+        size: { width: 1, height: 1, depth: 1 },
+        format: 'rgba8unorm',
+        usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
+      })
+      .createView();
+    return encoder.beginRenderPass({
+      colorAttachments: [
+        {
+          attachment: view,
+          loadValue: { r: 0.0, g: 1.0, b: 0.0, a: 1.0 },
+        },
+      ],
+    });
+  }
+
+  // Write buffer via draw call in render pass. Use bundle if needed.
+  encodeWriteAsStorageBufferInRenderPass(encoder, buffer, value, inBundle) {
+    const pipeline = this.createStorageWriteRenderPipeline(value);
+    const bindGroup = this.createBindGroup(pipeline, buffer);
+
+    const pass = this.beginSimpleRenderPass(encoder);
+    const renderer = inBundle
+      ? this.device.createRenderBundleEncoder({ colorFormats: ['rgba8unorm'] })
+      : pass;
+    renderer.setBindGroup(0, bindGroup);
+    renderer.setPipeline(pipeline);
+    renderer.draw(1, 1, 0, 0);
+
+    if (inBundle) pass.executeBundles([renderer.finish()]);
+    pass.endPass();
+  }
+
+  // Write buffer via dispatch call in compute pass.
+  encodeWriteAsStorageBufferInComputePass(encoder, buffer, value) {
+    const pipeline = this.createStorageWriteComputePipeline(value);
+    const bindGroup = this.createBindGroup(pipeline, buffer);
+    const pass = encoder.beginComputePass();
+    pass.setPipeline(pipeline);
+    pass.setBindGroup(0, bindGroup);
+    pass.dispatch(1);
+    pass.endPass();
+  }
+
+  /** Write buffer via BufferToBuffer copy. */
+  async encodeWriteByB2BCopy(encoder, buffer, value) {
+    const tmpBuffer = await this.createBufferWithValue(value);
+
+    // The write operation via b2b copy is just encoded into command encoder, it doesn't write immediately.
+    encoder.copyBufferToBuffer(tmpBuffer, 0, buffer, 0, kSize);
+  }
+
+  // Write buffer via TextureToBuffer copy.
+  async encodeWriteByT2BCopy(encoder, buffer, value) {
+    const tmpTexture = await this.createTextureWithValue(value);
+
+    // The write operation via t2b copy is just encoded into command encoder, it doesn't write immediately.
+    encoder.copyTextureToBuffer(
+      { texture: tmpTexture, mipLevel: 0, origin: { x: 0, y: 0, z: 0 } },
+      { buffer, bytesPerRow: 256 },
+      { width: 1, height: 1, depth: 1 }
+    );
+  }
+
+  // Write buffer via writeBuffer API on queue
+  writeByWriteBuffer(buffer, value) {
+    const data = new Uint32Array(kSize / 4).fill(value);
+    this.device.defaultQueue.writeBuffer(buffer, 0, data);
+  }
+
+  // Issue write operation via render pass, compute pass, copy, etc.
+  async encodeWriteOp(encoder, writeOp, buffer, value) {
+    switch (writeOp) {
+      case 'render':
+        this.encodeWriteAsStorageBufferInRenderPass(encoder, buffer, value, false);
+        break;
+      case 'render-via-bundle':
+        this.encodeWriteAsStorageBufferInRenderPass(encoder, buffer, value, true);
+        break;
+      case 'compute':
+        this.encodeWriteAsStorageBufferInComputePass(encoder, buffer, value);
+        break;
+      case 'b2b-copy':
+        await this.encodeWriteByB2BCopy(encoder, buffer, value);
+        break;
+      case 't2b-copy':
+        await this.encodeWriteByT2BCopy(encoder, buffer, value);
+        break;
+      default:
+        assert(false);
+    }
+  }
+
+  async createCommandBufferWithWriteOp(writeOp, buffer, value) {
+    const encoder = this.device.createCommandEncoder();
+    await this.encodeWriteOp(encoder, writeOp, buffer, value);
+    return encoder.finish();
+  }
+
+  async submitWriteOp(writeOp, buffer, value) {
+    if (writeOp === 'write-buffer') {
+      this.writeByWriteBuffer(buffer, value);
+    } else {
+      const encoder = this.device.createCommandEncoder();
+      await this.encodeWriteOp(encoder, writeOp, buffer, value);
+      this.device.defaultQueue.submit([encoder.finish()]);
+    }
+  }
+
+  verifyData(buffer, expectedValue) {
+    const bufferData = new Uint32Array(1);
+    bufferData[0] = expectedValue;
+    this.expectContents(buffer, bufferData);
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/memory_sync/buffer/rw_and_wr.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/memory_sync/buffer/rw_and_wr.spec.js
new file mode 100644
index 0000000..7ea75ec7
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/memory_sync/buffer/rw_and_wr.spec.js
@@ -0,0 +1,21 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Memory Synchronization Tests for Buffer: read before write and read after write.
+
+- Create a single buffer and initialize it to 0, wait on the fence to ensure the data is initialized.
+Write a number (say 1) into the buffer via render pass, compute pass, copy or writeBuffer.
+Read the data and use it in render, compute, or copy.
+Wait on another fence, then call expectContents to verify the written buffer.
+This is a read-after write test but if the write and read operations are reversed, it will be a read-before-write test.
+  - x= write op: {storage buffer in {compute, render, render-via-bundle}, t2b copy dst, b2b copy dst, writeBuffer}
+  - x= read op: {index buffer, vertex buffer, indirect buffer, uniform buffer, {readonly, readwrite} storage buffer in {compute, render, render-via-bundle}, b2b copy src, b2t copy src}
+  - x= read-write sequence: {read then write, write then read}
+  - if pass type is the same, x= {single pass, separate passes} (note: render has loose guarantees)
+  - if not single pass, x= writes in {same cmdbuf, separate cmdbufs, separate submits, separate queues}
+`;
+import { makeTestGroup } from '../../../../../common/framework/test_group.js';
+
+import { BufferSyncTest } from './buffer_sync_test.js';
+
+export const g = makeTestGroup(BufferSyncTest);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/memory_sync/buffer/ww.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/memory_sync/buffer/ww.spec.js
new file mode 100644
index 0000000..b0cedc3a
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/memory_sync/buffer/ww.spec.js
@@ -0,0 +1,95 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Memory Synchronization Tests for Buffer: write after write.
+
+- Create one single buffer and initialize it to 0. Wait on the fence to ensure the data is initialized.
+Write a number (say 1) into the buffer via render pass, compute pass, copy or writeBuffer.
+Write another number (say 2) into the same buffer via render pass, compute pass, copy, or writeBuffer.
+Wait on another fence, then call expectContents to verify the written buffer.
+  - x= 1st write type: {storage buffer in {compute, render, render-via-bundle}, t2b-copy, b2b-copy, writeBuffer}
+  - x= 2nd write type: {storage buffer in {compute, render, render-via-bundle}, t2b-copy, b2b-copy, writeBuffer}
+  - if pass type is the same, x= {single pass, separate passes} (note: render has loose guarantees)
+  - if not single pass, x= writes in {same cmdbuf, separate cmdbufs, separate submits, separate queues}
+`;
+import { poptions, params } from '../../../../../common/framework/params_builder.js';
+import { makeTestGroup } from '../../../../../common/framework/test_group.js';
+
+import { kAllWriteOps, BufferSyncTest } from './buffer_sync_test.js';
+
+export const g = makeTestGroup(BufferSyncTest);
+
+g.test('same_cmdbuf')
+  .desc('Test write-after-write operations in the same command buffer.')
+  .params(
+    params()
+      .combine(poptions('firstWriteOp', kAllWriteOps))
+      .combine(poptions('secondWriteOp', kAllWriteOps))
+  )
+  .fn(async t => {
+    const { firstWriteOp, secondWriteOp } = t.params;
+    const buffer = await t.createBufferWithValue(0);
+
+    const encoder = t.device.createCommandEncoder();
+    await t.encodeWriteOp(encoder, firstWriteOp, buffer, 1);
+    await t.encodeWriteOp(encoder, secondWriteOp, buffer, 2);
+    t.device.defaultQueue.submit([encoder.finish()]);
+
+    t.verifyData(buffer, 2);
+  });
+
+g.test('separate_cmdbufs')
+  .desc('Test write-after-write operations in separate command buffers via the same submit.')
+  .params(
+    params()
+      .combine(poptions('firstWriteOp', kAllWriteOps))
+      .combine(poptions('secondWriteOp', kAllWriteOps))
+  )
+  .fn(async t => {
+    const { firstWriteOp, secondWriteOp } = t.params;
+    const buffer = await t.createBufferWithValue(0);
+
+    const command_buffers = [];
+    command_buffers.push(await t.createCommandBufferWithWriteOp(firstWriteOp, buffer, 1));
+    command_buffers.push(await t.createCommandBufferWithWriteOp(secondWriteOp, buffer, 2));
+    t.device.defaultQueue.submit(command_buffers);
+
+    t.verifyData(buffer, 2);
+  });
+
+g.test('separate_submits')
+  .desc('Test write-after-write operations via separate submits in the same queue.')
+  .params(
+    params()
+      .combine(poptions('firstWriteOp', ['write-buffer', ...kAllWriteOps]))
+      .combine(poptions('secondWriteOp', ['write-buffer', ...kAllWriteOps]))
+  )
+  .fn(async t => {
+    const { firstWriteOp, secondWriteOp } = t.params;
+    const buffer = await t.createBufferWithValue(0);
+
+    await t.submitWriteOp(firstWriteOp, buffer, 1);
+    await t.submitWriteOp(secondWriteOp, buffer, 2);
+
+    t.verifyData(buffer, 2);
+  });
+
+g.test('separate_queues')
+  .desc('Test write-after-write operations in separate queues.')
+  .unimplemented();
+
+g.test('two_draws_in_the_same_render_pass')
+  .desc(
+    `Test write-after-write operations in the same render pass. The first write will write 1 into
+    a storage buffer. The second write will write 2 into the same buffer in the same pass. Expected
+    data in buffer is either 1 or 2. It may use bundle in each draw.`
+  )
+  .unimplemented();
+
+g.test('two_dispatches_in_the_same_compute_pass')
+  .desc(
+    `Test write-after-write operations in the same compute pass. The first write will write 1 into
+    a storage buffer. The second write will write 2 into the same buffer in the same pass. Expected
+    data in buffer is 2.`
+  )
+  .unimplemented();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pass/resolve.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pass/resolve.spec.js
index cf63ccbf..15fd2168 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pass/resolve.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pass/resolve.spec.js
@@ -1,7 +1,6 @@
 /**
  * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
  **/ export const description = `API Operation Tests for RenderPass StoreOp.
-
 Tests a render pass with a resolveTarget resolves correctly for many combinations of:
   - number of color attachments, some with and some without a resolveTarget
   - renderPass storeOp set to {‘store’, ‘clear’}
@@ -35,56 +34,58 @@
       .combine(poptions('resolveTargetBaseArrayLayer', [0, 1]))
   )
   .fn(t => {
-    // These shaders will draw a white triangle into a texture. After draw, the top left
-    // half of the texture will be white, and the bottom right half will be unchanged. When this
-    // texture is resolved, there will be two distinct colors in each portion of the texture, as
-    // well as a line between the portions that contain the midpoint color due to the multisample
-    // resolve.
-    const vertexModule = t.makeShaderModule('vertex', {
-      glsl: `
-      #version 450
-      const vec2 pos[3] = vec2[3](vec2(-1.0f, -1.0f), vec2(-1.0f, 1.0), vec2(1.0, 1.0));
-        void main() {
-          gl_Position = vec4(pos[gl_VertexIndex], 0.0f, 1.0f);
-        }
-      `,
-    });
-
-    const fragmentModule = t.makeShaderModule('fragment', {
-      glsl: `
-      #version 450
-        layout(location = 0) out vec4 fragColor0;
-        layout(location = 1) out vec4 fragColor1;
-        layout(location = 2) out vec4 fragColor2;
-        layout(location = 3) out vec4 fragColor3;
-        void main() {
-          fragColor0 = vec4(1.0, 1.0, 1.0, 1.0);
-          fragColor1 = vec4(1.0, 1.0, 1.0, 1.0);
-          fragColor2 = vec4(1.0, 1.0, 1.0, 1.0);
-          fragColor3 = vec4(1.0, 1.0, 1.0, 1.0);
-        }
-      `,
-    });
-
     const colorStateDescriptors = [];
     for (let i = 0; i < t.params.numColorAttachments; i++) {
       colorStateDescriptors.push({ format: kFormat });
     }
 
+    // These shaders will draw a white triangle into a texture. After draw, the top left
+    // half of the texture will be white, and the bottom right half will be unchanged. When this
+    // texture is resolved, there will be two distinct colors in each portion of the texture, as
+    // well as a line between the portions that contain the midpoint color due to the multisample
+    // resolve.
     const pipeline = t.device.createRenderPipeline({
-      vertexStage: { module: vertexModule, entryPoint: 'main' },
-      fragmentStage: { module: fragmentModule, entryPoint: 'main' },
+      vertexStage: {
+        module: t.device.createShaderModule({
+          code: `
+            [[builtin(position)]] var<out> Position : vec4<f32>;
+            [[builtin(vertex_idx)]] var<in> VertexIndex : i32;
+
+            [[stage(vertex)]] fn main() -> void {
+              const pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
+                  vec2<f32>(-1.0, -1.0),
+                  vec2<f32>(-1.0,  1.0),
+                  vec2<f32>( 1.0,  1.0));
+              Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
+              return;
+            }`,
+        }),
+
+        entryPoint: 'main',
+      },
+
+      fragmentStage: {
+        module: t.device.createShaderModule({
+          code: `
+            [[location(0)]] var<out> fragColor0 : vec4<f32>;
+            [[location(1)]] var<out> fragColor1 : vec4<f32>;
+            [[location(2)]] var<out> fragColor2 : vec4<f32>;
+            [[location(3)]] var<out> fragColor3 : vec4<f32>;
+
+            [[stage(fragment)]] fn main() -> void {
+              fragColor0 = vec4<f32>(1.0, 1.0, 1.0, 1.0);
+              fragColor1 = vec4<f32>(1.0, 1.0, 1.0, 1.0);
+              fragColor2 = vec4<f32>(1.0, 1.0, 1.0, 1.0);
+              fragColor3 = vec4<f32>(1.0, 1.0, 1.0, 1.0);
+              return;
+            }`,
+        }),
+
+        entryPoint: 'main',
+      },
+
       primitiveTopology: 'triangle-list',
-      rasterizationState: {
-        frontFace: 'ccw',
-      },
-
       colorStates: colorStateDescriptors,
-      vertexState: {
-        indexFormat: 'uint32',
-        vertexBuffers: [],
-      },
-
       sampleCount: 4,
     });
 
@@ -157,7 +158,7 @@
     });
 
     pass.setPipeline(pipeline);
-    pass.draw(3, 1, 0, 0);
+    pass.draw(3);
     pass.endPass();
     t.device.defaultQueue.submit([encoder.finish()]);
 
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pass/storeOp.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pass/storeOp.spec.js
index 83ae865..2d8f944 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pass/storeOp.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pass/storeOp.spec.js
@@ -261,13 +261,20 @@
     }
   });
 
-// Tests that render pass depth stencil store operations work correctly for all renderable color
-// formats, mip levels and array layers.
 g.test('render_pass_store_op,depth_stencil_attachment_only')
+  .desc(
+    `
+Tests that render pass depth stencil store operations work correctly for all renderable color
+formats, mip levels and array layers.
+
+- x= all (sized) depth stencil formats, all store ops, multiple mip levels, multiple array layers
+
+TODO: Also test unsized depth/stencil formats
+  `
+  )
   .params(
     params()
-      // TODO: Also test unsized depth/stencil formats
-      .combine(poptions('depthStencilFormat', kSizedDepthStencilFormats))
+      .combine(poptions('depthStencilFormat', kSizedDepthStencilFormats)) // TODO
       .combine(poptions('storeOperation', kStoreOps))
       .combine(poptions('mipLevel', kMipLevel))
       .combine(poptions('arrayLayer', kArrayLayers))
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pipeline/culling_tests.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pipeline/culling_tests.spec.js
index a10a987520..e01d300 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pipeline/culling_tests.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pipeline/culling_tests.spec.js
@@ -99,35 +99,49 @@
     // Draw two triangles with different winding orders:
     // 1. The top-left one is counterclockwise (CCW)
     // 2. The bottom-right one is clockwise (CW)
-    const vertexModule = t.makeShaderModule('vertex', {
-      glsl: `#version 450
-            const vec2 pos[6] = vec2[6](vec2(-1.0f,  1.0f),
-                                        vec2(-1.0f,  0.0f),
-                                        vec2( 0.0f,  1.0f),
-                                        vec2( 0.0f, -1.0f),
-                                        vec2( 1.0f,  0.0f),
-                                        vec2( 1.0f, -1.0f));
-            void main() {
-                gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
-            }`,
-    });
-
-    const fragmentModule = t.makeShaderModule('fragment', {
-      glsl: `#version 450
-      layout(location = 0) out vec4 fragColor;
-      void main() {
-        if (gl_FrontFacing) {
-          fragColor = vec4(0.0, 1.0, 0.0, 1.0);
-        } else {
-          fragColor = vec4(1.0, 0.0, 0.0, 1.0);
-        }
-      }`,
-    });
-
     pass.setPipeline(
       t.device.createRenderPipeline({
-        vertexStage: { module: vertexModule, entryPoint: 'main' },
-        fragmentStage: { module: fragmentModule, entryPoint: 'main' },
+        vertexStage: {
+          module: t.device.createShaderModule({
+            code: `
+              [[builtin(position)]] var<out> Position : vec4<f32>;
+              [[builtin(vertex_idx)]] var<in> VertexIndex : i32;
+
+              [[stage(vertex)]] fn main() -> void {
+                const pos : array<vec2<f32>, 6> = array<vec2<f32>, 6>(
+                    vec2<f32>(-1.0,  1.0),
+                    vec2<f32>(-1.0,  0.0),
+                    vec2<f32>( 0.0,  1.0),
+                    vec2<f32>( 0.0, -1.0),
+                    vec2<f32>( 1.0,  0.0),
+                    vec2<f32>( 1.0, -1.0));
+                Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
+                return;
+              }`,
+          }),
+
+          entryPoint: 'main',
+        },
+
+        fragmentStage: {
+          module: t.device.createShaderModule({
+            code: `
+              [[location(0)]] var<out> fragColor : vec4<f32>;
+              [[builtin(front_facing)]] var<in> FrontFacing : bool;
+
+              [[stage(fragment)]] fn main() -> void {
+                if (FrontFacing) {
+                  fragColor = vec4<f32>(0.0, 1.0, 0.0, 1.0);
+                } else {
+                  fragColor = vec4<f32>(1.0, 0.0, 0.0, 1.0);
+                }
+                return;
+              }`,
+          }),
+
+          entryPoint: 'main',
+        },
+
         primitiveTopology: t.params.primitiveTopology,
         rasterizationState: {
           frontFace: t.params.frontFace,
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pipeline/primitive_topology.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pipeline/primitive_topology.spec.js
index 770e8c72..bf95a27 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pipeline/primitive_topology.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/render_pipeline/primitive_topology.spec.js
@@ -232,35 +232,50 @@
       ],
     });
 
+    let indexFormat = undefined;
+    if (primitiveTopology === 'triangle-strip' || primitiveTopology === 'line-strip') {
+      indexFormat = 'uint32';
+    }
+
     // Draw a primitive using 6 vertices based on the type.
     // Pixels are generated based on vertex position.
     // If point, 1 pixel is generated at each vertex location.
     // Otherwise, >1 pixels could be generated.
-    const vertexModule = this.makeShaderModule('vertex', {
-      glsl: `#version 450
-            layout(location = 0) in vec4 pos;
-            void main() {
-                gl_Position = pos;
-                gl_PointSize = 1.0;
-            }`,
-    });
-
     // Output color is solid green.
-    const fragmentModule = this.makeShaderModule('fragment', {
-      glsl: `#version 450
-            layout(location = 0) out vec4 fragColor;
-            void main() {
-              fragColor = vec4(0.0, 1.0, 0.0, 1.0);
-            }`,
-    });
-
     renderPass.setPipeline(
       this.device.createRenderPipeline({
-        vertexStage: { module: vertexModule, entryPoint: 'main' },
-        fragmentStage: { module: fragmentModule, entryPoint: 'main' },
+        vertexStage: {
+          module: this.device.createShaderModule({
+            code: `
+              [[location(0)]] var<in> pos : vec4<f32>;
+              [[builtin(position)]] var<out> Position : vec4<f32>;
+
+              [[stage(vertex)]] fn main() -> void {
+                Position = pos;
+                return;
+              }`,
+          }),
+
+          entryPoint: 'main',
+        },
+
+        fragmentStage: {
+          module: this.device.createShaderModule({
+            code: `
+              [[location(0)]] var<out> fragColor : vec4<f32>;
+              [[stage(fragment)]] fn main() -> void {
+                fragColor = vec4<f32>(0.0, 1.0, 0.0, 1.0);
+                return;
+              }`,
+          }),
+
+          entryPoint: 'main',
+        },
+
         primitiveTopology,
         colorStates: [{ format: kColorFormat }],
         vertexState: {
+          indexFormat,
           vertexBuffers: [
             {
               arrayStride: 4 * Float32Array.BYTES_PER_ELEMENT,
@@ -290,9 +305,9 @@
       );
 
       renderPass.setIndexBuffer(indexBuffer, 'uint32');
-      renderPass.drawIndexed(7, 1, 0, 0, 0); // extra index for restart
+      renderPass.drawIndexed(7); // extra index for restart
     } else {
-      renderPass.draw(6, 1, 0, 0);
+      renderPass.draw(6);
     }
 
     renderPass.endPass();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/check_texture/by_copy.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/check_texture/by_copy.js
new file mode 100644
index 0000000..68f6f3c
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/check_texture/by_copy.js
@@ -0,0 +1,51 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ import { assert } from '../../../../../common/framework/util/util.js';
+import { kEncodableTextureFormatInfo } from '../../../../capability_info.js';
+
+export const checkContentsByBufferCopy = (t, params, texture, state, subresourceRange) => {
+  for (const { level: mipLevel, slice } of subresourceRange.each()) {
+    assert(params.dimension === '2d');
+    assert(params.format in kEncodableTextureFormatInfo);
+    const format = params.format;
+
+    t.expectSingleColor(texture, format, {
+      size: [t.textureWidth, t.textureHeight, 1],
+      dimension: params.dimension,
+      slice,
+      layout: { mipLevel },
+      exp: t.stateToTexelComponents[state],
+    });
+  }
+};
+
+export const checkContentsByTextureCopy = (t, params, texture, state, subresourceRange) => {
+  for (const { level, slice } of subresourceRange.each()) {
+    assert(params.dimension === '2d');
+    assert(params.format in kEncodableTextureFormatInfo);
+    const format = params.format;
+
+    const width = t.textureWidth >> level;
+    const height = t.textureHeight >> level;
+
+    const dst = t.device.createTexture({
+      size: [width, height, 1],
+      format: params.format,
+      usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC,
+    });
+
+    const commandEncoder = t.device.createCommandEncoder();
+    commandEncoder.copyTextureToTexture(
+      { texture, mipLevel: level, origin: { x: 0, y: 0, z: slice } },
+      { texture: dst, mipLevel: 0 },
+      { width, height, depth: 1 }
+    );
+
+    t.queue.submit([commandEncoder.finish()]);
+
+    t.expectSingleColor(dst, format, {
+      size: [width, height, 1],
+      exp: t.stateToTexelComponents[state],
+    });
+  }
+};
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/check_texture/by_ds_test.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/check_texture/by_ds_test.js
new file mode 100644
index 0000000..bb8e944
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/check_texture/by_ds_test.js
@@ -0,0 +1,182 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ import { assert } from '../../../../../common/framework/util/util.js';
+import { mipSize } from '../../../../util/texture/subresource.js';
+
+function makeFullscreenVertexModule(device) {
+  return device.createShaderModule({
+    code: `
+    [[builtin(position)]] var<out> Position : vec4<f32>;
+    [[builtin(vertex_idx)]] var<in> VertexIndex : i32;
+
+    [[stage(vertex)]]
+    fn main() -> void {
+      const pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
+        vec2<f32>(-1.0, -3.0),
+        vec2<f32>( 3.0,  1.0),
+        vec2<f32>(-1.0,  1.0));
+      Position = vec4<f32>(pos[VertexIndex], 0.0, 1.0);
+      return;
+    }
+    `,
+  });
+}
+
+function getDepthTestEqualPipeline(t, format, sampleCount, expected) {
+  return t.device.createRenderPipeline({
+    vertexStage: {
+      entryPoint: 'main',
+      module: makeFullscreenVertexModule(t.device),
+    },
+
+    fragmentStage: {
+      entryPoint: 'main',
+      module: t.device.createShaderModule({
+        code: `
+        [[builtin(frag_depth)]] var<out> FragDepth : f32;
+        [[location(0)]] var<out> outSuccess : f32;
+
+        [[stage(fragment)]]
+        fn main() -> void {
+          FragDepth = f32(${expected});
+          outSuccess = 1.0;
+          return;
+        }
+        `,
+      }),
+    },
+
+    colorStates: [{ format: 'r8unorm' }],
+    depthStencilState: {
+      format,
+      depthCompare: 'equal',
+    },
+
+    primitiveTopology: 'triangle-list',
+    sampleCount,
+  });
+}
+
+function getStencilTestEqualPipeline(t, format, sampleCount) {
+  return t.device.createRenderPipeline({
+    vertexStage: {
+      entryPoint: 'main',
+      module: makeFullscreenVertexModule(t.device),
+    },
+
+    fragmentStage: {
+      entryPoint: 'main',
+      module: t.device.createShaderModule({
+        code: `
+        [[location(0)]] var<out> outSuccess : f32;
+
+        [[stage(fragment)]]
+        fn main() -> void {
+          outSuccess = 1.0;
+          return;
+        }
+        `,
+      }),
+    },
+
+    colorStates: [
+      {
+        format: 'r8unorm',
+      },
+    ],
+
+    depthStencilState: {
+      format,
+      stencilFront: { compare: 'equal' },
+      stencilBack: { compare: 'equal' },
+    },
+
+    primitiveTopology: 'triangle-list',
+    sampleCount,
+  });
+}
+
+const checkContents = (type, t, params, texture, state, subresourceRange) => {
+  for (const viewDescriptor of t.generateTextureViewDescriptorsForRendering(
+    params.aspect,
+    subresourceRange
+  )) {
+    assert(viewDescriptor.baseMipLevel !== undefined);
+    const [width, height] = mipSize([t.textureWidth, t.textureHeight], viewDescriptor.baseMipLevel);
+
+    const renderTexture = t.device.createTexture({
+      size: [width, height, 1],
+      format: 'r8unorm',
+      usage: GPUTextureUsage.OUTPUT_ATTACHMENT | GPUTextureUsage.COPY_SRC,
+      sampleCount: params.sampleCount,
+    });
+
+    let resolveTexture = undefined;
+    let resolveTarget = undefined;
+    if (params.sampleCount > 1) {
+      resolveTexture = t.device.createTexture({
+        size: [width, height, 1],
+        format: 'r8unorm',
+        usage: GPUTextureUsage.OUTPUT_ATTACHMENT | GPUTextureUsage.COPY_SRC,
+      });
+
+      resolveTarget = resolveTexture.createView();
+    }
+
+    const commandEncoder = t.device.createCommandEncoder();
+    const pass = commandEncoder.beginRenderPass({
+      colorAttachments: [
+        {
+          attachment: renderTexture.createView(),
+          resolveTarget,
+          loadValue: [0, 0, 0, 0],
+          storeOp: 'store',
+        },
+      ],
+
+      depthStencilAttachment: {
+        attachment: texture.createView(viewDescriptor),
+        depthStoreOp: 'store',
+        depthLoadValue: 'load',
+        stencilStoreOp: 'store',
+        stencilLoadValue: 'load',
+      },
+    });
+
+    switch (type) {
+      case 'depth': {
+        const expectedDepth = t.stateToTexelComponents[state].Depth;
+        assert(expectedDepth !== undefined);
+
+        pass.setPipeline(
+          getDepthTestEqualPipeline(t, params.format, params.sampleCount, expectedDepth)
+        );
+
+        break;
+      }
+
+      case 'stencil': {
+        const expectedStencil = t.stateToTexelComponents[state].Stencil;
+        assert(expectedStencil !== undefined);
+
+        pass.setPipeline(getStencilTestEqualPipeline(t, params.format, params.sampleCount));
+        pass.setStencilReference(expectedStencil);
+        break;
+      }
+    }
+
+    pass.draw(3);
+    pass.endPass();
+
+    t.queue.submit([commandEncoder.finish()]);
+
+    t.expectSingleColor(resolveTexture || renderTexture, 'r8unorm', {
+      size: [width, height, 1],
+      exp: { R: 1 },
+    });
+  }
+};
+
+export const checkContentsByDepthTest = (...args) => checkContents('depth', ...args);
+
+export const checkContentsByStencilTest = (...args) => checkContents('stencil', ...args);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/check_texture/by_sampling.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/check_texture/by_sampling.js
new file mode 100644
index 0000000..9157f9e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/check_texture/by_sampling.js
@@ -0,0 +1,145 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ import { assert } from '../../../../../common/framework/util/util.js';
+import { kEncodableTextureFormatInfo } from '../../../../capability_info.js';
+import { getTexelDataRepresentation } from '../../../../util/texture/texelData.js';
+
+export const checkContentsBySampling = (t, params, texture, state, subresourceRange) => {
+  assert(params.dimension === '2d');
+  assert(params.format in kEncodableTextureFormatInfo);
+  const format = params.format;
+  const rep = getTexelDataRepresentation(format);
+
+  for (const { level, slices } of subresourceRange.mipLevels()) {
+    const width = t.textureWidth >> level;
+    const height = t.textureHeight >> level;
+
+    let ReadbackTypedArray = Float32Array;
+
+    // TODO: look up component type in texture format tables
+    let shaderType = 'f32';
+    if (params.format.indexOf('sint') !== -1) {
+      shaderType = 'i32';
+      ReadbackTypedArray = Int32Array;
+    } else if (params.format.indexOf('uint') !== -1) {
+      shaderType = 'u32';
+      ReadbackTypedArray = Uint32Array;
+    }
+
+    const componentOrder = rep.componentOrder;
+    const componentCount = componentOrder.length;
+
+    // For single-component textures, generates .r
+    // For multi-component textures, generates ex.)
+    //  .rgba[i], .bgra[i], .rgb[i]
+    const indexExpression =
+      componentCount === 1
+        ? componentOrder[0].toLowerCase()
+        : componentOrder.map(c => c.toLowerCase()).join('') + '[i]';
+
+    const _xd = '_' + params.dimension;
+    const _multisampled = params.sampleCount > 1 ? '_multisampled' : '';
+    const computePipeline = t.device.createComputePipeline({
+      computeStage: {
+        entryPoint: 'main',
+        module: t.device.createShaderModule({
+          code: `
+            [[block]] struct Constants {
+              [[offset(0)]] level : i32;
+            };
+
+            [[set(0), binding(0)]] var<uniform> constants : Constants;
+            [[set(0), binding(1)]] var<uniform_constant> myTexture : texture${_multisampled}${_xd}<${shaderType}>;
+
+            [[block]] struct Result {
+              [[offset(0)]] values : [[stride(4)]] array<${shaderType}>;
+            };
+            [[set(0), binding(3)]] var<storage_buffer> result : Result;
+
+            [[builtin(global_invocation_id)]] var<in> GlobalInvocationID : vec3<u32>;
+
+            [[stage(compute)]]
+            fn main() -> void {
+              var flatIndex : u32 = ${width}u * GlobalInvocationID.y + GlobalInvocationID.x;
+              flatIndex = flatIndex * ${componentCount}u;
+              var texel : vec4<${shaderType}> = textureLoad(
+                myTexture, vec2<i32>(GlobalInvocationID.xy), constants.level);
+
+              for (var i : u32 = flatIndex; i < flatIndex + ${componentCount}u; i = i + 1) {
+                result.values[i] = texel.${indexExpression};
+              }
+              return;
+            }`,
+        }),
+      },
+    });
+
+    for (const slice of slices) {
+      const ubo = t.device.createBuffer({
+        mappedAtCreation: true,
+        size: 4,
+        usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
+      });
+
+      new Int32Array(ubo.getMappedRange(), 0, 1)[0] = level;
+      ubo.unmap();
+
+      const byteLength =
+        width * height * ReadbackTypedArray.BYTES_PER_ELEMENT * rep.componentOrder.length;
+      const resultBuffer = t.device.createBuffer({
+        size: byteLength,
+        usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
+      });
+
+      const bindGroup = t.device.createBindGroup({
+        layout: computePipeline.getBindGroupLayout(0),
+        entries: [
+          {
+            binding: 0,
+            resource: { buffer: ubo },
+          },
+
+          {
+            binding: 1,
+            resource: texture.createView({
+              baseMipLevel: 0,
+              mipLevelCount: params.mipLevelCount,
+              baseArrayLayer: slice,
+              arrayLayerCount: 1,
+            }),
+          },
+
+          {
+            binding: 3,
+            resource: {
+              buffer: resultBuffer,
+            },
+          },
+        ],
+      });
+
+      const commandEncoder = t.device.createCommandEncoder();
+      const pass = commandEncoder.beginComputePass();
+      pass.setPipeline(computePipeline);
+      pass.setBindGroup(0, bindGroup);
+      pass.dispatch(width, height);
+      pass.endPass();
+      t.queue.submit([commandEncoder.finish()]);
+      ubo.destroy();
+
+      const expectedValues = new ReadbackTypedArray(new ArrayBuffer(byteLength));
+      const expectedState = t.stateToTexelComponents[state];
+      let i = 0;
+      for (let h = 0; h < height; ++h) {
+        for (let w = 0; w < height; ++w) {
+          for (const c of rep.componentOrder) {
+            const value = expectedState[c];
+            assert(value !== undefined);
+            expectedValues[i++] = value;
+          }
+        }
+      }
+      t.expectContents(resultBuffer, expectedValues);
+    }
+  }
+};
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/copied_texture_clear.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/copied_texture_clear.spec.js
deleted file mode 100644
index 28fb5b3..0000000
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/copied_texture_clear.spec.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
- **/ export const description = 'Test uninitialized textures are initialized to zero when copied.';
-import { makeTestGroup } from '../../../../common/framework/test_group.js';
-import { assert, unreachable } from '../../../../common/framework/util/util.js';
-
-import { ReadMethod, TextureZeroInitTest } from './texture_zero_init_test.js';
-
-class CopiedTextureClearTest extends TextureZeroInitTest {
-  checkContentsByBufferCopy(texture, state, subresourceRange) {
-    for (const { level: mipLevel, slice } of subresourceRange.each()) {
-      assert(this.params.dimension === '2d');
-
-      this.expectSingleColor(texture, this.params.format, {
-        size: [this.textureWidth, this.textureHeight, 1],
-        dimension: this.params.dimension,
-        slice,
-        layout: { mipLevel },
-        exp: this.stateToTexelComponents[state],
-      });
-    }
-  }
-
-  checkContentsByTextureCopy(texture, state, subresourceRange) {
-    for (const { level, slice } of subresourceRange.each()) {
-      assert(this.params.dimension === '2d');
-
-      const width = this.textureWidth >> level;
-      const height = this.textureHeight >> level;
-
-      const dst = this.device.createTexture({
-        size: [width, height, 1],
-        format: this.params.format,
-        usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC,
-      });
-
-      const commandEncoder = this.device.createCommandEncoder();
-      commandEncoder.copyTextureToTexture(
-        { texture, mipLevel: level, origin: { x: 0, y: 0, z: slice } },
-        { texture: dst, mipLevel: 0 },
-        { width, height, depth: 1 }
-      );
-
-      this.queue.submit([commandEncoder.finish()]);
-
-      this.expectSingleColor(dst, this.params.format, {
-        size: [width, height, 1],
-        exp: this.stateToTexelComponents[state],
-      });
-    }
-  }
-
-  checkContents(texture, state, subresourceRange) {
-    switch (this.params.readMethod) {
-      case ReadMethod.CopyToBuffer:
-        this.checkContentsByBufferCopy(texture, state, subresourceRange);
-        break;
-
-      case ReadMethod.CopyToTexture:
-        this.checkContentsByTextureCopy(texture, state, subresourceRange);
-        break;
-
-      default:
-        unreachable();
-    }
-  }
-}
-
-export const g = makeTestGroup(CopiedTextureClearTest);
-
-g.test('uninitialized_texture_is_zero')
-  .params(TextureZeroInitTest.generateParams([ReadMethod.CopyToBuffer, ReadMethod.CopyToTexture]))
-  .fn(t => {
-    t.run();
-  });
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/depth_stencil_attachment_clear.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/depth_stencil_attachment_clear.spec.js
deleted file mode 100644
index 06004ea..0000000
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/depth_stencil_attachment_clear.spec.js
+++ /dev/null
@@ -1,213 +0,0 @@
-/**
- * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
- **/ export const description =
-  'Test uninitialized textures are initialized to zero when used as a depth/stencil attachment.';
-import { makeTestGroup } from '../../../../common/framework/test_group.js';
-import { unreachable } from '../../../../common/framework/util/util.js';
-
-import {
-  ReadMethod,
-  TextureZeroInitTest,
-  initializedStateAsDepth,
-  initializedStateAsStencil,
-} from './texture_zero_init_test.js';
-
-class DepthStencilAttachmentClearTest extends TextureZeroInitTest {
-  // Construct a pipeline which will render a single triangle with depth
-  // equal to |initializeStateAsDepth(state)|. The depth compare function
-  // is set to "equal" so the fragment shader will only write 1.0 to the
-  // R8Unorm output if the depth buffer contains exactly the expected value.
-  getDepthTestReadbackPipeline(state, format, sampleCount) {
-    return this.device.createRenderPipeline({
-      vertexStage: {
-        entryPoint: 'main',
-        module: this.makeShaderModule('vertex', {
-          glsl: `#version 310 es
-          void main() {
-            const vec2 pos[3] = vec2[3](
-                vec2(-1.f, -3.f), vec2(3.f, 1.f), vec2(-1.f, 1.f));
-            gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f);
-          }
-          `,
-        }),
-      },
-
-      fragmentStage: {
-        entryPoint: 'main',
-        module: this.makeShaderModule('fragment', {
-          glsl: `#version 310 es
-          precision highp float;
-          layout(location = 0) out float outSuccess;
-
-          void main() {
-            gl_FragDepth = float(${initializedStateAsDepth(state)});
-            outSuccess = 1.0;
-          }
-          `,
-        }),
-      },
-
-      colorStates: [
-        {
-          format: 'r8unorm',
-        },
-      ],
-
-      depthStencilState: {
-        format,
-        depthCompare: 'equal',
-      },
-
-      primitiveTopology: 'triangle-list',
-      sampleCount,
-    });
-  }
-
-  // Construct a pipeline which will render a single triangle.
-  // The stencil compare function is set to "equal" so the fragment shader
-  // will only write 1.0 to the R8Unorm output if the stencil buffer contains
-  // exactly the stencil reference value.
-  getStencilTestReadbackPipeline(format, sampleCount) {
-    return this.device.createRenderPipeline({
-      vertexStage: {
-        entryPoint: 'main',
-        module: this.makeShaderModule('vertex', {
-          glsl: `#version 310 es
-          void main() {
-            const vec2 pos[3] = vec2[3](
-                vec2(-1.f, -3.f), vec2(3.f, 1.f), vec2(-1.f, 1.f));
-            gl_Position = vec4(pos[gl_VertexIndex], 0.f, 1.f);
-          }
-          `,
-        }),
-      },
-
-      fragmentStage: {
-        entryPoint: 'main',
-        module: this.makeShaderModule('fragment', {
-          glsl: `#version 310 es
-          precision highp float;
-          layout(location = 0) out float outSuccess;
-
-          void main() {
-            outSuccess = 1.0;
-          }
-          `,
-        }),
-      },
-
-      colorStates: [
-        {
-          format: 'r8unorm',
-        },
-      ],
-
-      depthStencilState: {
-        format,
-        stencilFront: {
-          compare: 'equal',
-        },
-
-        stencilBack: {
-          compare: 'equal',
-        },
-      },
-
-      primitiveTopology: 'triangle-list',
-      sampleCount,
-    });
-  }
-
-  // Check the contents by running either a depth or stencil test. The test will
-  // render 1.0 to an R8Unorm texture if the depth/stencil buffer is equal to the expected
-  // value. This is done by using a depth compare function and explicitly setting the depth
-  // value with gl_FragDepth in the shader, or by using a stencil compare function and
-  // setting the stencil reference value in the render pass.
-  checkContents(texture, state, subresourceRange) {
-    for (const viewDescriptor of this.generateTextureViewDescriptorsForRendering(
-      this.params.aspect,
-      subresourceRange
-    )) {
-      const width = this.textureWidth >> viewDescriptor.baseMipLevel;
-      const height = this.textureHeight >> viewDescriptor.baseMipLevel;
-
-      const renderTexture = this.device.createTexture({
-        size: [width, height, 1],
-        format: 'r8unorm',
-        usage: GPUTextureUsage.OUTPUT_ATTACHMENT | GPUTextureUsage.COPY_SRC,
-        sampleCount: this.params.sampleCount,
-      });
-
-      let resolveTexture = undefined;
-      let resolveTarget = undefined;
-      if (this.params.sampleCount > 1) {
-        resolveTexture = this.device.createTexture({
-          size: [width, height, 1],
-          format: 'r8unorm',
-          usage: GPUTextureUsage.OUTPUT_ATTACHMENT | GPUTextureUsage.COPY_SRC,
-        });
-
-        resolveTarget = resolveTexture.createView();
-      }
-
-      const commandEncoder = this.device.createCommandEncoder();
-      const pass = commandEncoder.beginRenderPass({
-        colorAttachments: [
-          {
-            attachment: renderTexture.createView(),
-            resolveTarget,
-            loadValue: [0, 0, 0, 0],
-            storeOp: 'store',
-          },
-        ],
-
-        depthStencilAttachment: {
-          attachment: texture.createView(viewDescriptor),
-          depthStoreOp: 'store',
-          depthLoadValue: 'load',
-          stencilStoreOp: 'store',
-          stencilLoadValue: 'load',
-        },
-      });
-
-      switch (this.params.readMethod) {
-        case ReadMethod.DepthTest:
-          pass.setPipeline(
-            this.getDepthTestReadbackPipeline(state, this.params.format, this.params.sampleCount)
-          );
-
-          break;
-
-        case ReadMethod.StencilTest:
-          pass.setPipeline(
-            this.getStencilTestReadbackPipeline(this.params.format, this.params.sampleCount)
-          );
-
-          // Set the stencil reference. The rendering pipeline uses stencil compare function "equal"
-          // so this pass will write 1.0 to the output only if the stencil buffer is equal to this
-          // reference value.
-          pass.setStencilReference(initializedStateAsStencil(state));
-          break;
-
-        default:
-          unreachable();
-      }
-
-      pass.draw(3, 1, 0, 0);
-      pass.endPass();
-
-      this.queue.submit([commandEncoder.finish()]);
-
-      this.expectSingleColor(resolveTexture || renderTexture, 'r8unorm', {
-        size: [width, height, 1],
-        exp: { R: 1 },
-      });
-    }
-  }
-}
-
-export const g = makeTestGroup(DepthStencilAttachmentClearTest);
-
-g.test('uninitialized_texture_is_zero')
-  .params(TextureZeroInitTest.generateParams([ReadMethod.DepthTest, ReadMethod.StencilTest]))
-  .fn(t => t.run());
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/sampled_texture_clear.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/sampled_texture_clear.spec.js
deleted file mode 100644
index efbf5e7..0000000
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/sampled_texture_clear.spec.js
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
- **/ export const description = 'Test uninitialized textures are initialized to zero when sampled.';
-import { makeTestGroup } from '../../../../common/framework/test_group.js';
-import { assert } from '../../../../common/framework/util/util.js';
-
-import { getTexelDataRepresentation } from '../../../util/texture/texelData.js';
-
-import {
-  ReadMethod,
-  TextureZeroInitTest,
-  initializedStateAsFloat,
-  initializedStateAsSint,
-  initializedStateAsUint,
-} from './texture_zero_init_test.js';
-
-class SampledTextureClearTest extends TextureZeroInitTest {
-  getSamplingReadbackPipeline(prefix, sampleCount, dimension) {
-    const componentOrder = getTexelDataRepresentation(this.params.format).componentOrder;
-    const MS = sampleCount > 1 ? 'MS' : '';
-    const XD = dimension.toUpperCase();
-    const componentCount = componentOrder.length;
-    const indexExpression =
-      componentCount === 1
-        ? componentOrder[0].toLowerCase()
-        : componentOrder.map(c => c.toLowerCase()).join('') + '[i]';
-
-    const glsl = `#version 310 es
-      precision highp float;
-      precision highp ${prefix}texture${XD}${MS};
-      precision highp sampler;
-
-      layout(set = 0, binding = 0, std140) uniform Constants {
-        int level;
-      };
-
-      layout(set = 0, binding = 1) uniform ${prefix}texture${XD}${MS} myTexture;
-      layout(set = 0, binding = 2) uniform sampler mySampler;
-      layout(set = 0, binding = 3, std430) writeonly buffer Result {
-        uint result[];
-      };
-
-      void writeResult(uint flatIndex, uvec4 texel) {
-        for (uint i = flatIndex; i < flatIndex + ${componentCount}u; ++i) {
-          result[i] = texel.${indexExpression};
-        }
-      }
-
-      void writeResult(uint flatIndex, ivec4 texel) {
-        for (uint i = flatIndex; i < flatIndex + ${componentCount}u; ++i) {
-          result[i] = uint(texel.${indexExpression});
-        }
-      }
-
-      void writeResult(uint flatIndex, vec4 texel) {
-        for (uint i = flatIndex; i < flatIndex + ${componentCount}u; ++i) {
-          result[i] = floatBitsToUint(texel.${indexExpression});
-        }
-      }
-
-      void main() {
-        uint flatIndex = gl_NumWorkGroups.x * gl_GlobalInvocationID.y + gl_GlobalInvocationID.x;
-        flatIndex = flatIndex * ${componentCount}u;
-
-        writeResult(flatIndex, texelFetch(
-          ${prefix}sampler${XD}${MS}(myTexture, mySampler),
-          ivec2(gl_GlobalInvocationID.xy), level));
-      }
-      `;
-
-    return this.device.createComputePipeline({
-      layout: undefined,
-      computeStage: {
-        entryPoint: 'main',
-        module: this.makeShaderModule('compute', { glsl }),
-      },
-    });
-  }
-
-  checkContents(texture, state, subresourceRange) {
-    assert(this.params.dimension === '2d');
-
-    const sampler = this.device.createSampler();
-
-    for (const { level, slices } of subresourceRange.mipLevels()) {
-      const width = this.textureWidth >> level;
-      const height = this.textureHeight >> level;
-
-      let readbackTypedArray = Float32Array;
-      let prefix = '';
-      let expectedShaderValue = initializedStateAsFloat(state);
-      if (this.params.format.indexOf('sint') !== -1) {
-        prefix = 'i';
-        expectedShaderValue = initializedStateAsSint(state);
-        readbackTypedArray = Int32Array;
-      } else if (this.params.format.indexOf('uint') !== -1) {
-        prefix = 'u';
-        expectedShaderValue = initializedStateAsUint(state);
-        readbackTypedArray = Uint32Array;
-      }
-
-      const computePipeline = this.getSamplingReadbackPipeline(
-        prefix,
-        this.params.sampleCount,
-        this.params.dimension
-      );
-
-      for (const slice of slices) {
-        const ubo = this.device.createBuffer({
-          mappedAtCreation: true,
-          size: 4,
-          usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
-        });
-
-        new Int32Array(ubo.getMappedRange(), 0, 1)[0] = level;
-        ubo.unmap();
-
-        const byteLength =
-          width *
-          height *
-          Uint32Array.BYTES_PER_ELEMENT *
-          getTexelDataRepresentation(this.params.format).componentOrder.length;
-        const resultBuffer = this.device.createBuffer({
-          size: byteLength,
-          usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
-        });
-
-        const bindGroup = this.device.createBindGroup({
-          layout: computePipeline.getBindGroupLayout(0),
-          entries: [
-            {
-              binding: 0,
-              resource: { buffer: ubo },
-            },
-
-            {
-              binding: 1,
-              resource: texture.createView({
-                baseMipLevel: 0,
-                mipLevelCount: this.params.mipLevelCount,
-                baseArrayLayer: slice,
-                arrayLayerCount: 1,
-              }),
-            },
-
-            { binding: 2, resource: sampler },
-            {
-              binding: 3,
-              resource: {
-                buffer: resultBuffer,
-              },
-            },
-          ],
-        });
-
-        const commandEncoder = this.device.createCommandEncoder();
-        const pass = commandEncoder.beginComputePass();
-        pass.setPipeline(computePipeline);
-        pass.setBindGroup(0, bindGroup);
-        pass.dispatch(width, height);
-        pass.endPass();
-        this.queue.submit([commandEncoder.finish()]);
-        ubo.destroy();
-
-        const mappedResultBuffer = this.createCopyForMapRead(resultBuffer, 0, byteLength);
-        resultBuffer.destroy();
-
-        this.eventualAsyncExpectation(async niceStack => {
-          await mappedResultBuffer.mapAsync(GPUMapMode.READ);
-          const actual = mappedResultBuffer.getMappedRange();
-          const expected = new readbackTypedArray(new ArrayBuffer(actual.byteLength));
-          expected.fill(expectedShaderValue);
-
-          // TODO: Have a better way to determine approximately equal, maybe in ULPs.
-          let tolerance;
-          if (this.params.format === 'rgb10a2unorm') {
-            tolerance = i => {
-              // The alpha component is only two bits. Use a generous tolerance.
-              return i % 4 === 3 ? 0.18 : 0.01;
-            };
-          } else {
-            tolerance = 0.01;
-          }
-
-          const check = this.checkBuffer(new readbackTypedArray(actual), expected, tolerance);
-          if (check !== undefined) {
-            niceStack.message = check;
-            this.rec.expectationFailed(niceStack);
-          }
-          mappedResultBuffer.destroy();
-        });
-      }
-    }
-  }
-}
-
-export const g = makeTestGroup(SampledTextureClearTest);
-
-g.test('uninitialized_texture_is_zero')
-  .params(TextureZeroInitTest.generateParams([ReadMethod.Sample]))
-  .fn(t => t.run());
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/texture_zero_init.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/texture_zero_init.spec.js
new file mode 100644
index 0000000..9dab156
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/texture_zero_init.spec.js
@@ -0,0 +1,558 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = 'Test uninitialized textures are initialized to zero when read.';
+import { params, poptions, pbool } from '../../../../common/framework/params_builder.js';
+
+import { makeTestGroup } from '../../../../common/framework/test_group.js';
+import { assert, unreachable } from '../../../../common/framework/util/util.js';
+import {
+  kAllTextureFormatInfo,
+  kEncodableTextureFormatInfo,
+  kTextureAspects,
+  kUncompressedTextureFormatInfo,
+  kUncompressedTextureFormats,
+} from '../../../capability_info.js';
+import { GPUConst } from '../../../constants.js';
+import { GPUTest } from '../../../gpu_test.js';
+import { createTextureUploadBuffer } from '../../../util/texture/layout.js';
+import { mipSize, SubresourceRange } from '../../../util/texture/subresource.js';
+import { getTexelDataRepresentation } from '../../../util/texture/texelData.js';
+
+export let UninitializeMethod;
+(function (UninitializeMethod) {
+  UninitializeMethod['Creation'] = 'Creation';
+  UninitializeMethod['StoreOpClear'] = 'StoreOpClear';
+})(UninitializeMethod || (UninitializeMethod = {}));
+
+const kUninitializeMethods = Object.keys(UninitializeMethod);
+
+export let ReadMethod;
+(function (ReadMethod) {
+  ReadMethod['Sample'] = 'Sample';
+  ReadMethod['CopyToBuffer'] = 'CopyToBuffer';
+  ReadMethod['CopyToTexture'] = 'CopyToTexture';
+  ReadMethod['DepthTest'] = 'DepthTest';
+  ReadMethod['StencilTest'] = 'StencilTest';
+  ReadMethod['ColorBlending'] = 'ColorBlending';
+  ReadMethod['Storage'] = 'Storage';
+})(ReadMethod || (ReadMethod = {}));
+
+const kMipLevelCounts = [1, 5];
+
+// For each mip level count, define the mip ranges to leave uninitialized.
+const kUninitializedMipRangesToTest = {
+  1: [{ begin: 0, end: 1 }], // Test the only mip
+  5: [
+    { begin: 0, end: 2 },
+    { begin: 3, end: 4 },
+  ],
+  // Test a range and a single mip
+};
+
+// Test with these sample counts.
+const kSampleCounts = [1, 4];
+
+// Test with these slice counts. This means the depth of a 3d texture or the number
+// or layers in a 2D or a 1D texture array.
+
+// For each slice count, define the slices to leave uninitialized.
+const kUninitializedSliceRangesToTest = {
+  1: [{ begin: 0, end: 1 }], // Test the only slice
+  7: [
+    { begin: 2, end: 4 },
+    { begin: 6, end: 7 },
+  ],
+  // Test a range and a single slice
+};
+
+// Test with these combinations of texture dimension and sliceCount.
+const kCreationSizes = [
+  // { dimension: '1d', sliceCount: 7 }, // TODO: 1d textures
+  { dimension: '2d', sliceCount: 1 }, // 2d textures
+  { dimension: '2d', sliceCount: 7 }, // 2d array textures
+  // { dimension: '3d', sliceCount: 7 }, // TODO: 3d textures
+];
+
+// Enums to abstract over color / depth / stencil values in textures. Depending on the texture format,
+// the data for each value may have a different representation. These enums are converted to a
+// representation such that their values can be compared. ex.) An integer is needed to upload to an
+// unsigned normalized format, but its value is read as a float in the shader.
+export let InitializedState;
+(function (InitializedState) {
+  InitializedState[(InitializedState['Canary'] = 0)] = 'Canary';
+  InitializedState[(InitializedState['Zero'] = 1)] = 'Zero';
+})(InitializedState || (InitializedState = {}));
+
+const initializedStateAsFloat = {
+  [InitializedState.Zero]: 0,
+  [InitializedState.Canary]: 1,
+};
+
+const initializedStateAsUint = {
+  [InitializedState.Zero]: 0,
+  [InitializedState.Canary]: 1,
+};
+
+const initializedStateAsSint = {
+  [InitializedState.Zero]: 0,
+  [InitializedState.Canary]: -1,
+};
+
+function initializedStateAsColor(state, format) {
+  let value;
+  if (format.indexOf('uint') !== -1) {
+    value = initializedStateAsUint[state];
+  } else if (format.indexOf('sint') !== -1) {
+    value = initializedStateAsSint[state];
+  } else {
+    value = initializedStateAsFloat[state];
+  }
+  return [value, value, value, value];
+}
+
+const initializedStateAsDepth = {
+  [InitializedState.Zero]: 0,
+  [InitializedState.Canary]: 0.8,
+};
+
+const initializedStateAsStencil = {
+  [InitializedState.Zero]: 0,
+  [InitializedState.Canary]: 42,
+};
+
+function getRequiredTextureUsage(format, sampleCount, uninitializeMethod, readMethod) {
+  let usage = GPUConst.TextureUsage.COPY_DST;
+
+  switch (uninitializeMethod) {
+    case UninitializeMethod.Creation:
+      break;
+    case UninitializeMethod.StoreOpClear:
+      usage |= GPUConst.TextureUsage.OUTPUT_ATTACHMENT;
+      break;
+    default:
+      unreachable();
+  }
+
+  switch (readMethod) {
+    case ReadMethod.CopyToBuffer:
+    case ReadMethod.CopyToTexture:
+      usage |= GPUConst.TextureUsage.COPY_SRC;
+      break;
+    case ReadMethod.Sample:
+      usage |= GPUConst.TextureUsage.SAMPLED;
+      break;
+    case ReadMethod.Storage:
+      usage |= GPUConst.TextureUsage.STORAGE;
+      break;
+    case ReadMethod.DepthTest:
+    case ReadMethod.StencilTest:
+    case ReadMethod.ColorBlending:
+      usage |= GPUConst.TextureUsage.OUTPUT_ATTACHMENT;
+      break;
+    default:
+      unreachable();
+  }
+
+  if (sampleCount > 1) {
+    // Copies to multisampled textures are not allowed. We need OutputAttachment to initialize
+    // canary data in multisampled textures.
+    usage |= GPUConst.TextureUsage.OUTPUT_ATTACHMENT;
+  }
+
+  if (!kUncompressedTextureFormatInfo[format].copyDst) {
+    // Copies are not possible. We need OutputAttachment to initialize
+    // canary data.
+    assert(kUncompressedTextureFormatInfo[format].renderable);
+    usage |= GPUConst.TextureUsage.OUTPUT_ATTACHMENT;
+  }
+
+  return usage;
+}
+
+export class TextureZeroInitTest extends GPUTest {
+  constructor(rec, params) {
+    super(rec, params);
+    this.p = params;
+
+    const stateToTexelComponents = state => {
+      const [R, G, B, A] = initializedStateAsColor(state, this.p.format);
+      return {
+        R,
+        G,
+        B,
+        A,
+        Depth: initializedStateAsDepth[state],
+        Stencil: initializedStateAsStencil[state],
+      };
+    };
+
+    this.stateToTexelComponents = {
+      [InitializedState.Zero]: stateToTexelComponents(InitializedState.Zero),
+      [InitializedState.Canary]: stateToTexelComponents(InitializedState.Canary),
+    };
+  }
+
+  get textureWidth() {
+    let width = 1 << this.p.mipLevelCount;
+    if (this.p.nonPowerOfTwo) {
+      width = 2 * width - 1;
+    }
+    return width;
+  }
+
+  get textureHeight() {
+    let height = 1 << this.p.mipLevelCount;
+    if (this.p.nonPowerOfTwo) {
+      height = 2 * height - 1;
+    }
+    return height;
+  }
+
+  // Used to iterate subresources and check that their uninitialized contents are zero when accessed
+  *iterateUninitializedSubresources() {
+    for (const mipRange of kUninitializedMipRangesToTest[this.p.mipLevelCount]) {
+      for (const sliceRange of kUninitializedSliceRangesToTest[this.p.sliceCount]) {
+        yield new SubresourceRange({ mipRange, sliceRange });
+      }
+    }
+  }
+
+  // Used to iterate and initialize other subresources not checked for zero-initialization.
+  // Zero-initialization of uninitialized subresources should not have side effects on already
+  // initialized subresources.
+  *iterateInitializedSubresources() {
+    const uninitialized = new Array(this.p.mipLevelCount);
+    for (let level = 0; level < uninitialized.length; ++level) {
+      uninitialized[level] = new Array(this.p.sliceCount);
+    }
+    for (const subresources of this.iterateUninitializedSubresources()) {
+      for (const { level, slice } of subresources.each()) {
+        uninitialized[level][slice] = true;
+      }
+    }
+    for (let level = 0; level < uninitialized.length; ++level) {
+      for (let slice = 0; slice < uninitialized[level].length; ++slice) {
+        if (!uninitialized[level][slice]) {
+          yield new SubresourceRange({
+            mipRange: { begin: level, count: 1 },
+            sliceRange: { begin: slice, count: 1 },
+          });
+        }
+      }
+    }
+  }
+
+  *generateTextureViewDescriptorsForRendering(aspect, subresourceRange) {
+    const viewDescriptor = {
+      dimension: '2d',
+      aspect,
+    };
+
+    if (subresourceRange === undefined) {
+      return viewDescriptor;
+    }
+
+    for (const { level, slice } of subresourceRange.each()) {
+      yield {
+        ...viewDescriptor,
+        baseMipLevel: level,
+        mipLevelCount: 1,
+        baseArrayLayer: slice,
+        arrayLayerCount: 1,
+      };
+    }
+  }
+
+  initializeWithStoreOp(state, texture, subresourceRange) {
+    const commandEncoder = this.device.createCommandEncoder();
+    for (const viewDescriptor of this.generateTextureViewDescriptorsForRendering(
+      this.p.aspect,
+      subresourceRange
+    )) {
+      if (kUncompressedTextureFormatInfo[this.p.format].color) {
+        commandEncoder
+          .beginRenderPass({
+            colorAttachments: [
+              {
+                attachment: texture.createView(viewDescriptor),
+                storeOp: 'store',
+                loadValue: initializedStateAsColor(state, this.p.format),
+              },
+            ],
+          })
+          .endPass();
+      } else {
+        commandEncoder
+          .beginRenderPass({
+            colorAttachments: [],
+            depthStencilAttachment: {
+              attachment: texture.createView(viewDescriptor),
+              depthStoreOp: 'store',
+              depthLoadValue: initializedStateAsDepth[state],
+              stencilStoreOp: 'store',
+              stencilLoadValue: initializedStateAsStencil[state],
+            },
+          })
+          .endPass();
+      }
+    }
+    this.queue.submit([commandEncoder.finish()]);
+  }
+
+  initializeWithCopy(texture, state, subresourceRange) {
+    assert(this.p.format in kEncodableTextureFormatInfo);
+    const format = this.p.format;
+
+    if (this.p.dimension === '1d' || this.p.dimension === '3d') {
+      // TODO: https://github.com/gpuweb/gpuweb/issues/69
+      // Copies with 1D and 3D textures are not yet specified
+      unreachable();
+    }
+
+    const firstSubresource = subresourceRange.each().next().value;
+    assert(typeof firstSubresource !== 'undefined');
+
+    const [largestWidth, largestHeight] = mipSize(
+      [this.textureWidth, this.textureHeight],
+      firstSubresource.level
+    );
+
+    const texelData = new Uint8Array(
+      getTexelDataRepresentation(format).getBytes(this.stateToTexelComponents[state])
+    );
+
+    const { buffer, bytesPerRow, rowsPerImage } = createTextureUploadBuffer(
+      texelData,
+      this.device,
+      format,
+      this.p.dimension,
+      [largestWidth, largestHeight, 1]
+    );
+
+    const commandEncoder = this.device.createCommandEncoder();
+
+    for (const { level, slice } of subresourceRange.each()) {
+      const [width, height] = mipSize([this.textureWidth, this.textureHeight], level);
+
+      commandEncoder.copyBufferToTexture(
+        {
+          buffer,
+          bytesPerRow,
+          rowsPerImage,
+        },
+
+        { texture, mipLevel: level, origin: { x: 0, y: 0, z: slice } },
+        { width, height, depth: 1 }
+      );
+    }
+    this.queue.submit([commandEncoder.finish()]);
+    buffer.destroy();
+  }
+
+  initializeTexture(texture, state, subresourceRange) {
+    if (this.p.sampleCount > 1 || !kUncompressedTextureFormatInfo[this.p.format].copyDst) {
+      // Copies to multisampled textures not yet specified.
+      // Use a storeOp for now.
+      assert(kUncompressedTextureFormatInfo[this.p.format].renderable);
+      this.initializeWithStoreOp(state, texture, subresourceRange);
+    } else {
+      this.initializeWithCopy(texture, state, subresourceRange);
+    }
+  }
+
+  discardTexture(texture, subresourceRange) {
+    const commandEncoder = this.device.createCommandEncoder();
+
+    for (const desc of this.generateTextureViewDescriptorsForRendering(
+      this.p.aspect,
+      subresourceRange
+    )) {
+      if (kUncompressedTextureFormatInfo[this.p.format].color) {
+        commandEncoder
+          .beginRenderPass({
+            colorAttachments: [
+              {
+                attachment: texture.createView(desc),
+                storeOp: 'clear',
+                loadValue: 'load',
+              },
+            ],
+          })
+          .endPass();
+      } else {
+        commandEncoder
+          .beginRenderPass({
+            colorAttachments: [],
+            depthStencilAttachment: {
+              attachment: texture.createView(desc),
+              depthStoreOp: 'clear',
+              depthLoadValue: 'load',
+              stencilStoreOp: 'clear',
+              stencilLoadValue: 'load',
+            },
+          })
+          .endPass();
+      }
+    }
+    this.queue.submit([commandEncoder.finish()]);
+  }
+}
+
+const paramsBuilder = params()
+  .combine(
+    poptions('readMethod', [
+      ReadMethod.CopyToBuffer,
+      ReadMethod.CopyToTexture,
+      ReadMethod.Sample,
+      ReadMethod.DepthTest,
+      ReadMethod.StencilTest,
+    ])
+  )
+  .combine(poptions('format', kUncompressedTextureFormats))
+  .combine(poptions('aspect', kTextureAspects))
+  .unless(({ readMethod, format, aspect }) => {
+    const info = kUncompressedTextureFormatInfo[format];
+    // console.log(readMethod, format, aspect, info.depth, info.stencil);
+    return (
+      (readMethod === ReadMethod.DepthTest && (!info.depth || aspect === 'stencil-only')) ||
+      (readMethod === ReadMethod.StencilTest && (!info.stencil || aspect === 'depth-only')) ||
+      (readMethod === ReadMethod.ColorBlending && !info.color) ||
+      // TODO: Test with depth/stencil sampling
+      (readMethod === ReadMethod.Sample && (info.depth || info.stencil)) ||
+      (aspect === 'depth-only' && !info.depth) ||
+      (aspect === 'stencil-only' && !info.stencil) ||
+      (aspect === 'all' && info.depth && info.stencil) ||
+      // Cannot copy from a packed depth format.
+      // TODO: Test copying out of the stencil aspect.
+      ((readMethod === ReadMethod.CopyToBuffer || readMethod === ReadMethod.CopyToTexture) &&
+        (format === 'depth24plus' || format === 'depth24plus-stencil8'))
+    );
+  })
+  .combine(poptions('mipLevelCount', kMipLevelCounts))
+  .combine(poptions('sampleCount', kSampleCounts))
+  .unless(
+    ({ readMethod, sampleCount }) =>
+      // We can only read from multisampled textures by sampling.
+      sampleCount > 1 &&
+      (readMethod === ReadMethod.CopyToBuffer || readMethod === ReadMethod.CopyToTexture)
+  )
+
+  // Multisampled textures may only have one mip
+  .unless(({ sampleCount, mipLevelCount }) => sampleCount > 1 && mipLevelCount > 1)
+  .combine(poptions('uninitializeMethod', kUninitializeMethods))
+  .combine(kCreationSizes)
+  // Multisampled 3D / 2D array textures not supported.
+  .unless(({ sampleCount, sliceCount }) => sampleCount > 1 && sliceCount > 1)
+  .unless(({ format, sampleCount, uninitializeMethod, readMethod }) => {
+    const usage = getRequiredTextureUsage(format, sampleCount, uninitializeMethod, readMethod);
+    const info = kUncompressedTextureFormatInfo[format];
+
+    return (
+      ((usage & GPUConst.TextureUsage.OUTPUT_ATTACHMENT) !== 0 && !info.renderable) ||
+      ((usage & GPUConst.TextureUsage.STORAGE) !== 0 && !info.storage)
+    );
+  })
+  .combine(pbool('nonPowerOfTwo'))
+  .combine(pbool('canaryOnCreation'))
+  .filter(({ canaryOnCreation, format }) => {
+    // We can only initialize the texture if it's encodable or renderable.
+    const canInitialize =
+      format in kEncodableTextureFormatInfo || kAllTextureFormatInfo[format].renderable;
+
+    // Filter out cases where we want canary values but can't initialize.
+    return !canaryOnCreation || canInitialize;
+  });
+
+import { checkContentsByBufferCopy, checkContentsByTextureCopy } from './check_texture/by_copy.js';
+import {
+  checkContentsByDepthTest,
+  checkContentsByStencilTest,
+} from './check_texture/by_ds_test.js';
+import { checkContentsBySampling } from './check_texture/by_sampling.js';
+
+const checkContentsImpl = {
+  Sample: checkContentsBySampling,
+  CopyToBuffer: checkContentsByBufferCopy,
+  CopyToTexture: checkContentsByTextureCopy,
+  DepthTest: checkContentsByDepthTest,
+  StencilTest: checkContentsByStencilTest,
+  ColorBlending: t => t.skip('Not implemented'),
+  Storage: t => t.skip('Not implemented'),
+};
+
+export const g = makeTestGroup(TextureZeroInitTest);
+
+g.test('uninitialized_texture_is_zero')
+  .params(paramsBuilder)
+  .fn(async t => {
+    const extension = kUncompressedTextureFormatInfo[t.params.format].extension;
+    if (extension !== undefined) {
+      await t.selectDeviceOrSkipTestCase({
+        extensions: [extension],
+      });
+    }
+
+    const usage = getRequiredTextureUsage(
+      t.params.format,
+      t.params.sampleCount,
+      t.params.uninitializeMethod,
+      t.params.readMethod
+    );
+
+    const texture = t.device.createTexture({
+      size: [t.textureWidth, t.textureHeight, t.params.sliceCount],
+      format: t.params.format,
+      dimension: t.params.dimension,
+      usage,
+      mipLevelCount: t.params.mipLevelCount,
+      sampleCount: t.params.sampleCount,
+    });
+
+    if (t.params.canaryOnCreation) {
+      // Initialize some subresources with canary values
+      for (const subresourceRange of t.iterateInitializedSubresources()) {
+        t.initializeTexture(texture, InitializedState.Canary, subresourceRange);
+      }
+    }
+
+    switch (t.params.uninitializeMethod) {
+      case UninitializeMethod.Creation:
+        break;
+      case UninitializeMethod.StoreOpClear:
+        // Initialize the rest of the resources.
+        for (const subresourceRange of t.iterateUninitializedSubresources()) {
+          t.initializeTexture(texture, InitializedState.Canary, subresourceRange);
+        }
+        // Then use a store op to discard their contents.
+        for (const subresourceRange of t.iterateUninitializedSubresources()) {
+          t.discardTexture(texture, subresourceRange);
+        }
+        break;
+      default:
+        unreachable();
+    }
+
+    // Check that all uninitialized resources are zero.
+    for (const subresourceRange of t.iterateUninitializedSubresources()) {
+      checkContentsImpl[t.params.readMethod](
+        t,
+        t.params,
+        texture,
+        InitializedState.Zero,
+        subresourceRange
+      );
+    }
+
+    if (t.params.canaryOnCreation) {
+      // Check the all other resources are unchanged.
+      for (const subresourceRange of t.iterateInitializedSubresources()) {
+        checkContentsImpl[t.params.readMethod](
+          t,
+          t.params,
+          texture,
+          InitializedState.Canary,
+          subresourceRange
+        );
+      }
+    }
+  });
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/texture_zero_init_test.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/texture_zero_init_test.js
deleted file mode 100644
index f734073..0000000
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/operation/resource_init/texture_zero_init_test.js
+++ /dev/null
@@ -1,550 +0,0 @@
-/**
- * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
- **/ import { params, poptions, pbool } from '../../../../common/framework/params_builder.js';
-import { assert, unreachable } from '../../../../common/framework/util/util.js';
-import {
-  kTextureAspects,
-  kUncompressedTextureFormatInfo,
-  kUncompressedTextureFormats,
-} from '../../../capability_info.js';
-import { GPUConst } from '../../../constants.js';
-import { GPUTest } from '../../../gpu_test.js';
-import { createTextureUploadBuffer } from '../../../util/texture/layout.js';
-import { SubresourceRange } from '../../../util/texture/subresource.js';
-import { getTexelDataRepresentation } from '../../../util/texture/texelData.js';
-var UninitializeMethod;
-(function (UninitializeMethod) {
-  UninitializeMethod['Creation'] = 'Creation';
-  UninitializeMethod['StoreOpClear'] = 'StoreOpClear';
-})(UninitializeMethod || (UninitializeMethod = {}));
-
-const kUninitializeMethods = Object.keys(UninitializeMethod);
-
-export let ReadMethod;
-(function (ReadMethod) {
-  ReadMethod['Sample'] = 'Sample';
-  ReadMethod['CopyToBuffer'] = 'CopyToBuffer';
-  ReadMethod['CopyToTexture'] = 'CopyToTexture';
-  ReadMethod['DepthTest'] = 'DepthTest';
-  ReadMethod['StencilTest'] = 'StencilTest';
-  ReadMethod['ColorBlending'] = 'ColorBlending';
-  ReadMethod['Storage'] = 'Storage';
-})(ReadMethod || (ReadMethod = {}));
-
-const kMipLevelCounts = [1, 5];
-
-// For each mip level count, define the mip ranges to leave uninitialized.
-const kUninitializedMipRangesToTest = {
-  1: [{ begin: 0, end: 1 }], // Test the only mip
-  5: [
-    { begin: 0, end: 2 },
-    { begin: 3, end: 4 },
-  ],
-  // Test a range and a single mip
-};
-
-// Test with these sample counts.
-
-const kSampleCounts = [1, 4];
-
-// Test with these slice counts. This means the depth of a 3d texture or the number
-// or layers in a 2D or a 1D texture array.
-
-// For each slice count, define the slices to leave uninitialized.
-const kUninitializedSliceRangesToTest = {
-  1: [{ begin: 0, end: 1 }], // Test the only slice
-  7: [
-    { begin: 2, end: 4 },
-    { begin: 6, end: 7 },
-  ],
-  // Test a range and a single slice
-};
-
-// Test with these combinations of texture dimension and sliceCount.
-const kCreationSizes = [
-  // { dimension: '1d', sliceCount: 7 }, // TODO: 1d textures
-  { dimension: '2d', sliceCount: 1 }, // 2d textures
-  { dimension: '2d', sliceCount: 7 }, // 2d array textures
-  // { dimension: '3d', sliceCount: 7 }, // TODO: 3d textures
-];
-
-// Enums to abstract over color / depth / stencil values in textures. Depending on the texture format,
-// the data for each value may have a different representation. These enums are converted to a
-// representation such that their values can be compared. ex.) An integer is needed to upload to an
-// unsigned normalized format, but its value is read as a float in the shader.
-export let InitializedState;
-(function (InitializedState) {
-  InitializedState[(InitializedState['Canary'] = 0)] = 'Canary';
-  InitializedState[(InitializedState['Zero'] = 1)] = 'Zero';
-})(InitializedState || (InitializedState = {}));
-
-export function initializedStateAsFloat(state) {
-  switch (state) {
-    case InitializedState.Zero:
-      return 0;
-    case InitializedState.Canary:
-      return 1;
-    default:
-      unreachable();
-  }
-}
-
-export function initializedStateAsUint(state) {
-  switch (state) {
-    case InitializedState.Zero:
-      return 0;
-    case InitializedState.Canary:
-      return 255;
-    default:
-      unreachable();
-  }
-}
-
-export function initializedStateAsSint(state) {
-  switch (state) {
-    case InitializedState.Zero:
-      return 0;
-    case InitializedState.Canary:
-      return -1;
-    default:
-      unreachable();
-  }
-}
-
-export function initializedStateAsColor(state, format) {
-  let value;
-  if (format.indexOf('uint') !== -1) {
-    value = initializedStateAsUint(state);
-  } else if (format.indexOf('sint') !== -1) {
-    value = initializedStateAsSint(state);
-  } else {
-    value = initializedStateAsFloat(state);
-  }
-  return [value, value, value, value];
-}
-
-export function initializedStateAsDepth(state) {
-  switch (state) {
-    case InitializedState.Zero:
-      return 0;
-    case InitializedState.Canary:
-      return 1;
-    default:
-      unreachable();
-  }
-}
-
-export function initializedStateAsStencil(state) {
-  switch (state) {
-    case InitializedState.Zero:
-      return 0;
-    case InitializedState.Canary:
-      return 42;
-    default:
-      unreachable();
-  }
-}
-
-function getRequiredTextureUsage(format, sampleCount, uninitializeMethod, readMethod) {
-  let usage = GPUConst.TextureUsage.COPY_DST;
-
-  switch (uninitializeMethod) {
-    case UninitializeMethod.Creation:
-      break;
-    case UninitializeMethod.StoreOpClear:
-      usage |= GPUConst.TextureUsage.OUTPUT_ATTACHMENT;
-      break;
-    default:
-      unreachable();
-  }
-
-  switch (readMethod) {
-    case ReadMethod.CopyToBuffer:
-    case ReadMethod.CopyToTexture:
-      usage |= GPUConst.TextureUsage.COPY_SRC;
-      break;
-    case ReadMethod.Sample:
-      usage |= GPUConst.TextureUsage.SAMPLED;
-      break;
-    case ReadMethod.Storage:
-      usage |= GPUConst.TextureUsage.STORAGE;
-      break;
-    case ReadMethod.DepthTest:
-    case ReadMethod.StencilTest:
-    case ReadMethod.ColorBlending:
-      usage |= GPUConst.TextureUsage.OUTPUT_ATTACHMENT;
-      break;
-    default:
-      unreachable();
-  }
-
-  if (sampleCount > 1) {
-    // Copies to multisampled textures are not allowed. We need OutputAttachment to initialize
-    // canary data in multisampled textures.
-    usage |= GPUConst.TextureUsage.OUTPUT_ATTACHMENT;
-  }
-
-  if (!kUncompressedTextureFormatInfo[format].copyDst) {
-    // Copies are not possible. We need OutputAttachment to initialize
-    // canary data.
-    assert(kUncompressedTextureFormatInfo[format].renderable);
-    usage |= GPUConst.TextureUsage.OUTPUT_ATTACHMENT;
-  }
-
-  return usage;
-}
-
-export class TextureZeroInitTest extends GPUTest {
-  constructor(rec, params) {
-    super(rec, params);
-
-    const stateToTexelComponents = state => {
-      const [R, G, B, A] = initializedStateAsColor(state, this.params.format);
-      return {
-        R,
-        G,
-        B,
-        A,
-        Depth: initializedStateAsDepth(state),
-        Stencil: initializedStateAsStencil(state),
-      };
-    };
-
-    this.stateToTexelComponents = {
-      [InitializedState.Zero]: stateToTexelComponents(InitializedState.Zero),
-      [InitializedState.Canary]: stateToTexelComponents(InitializedState.Canary),
-    };
-  }
-
-  get params() {
-    return super.params;
-  }
-
-  get textureWidth() {
-    let width = 1 << this.params.mipLevelCount;
-    if (this.params.nonPowerOfTwo) {
-      width = 2 * width - 1;
-    }
-    return width;
-  }
-
-  get textureHeight() {
-    let height = 1 << this.params.mipLevelCount;
-    if (this.params.nonPowerOfTwo) {
-      height = 2 * height - 1;
-    }
-    return height;
-  }
-
-  // Used to iterate subresources and check that their uninitialized contents are zero when accessed
-  *iterateUninitializedSubresources() {
-    for (const mipRange of kUninitializedMipRangesToTest[this.params.mipLevelCount]) {
-      for (const sliceRange of kUninitializedSliceRangesToTest[this.params.sliceCount]) {
-        yield new SubresourceRange({ mipRange, sliceRange });
-      }
-    }
-  }
-
-  // Used to iterate and initialize other subresources not checked for zero-initialization.
-  // Zero-initialization of uninitialized subresources should not have side effects on already
-  // initialized subresources.
-  *iterateInitializedSubresources() {
-    const uninitialized = new Array(this.params.mipLevelCount);
-    for (let level = 0; level < uninitialized.length; ++level) {
-      uninitialized[level] = new Array(this.params.sliceCount);
-    }
-    for (const subresources of this.iterateUninitializedSubresources()) {
-      for (const { level, slice } of subresources.each()) {
-        uninitialized[level][slice] = true;
-      }
-    }
-    for (let level = 0; level < uninitialized.length; ++level) {
-      for (let slice = 0; slice < uninitialized[level].length; ++slice) {
-        if (!uninitialized[level][slice]) {
-          yield new SubresourceRange({
-            mipRange: { begin: level, count: 1 },
-            sliceRange: { begin: slice, count: 1 },
-          });
-        }
-      }
-    }
-  }
-
-  *generateTextureViewDescriptorsForRendering(aspect, subresourceRange) {
-    const viewDescriptor = {
-      dimension: '2d',
-      aspect,
-    };
-
-    if (subresourceRange === undefined) {
-      return viewDescriptor;
-    }
-
-    for (const { level, slice } of subresourceRange.each()) {
-      yield {
-        ...viewDescriptor,
-        baseMipLevel: level,
-        mipLevelCount: 1,
-        baseArrayLayer: slice,
-        arrayLayerCount: 1,
-      };
-    }
-  }
-
-  initializeWithStoreOp(state, texture, subresourceRange) {
-    const commandEncoder = this.device.createCommandEncoder();
-    for (const viewDescriptor of this.generateTextureViewDescriptorsForRendering(
-      this.params.aspect,
-      subresourceRange
-    )) {
-      if (kUncompressedTextureFormatInfo[this.params.format].color) {
-        commandEncoder
-          .beginRenderPass({
-            colorAttachments: [
-              {
-                attachment: texture.createView(viewDescriptor),
-                storeOp: 'store',
-                loadValue: initializedStateAsColor(state, this.params.format),
-              },
-            ],
-          })
-          .endPass();
-      } else {
-        commandEncoder
-          .beginRenderPass({
-            colorAttachments: [],
-            depthStencilAttachment: {
-              attachment: texture.createView(viewDescriptor),
-              depthStoreOp: 'store',
-              depthLoadValue: initializedStateAsDepth(state),
-              stencilStoreOp: 'store',
-              stencilLoadValue: initializedStateAsStencil(state),
-            },
-          })
-          .endPass();
-      }
-    }
-    this.queue.submit([commandEncoder.finish()]);
-  }
-
-  initializeWithCopy(texture, state, subresourceRange) {
-    if (this.params.dimension === '1d' || this.params.dimension === '3d') {
-      // TODO: https://github.com/gpuweb/gpuweb/issues/69
-      // Copies with 1D and 3D textures are not yet specified
-      unreachable();
-    }
-
-    const firstSubresource = subresourceRange.each().next().value;
-    assert(typeof firstSubresource !== 'undefined');
-
-    const largestWidth = this.textureWidth >> firstSubresource.level;
-    const largestHeight = this.textureHeight >> firstSubresource.level;
-
-    const texelData = new Uint8Array(
-      getTexelDataRepresentation(this.params.format).getBytes(this.stateToTexelComponents[state])
-    );
-
-    const { buffer, bytesPerRow, rowsPerImage } = createTextureUploadBuffer(
-      texelData,
-      this.device,
-      this.params.format,
-      this.params.dimension,
-      [largestWidth, largestHeight, 1]
-    );
-
-    const commandEncoder = this.device.createCommandEncoder();
-
-    for (const { level, slice } of subresourceRange.each()) {
-      const width = this.textureWidth >> level;
-      const height = this.textureHeight >> level;
-
-      commandEncoder.copyBufferToTexture(
-        {
-          buffer,
-          bytesPerRow,
-          rowsPerImage,
-        },
-
-        { texture, mipLevel: level, origin: { x: 0, y: 0, z: slice } },
-        { width, height, depth: 1 }
-      );
-    }
-    this.queue.submit([commandEncoder.finish()]);
-    buffer.destroy();
-  }
-
-  initializeTexture(texture, state, subresourceRange) {
-    if (
-      this.params.sampleCount > 1 ||
-      !kUncompressedTextureFormatInfo[this.params.format].copyDst
-    ) {
-      // Copies to multisampled textures not yet specified.
-      // Use a storeOp for now.
-      assert(kUncompressedTextureFormatInfo[this.params.format].renderable);
-      this.initializeWithStoreOp(state, texture, subresourceRange);
-    } else {
-      this.initializeWithCopy(texture, state, subresourceRange);
-    }
-  }
-
-  discardTexture(texture, subresourceRange) {
-    const commandEncoder = this.device.createCommandEncoder();
-
-    for (const desc of this.generateTextureViewDescriptorsForRendering(
-      this.params.aspect,
-      subresourceRange
-    )) {
-      if (kUncompressedTextureFormatInfo[this.params.format].color) {
-        commandEncoder
-          .beginRenderPass({
-            colorAttachments: [
-              {
-                attachment: texture.createView(desc),
-                storeOp: 'clear',
-                loadValue: 'load',
-              },
-            ],
-          })
-          .endPass();
-      } else {
-        commandEncoder
-          .beginRenderPass({
-            colorAttachments: [],
-            depthStencilAttachment: {
-              attachment: texture.createView(desc),
-              depthStoreOp: 'clear',
-              depthLoadValue: 'load',
-              stencilStoreOp: 'clear',
-              stencilLoadValue: 'load',
-            },
-          })
-          .endPass();
-      }
-    }
-    this.queue.submit([commandEncoder.finish()]);
-  }
-
-  static generateParams(readMethods) {
-    return (
-      // TODO: Consider making a list of "valid" texture descriptors in capability_info.
-      params()
-        .combine(poptions('format', kUncompressedTextureFormats))
-        .combine(poptions('aspect', kTextureAspects))
-        .unless(
-          ({ format, aspect }) =>
-            (aspect === 'depth-only' && !kUncompressedTextureFormatInfo[format].depth) ||
-            (aspect === 'stencil-only' && !kUncompressedTextureFormatInfo[format].stencil)
-        )
-        .combine(poptions('mipLevelCount', kMipLevelCounts))
-        .combine(poptions('sampleCount', kSampleCounts))
-        // Multisampled textures may only have one mip
-        .unless(({ sampleCount, mipLevelCount }) => sampleCount > 1 && mipLevelCount > 1)
-        .combine(poptions('uninitializeMethod', kUninitializeMethods))
-        .combine(poptions('readMethod', readMethods))
-        .unless(
-          ({ readMethod, format }) =>
-            // It doesn't make sense to copy from a packed depth format.
-            // This is not specified yet, but it will probably be disallowed as the bits may
-            // be vendor-specific.
-            // TODO: Test copying out of the stencil aspect.
-            (readMethod === ReadMethod.CopyToBuffer || readMethod === ReadMethod.CopyToTexture) &&
-            (format === 'depth24plus' || format === 'depth24plus-stencil8')
-        )
-        .unless(({ readMethod, format }) => {
-          const info = kUncompressedTextureFormatInfo[format];
-          return (
-            (readMethod === ReadMethod.DepthTest && !info.depth) ||
-            (readMethod === ReadMethod.StencilTest && !info.stencil) ||
-            (readMethod === ReadMethod.ColorBlending && !info.color) ||
-            // TODO: Test with depth sampling
-            (readMethod === ReadMethod.Sample && info.depth)
-          );
-        })
-        .unless(
-          ({ readMethod, sampleCount }) =>
-            // We can only read from multisampled textures by sampling.
-            sampleCount > 1 &&
-            (readMethod === ReadMethod.CopyToBuffer || readMethod === ReadMethod.CopyToTexture)
-        )
-        .combine(kCreationSizes)
-        // Multisampled 3D / 2D array textures not supported.
-        .unless(({ sampleCount, sliceCount }) => sampleCount > 1 && sliceCount > 1)
-        .filter(({ format, sampleCount, uninitializeMethod, readMethod }) => {
-          const usage = getRequiredTextureUsage(
-            format,
-            sampleCount,
-            uninitializeMethod,
-            readMethod
-          );
-
-          const info = kUncompressedTextureFormatInfo[format];
-
-          if (usage & GPUConst.TextureUsage.OUTPUT_ATTACHMENT && !info.renderable) {
-            return false;
-          }
-
-          if (usage & GPUConst.TextureUsage.STORAGE && !info.storage) {
-            return false;
-          }
-
-          return true;
-        })
-        .combine(pbool('nonPowerOfTwo'))
-    );
-  }
-
-  run() {
-    const {
-      format,
-      dimension,
-      mipLevelCount,
-      sliceCount,
-      sampleCount,
-      uninitializeMethod,
-      readMethod,
-    } = this.params;
-
-    const usage = getRequiredTextureUsage(format, sampleCount, uninitializeMethod, readMethod);
-
-    const texture = this.device.createTexture({
-      size: [this.textureWidth, this.textureHeight, sliceCount],
-      format,
-      dimension,
-      usage,
-      mipLevelCount,
-      sampleCount,
-    });
-
-    // Initialize some subresources with canary values
-    for (const subresourceRange of this.iterateInitializedSubresources()) {
-      this.initializeTexture(texture, InitializedState.Canary, subresourceRange);
-    }
-
-    switch (uninitializeMethod) {
-      case UninitializeMethod.Creation:
-        break;
-      case UninitializeMethod.StoreOpClear:
-        // Initialize the rest of the resources.
-        for (const subresourceRange of this.iterateUninitializedSubresources()) {
-          this.initializeTexture(texture, InitializedState.Canary, subresourceRange);
-        }
-        // Then use a store op to discard their contents.
-        for (const subresourceRange of this.iterateUninitializedSubresources()) {
-          this.discardTexture(texture, subresourceRange);
-        }
-        break;
-      default:
-        unreachable();
-    }
-
-    // Check that all uninitialized resources are zero.
-    for (const subresourceRange of this.iterateUninitializedSubresources()) {
-      this.checkContents(texture, InitializedState.Zero, subresourceRange);
-    }
-
-    // Check the all other resources are unchanged.
-    for (const subresourceRange of this.iterateInitializedSubresources()) {
-      this.checkContents(texture, InitializedState.Canary, subresourceRange);
-    }
-  }
-}
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer/create.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer/create.spec.js
new file mode 100644
index 0000000..8954fca2d
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer/create.spec.js
@@ -0,0 +1,43 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Tests for validation in createBuffer.
+`;
+import { params, pbool, poptions } from '../../../../common/framework/params_builder.js';
+import { makeTestGroup } from '../../../../common/framework/test_group.js';
+import { assert } from '../../../../common/framework/util/util.js';
+import { kBufferSizeAlignment } from '../../../capability_info.js';
+import { ValidationTest } from '../validation_test.js';
+
+export const g = makeTestGroup(ValidationTest);
+
+assert(kBufferSizeAlignment === 4);
+g.test('size')
+  .desc('Test buffer size alignment.')
+  .params(
+    params()
+      .combine(pbool('mappedAtCreation'))
+      .combine(
+        poptions('size', [
+          0,
+          kBufferSizeAlignment * 0.5,
+          kBufferSizeAlignment,
+          kBufferSizeAlignment * 1.5,
+          kBufferSizeAlignment * 2,
+        ])
+      )
+  )
+  .unimplemented();
+
+g.test('usage')
+  .desc('Test combinations of (one to two?) usage flags.')
+  .params(
+    params() //
+      .combine(pbool('mappedAtCreation'))
+      .combine(
+        poptions('usage', [
+          // TODO
+        ])
+      )
+  )
+  .unimplemented();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer/destroy.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer/destroy.spec.js
new file mode 100644
index 0000000..9da3682
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer/destroy.spec.js
@@ -0,0 +1,29 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Destroying a buffer more than once is allowed.
+`;
+import { params, pbool } from '../../../../common/framework/params_builder.js';
+import { makeTestGroup } from '../../../../common/framework/test_group.js';
+import { GPUConst } from '../../../constants.js';
+import { ValidationTest } from '../validation_test.js';
+
+export const g = makeTestGroup(ValidationTest);
+
+g.test('twice')
+  .desc('Tests various mapping-related descripton options that could affect how state is tracked.')
+  .params(
+    params()
+      .combine(pbool('mappedAtCreation'))
+      .combine([
+        { size: 4, usage: GPUConst.BufferUsage.COPY_SRC },
+        { size: 4, usage: GPUConst.BufferUsage.MAP_WRITE | GPUConst.BufferUsage.COPY_SRC },
+        { size: 4, usage: GPUConst.BufferUsage.COPY_DST | GPUConst.BufferUsage.MAP_READ },
+      ])
+  )
+  .fn(async t => {
+    const buf = t.device.createBuffer(t.params);
+
+    buf.destroy();
+    buf.destroy();
+  });
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer_mapping.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer/mapping.spec.js
similarity index 98%
rename from third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer_mapping.spec.js
rename to third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer/mapping.spec.js
index b59f4f8..5316fa9 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer_mapping.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/buffer/mapping.spec.js
@@ -3,13 +3,12 @@
  **/ export const description = `
 Validation tests for GPUBuffer.mapAsync, GPUBuffer.unmap and GPUBuffer.getMappedRange.
 `;
-import { pbool, poptions, params } from '../../../common/framework/params_builder.js';
-import { makeTestGroup } from '../../../common/framework/test_group.js';
-import { unreachable } from '../../../common/framework/util/util.js';
-import { kBufferUsages } from '../../capability_info.js';
-import { GPUConst } from '../../constants.js';
-
-import { ValidationTest } from './validation_test.js';
+import { pbool, poptions, params } from '../../../../common/framework/params_builder.js';
+import { makeTestGroup } from '../../../../common/framework/test_group.js';
+import { unreachable } from '../../../../common/framework/util/util.js';
+import { kBufferUsages } from '../../../capability_info.js';
+import { GPUConst } from '../../../constants.js';
+import { ValidationTest } from '../validation_test.js';
 
 class F extends ValidationTest {
   async testMapAsyncCall(success, rejectName, buffer, mode, offset, size) {
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/encoding/cmds/dynamic_render_state.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/encoding/cmds/dynamic_render_state.spec.js
new file mode 100644
index 0000000..27e28b3
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/encoding/cmds/dynamic_render_state.spec.js
@@ -0,0 +1,274 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+API validation tests for dynamic state commands (setViewport/ScissorRect/BlendColor...).
+`;
+import { params } from '../../../../../common/framework/params_builder.js';
+import { makeTestGroup } from '../../../../../common/framework/test_group.js';
+import { ValidationTest } from '../../validation_test.js';
+
+class F extends ValidationTest {
+  testViewportCall(success, v, attachmentSize = { width: 1, height: 1, depth: 1 }) {
+    const attachment = this.device.createTexture({
+      format: 'rgba8unorm',
+      size: attachmentSize,
+      usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
+    });
+
+    const encoder = this.device.createCommandEncoder();
+    const pass = encoder.beginRenderPass({
+      colorAttachments: [
+        {
+          attachment: attachment.createView(),
+          loadValue: 'load',
+        },
+      ],
+    });
+
+    pass.setViewport(v.x, v.y, v.w, v.h, v.minDepth, v.maxDepth);
+    pass.endPass();
+
+    this.expectValidationError(() => {
+      encoder.finish();
+    }, !success);
+  }
+
+  testScissorCall(success, s, attachmentSize = { width: 1, height: 1, depth: 1 }) {
+    const attachment = this.device.createTexture({
+      format: 'rgba8unorm',
+      size: attachmentSize,
+      usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
+    });
+
+    const encoder = this.device.createCommandEncoder();
+    const pass = encoder.beginRenderPass({
+      colorAttachments: [
+        {
+          attachment: attachment.createView(),
+          loadValue: 'load',
+        },
+      ],
+    });
+
+    if (success === 'type-error') {
+      this.shouldThrow('TypeError', () => {
+        pass.setScissorRect(s.x, s.y, s.w, s.h);
+      });
+    } else {
+      pass.setScissorRect(s.x, s.y, s.w, s.h);
+      pass.endPass();
+
+      this.expectValidationError(() => {
+        encoder.finish();
+      }, !success);
+    }
+  }
+
+  createDummyRenderPassEncoder() {
+    const attachment = this.device.createTexture({
+      format: 'rgba8unorm',
+      size: [1, 1, 1],
+      usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
+    });
+
+    const encoder = this.device.createCommandEncoder();
+    const pass = encoder.beginRenderPass({
+      colorAttachments: [
+        {
+          attachment: attachment.createView(),
+          loadValue: 'load',
+        },
+      ],
+    });
+
+    return { encoder, pass };
+  }
+}
+
+export const g = makeTestGroup(F);
+
+g.test('setViewport,x_y_width_height_nonnegative')
+  .desc('Test that the parameters of setViewport to define the box must be non-negative.')
+  .params([
+    // Control case: everything to 0 is ok, covers the empty viewport case.
+    { x: 0, y: 0, w: 0, h: 0 },
+
+    // Test -1
+    { x: -1, y: 0, w: 0, h: 0 },
+    { x: 0, y: -1, w: 0, h: 0 },
+    { x: 0, y: 0, w: -1, h: 0 },
+    { x: 0, y: 0, w: 0, h: -1 },
+
+    // TODO Test -0 (it should be valid) but can't be tested because the harness complains about duplicate parameters.
+    // TODO Test the first value smaller than -0
+  ])
+  .fn(t => {
+    const { x, y, w, h } = t.params;
+    const success = x >= 0 && y >= 0 && w >= 0 && h >= 0;
+    t.testViewportCall(success, { x, y, w, h, minDepth: 0, maxDepth: 1 });
+  });
+
+g.test('setViewport,xy_rect_contained_in_attachment')
+  .desc(
+    'Test that the rectangle defined by x, y, width, height must be contained in the attachments'
+  )
+  .params(
+    params()
+      .combine([
+        { attachmentWidth: 3, attachmentHeight: 5 },
+        { attachmentWidth: 5, attachmentHeight: 3 },
+        { attachmentWidth: 1024, attachmentHeight: 1 },
+        { attachmentWidth: 1, attachmentHeight: 1024 },
+      ])
+      .combine([
+        // Control case: a full viewport is valid.
+        { dx: 0, dy: 0, dw: 0, dh: 0 },
+
+        // Other valid cases with a partial viewport.
+        { dx: 1, dy: 0, dw: -1, dh: 0 },
+        { dx: 0, dy: 1, dw: 0, dh: -1 },
+        { dx: 0, dy: 0, dw: -1, dh: 0 },
+        { dx: 0, dy: 0, dw: 0, dh: -1 },
+
+        // Test with a small value that causes the viewport to go outside the attachment.
+        { dx: 1, dy: 0, dw: 0, dh: 0 },
+        { dx: 0, dy: 1, dw: 0, dh: 0 },
+        { dx: 0, dy: 0, dw: 1, dh: 0 },
+        { dx: 0, dy: 0, dw: 0, dh: 1 },
+      ])
+  )
+  .fn(t => {
+    const { attachmentWidth, attachmentHeight, dx, dy, dw, dh } = t.params;
+    const x = dx;
+    const y = dy;
+    const w = attachmentWidth + dw;
+    const h = attachmentWidth + dh;
+
+    const success = x + w <= attachmentWidth && y + h <= attachmentHeight;
+    t.testViewportCall(
+      success,
+      { x, y, w, h, minDepth: 0, maxDepth: 1 },
+      { width: attachmentWidth, height: attachmentHeight, depth: 1 }
+    );
+  });
+
+g.test('setViewport,depth_rangeAndOrder')
+  .desc('Test that 0 <= minDepth <= maxDepth <= 1')
+  .params([
+    // Success cases
+    { minDepth: 0, maxDepth: 1 },
+    { minDepth: -0, maxDepth: -0 },
+    { minDepth: 1, maxDepth: 1 },
+    { minDepth: 0.3, maxDepth: 0.7 },
+    { minDepth: 0.7, maxDepth: 0.7 },
+    { minDepth: 0.3, maxDepth: 0.3 },
+
+    // Invalid cases
+    { minDepth: -0.1, maxDepth: 1 },
+    { minDepth: 0, maxDepth: 1.1 },
+    { minDepth: 0.5, maxDepth: 0.49999 },
+  ])
+  .fn(t => {
+    const { minDepth, maxDepth } = t.params;
+    const success =
+      0 <= minDepth && minDepth <= 1 && 0 <= maxDepth && maxDepth <= 1 && minDepth <= maxDepth;
+    t.testViewportCall(success, { x: 0, y: 0, w: 1, h: 1, minDepth, maxDepth });
+  });
+
+g.test('setScissorRect,x_y_width_height_nonnegative')
+  .desc(
+    'Test that the parameters of setScissorRect to define the box must be non-negative or a TypeError is thrown.'
+  )
+  .params([
+    // Control case: everything to 0 is ok, covers the empty scissor case.
+    { x: 0, y: 0, w: 0, h: 0 },
+
+    // Test -1
+    { x: -1, y: 0, w: 0, h: 0 },
+    { x: 0, y: -1, w: 0, h: 0 },
+    { x: 0, y: 0, w: -1, h: 0 },
+    { x: 0, y: 0, w: 0, h: -1 },
+
+    // TODO Test -0 (it should be valid) but can't be tested because the harness complains about duplicate parameters.
+    // TODO Test the first value smaller than -0
+  ])
+  .fn(t => {
+    const { x, y, w, h } = t.params;
+    const success = x >= 0 && y >= 0 && w >= 0 && h >= 0;
+    t.testScissorCall(success ? true : 'type-error', { x, y, w, h });
+  });
+
+g.test('setScissorRect,xy_rect_contained_in_attachment')
+  .desc(
+    'Test that the rectangle defined by x, y, width, height must be contained in the attachments'
+  )
+  .params(
+    params()
+      .combine([
+        { attachmentWidth: 3, attachmentHeight: 5 },
+        { attachmentWidth: 5, attachmentHeight: 3 },
+        { attachmentWidth: 1024, attachmentHeight: 1 },
+        { attachmentWidth: 1, attachmentHeight: 1024 },
+      ])
+      .combine([
+        // Control case: a full scissor is valid.
+        { dx: 0, dy: 0, dw: 0, dh: 0 },
+
+        // Other valid cases with a partial scissor.
+        { dx: 1, dy: 0, dw: -1, dh: 0 },
+        { dx: 0, dy: 1, dw: 0, dh: -1 },
+        { dx: 0, dy: 0, dw: -1, dh: 0 },
+        { dx: 0, dy: 0, dw: 0, dh: -1 },
+
+        // Test with a small value that causes the scissor to go outside the attachment.
+        { dx: 1, dy: 0, dw: 0, dh: 0 },
+        { dx: 0, dy: 1, dw: 0, dh: 0 },
+        { dx: 0, dy: 0, dw: 1, dh: 0 },
+        { dx: 0, dy: 0, dw: 0, dh: 1 },
+      ])
+  )
+  .fn(t => {
+    const { attachmentWidth, attachmentHeight, dx, dy, dw, dh } = t.params;
+    const x = dx;
+    const y = dy;
+    const w = attachmentWidth + dw;
+    const h = attachmentWidth + dh;
+
+    const success = x + w <= attachmentWidth && y + h <= attachmentHeight;
+    t.testScissorCall(
+      success,
+      { x, y, w, h },
+      { width: attachmentWidth, height: attachmentHeight, depth: 1 }
+    );
+  });
+
+g.test('setBlendColor')
+  .desc('Test that almost any color value is valid for setBlendColor')
+  .params([
+    { r: 1.0, g: 1.0, b: 1.0, a: 1.0 },
+    { r: -1.0, g: -1.0, b: -1.0, a: -1.0 },
+    { r: Number.MAX_SAFE_INTEGER, g: Number.MIN_SAFE_INTEGER, b: -0, a: 100000 },
+  ])
+  .fn(t => {
+    const { r, g, b, a } = t.params;
+    const encoders = t.createDummyRenderPassEncoder();
+    encoders.pass.setBlendColor({ r, g, b, a });
+    encoders.pass.endPass();
+    encoders.encoder.finish();
+  });
+
+g.test('setStencilReference')
+  .desc('Test that almost any stencil reference value is valid for setStencilReference')
+  .params([
+    { value: 1 }, //
+    { value: 0 },
+    { value: 1000 },
+    { value: 0xffffffff },
+  ])
+  .fn(t => {
+    const { value } = t.params;
+    const encoders = t.createDummyRenderPassEncoder();
+    encoders.pass.setStencilReference(value);
+    encoders.pass.endPass();
+    encoders.encoder.finish();
+  });
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/encoding/cmds/index_access.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/encoding/cmds/index_access.spec.js
index 3cf79f5..e48670c 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/encoding/cmds/index_access.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/encoding/cmds/index_access.spec.js
@@ -25,31 +25,37 @@
   }
 
   createRenderPipeline() {
-    const vertexModule = this.makeShaderModule('vertex', {
-      glsl: `
-        #version 450
-        void main() {
-          gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
-        }
-      `,
-    });
-
-    const fragmentModule = this.makeShaderModule('fragment', {
-      glsl: `
-        #version 450
-        layout(location = 0) out vec4 fragColor;
-        void main() {
-            fragColor = vec4(0.0, 1.0, 0.0, 1.0);
-        }
-      `,
-    });
-
     return this.device.createRenderPipeline({
-      layout: this.device.createPipelineLayout({ bindGroupLayouts: [] }),
-      vertexStage: { module: vertexModule, entryPoint: 'main' },
-      fragmentStage: { module: fragmentModule, entryPoint: 'main' },
+      vertexStage: {
+        module: this.device.createShaderModule({
+          code: `
+            [[builtin(position)]] var<out> Position : vec4<f32>;
+
+            [[stage(vertex)]] fn main() -> void {
+              Position = vec4<f32>(0.0, 0.0, 0.0, 1.0);
+              return;
+            }`,
+        }),
+
+        entryPoint: 'main',
+      },
+
+      fragmentStage: {
+        module: this.device.createShaderModule({
+          code: `
+            [[location(0)]] var<out> fragColor : vec4<f32>;
+            [[stage(fragment)]] fn main() -> void {
+              fragColor = vec4<f32>(0.0, 1.0, 0.0, 1.0);
+              return;
+            }`,
+        }),
+
+        entryPoint: 'main',
+      },
+
       primitiveTopology: 'triangle-strip',
       colorStates: [{ format: 'rgba8unorm' }],
+      vertexState: { indexFormat: 'uint32' },
     });
   }
 
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/error_scope.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/error_scope.spec.js
index edee0ba6..576fbd4 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/error_scope.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/error_scope.spec.js
@@ -1,7 +1,20 @@
 /**
  * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
  **/ export const description = `
-error scope validation tests.
+Error scope validation tests.
+
+Note these must create their own device, not use GPUTest (that one already has error scopes on it).
+
+TODO: shorten test names; detail should move to the description.)
+
+TODO: consider slightly revising these tests to make sure they're complete. {
+    - push 0, pop 1
+    - push validation, push oom, pop, pop, pop
+    - push oom, push validation, pop, pop, pop
+    - push validation, pop, pop
+    - push oom, pop, pop
+    - push various x100000 (or some other large number), pop x100000, pop
+    - }
 `;
 import { Fixture } from '../../../common/framework/fixture.js';
 import { makeTestGroup } from '../../../common/framework/test_group.js';
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/fences.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/fences.spec.js
index e92bdd3..a561ccd9 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/fences.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/fences.spec.js
@@ -2,6 +2,22 @@
  * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
  **/ export const description = `
 fences validation tests.
+
+TODO: Add some more tests/cases (may replace some existing tests), e.g.:
+  For fence values 0 < x < y < z:
+  - initialValue=0, signal(0)
+  - initialValue=x, signal(x)
+  - initialValue=x, signal(y)
+  - initialValue=y, signal(x)
+  - initialValue=x, signal(y), signal(y)
+  - initialValue=x, signal(y), signal(z), wait(z)
+  - initialValue=x, signal(z), signal(y)
+  - initialValue=x, wait(x)
+  - initialValue=y, wait(x)
+  - initialValue=x, wait(y)
+  - initialValue=x, signal(y), wait(x)
+  - initialValue=x, signal(y), wait(y)
+  - etc.
 `;
 import { makeTestGroup } from '../../../common/framework/test_group.js';
 import { assert } from '../../../common/framework/util/util.js';
@@ -57,6 +73,8 @@
   await fence.onCompletion(6);
 });
 
+// TODO: Move these two tests to device_mismatched. Probably merge into one test.
+// Parameterize over whether another device is used, to test the control case.
 g.test('signal_a_fence_on_a_different_device_than_it_was_created_on_is_invalid').fn(async t => {
   const anotherDevice = await t.device.adapter.requestDevice();
   assert(anotherDevice !== null);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/initialization/requestDevice.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/initialization/requestDevice.spec.js
new file mode 100644
index 0000000..a898b457
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/initialization/requestDevice.spec.js
@@ -0,0 +1,36 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Test validation conditions for requestDevice.
+`;
+import { Fixture } from '../../../../common/framework/fixture.js';
+import { makeTestGroup } from '../../../../common/framework/test_group.js';
+
+export const g = makeTestGroup(Fixture);
+
+g.test('features,nonexistent')
+  .desc('requestDevice with a made-up feature name. Should resolve to null.')
+  .unimplemented();
+
+g.test('features,known_but_unavailable')
+  .desc(
+    `requestDevice with a valid feature that's unavailable on the adapter. Should resolve to null.
+(Skipped if such a feature can't be found. But most browsers should support both BC and ETC
+while most hardware should only support one.)`
+  )
+  .unimplemented();
+
+g.test('limits')
+  .desc(
+    `For each limit, request with various values. Some should resolve to null. (TODO: which?)
+
+- value = {
+    - less than default
+    - default
+    - default + 1
+    - best available
+    - better than what's available
+    - }
+  `
+  )
+  .unimplemented();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/query_set/destroy.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/query_set/destroy.spec.js
new file mode 100644
index 0000000..cb91014
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/query_set/destroy.spec.js
@@ -0,0 +1,16 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Destroying a query set more than once is allowed.
+`;
+import { makeTestGroup } from '../../../../common/framework/test_group.js';
+import { ValidationTest } from '../validation_test.js';
+
+export const g = makeTestGroup(ValidationTest);
+
+g.test('twice').fn(async t => {
+  const qset = t.device.createQuerySet({ type: 'occlusion', count: 1 });
+
+  qset.destroy();
+  qset.destroy();
+});
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/buffer_mapped.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/buffer_mapped.spec.js
new file mode 100644
index 0000000..24cde2e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/buffer_mapped.spec.js
@@ -0,0 +1,15 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Tests for map-state of mappable buffers used in submitted command buffers.
+
+- x= just before queue op, buffer in {BufferMapStatesToTest}
+- x= in every possible place for mappable buffer:
+  {writeBuffer, copyB2B {src,dst}, copyB2T, copyT2B, ..?}
+
+TODO: implement
+`;
+import { makeTestGroup } from '../../../../common/framework/test_group.js';
+import { ValidationTest } from '../validation_test.js';
+
+export const g = makeTestGroup(ValidationTest);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/copyImageBitmapToTexture.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/copyImageBitmapToTexture.spec.js
index aa6f30f..15961bbf 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/copyImageBitmapToTexture.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/copyImageBitmapToTexture.spec.js
@@ -3,6 +3,8 @@
  **/ export const description = `
 copyImageBitmapToTexture Validation Tests in Queue.
 
+TODO: Split this test plan per-test.
+
 Test Plan:
 - For source.imageBitmap:
   - imageBitmap generated from ImageData:
@@ -422,3 +424,21 @@
       success
     );
   });
+
+g.test('ImageBitmap_sources')
+  .desc(
+    `Test ImageBitmap generated from all possible ImageBitmapSource, relevant ImageBitmapOptions
+    (https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#images-2)
+    and various source filetypes and metadata (weird dimensions, EXIF orientations, video rotations
+    and visible/crop rectangles, etc. (In theory these things are handled inside createImageBitmap,
+    but in theory could affect the internal representation of the ImageBitmap.)`
+  )
+  .unimplemented();
+
+g.test('zero_sized')
+  .desc(
+    `Test valid zero-sized copies.
+
+- copySize { [0,x,x], [x,0,x], [x,x,0], [0,0,0] }`
+  )
+  .unimplemented();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/destroyed/buffer.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/destroyed/buffer.spec.js
new file mode 100644
index 0000000..028c4aa
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/destroyed/buffer.spec.js
@@ -0,0 +1,17 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Tests using a destroyed buffer on a queue.
+
+- used in {writeBuffer,
+  setBindGroup, copyB2B {src,dst}, copyB2T, copyT2B,
+  setIndexBuffer, {draw,dispatch}Indirect, ..?}
+- x= if applicable, {in pass, in bundle}
+- x= {destroyed, not destroyed (control case)}
+
+TODO: implement. (Search for other places some of these cases may have already been tested.)
+`;
+import { makeTestGroup } from '../../../../../common/framework/test_group.js';
+import { ValidationTest } from '../../validation_test.js';
+
+export const g = makeTestGroup(ValidationTest);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/destroyed/query_set.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/destroyed/query_set.spec.js
new file mode 100644
index 0000000..b5b418e
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/destroyed/query_set.spec.js
@@ -0,0 +1,15 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Tests using a destroyed query set on a queue.
+
+- used in {resolveQuerySet, timestamp {compute, render, non-pass},
+    pipeline statistics {compute, render}, occlusion}
+- x= {destroyed, not destroyed (control case)}
+
+TODO: implement. (Search for other places some of these cases may have already been tested.)
+`;
+import { makeTestGroup } from '../../../../../common/framework/test_group.js';
+import { ValidationTest } from '../../validation_test.js';
+
+export const g = makeTestGroup(ValidationTest);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/destroyed/texture.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/destroyed/texture.spec.js
new file mode 100644
index 0000000..2cd362b
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/destroyed/texture.spec.js
@@ -0,0 +1,17 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Tests using a destroyed texture on a queue.
+
+- used in {writeTexture,
+  setBindGroup, copyT2T {src,dst}, copyB2T, copyT2B, copyImageBitmapToTexture,
+  color attachment {0,>0}, {D,S,DS} attachment, ..?}
+- x= if applicable, {in pass, in bundle}
+- x= {destroyed, not destroyed (control case)}
+
+TODO: implement. (Search for other places some of these cases may have already been tested.)
+`;
+import { makeTestGroup } from '../../../../../common/framework/test_group.js';
+import { ValidationTest } from '../../validation_test.js';
+
+export const g = makeTestGroup(ValidationTest);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/writeBuffer.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/writeBuffer.spec.js
new file mode 100644
index 0000000..e0cf466
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/queue/writeBuffer.spec.js
@@ -0,0 +1,20 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Tests writeBuffer validation.
+
+- buffer missing usage flag
+- bufferOffset {ok, too large for buffer}
+- dataOffset {ok, too large for data}
+- size {ok, too large for buffer}
+- size {ok, too large for data}
+- size unspecified; default {ok, too large for buffer}
+
+Note: destroyed buffer is tested in destroyed/.
+
+TODO: implement.
+`;
+import { makeTestGroup } from '../../../../common/framework/test_group.js';
+import { ValidationTest } from '../validation_test.js';
+
+export const g = makeTestGroup(ValidationTest);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/render_pass.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/render_pass.spec.js
index b9db03b..15c69ff1 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/render_pass.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/render_pass.spec.js
@@ -15,35 +15,50 @@
     });
   }
 
-  createRenderPipeline(pipelineLayout) {
-    const vertexModule = this.makeShaderModule('vertex', {
-      glsl: `#version 450
-          layout (set = 0, binding = 0) uniform vertexUniformBuffer {
-              mat2 transform;
-          };
-          void main() {
-              const vec2 pos[3] = vec2[3](vec2(-1.f, -1.f), vec2(1.f, -1.f), vec2(-1.f, 1.f));
-              gl_Position = vec4(transform * pos[gl_VertexIndex], 0.f, 1.f);
-          }
-        `,
-    });
-
-    const fragmentModule = this.makeShaderModule('fragment', {
-      glsl: `
-        #version 450
-        layout (set = 1, binding = 0) uniform fragmentUniformBuffer {
-          vec4 color;
-        };
-        layout(location = 0) out vec4 fragColor;
-        void main() {
-        }
-      `,
-    });
-
+  createRenderPipeline() {
     const pipeline = this.device.createRenderPipeline({
-      vertexStage: { module: vertexModule, entryPoint: 'main' },
-      fragmentStage: { module: fragmentModule, entryPoint: 'main' },
-      layout: pipelineLayout,
+      vertexStage: {
+        module: this.device.createShaderModule({
+          code: `
+            [[block]] struct VertexUniforms {
+              [[offset(0)]] transform : mat2x2<f32> ;
+            };
+            [[set(0), binding(0)]] var<uniform> uniforms : VertexUniforms;
+
+            [[builtin(position)]] var<out> Position : vec4<f32>;
+            [[builtin(vertex_idx)]] var<in> VertexIndex : i32;
+            [[stage(vertex)]] fn main() -> void {
+              var pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
+                vec2<f32>(-1.0, -1.0),
+                vec2<f32>( 1.0, -1.0),
+                vec2<f32>(-1.0,  1.0)
+              );
+              Position = vec4<f32>(uniforms.transform * pos[VertexIndex], 0.0, 1.0);
+              return;
+            }`,
+        }),
+
+        entryPoint: 'main',
+      },
+
+      fragmentStage: {
+        module: this.device.createShaderModule({
+          code: `
+            [[block]] struct FragmentUniforms {
+              [[offset(0)]] color : vec4<f32>;
+            };
+            [[set(1), binding(0)]] var<uniform> uniforms : FragmentUniforms;
+
+            [[location(0)]] var<out> fragColor : vec4<f32>;
+            [[stage(fragment)]] fn main() -> void {
+              fragColor = uniforms.color;
+              return;
+            }`,
+        }),
+
+        entryPoint: 'main',
+      },
+
       primitiveTopology: 'triangle-list',
       colorStates: [{ format: 'rgba8unorm' }],
     });
@@ -81,16 +96,21 @@
   .fn(async t => {
     const { setBindGroup1, setBindGroup2, _success } = t.params;
 
+    const pipeline = t.createRenderPipeline();
+
     const uniformBuffer = t.getUniformBuffer();
 
-    const bindGroupLayout1 = t.device.createBindGroupLayout({
+    const bindGroup0 = t.device.createBindGroup({
       entries: [
         {
           binding: 0,
-          visibility: GPUShaderStage.VERTEX,
-          type: 'uniform-buffer',
+          resource: {
+            buffer: uniformBuffer,
+          },
         },
       ],
+
+      layout: pipeline.getBindGroupLayout(0),
     });
 
     const bindGroup1 = t.device.createBindGroup({
@@ -103,48 +123,19 @@
         },
       ],
 
-      layout: bindGroupLayout1,
+      layout: pipeline.getBindGroupLayout(1),
     });
 
-    const bindGroupLayout2 = t.device.createBindGroupLayout({
-      entries: [
-        {
-          binding: 0,
-          visibility: GPUShaderStage.FRAGMENT,
-          type: 'uniform-buffer',
-        },
-      ],
-    });
-
-    const bindGroup2 = t.device.createBindGroup({
-      entries: [
-        {
-          binding: 0,
-          resource: {
-            buffer: uniformBuffer,
-          },
-        },
-      ],
-
-      layout: bindGroupLayout2,
-    });
-
-    const pipelineLayout = t.device.createPipelineLayout({
-      bindGroupLayouts: [bindGroupLayout1, bindGroupLayout2],
-    });
-
-    const pipeline = t.createRenderPipeline(pipelineLayout);
-
     const commandEncoder = t.device.createCommandEncoder();
     const renderPass = t.beginRenderPass(commandEncoder);
     renderPass.setPipeline(pipeline);
     if (setBindGroup1) {
-      renderPass.setBindGroup(0, bindGroup1);
+      renderPass.setBindGroup(0, bindGroup0);
     }
     if (setBindGroup2) {
-      renderPass.setBindGroup(1, bindGroup2);
+      renderPass.setBindGroup(1, bindGroup1);
     }
-    renderPass.draw(3, 1, 0, 0);
+    renderPass.draw(3);
     renderPass.endPass();
     t.expectValidationError(() => {
       commandEncoder.finish();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setBlendColor.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setBlendColor.spec.js
deleted file mode 100644
index 8a302ff..0000000
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setBlendColor.spec.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
- **/ export const description = `
-setBlendColor validation tests.
-`;
-import { makeTestGroup } from '../../../common/framework/test_group.js';
-
-import { ValidationTest } from './validation_test.js';
-
-// TODO: Move beginRenderPass to a Fixture class.
-class F extends ValidationTest {
-  beginRenderPass(commandEncoder) {
-    const attachmentTexture = this.device.createTexture({
-      format: 'rgba8unorm',
-      size: { width: 16, height: 16, depth: 1 },
-      usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
-    });
-
-    return commandEncoder.beginRenderPass({
-      colorAttachments: [
-        {
-          attachment: attachmentTexture.createView(),
-          loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 },
-        },
-      ],
-    });
-  }
-}
-
-export const g = makeTestGroup(F);
-
-g.test('basic_use_of_setBlendColor').fn(t => {
-  const commandEncoder = t.device.createCommandEncoder();
-  const renderPass = t.beginRenderPass(commandEncoder);
-  renderPass.setBlendColor({ r: 0, g: 0, b: 0, a: 0 });
-  renderPass.endPass();
-  commandEncoder.finish();
-});
-
-g.test('setBlendColor_allows_any_number_value').fn(t => {
-  const values = [Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER];
-  for (const value of values) {
-    const commandEncoder = t.device.createCommandEncoder();
-    const renderPass = t.beginRenderPass(commandEncoder);
-    renderPass.setBlendColor({ r: value, g: value, b: value, a: value });
-    renderPass.endPass();
-    commandEncoder.finish();
-  }
-});
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setScissorRect.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setScissorRect.spec.js
deleted file mode 100644
index c049e92..0000000
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setScissorRect.spec.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
- **/ export const description = `
-setScissorRect validation tests.
-`;
-import { makeTestGroup } from '../../../common/framework/test_group.js';
-
-import { ValidationTest } from './validation_test.js';
-
-const TEXTURE_WIDTH = 16;
-const TEXTURE_HEIGHT = 16;
-
-// TODO: Move this fixture class to a common file.
-class F extends ValidationTest {
-  beginRenderPass(commandEncoder) {
-    const attachmentTexture = this.device.createTexture({
-      format: 'rgba8unorm',
-      size: { width: TEXTURE_WIDTH, height: TEXTURE_HEIGHT, depth: 1 },
-      usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
-    });
-
-    return commandEncoder.beginRenderPass({
-      colorAttachments: [
-        {
-          attachment: attachmentTexture.createView(),
-          loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 },
-        },
-      ],
-    });
-  }
-}
-
-export const g = makeTestGroup(F);
-
-g.test('use_of_setScissorRect')
-  .params([
-    { x: 0, y: 0, width: 1, height: 1, _success: true }, // Basic use
-    { x: 0, y: 0, width: 0, height: 1, _success: false }, // Width of zero is not allowed
-    { x: 0, y: 0, width: 1, height: 0, _success: false }, // Height of zero is not allowed
-    { x: 0, y: 0, width: 0, height: 0, _success: false }, // Both width and height of zero are not allowed
-    { x: 0, y: 0, width: TEXTURE_WIDTH + 1, height: TEXTURE_HEIGHT + 1, _success: false }, // Scissor larger than the framebuffer is not allowed
-  ])
-  .fn(async t => {
-    const { x, y, width, height, _success } = t.params;
-
-    const commandEncoder = t.device.createCommandEncoder();
-    const renderPass = t.beginRenderPass(commandEncoder);
-    renderPass.setScissorRect(x, y, width, height);
-    renderPass.endPass();
-
-    t.expectValidationError(() => {
-      commandEncoder.finish();
-    }, !_success);
-  });
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setStencilReference.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setStencilReference.spec.js
deleted file mode 100644
index f79a24044..0000000
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setStencilReference.spec.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
- **/ export const description = `
-setStencilReference validation tests.
-`;
-import { poptions } from '../../../common/framework/params_builder.js';
-import { makeTestGroup } from '../../../common/framework/test_group.js';
-
-import { ValidationTest } from './validation_test.js';
-
-// TODO: Move this fixture class to a common file.
-class F extends ValidationTest {
-  beginRenderPass(commandEncoder) {
-    const attachmentTexture = this.device.createTexture({
-      format: 'rgba8unorm',
-      size: { width: 16, height: 16, depth: 1 },
-      usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
-    });
-
-    return commandEncoder.beginRenderPass({
-      colorAttachments: [
-        {
-          attachment: attachmentTexture.createView(),
-          loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 },
-        },
-      ],
-    });
-  }
-}
-
-export const g = makeTestGroup(F);
-
-g.test('use_of_setStencilReference')
-  .params(poptions('reference', [0, 0xffffffff]))
-  .fn(t => {
-    const { reference } = t.params;
-
-    const commandEncoder = t.device.createCommandEncoder();
-    const renderPass = t.beginRenderPass(commandEncoder);
-    renderPass.setStencilReference(reference);
-    renderPass.endPass();
-    commandEncoder.finish();
-  });
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setVertexBuffer.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setVertexBuffer.spec.js
index a7a1739..ad7dba4 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setVertexBuffer.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setVertexBuffer.spec.js
@@ -17,10 +17,37 @@
   }
 
   createRenderPipeline(bufferCount) {
-    const descriptor = {
-      vertexStage: this.getVertexStage(bufferCount),
-      fragmentStage: this.getFragmentStage(),
-      layout: this.getPipelineLayout(),
+    return this.device.createRenderPipeline({
+      vertexStage: {
+        module: this.device.createShaderModule({
+          code: `
+            ${range(
+              bufferCount,
+              i => `\n[[location(${i})]] var<in> a_position${i} : vec3<f32>;`
+            ).join('')}
+            [[builtin(position)]] var<out> Position : vec4<f32>;
+            [[stage(vertex)]] fn main() -> void {
+              Position = vec4<f32>(0.0, 0.0, 0.0, 1.0);
+              return;
+            }`,
+        }),
+
+        entryPoint: 'main',
+      },
+
+      fragmentStage: {
+        module: this.device.createShaderModule({
+          code: `
+            [[location(0)]] var<out> fragColor : vec4<f32>;
+            [[stage(fragment)]] fn main() -> void {
+              fragColor = vec4<f32>(0.0, 1.0, 0.0, 1.0);
+              return;
+            }`,
+        }),
+
+        entryPoint: 'main',
+      },
+
       primitiveTopology: 'triangle-list',
       colorStates: [{ format: 'rgba8unorm' }],
       vertexState: {
@@ -35,41 +62,7 @@
           },
         ],
       },
-    };
-
-    return this.device.createRenderPipeline(descriptor);
-  }
-
-  getVertexStage(bufferCount) {
-    const glsl = `
-      #version 450
-      ${range(bufferCount, i => `\nlayout(location = ${i}) in vec3 a_position${i};`).join('')}
-      void main() {
-        gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
-       }
-    `;
-    return {
-      module: this.makeShaderModule('vertex', { glsl }),
-      entryPoint: 'main',
-    };
-  }
-
-  getFragmentStage() {
-    const glsl = `
-      #version 450
-      layout(location = 0) out vec4 fragColor;
-      void main() {
-        fragColor = vec4(0.0, 1.0, 0.0, 1.0);
-      }
-    `;
-    return {
-      module: this.makeShaderModule('fragment', { glsl }),
-      entryPoint: 'main',
-    };
-  }
-
-  getPipelineLayout() {
-    return this.device.createPipelineLayout({ bindGroupLayouts: [] });
+    });
   }
 
   beginRenderPass(commandEncoder) {
@@ -104,7 +97,7 @@
     const commandEncoder = t.device.createCommandEncoder();
     const renderPass = t.beginRenderPass(commandEncoder);
     renderPass.setPipeline(pipeline1);
-    renderPass.draw(3, 1, 0, 0);
+    renderPass.draw(3);
     renderPass.endPass();
 
     t.expectValidationError(() => {
@@ -118,9 +111,9 @@
     renderPass.setPipeline(pipeline2);
     renderPass.setVertexBuffer(0, vertexBuffer1);
     renderPass.setVertexBuffer(1, vertexBuffer2);
-    renderPass.draw(3, 1, 0, 0);
+    renderPass.draw(3);
     renderPass.setPipeline(pipeline1);
-    renderPass.draw(3, 1, 0, 0);
+    renderPass.draw(3);
     renderPass.endPass();
 
     commandEncoder.finish();
@@ -142,14 +135,14 @@
       renderPass.setPipeline(pipeline2);
       renderPass.setVertexBuffer(0, vertexBuffer1);
       renderPass.setVertexBuffer(1, vertexBuffer2);
-      renderPass.draw(3, 1, 0, 0);
+      renderPass.draw(3);
       renderPass.endPass();
     }
     {
       const renderPass = t.beginRenderPass(commandEncoder);
       renderPass.setPipeline(pipeline1);
       renderPass.setVertexBuffer(0, vertexBuffer1);
-      renderPass.draw(3, 1, 0, 0);
+      renderPass.draw(3);
       renderPass.endPass();
     }
     commandEncoder.finish();
@@ -162,13 +155,13 @@
       renderPass.setPipeline(pipeline2);
       renderPass.setVertexBuffer(0, vertexBuffer1);
       renderPass.setVertexBuffer(1, vertexBuffer2);
-      renderPass.draw(3, 1, 0, 0);
+      renderPass.draw(3);
       renderPass.endPass();
     }
     {
       const renderPass = t.beginRenderPass(commandEncoder);
       renderPass.setPipeline(pipeline1);
-      renderPass.draw(3, 1, 0, 0);
+      renderPass.draw(3);
       renderPass.endPass();
     }
 
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setViewport.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setViewport.spec.js
deleted file mode 100644
index e2ef691..0000000
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/setViewport.spec.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/**
- * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
- **/ export const description = `
-setViewport validation tests.
-`;
-import { makeTestGroup } from '../../../common/framework/test_group.js';
-
-import { ValidationTest } from './validation_test.js';
-
-const TEXTURE_WIDTH = 16;
-const TEXTURE_HEIGHT = 16;
-
-// TODO: Move this fixture class to a common file.
-class F extends ValidationTest {
-  beginRenderPass(commandEncoder) {
-    const attachmentTexture = this.device.createTexture({
-      format: 'rgba8unorm',
-      size: { width: TEXTURE_WIDTH, height: TEXTURE_HEIGHT, depth: 1 },
-      usage: GPUTextureUsage.OUTPUT_ATTACHMENT,
-    });
-
-    return commandEncoder.beginRenderPass({
-      colorAttachments: [
-        {
-          attachment: attachmentTexture.createView(),
-          loadValue: { r: 1.0, g: 0.0, b: 0.0, a: 1.0 },
-        },
-      ],
-    });
-  }
-}
-
-export const g = makeTestGroup(F);
-
-g.test('use_of_setViewport')
-  .params([
-    { x: 0, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: 1, _success: true }, // Basic use
-    { x: 0, y: 0, width: 0, height: 1, minDepth: 0, maxDepth: 1, _success: false }, // Width of zero is not allowed
-    { x: 0, y: 0, width: 1, height: 0, minDepth: 0, maxDepth: 1, _success: false }, // Height of zero is not allowed
-    { x: 0, y: 0, width: 0, height: 0, minDepth: 0, maxDepth: 1, _success: false }, // Both width and height of zero are not allowed
-    { x: -1, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: 1, _success: true }, // Negative x is allowed
-    { x: 0, y: -1, width: 1, height: 1, minDepth: 0, maxDepth: 1, _success: true }, // Negative y is allowed
-    { x: 0, y: 0, width: -1, height: 1, minDepth: 0, maxDepth: 1, _success: false }, // Negative width is not allowed
-    { x: 0, y: 0, width: 1, height: -1, minDepth: 0, maxDepth: 1, _success: false }, // Negative height is not allowed
-    { x: 0, y: 0, width: 1, height: 1, minDepth: -1, maxDepth: 1, _success: false }, // Negative minDepth is not allowed
-    { x: 0, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: -1, _success: false }, // Negative maxDepth is not allowed
-    { x: 0, y: 0, width: 1, height: 1, minDepth: 10, maxDepth: 1, _success: false }, // minDepth greater than 1 is not allowed
-    { x: 0, y: 0, width: 1, height: 1, minDepth: 0, maxDepth: 10, _success: false }, // maxDepth greater than 1 is not allowed
-    { x: 0, y: 0, width: 1, height: 1, minDepth: 0.5, maxDepth: 0.5, _success: true }, // minDepth equal to maxDepth is allowed
-    { x: 0, y: 0, width: 1, height: 1, minDepth: 0.8, maxDepth: 0.5, _success: true }, // minDepth greater than maxDepth is allowed
-    {
-      x: 0,
-      y: 0,
-      width: TEXTURE_WIDTH + 1,
-      height: TEXTURE_HEIGHT + 1,
-      minDepth: 0,
-      maxDepth: 1,
-      _success: true,
-    },
-    // Viewport larger than the framebuffer is allowed
-  ])
-  .fn(async t => {
-    const { x, y, width, height, minDepth, maxDepth, _success } = t.params;
-
-    const commandEncoder = t.device.createCommandEncoder();
-    const renderPass = t.beginRenderPass(commandEncoder);
-    renderPass.setViewport(x, y, width, height, minDepth, maxDepth);
-    renderPass.endPass();
-
-    t.expectValidationError(() => {
-      commandEncoder.finish();
-    }, !_success);
-  });
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/texture/destroy.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/texture/destroy.spec.js
new file mode 100644
index 0000000..262ae60
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/texture/destroy.spec.js
@@ -0,0 +1,20 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = `
+Destroying a texture more than once is allowed.
+`;
+import { makeTestGroup } from '../../../../common/framework/test_group.js';
+import { ValidationTest } from '../validation_test.js';
+
+export const g = makeTestGroup(ValidationTest);
+
+g.test('twice').fn(async t => {
+  const tex = t.device.createTexture({
+    size: [1, 1, 1],
+    format: 'r8unorm',
+    usage: GPUTextureUsage.SAMPLED,
+  });
+
+  tex.destroy();
+  tex.destroy();
+});
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/vertex_state.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/vertex_state.spec.js
index 7a30e3a..9dfae40 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/vertex_state.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/api/validation/vertex_state.spec.js
@@ -15,17 +15,10 @@
 const SIZEOF_FLOAT = Float32Array.BYTES_PER_ELEMENT;
 
 const VERTEX_SHADER_CODE_WITH_NO_INPUT = `
-  #version 450
-  void main() {
-    gl_Position = vec4(0.0);
-  }
-`;
-
-const FRAGMENT_SHADER_CODE = `
-  #version 450
-  layout(location = 0) out vec4 fragColor;
-  void main() {
-    fragColor = vec4(0.0, 1.0, 0.0, 1.0);
+  [[builtin(position)]] var<out> Position : vec4<f32>;
+  [[stage(vertex)]] fn main() -> void {
+    Position = vec4<f32>(0.0, 0.0, 0.0, 0.0);
+    return;
   }
 `;
 
@@ -37,16 +30,23 @@
   getDescriptor(vertexState, vertexShaderCode) {
     const descriptor = {
       vertexStage: {
-        module: this.makeShaderModule('vertex', { glsl: vertexShaderCode }),
+        module: this.device.createShaderModule({ code: vertexShaderCode }),
         entryPoint: 'main',
       },
 
       fragmentStage: {
-        module: this.makeShaderModule('fragment', { glsl: FRAGMENT_SHADER_CODE }),
+        module: this.device.createShaderModule({
+          code: `
+            [[location(0)]] var<out> fragColor : vec4<f32>;
+            [[stage(fragment)]] fn main() -> void {
+              fragColor = vec4<f32>(0.0, 1.0, 0.0, 1.0);
+              return;
+            }`,
+        }),
+
         entryPoint: 'main',
       },
 
-      layout: this.device.createPipelineLayout({ bindGroupLayouts: [] }),
       primitiveTopology: 'triangle-list',
       colorStates: [{ format: 'rgba8unorm' }],
       vertexState,
@@ -167,23 +167,27 @@
   {
     // Control case: pipeline with one input per attribute
     const code = `
-      #version 450
-      layout(location = 0) in vec4 a;
-      layout(location = 1) in vec4 b;
-      void main() {
-          gl_Position = vec4(0.0);
+      [[location(0)]] var<in> a : vec4<f32>;
+      [[location(1)]] var<in> b : vec4<f32>;
+
+      [[builtin(position)]] var<out> Position : vec4<f32>;
+      [[stage(vertex)]] fn main() -> void {
+        Position = vec4<f32>(0.0, 0.0, 0.0, 0.0);
+        return;
       }
-    `;
+  `;
     const descriptor = t.getDescriptor(vertexState, code);
     t.device.createRenderPipeline(descriptor);
   }
   {
     // Check it is valid for the pipeline to use a subset of the VertexState
     const code = `
-      #version 450
-      layout(location = 0) in vec4 a;
-      void main() {
-          gl_Position = vec4(0.0);
+      [[location(0)]] var<in> a : vec4<f32>;
+
+      [[builtin(position)]] var<out> Position : vec4<f32>;
+      [[stage(vertex)]] fn main() -> void {
+        Position = vec4<f32>(0.0, 0.0, 0.0, 0.0);
+        return;
       }
     `;
     const descriptor = t.getDescriptor(vertexState, code);
@@ -192,10 +196,12 @@
   {
     // Check for an error when the pipeline uses an attribute not in the vertex input
     const code = `
-      #version 450
-      layout(location = 2) in vec4 a;
-      void main() {
-          gl_Position = vec4(0.0);
+      [[location(2)]] var<in> a : vec4<f32>;
+
+      [[builtin(position)]] var<out> Position : vec4<f32>;
+      [[stage(vertex)]] fn main() -> void {
+        Position = vec4<f32>(0.0, 0.0, 0.0, 0.0);
+        return;
       }
     `;
     const descriptor = t.getDescriptor(vertexState, code);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/capability_info.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/capability_info.js
index 8392d56..458acc27 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/capability_info.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/capability_info.js
@@ -12,6 +12,8 @@
 
 // Buffers
 
+export const kBufferSizeAlignment = 4;
+
 export const kBufferUsageInfo = {
   [GPUConst.BufferUsage.MAP_READ]: {},
   [GPUConst.BufferUsage.MAP_WRITE]: {},
@@ -42,6 +44,8 @@
     bytesPerBlock: 1,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'unorm',
+    componentType: 'float',
   },
   r8snorm: {
     renderable: false,
@@ -54,6 +58,8 @@
     bytesPerBlock: 1,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'snorm',
+    componentType: 'float',
   },
   r8uint: {
     renderable: true,
@@ -66,6 +72,8 @@
     bytesPerBlock: 1,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'uint',
+    componentType: 'uint',
   },
   r8sint: {
     renderable: true,
@@ -78,6 +86,8 @@
     bytesPerBlock: 1,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'sint',
+    componentType: 'sint',
   },
   // 16-bit formats
   r16uint: {
@@ -91,6 +101,8 @@
     bytesPerBlock: 2,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'uint',
+    componentType: 'uint',
   },
   r16sint: {
     renderable: true,
@@ -103,6 +115,8 @@
     bytesPerBlock: 2,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'sint',
+    componentType: 'sint',
   },
   r16float: {
     renderable: true,
@@ -115,6 +129,8 @@
     bytesPerBlock: 2,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'float',
+    componentType: 'float',
   },
   rg8unorm: {
     renderable: true,
@@ -127,6 +143,8 @@
     bytesPerBlock: 2,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'unorm',
+    componentType: 'float',
   },
   rg8snorm: {
     renderable: false,
@@ -139,6 +157,8 @@
     bytesPerBlock: 2,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'snorm',
+    componentType: 'float',
   },
   rg8uint: {
     renderable: true,
@@ -151,6 +171,8 @@
     bytesPerBlock: 2,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'uint',
+    componentType: 'uint',
   },
   rg8sint: {
     renderable: true,
@@ -163,6 +185,8 @@
     bytesPerBlock: 2,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'sint',
+    componentType: 'sint',
   },
   // 32-bit formats
   r32uint: {
@@ -176,6 +200,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'uint',
+    componentType: 'uint',
   },
   r32sint: {
     renderable: true,
@@ -188,6 +214,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'sint',
+    componentType: 'sint',
   },
   r32float: {
     renderable: true,
@@ -200,6 +228,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'float',
+    componentType: 'float',
   },
   rg16uint: {
     renderable: true,
@@ -212,6 +242,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'uint',
+    componentType: 'uint',
   },
   rg16sint: {
     renderable: true,
@@ -224,6 +256,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'sint',
+    componentType: 'sint',
   },
   rg16float: {
     renderable: true,
@@ -236,6 +270,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'float',
+    componentType: 'float',
   },
   rgba8unorm: {
     renderable: true,
@@ -248,6 +284,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'unorm',
+    componentType: 'float',
   },
   'rgba8unorm-srgb': {
     renderable: true,
@@ -260,6 +298,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'unorm',
+    componentType: 'float',
   },
   rgba8snorm: {
     renderable: false,
@@ -272,6 +312,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'snorm',
+    componentType: 'float',
   },
   rgba8uint: {
     renderable: true,
@@ -284,6 +326,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'uint',
+    componentType: 'uint',
   },
   rgba8sint: {
     renderable: true,
@@ -296,6 +340,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'sint',
+    componentType: 'sint',
   },
   bgra8unorm: {
     renderable: true,
@@ -308,6 +354,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'unorm',
+    componentType: 'float',
   },
   'bgra8unorm-srgb': {
     renderable: true,
@@ -320,6 +368,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'unorm',
+    componentType: 'float',
   },
   // Packed 32-bit formats
   rgb10a2unorm: {
@@ -333,6 +383,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'unorm',
+    componentType: 'float',
   },
   rg11b10ufloat: {
     renderable: false,
@@ -345,6 +397,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'ufloat',
+    componentType: 'float',
   },
   rgb9e5ufloat: {
     renderable: false,
@@ -357,6 +411,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'ufloat',
+    componentType: 'float',
   },
   // 64-bit formats
   rg32uint: {
@@ -370,6 +426,8 @@
     bytesPerBlock: 8,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'uint',
+    componentType: 'uint',
   },
   rg32sint: {
     renderable: true,
@@ -382,6 +440,8 @@
     bytesPerBlock: 8,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'sint',
+    componentType: 'sint',
   },
   rg32float: {
     renderable: true,
@@ -394,6 +454,8 @@
     bytesPerBlock: 8,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'float',
+    componentType: 'float',
   },
   rgba16uint: {
     renderable: true,
@@ -406,6 +468,8 @@
     bytesPerBlock: 8,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'uint',
+    componentType: 'uint',
   },
   rgba16sint: {
     renderable: true,
@@ -418,6 +482,8 @@
     bytesPerBlock: 8,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'sint',
+    componentType: 'sint',
   },
   rgba16float: {
     renderable: true,
@@ -430,6 +496,8 @@
     bytesPerBlock: 8,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'float',
+    componentType: 'float',
   },
   // 128-bit formats
   rgba32uint: {
@@ -443,6 +511,8 @@
     bytesPerBlock: 16,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'uint',
+    componentType: 'uint',
   },
   rgba32sint: {
     renderable: true,
@@ -455,6 +525,8 @@
     bytesPerBlock: 16,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'sint',
+    componentType: 'sint',
   },
   rgba32float: {
     renderable: true,
@@ -467,6 +539,8 @@
     bytesPerBlock: 16,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'float',
+    componentType: 'float',
   },
 };
 
@@ -484,6 +558,8 @@
     bytesPerBlock: 4,
     blockWidth: 1,
     blockHeight: 1,
+    dataType: 'float',
+    componentType: 'float',
   },
 };
 
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/examples.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/examples.spec.js
index c98e3e7..c21b117 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/examples.spec.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/examples.spec.js
@@ -118,6 +118,10 @@
 // One of the following two tests should be skipped on most platforms.
 
 g.test('gpu,with_texture_compression,bc')
+  .desc(
+    `Example of a test using a device descriptor.
+Tests that a BC format passes validation iff the feature is enabled.`
+  )
   .params(pbool('textureCompressionBC'))
   .fn(async t => {
     const { textureCompressionBC } = t.params;
@@ -141,6 +145,11 @@
   });
 
 g.test('gpu,with_texture_compression,etc')
+  .desc(
+    `Example of a test using a device descriptor.
+
+TODO: Test that an ETC format passes validation iff the feature is enabled.`
+  )
   .params(pbool('textureCompressionETC'))
   .fn(async t => {
     const { textureCompressionETC } = t.params;
@@ -151,6 +160,5 @@
       });
     }
 
-    t.device;
     // TODO: Should actually test createTexture with an ETC format here.
   });
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/listing.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/listing.js
index cd8245c..5d79159 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/listing.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/listing.js
@@ -117,7 +117,7 @@
       "operation",
       "copyBetweenLinearDataAndTexture"
     ],
-    "description": "writeTexture + copyBufferToTexture + copyTextureToBuffer operation tests.\n\n* copy_with_various_rows_per_image_and_bytes_per_row: test that copying data with various bytesPerRow (including { ==, > } bytesInACompleteRow) and rowsPerImage (including { ==, > } copyExtent.height) values and minimum required bytes in copy works for every format. Also covers special code paths:\n  - bufferSize - offset < bytesPerImage * copyExtent.depth\n  - when bytesPerRow is not a multiple of 512 and copyExtent.depth > 1: copyExtent.depth % 2 == { 0, 1 }\n  - bytesPerRow == bytesInACompleteCopyImage\n\n* copy_with_various_offsets_and_data_sizes: test that copying data with various offset (including { ==, > } 0 and is/isn't power of 2) values and additional data paddings works for every format with 2d and 2d-array textures. Also covers special code paths:\n  - offset + bytesInCopyExtentPerRow { ==, > } bytesPerRow\n  - offset > bytesInACompleteCopyImage\n\n* copy_with_various_origins_and_copy_extents: test that copying slices of a texture works with various origin (including { origin.x, origin.y, origin.z } { ==, > } 0 and is/isn't power of 2) and copyExtent (including { copyExtent.x, copyExtent.y, copyExtent.z } { ==, > } 0 and is/isn't power of 2) values (also including {origin._ + copyExtent._ { ==, < } the subresource size of textureCopyView) works for all formats. origin and copyExtent values are passed as [number, number, number] instead of GPUExtent3DDict.\n\n* copy_various_mip_levels: test that copying various mip levels works for all formats. Also covers special code paths:\n  - the physical size of the subresouce is not equal to the logical size\n  - bufferSize - offset < bytesPerImage * copyExtent.depth and copyExtent needs to be clamped\n\n* copy_with_no_image_or_slice_padding_and_undefined_values: test that when copying a single row we can set any bytesPerRow value and when copying a single slice we can set rowsPerImage to 0. Also test setting offset, rowsPerImage, mipLevel, origin, origin.{x,y,z} to undefined.\n\n* TODO:\n  - add another initMethod which renders the texture\n  - because of expectContests 4-bytes alignment we don't test CopyT2B with buffer size not divisible by 4\n  - add tests for 1d / 3d textures"
+    "description": "writeTexture + copyBufferToTexture + copyTextureToBuffer operation tests.\n\n* copy_with_various_rows_per_image_and_bytes_per_row: test that copying data with various bytesPerRow (including { ==, > } bytesInACompleteRow) and rowsPerImage (including { ==, > } copyExtent.height) values and minimum required bytes in copy works for every format. Also covers special code paths:\n  - bufferSize - offset < bytesPerImage * copyExtent.depth\n  - when bytesPerRow is not a multiple of 512 and copyExtent.depth > 1: copyExtent.depth % 2 == { 0, 1 }\n  - bytesPerRow == bytesInACompleteCopyImage\n\n* copy_with_various_offsets_and_data_sizes: test that copying data with various offset (including { ==, > } 0 and is/isn't power of 2) values and additional data paddings works for every format with 2d and 2d-array textures. Also covers special code paths:\n  - offset + bytesInCopyExtentPerRow { ==, > } bytesPerRow\n  - offset > bytesInACompleteCopyImage\n\n* copy_with_various_origins_and_copy_extents: test that copying slices of a texture works with various origin (including { origin.x, origin.y, origin.z } { ==, > } 0 and is/isn't power of 2) and copyExtent (including { copyExtent.x, copyExtent.y, copyExtent.z } { ==, > } 0 and is/isn't power of 2) values (also including {origin._ + copyExtent._ { ==, < } the subresource size of textureCopyView) works for all formats. origin and copyExtent values are passed as [number, number, number] instead of GPUExtent3DDict.\n\n* copy_various_mip_levels: test that copying various mip levels works for all formats. Also covers special code paths:\n  - the physical size of the subresouce is not equal to the logical size\n  - bufferSize - offset < bytesPerImage * copyExtent.depth and copyExtent needs to be clamped\n\n* copy_with_no_image_or_slice_padding_and_undefined_values: test that when copying a single row we can set any bytesPerRow value and when copying a single slice we can set rowsPerImage to 0. Also test setting offset, rowsPerImage, mipLevel, origin, origin.{x,y,z} to undefined.\n\n* TODO:\n  - add another initMethod which renders the texture\n  - test copyT2B with buffer size not divisible by 4 (not done because expectContents 4-byte alignment)\n  - add tests for 1d / 3d textures"
   },
   {
     "file": [
@@ -131,10 +131,38 @@
     "file": [
       "api",
       "operation",
+      "labels"
+    ],
+    "description": "For every create function, the descriptor.label is carried over to the object.label.\n\nTODO: implement"
+  },
+  {
+    "file": [
+      "api",
+      "operation",
+      "memory_sync",
+      "buffer",
+      "rw_and_wr"
+    ],
+    "description": "Memory Synchronization Tests for Buffer: read before write and read after write.\n\n- Create a single buffer and initialize it to 0, wait on the fence to ensure the data is initialized.\nWrite a number (say 1) into the buffer via render pass, compute pass, copy or writeBuffer.\nRead the data and use it in render, compute, or copy.\nWait on another fence, then call expectContents to verify the written buffer.\nThis is a read-after write test but if the write and read operations are reversed, it will be a read-before-write test.\n  - x= write op: {storage buffer in {compute, render, render-via-bundle}, t2b copy dst, b2b copy dst, writeBuffer}\n  - x= read op: {index buffer, vertex buffer, indirect buffer, uniform buffer, {readonly, readwrite} storage buffer in {compute, render, render-via-bundle}, b2b copy src, b2t copy src}\n  - x= read-write sequence: {read then write, write then read}\n  - if pass type is the same, x= {single pass, separate passes} (note: render has loose guarantees)\n  - if not single pass, x= writes in {same cmdbuf, separate cmdbufs, separate submits, separate queues}"
+  },
+  {
+    "file": [
+      "api",
+      "operation",
+      "memory_sync",
+      "buffer",
+      "ww"
+    ],
+    "description": "Memory Synchronization Tests for Buffer: write after write.\n\n- Create one single buffer and initialize it to 0. Wait on the fence to ensure the data is initialized.\nWrite a number (say 1) into the buffer via render pass, compute pass, copy or writeBuffer.\nWrite another number (say 2) into the same buffer via render pass, compute pass, copy, or writeBuffer.\nWait on another fence, then call expectContents to verify the written buffer.\n  - x= 1st write type: {storage buffer in {compute, render, render-via-bundle}, t2b-copy, b2b-copy, writeBuffer}\n  - x= 2nd write type: {storage buffer in {compute, render, render-via-bundle}, t2b-copy, b2b-copy, writeBuffer}\n  - if pass type is the same, x= {single pass, separate passes} (note: render has loose guarantees)\n  - if not single pass, x= writes in {same cmdbuf, separate cmdbufs, separate submits, separate queues}"
+  },
+  {
+    "file": [
+      "api",
+      "operation",
       "render_pass",
       "resolve"
     ],
-    "description": "API Operation Tests for RenderPass StoreOp.\n\nTests a render pass with a resolveTarget resolves correctly for many combinations of:\n  - number of color attachments, some with and some without a resolveTarget\n  - renderPass storeOp set to {‘store’, ‘clear’}\n  - resolveTarget mip level set to {‘0’, base mip > ‘0’}\n  - resolveTarget base array layer set to {‘0’, base layer > '0'} for 2D textures\n  TODO: test all renderable color formats\n  TODO: test that any not-resolved attachments are rendered to correctly."
+    "description": "API Operation Tests for RenderPass StoreOp.\nTests a render pass with a resolveTarget resolves correctly for many combinations of:\n  - number of color attachments, some with and some without a resolveTarget\n  - renderPass storeOp set to {‘store’, ‘clear’}\n  - resolveTarget mip level set to {‘0’, base mip > ‘0’}\n  - resolveTarget base array layer set to {‘0’, base layer > '0'} for 2D textures\n  TODO: test all renderable color formats\n  TODO: test that any not-resolved attachments are rendered to correctly."
   },
   {
     "file": [
@@ -168,27 +196,9 @@
       "api",
       "operation",
       "resource_init",
-      "copied_texture_clear"
+      "texture_zero_init"
     ],
-    "description": "Test uninitialized textures are initialized to zero when copied."
-  },
-  {
-    "file": [
-      "api",
-      "operation",
-      "resource_init",
-      "depth_stencil_attachment_clear"
-    ],
-    "description": "Test uninitialized textures are initialized to zero when used as a depth/stencil attachment."
-  },
-  {
-    "file": [
-      "api",
-      "operation",
-      "resource_init",
-      "sampled_texture_clear"
-    ],
-    "description": "Test uninitialized textures are initialized to zero when sampled."
+    "description": "Test uninitialized textures are initialized to zero when read."
   },
   {
     "file": [
@@ -208,7 +218,26 @@
     "file": [
       "api",
       "validation",
-      "buffer_mapping"
+      "buffer",
+      "create"
+    ],
+    "description": "Tests for validation in createBuffer."
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "buffer",
+      "destroy"
+    ],
+    "description": "Destroying a buffer more than once is allowed."
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "buffer",
+      "mapping"
     ],
     "description": "Validation tests for GPUBuffer.mapAsync, GPUBuffer.unmap and GPUBuffer.getMappedRange."
   },
@@ -216,6 +245,24 @@
     "file": [
       "api",
       "validation",
+      "capability_checks",
+      "features"
+    ],
+    "readme": "Test every method or option that shouldn't be valid without an feature enabled.\n\n- x= that feature {enabled, disabled}\n\nOne file for each feature name.\n\nTODO: implement"
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "capability_checks",
+      "limits"
+    ],
+    "readme": "Test everything that shouldn't be valid without a higher-than-specified limit.\n\n- x= that limit {default, max supported (if different), lower than default (TODO: if allowed)}\n\nOne file for each limit name.\n\nTODO: implement"
+  },
+  {
+    "file": [
+      "api",
+      "validation",
       "copyBufferToBuffer"
     ],
     "description": "copyBufferToBuffer tests.\n\nTest Plan:\n* Buffer is valid/invalid\n  - the source buffer is invalid\n  - the destination buffer is invalid\n* Buffer usages\n  - the source buffer is created without GPUBufferUsage::COPY_SRC\n  - the destination buffer is created without GPUBufferUsage::COPY_DEST\n* CopySize\n  - copySize is not a multiple of 4\n  - copySize is 0\n* copy offsets\n  - sourceOffset is not a multiple of 4\n  - destinationOffset is not a multiple of 4\n* Arthimetic overflow\n  - (sourceOffset + copySize) is overflow\n  - (destinationOffset + copySize) is overflow\n* Out of bounds\n  - (sourceOffset + copySize) > size of source buffer\n  - (destinationOffset + copySize) > size of destination buffer\n* Source buffer and destination buffer are the same buffer"
@@ -336,6 +383,16 @@
       "validation",
       "encoding",
       "cmds",
+      "dynamic_render_state"
+    ],
+    "description": "API validation tests for dynamic state commands (setViewport/ScissorRect/BlendColor...)."
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "encoding",
+      "cmds",
       "index_access"
     ],
     "description": "indexed draws validation tests."
@@ -346,7 +403,7 @@
       "validation",
       "error_scope"
     ],
-    "description": "error scope validation tests."
+    "description": "Error scope validation tests.\n\nNote these must create their own device, not use GPUTest (that one already has error scopes on it).\n\nTODO: shorten test names; detail should move to the description.)\n\nTODO: consider slightly revising these tests to make sure they're complete. {\n    - push 0, pop 1\n    - push validation, push oom, pop, pop, pop\n    - push oom, push validation, pop, pop, pop\n    - push validation, pop, pop\n    - push oom, pop, pop\n    - push various x100000 (or some other large number), pop x100000, pop\n    - }"
   },
   {
     "file": [
@@ -354,7 +411,42 @@
       "validation",
       "fences"
     ],
-    "description": "fences validation tests."
+    "description": "fences validation tests.\n\nTODO: Add some more tests/cases (may replace some existing tests), e.g.:\n  For fence values 0 < x < y < z:\n  - initialValue=0, signal(0)\n  - initialValue=x, signal(x)\n  - initialValue=x, signal(y)\n  - initialValue=y, signal(x)\n  - initialValue=x, signal(y), signal(y)\n  - initialValue=x, signal(y), signal(z), wait(z)\n  - initialValue=x, signal(z), signal(y)\n  - initialValue=x, wait(x)\n  - initialValue=y, wait(x)\n  - initialValue=x, wait(y)\n  - initialValue=x, signal(y), wait(x)\n  - initialValue=x, signal(y), wait(y)\n  - etc."
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "initialization",
+      "requestDevice"
+    ],
+    "description": "Test validation conditions for requestDevice."
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "query_set",
+      "destroy"
+    ],
+    "description": "Destroying a query set more than once is allowed."
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "queue"
+    ],
+    "readme": "Tests for validation that occurs inside queued operations\n(submit, writeBuffer, writeTexture, copyImageBitmapToTexture).\n\nBufferMapStatesToTest = {\n  mapped -> unmapped,\n  mapped at creation -> unmapped,\n  mapping pending -> unmapped,\n  pending -> mapped (await map),\n  unmapped -> pending (noawait map),\n  created mapped-at-creation,\n}\n\nNote writeTexture is tested in copyBetweenLinearDataAndTexture."
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "queue",
+      "buffer_mapped"
+    ],
+    "description": "Tests for map-state of mappable buffers used in submitted command buffers.\n\n- x= just before queue op, buffer in {BufferMapStatesToTest}\n- x= in every possible place for mappable buffer:\n  {writeBuffer, copyB2B {src,dst}, copyB2T, copyT2B, ..?}\n\nTODO: implement"
   },
   {
     "file": [
@@ -363,7 +455,46 @@
       "queue",
       "copyImageBitmapToTexture"
     ],
-    "description": "copyImageBitmapToTexture Validation Tests in Queue.\n\nTest Plan:\n- For source.imageBitmap:\n  - imageBitmap generated from ImageData:\n    - Check that an error is generated when imageBitmap is closed.\n\n- For destination.texture:\n  - For 2d destination textures:\n    - Check that an error is generated when texture is in destroyed state.\n    - Check that an error is generated when texture is an error texture.\n    - Check that an error is generated when texture is created without usage COPY_DST.\n    - Check that an error is generated when sample count is not 1.\n    - Check that an error is generated when mipLevel is too large.\n    - Check that an error is generated when texture format is not valid.\n\n- For copySize:\n  - Noop copy shouldn't throw any exception or return any validation error.\n  - Check that an error is generated when destination.texture.origin + copySize is too large.\n\nTODO: 1d, 3d texture and 2d array textures."
+    "description": "copyImageBitmapToTexture Validation Tests in Queue.\n\nTODO: Split this test plan per-test.\n\nTest Plan:\n- For source.imageBitmap:\n  - imageBitmap generated from ImageData:\n    - Check that an error is generated when imageBitmap is closed.\n\n- For destination.texture:\n  - For 2d destination textures:\n    - Check that an error is generated when texture is in destroyed state.\n    - Check that an error is generated when texture is an error texture.\n    - Check that an error is generated when texture is created without usage COPY_DST.\n    - Check that an error is generated when sample count is not 1.\n    - Check that an error is generated when mipLevel is too large.\n    - Check that an error is generated when texture format is not valid.\n\n- For copySize:\n  - Noop copy shouldn't throw any exception or return any validation error.\n  - Check that an error is generated when destination.texture.origin + copySize is too large.\n\nTODO: 1d, 3d texture and 2d array textures."
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "queue",
+      "destroyed",
+      "buffer"
+    ],
+    "description": "Tests using a destroyed buffer on a queue.\n\n- used in {writeBuffer,\n  setBindGroup, copyB2B {src,dst}, copyB2T, copyT2B,\n  setIndexBuffer, {draw,dispatch}Indirect, ..?}\n- x= if applicable, {in pass, in bundle}\n- x= {destroyed, not destroyed (control case)}\n\nTODO: implement. (Search for other places some of these cases may have already been tested.)"
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "queue",
+      "destroyed",
+      "query_set"
+    ],
+    "description": "Tests using a destroyed query set on a queue.\n\n- used in {resolveQuerySet, timestamp {compute, render, non-pass},\n    pipeline statistics {compute, render}, occlusion}\n- x= {destroyed, not destroyed (control case)}\n\nTODO: implement. (Search for other places some of these cases may have already been tested.)"
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "queue",
+      "destroyed",
+      "texture"
+    ],
+    "description": "Tests using a destroyed texture on a queue.\n\n- used in {writeTexture,\n  setBindGroup, copyT2T {src,dst}, copyB2T, copyT2B, copyImageBitmapToTexture,\n  color attachment {0,>0}, {D,S,DS} attachment, ..?}\n- x= if applicable, {in pass, in bundle}\n- x= {destroyed, not destroyed (control case)}\n\nTODO: implement. (Search for other places some of these cases may have already been tested.)"
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "queue",
+      "writeBuffer"
+    ],
+    "description": "Tests writeBuffer validation.\n\n- buffer missing usage flag\n- bufferOffset {ok, too large for buffer}\n- dataOffset {ok, too large for data}\n- size {ok, too large for buffer}\n- size {ok, too large for data}\n- size unspecified; default {ok, too large for buffer}\n\nNote: destroyed buffer is tested in destroyed/.\n\nTODO: implement."
   },
   {
     "file": [
@@ -428,30 +559,6 @@
     "file": [
       "api",
       "validation",
-      "setBlendColor"
-    ],
-    "description": "setBlendColor validation tests."
-  },
-  {
-    "file": [
-      "api",
-      "validation",
-      "setScissorRect"
-    ],
-    "description": "setScissorRect validation tests."
-  },
-  {
-    "file": [
-      "api",
-      "validation",
-      "setStencilReference"
-    ],
-    "description": "setStencilReference validation tests."
-  },
-  {
-    "file": [
-      "api",
-      "validation",
       "setVertexBuffer"
     ],
     "description": "setVertexBuffer validation tests."
@@ -460,9 +567,28 @@
     "file": [
       "api",
       "validation",
-      "setViewport"
+      "state",
+      "device_lost"
     ],
-    "description": "setViewport validation tests."
+    "readme": "Tests of behavior while the device is lost.\n\n- x= every method in the API.\n\nTODO: implement"
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "state",
+      "device_mismatched"
+    ],
+    "readme": "Tests of behavior on one device using objects from another device.\n\n- x= every place in the API where an object is passed (as this, an arg, or a dictionary member).\n\nTODO: implement"
+  },
+  {
+    "file": [
+      "api",
+      "validation",
+      "texture",
+      "destroy"
+    ],
+    "description": "Destroying a texture more than once is allowed."
   },
   {
     "file": [
@@ -482,7 +608,7 @@
     "file": [
       "idl"
     ],
-    "readme": "Tests to check that the WebGPU IDL is correctly implemented, for examples that objects exposed\nexactly the correct members, and that methods throw when passed incomplete dictionaries."
+    "readme": "Tests to check that the WebGPU IDL is correctly implemented, for examples that objects exposed\nexactly the correct members, and that methods throw when passed incomplete dictionaries.\n\nSee https://github.com/gpuweb/cts/issues/332"
   },
   {
     "file": [
@@ -537,13 +663,21 @@
   },
   {
     "file": [
-      "web-platform"
+      "util",
+      "texture",
+      "texelData"
+    ],
+    "description": "Test helpers for texel data produce the expected data in the shader"
+  },
+  {
+    "file": [
+      "web_platform"
     ],
     "readme": "Tests for Web platform-specific interactions like GPUSwapChain and canvas, WebXR,\nImageBitmaps, and video APIs."
   },
   {
     "file": [
-      "web-platform",
+      "web_platform",
       "canvas",
       "context_creation"
     ],
@@ -551,9 +685,16 @@
   },
   {
     "file": [
-      "web-platform",
+      "web_platform",
       "copyImageBitmapToTexture"
     ],
     "description": "copy imageBitmap To texture tests."
+  },
+  {
+    "file": [
+      "web_platform",
+      "reftests"
+    ],
+    "readme": "Reference tests (reftests) for WebGPU canvas presentation.\n\nThese render some contents to a canvas using WebGPU, and WPT compares the rendering result with\nthe \"reference\" versions (in `ref/`) which render with 2D canvas.\n\nThis tests things like:\n- The canvas has the correct orientation.\n- The canvas renders with the correct transfer function.\n- The canvas blends and interpolates in the correct color encoding.\n\nTODO: Test all possible output texture formats (currently only testing bgra8unorm).\nTODO: Test all possible ways to write into those formats (currently only testing B2T copy)."
   }
 ];
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/conversion.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/conversion.js
index bdba99cf..84d1d18 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/conversion.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/conversion.js
@@ -1,6 +1,8 @@
 /**
  * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
  **/ import { assert } from '../../common/framework/util/util.js';
+import { clamp } from './math.js';
+
 export function floatAsNormalizedInteger(float, bits, signed) {
   if (signed) {
     assert(float >= -1 && float <= 1);
@@ -13,10 +15,26 @@
   }
 }
 
+export function normalizedIntegerAsFloat(integer, bits, signed) {
+  assert(Number.isInteger(integer));
+  if (signed) {
+    const max = Math.pow(2, bits - 1) - 1;
+    assert(integer >= -max - 1 && integer <= max);
+    if (integer === -max - 1) {
+      integer = -max;
+    }
+    return integer / max;
+  } else {
+    const max = Math.pow(2, bits) - 1;
+    assert(integer >= 0 && integer <= max);
+    return integer / max;
+  }
+}
+
 // Does not handle clamping, underflow, overflow, denormalized numbers
-export function float32ToFloatBits(n, signBits, exponentBits, fractionBits, bias) {
+export function float32ToFloatBits(n, signBits, exponentBits, mantissaBits, bias) {
   assert(exponentBits <= 8);
-  assert(fractionBits <= 23);
+  assert(mantissaBits <= 23);
   assert(Number.isFinite(n));
 
   if (n === 0) {
@@ -32,21 +50,68 @@
   const bits = buf.getUint32(0, true);
   // bits (32): seeeeeeeefffffffffffffffffffffff
 
-  const fractionBitsToDiscard = 23 - fractionBits;
+  const mantissaBitsToDiscard = 23 - mantissaBits;
 
   // 0 or 1
   const sign = (bits >> 31) & signBits;
 
-  // >> to remove fraction, & to remove sign, - 127 to remove bias.
+  // >> to remove mantissa, & to remove sign, - 127 to remove bias.
   const exp = ((bits >> 23) & 0xff) - 127;
 
   // Convert to the new biased exponent.
   const newBiasedExp = bias + exp;
   assert(newBiasedExp >= 0 && newBiasedExp < 1 << exponentBits);
 
-  // Mask only the fraction, and discard the lower bits.
-  const newFraction = (bits & 0x7fffff) >> fractionBitsToDiscard;
-  return (sign << (exponentBits + fractionBits)) | (newBiasedExp << fractionBits) | newFraction;
+  // Mask only the mantissa, and discard the lower bits.
+  const newMantissa = (bits & 0x7fffff) >> mantissaBitsToDiscard;
+  return (sign << (exponentBits + mantissaBits)) | (newBiasedExp << mantissaBits) | newMantissa;
+}
+
+// Three partial-precision floating-point numbers encoded into a single 32-bit value all
+// sharing the same 5-bit exponent.
+// There is no sign bit, and there is a shared 5-bit biased (15) exponent and a 9-bit
+// mantissa for each channel. The mantissa does NOT have an implicit leading "1.",
+// and instead has an implicit leading "0.".
+export function encodeRGB9E5UFloat(r, g, b) {
+  for (const v of [r, g, b]) {
+    assert(v >= 0 && v < Math.pow(2, 16));
+  }
+
+  const buf = new DataView(new ArrayBuffer(Float32Array.BYTES_PER_ELEMENT));
+  const extractMantissaAndExponent = n => {
+    const mantissaBits = 9;
+    buf.setFloat32(0, n, true);
+    const bits = buf.getUint32(0, true);
+    // >> to remove mantissa, & to remove sign
+    let biasedExponent = (bits >> 23) & 0xff;
+    const mantissaBitsToDiscard = 23 - mantissaBits;
+    let mantissa = (bits & 0x7fffff) >> mantissaBitsToDiscard;
+
+    // RGB9E5UFloat has an implicit leading 0. instead of a leading 1.,
+    // so we need to move the 1. into the mantissa and bump the exponent.
+    // For float32 encoding, the leading 1 is only present if the biased
+    // exponent is non-zero.
+    if (biasedExponent !== 0) {
+      mantissa = (mantissa >> 1) | 0b100000000;
+      biasedExponent += 1;
+    }
+    return { biasedExponent, mantissa };
+  };
+
+  const { biasedExponent: rExp, mantissa: rOrigMantissa } = extractMantissaAndExponent(r);
+  const { biasedExponent: gExp, mantissa: gOrigMantissa } = extractMantissaAndExponent(g);
+  const { biasedExponent: bExp, mantissa: bOrigMantissa } = extractMantissaAndExponent(b);
+
+  // Use the largest exponent, and shift the mantissa accordingly
+  const exp = Math.max(rExp, gExp, bExp);
+  const rMantissa = rOrigMantissa >> (exp - rExp);
+  const gMantissa = gOrigMantissa >> (exp - gExp);
+  const bMantissa = bOrigMantissa >> (exp - bExp);
+
+  const bias = 15;
+  const biasedExp = exp === 0 ? 0 : exp - 127 + bias;
+  assert(biasedExp >= 0 && biasedExp <= 31);
+  return rMantissa | (gMantissa << 9) | (bMantissa << 18) | (biasedExp << 27);
 }
 
 export function assertInIntegerRange(n, bits, signed) {
@@ -61,6 +126,11 @@
 }
 
 export function gammaCompress(n) {
-  n = n <= 0.0031308 ? 12.92 * n : 1.055 * Math.pow(n, 1 / 2.4) - 0.055;
-  return n < 0 ? 0 : n > 1 ? 1 : n;
+  n = n <= 0.0031308 ? (323 * n) / 25 : (211 * Math.pow(n, 5 / 12) - 11) / 200;
+  return clamp(n, 0, 1);
+}
+
+export function gammaDecompress(n) {
+  n = n <= 0.04045 ? (n * 25) / 323 : Math.pow((200 * n + 11) / 211, 12 / 5);
+  return clamp(n, 0, 1);
 }
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/math.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/math.js
index 4761467..ec67f64 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/math.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/math.js
@@ -1,6 +1,7 @@
 /**
  * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
- **/ export function align(n, alignment) {
+ **/ import { assert } from '../../common/framework/util/util.js';
+export function align(n, alignment) {
   return Math.ceil(n / alignment) * alignment;
 }
 
@@ -9,3 +10,8 @@
 }
 
 export const kMaxSafeMultipleOf8 = Number.MAX_SAFE_INTEGER - 7;
+
+export function clamp(n, min, max) {
+  assert(max >= min);
+  return Math.min(Math.max(n, min), max);
+}
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/texture/subresource.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/texture/subresource.js
index 3233f70c..ae6c518 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/texture/subresource.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/texture/subresource.js
@@ -42,3 +42,16 @@
     }
   }
 }
+
+export function mipSize(size, level) {
+  const rShiftMax1 = s => Math.max(s >> level, 1);
+  if (size instanceof Array) {
+    return size.map(rShiftMax1);
+  } else {
+    return {
+      width: rShiftMax1(size.width),
+      height: rShiftMax1(size.height),
+      depth: rShiftMax1(size.depth),
+    };
+  }
+}
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/texture/texelData.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/texture/texelData.js
index 4eb26c4..c96f496 100644
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/texture/texelData.js
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/texture/texelData.js
@@ -1,12 +1,18 @@
 /**
  * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
  **/ import { assert, unreachable } from '../../../common/framework/util/util.js';
-import { kUncompressedTextureFormatInfo } from '../../capability_info.js';
+import {
+  kEncodableTextureFormatInfo,
+  kUncompressedTextureFormatInfo,
+} from '../../capability_info.js';
 import {
   assertInIntegerRange,
   float32ToFloatBits,
   floatAsNormalizedInteger,
   gammaCompress,
+  encodeRGB9E5UFloat,
+  normalizedIntegerAsFloat,
+  gammaDecompress,
 } from '../conversion.js';
 
 export let TexelComponent;
@@ -56,21 +62,26 @@
   type: TexelWriteType.Sint,
 });
 
-const unorm2 = { write: unorm(2), bitLength: 2 };
-const unorm8 = { write: unorm(8), bitLength: 8 };
-const unorm10 = { write: unorm(10), bitLength: 10 };
+const decodeUnorm = bitLength => n => normalizedIntegerAsFloat(n, bitLength, false);
+const decodeSnorm = bitLength => n => normalizedIntegerAsFloat(n, bitLength, true);
+const identity = n => n;
 
-const snorm8 = { write: snorm(8), bitLength: 8 };
+const unorm2 = { decode: decodeUnorm(2), write: unorm(2), bitLength: 2 };
+const unorm8 = { decode: decodeUnorm(8), write: unorm(8), bitLength: 8 };
+const unorm10 = { decode: decodeUnorm(10), write: unorm(10), bitLength: 10 };
 
-const uint8 = { write: uint(8), bitLength: 8 };
-const uint16 = { write: uint(16), bitLength: 16 };
-const uint32 = { write: uint(32), bitLength: 32 };
+const snorm8 = { decode: decodeSnorm(8), write: snorm(8), bitLength: 8 };
 
-const sint8 = { write: sint(8), bitLength: 8 };
-const sint16 = { write: sint(16), bitLength: 16 };
-const sint32 = { write: sint(32), bitLength: 32 };
+const uint8 = { decode: identity, write: uint(8), bitLength: 8 };
+const uint16 = { decode: identity, write: uint(16), bitLength: 16 };
+const uint32 = { decode: identity, write: uint(32), bitLength: 32 };
+
+const sint8 = { decode: identity, write: sint(8), bitLength: 8 };
+const sint16 = { decode: identity, write: sint(16), bitLength: 16 };
+const sint32 = { decode: identity, write: sint(32), bitLength: 32 };
 
 const float10 = {
+  decode: identity,
   write: n => ({
     value: float32ToFloatBits(n, 0, 5, 5, 15),
     type: TexelWriteType.Uint,
@@ -80,6 +91,7 @@
 };
 
 const float11 = {
+  decode: identity,
   write: n => ({
     value: float32ToFloatBits(n, 0, 5, 6, 15),
     type: TexelWriteType.Uint,
@@ -89,6 +101,7 @@
 };
 
 const float16 = {
+  decode: identity,
   write: n => ({
     value: float32ToFloatBits(n, 1, 5, 10, 15),
     type: TexelWriteType.Uint,
@@ -98,6 +111,7 @@
 };
 
 const float32 = {
+  decode: identity,
   write: n => ({
     value: Math.fround(n),
     type: TexelWriteType.Float,
@@ -107,6 +121,7 @@
 };
 
 const componentUnimplemented = {
+  decode: identity,
   write: () => {
     unreachable('TexelComponentInfo not implemented for this texture format');
   },
@@ -201,9 +216,6 @@
 };
 
 class TexelDataRepresentationImpl {
-  // TODO: Determine endianness of the GPU data?
-  isGPULittleEndian = true;
-
   constructor(format, componentOrder, componentInfo, sRGB) {
     this.format = format;
     this.componentOrder = componentOrder;
@@ -217,20 +229,7 @@
     }, 0);
   }
 
-  setComponent(data, component, n) {
-    const componentIndex = this.componentOrder.indexOf(component);
-    assert(componentIndex !== -1);
-    const bitOffset = this.componentOrder.slice(0, componentIndex).reduce((acc, curr) => {
-      const componentInfo = this.componentInfo[curr];
-      assert(!!componentInfo);
-      return acc + componentInfo.bitLength;
-    }, 0);
-
-    const componentInfo = this.componentInfo[component];
-    assert(!!componentInfo);
-    const { write, bitLength } = componentInfo;
-
-    const { value, type } = write(n);
+  writeTexelData(data, bitOffset, bitLength, type, value) {
     switch (type) {
       case TexelWriteType.Float: {
         const byteOffset = Math.floor(bitOffset / 8);
@@ -238,7 +237,7 @@
         assert(byteOffset === bitOffset / 8 && byteLength === bitLength / 8);
         switch (byteLength) {
           case 4:
-            new DataView(data, byteOffset, byteLength).setFloat32(0, value, this.isGPULittleEndian);
+            new DataView(data, byteOffset, byteLength).setFloat32(0, value, true);
             break;
           default:
             unreachable();
@@ -255,10 +254,10 @@
             new DataView(data, byteOffset, byteLength).setInt8(0, value);
             break;
           case 2:
-            new DataView(data, byteOffset, byteLength).setInt16(0, value, this.isGPULittleEndian);
+            new DataView(data, byteOffset, byteLength).setInt16(0, value, true);
             break;
           case 4:
-            new DataView(data, byteOffset, byteLength).setInt32(0, value, this.isGPULittleEndian);
+            new DataView(data, byteOffset, byteLength).setInt32(0, value, true);
             break;
           default:
             unreachable();
@@ -275,20 +274,10 @@
               new DataView(data, byteOffset, byteLength).setUint8(0, value);
               break;
             case 2:
-              new DataView(data, byteOffset, byteLength).setUint16(
-                0,
-                value,
-                this.isGPULittleEndian
-              );
-
+              new DataView(data, byteOffset, byteLength).setUint16(0, value, true);
               break;
             case 4:
-              new DataView(data, byteOffset, byteLength).setUint32(
-                0,
-                value,
-                this.isGPULittleEndian
-              );
-
+              new DataView(data, byteOffset, byteLength).setUint32(0, value, true);
               break;
             default:
               unreachable();
@@ -299,7 +288,7 @@
           switch (this.totalBitLength()) {
             case 32: {
               const view = new DataView(data);
-              const currentValue = view.getUint32(0, this.isGPULittleEndian);
+              const currentValue = view.getUint32(0, true);
 
               let mask = 0xffffffff;
               const bitsToClearRight = bitOffset;
@@ -310,7 +299,7 @@
 
               const newValue = (currentValue & ~mask) | (value << bitOffset);
 
-              view.setUint32(0, newValue, this.isGPULittleEndian);
+              view.setUint32(0, newValue, true);
               break;
             }
             default:
@@ -324,6 +313,55 @@
     }
   }
 
+  getComponentBitOffset(component) {
+    const componentIndex = this.componentOrder.indexOf(component);
+    assert(componentIndex !== -1);
+    return this.componentOrder.slice(0, componentIndex).reduce((acc, curr) => {
+      const componentInfo = this.componentInfo[curr];
+      assert(!!componentInfo);
+      return acc + componentInfo.bitLength;
+    }, 0);
+  }
+
+  setComponent(data, component, n) {
+    const bitOffset = this.getComponentBitOffset(component);
+    const componentInfo = this.componentInfo[component];
+    assert(!!componentInfo);
+    const { write, bitLength } = componentInfo;
+
+    const { value, type } = write(n);
+    this.writeTexelData(data, bitOffset, bitLength, type, value);
+  }
+
+  setComponentBytes(data, component, value) {
+    assert(this.format in kEncodableTextureFormatInfo);
+    const format = this.format;
+
+    const componentInfo = this.componentInfo[component];
+    assert(!!componentInfo);
+
+    const bitOffset = this.getComponentBitOffset(component);
+    const { bitLength } = componentInfo;
+
+    switch (kEncodableTextureFormatInfo[format].dataType) {
+      case 'float':
+      case 'ufloat':
+        // Use the shader encoding which can pack floats as uint data.
+        this.setComponent(data, component, value);
+        break;
+      case 'snorm':
+      case 'sint': {
+        this.writeTexelData(data, bitOffset, bitLength, TexelWriteType.Sint, value);
+        break;
+      }
+      case 'unorm':
+      case 'uint': {
+        this.writeTexelData(data, bitOffset, bitLength, TexelWriteType.Uint, value);
+        break;
+      }
+    }
+  }
+
   getBytes(components) {
     if (this.sRGB) {
       components = Object.assign({}, components);
@@ -340,6 +378,26 @@
     const bytesPerBlock = kUncompressedTextureFormatInfo[this.format].bytesPerBlock;
     assert(!!bytesPerBlock);
 
+    if (this.format === 'rgb9e5ufloat') {
+      assert(this.componentOrder.length === 3);
+      assert(this.componentOrder[0] === TexelComponent.R);
+      assert(this.componentOrder[1] === TexelComponent.G);
+      assert(this.componentOrder[2] === TexelComponent.B);
+      assert(bytesPerBlock === 4);
+      assert(components.R !== undefined);
+      assert(components.G !== undefined);
+      assert(components.B !== undefined);
+
+      const buf = new ArrayBuffer(bytesPerBlock);
+      new DataView(buf).setUint32(
+        0,
+        encodeRGB9E5UFloat(components.R, components.G, components.B),
+        true
+      );
+
+      return buf;
+    }
+
     const data = new ArrayBuffer(bytesPerBlock);
     for (const c of this.componentOrder) {
       const componentValue = components[c];
@@ -348,6 +406,61 @@
     }
     return data;
   }
+
+  packData(components) {
+    const bytesPerBlock = kUncompressedTextureFormatInfo[this.format].bytesPerBlock;
+    assert(!!bytesPerBlock);
+
+    if (this.format === 'rgb9e5ufloat') {
+      assert(this.componentOrder.length === 3);
+      assert(this.componentOrder[0] === TexelComponent.R);
+      assert(this.componentOrder[1] === TexelComponent.G);
+      assert(this.componentOrder[2] === TexelComponent.B);
+      assert(bytesPerBlock === 4);
+      assert(components.R !== undefined);
+      assert(components.G !== undefined);
+      assert(components.B !== undefined);
+
+      const buf = new ArrayBuffer(bytesPerBlock);
+      new DataView(buf).setUint32(
+        0,
+        encodeRGB9E5UFloat(components.R, components.G, components.B),
+        true
+      );
+
+      return buf;
+    }
+
+    const data = new ArrayBuffer(bytesPerBlock);
+    for (const c of this.componentOrder) {
+      const componentValue = components[c];
+      assert(componentValue !== undefined);
+      this.setComponentBytes(data, c, componentValue);
+    }
+    return data;
+  }
+
+  decode(components) {
+    const values = {};
+    for (const c of this.componentOrder) {
+      const componentValue = components[c];
+      const info = this.componentInfo[c];
+      assert(componentValue !== undefined);
+      assert(!!info);
+      values[c] = info.decode(componentValue);
+    }
+    if (this.sRGB) {
+      assert('R' in values && values.R !== undefined);
+      assert('G' in values && values.G !== undefined);
+      assert('B' in values && values.B !== undefined);
+      [values.R, values.G, values.B] = [
+        gammaDecompress(values.R),
+        gammaDecompress(values.G),
+        gammaDecompress(values.B),
+      ];
+    }
+    return values;
+  }
 }
 
 const kRepresentationCache = new Map();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/texture/texelData.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/texture/texelData.spec.js
new file mode 100644
index 0000000..03ff8d6
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/util/texture/texelData.spec.js
@@ -0,0 +1,340 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description =
+  'Test helpers for texel data produce the expected data in the shader';
+import { params, poptions } from '../../../common/framework/params_builder.js';
+import { makeTestGroup } from '../../../common/framework/test_group.js';
+import { unreachable, assert } from '../../../common/framework/util/util.js';
+import { kEncodableTextureFormats, kEncodableTextureFormatInfo } from '../../capability_info.js';
+import { GPUTest } from '../../gpu_test.js';
+
+import { getTexelDataRepresentation } from './texelData.js';
+
+export const g = makeTestGroup(GPUTest);
+
+let ReadbackTypedArray;
+
+function doTest(t) {
+  const { format } = t.params;
+  const componentData = (() => {
+    const { R, G, B, A } = t.params;
+    return { R, G, B, A };
+  })();
+
+  const rep = getTexelDataRepresentation(format);
+  const texelData = rep.packData(componentData);
+  const texture = t.device.createTexture({
+    format,
+    size: [1, 1, 1],
+    usage: GPUTextureUsage.COPY_DST | GPUTextureUsage.SAMPLED,
+  });
+
+  t.device.defaultQueue.writeTexture(
+    { texture },
+    texelData,
+    {
+      bytesPerRow: texelData.byteLength,
+    },
+
+    [1]
+  );
+
+  let shaderType;
+  switch (kEncodableTextureFormatInfo[format].componentType) {
+    case 'sint':
+      ReadbackTypedArray = Int32Array;
+      shaderType = 'i32';
+      break;
+    case 'uint':
+      ReadbackTypedArray = Uint32Array;
+      shaderType = 'u32';
+      break;
+    case 'float':
+      ReadbackTypedArray = Float32Array;
+      shaderType = 'f32';
+      break;
+    default:
+      unreachable();
+  }
+
+  const shader = `
+  [[set(0), binding(0)]] var<uniform_constant> tex : texture_2d<${shaderType}>;
+
+  [[block]] struct Output {
+    ${rep.componentOrder
+      .map((C, i) => `[[offset(${i * 4})]] result${C} : ${shaderType};`)
+      .join('\n')}
+  };
+  [[set(0), binding(1)]] var<storage_buffer> output : Output;
+
+  [[stage(compute)]]
+  fn main() -> void {
+      var texel : vec4<${shaderType}> = textureLoad(tex, vec2<i32>(0, 0), 0);
+      ${rep.componentOrder.map(C => `output.result${C} = texel.${C.toLowerCase()};`).join('\n')}
+      return;
+  }`;
+
+  const pipeline = t.device.createComputePipeline({
+    computeStage: {
+      module: t.device.createShaderModule({
+        code: shader,
+      }),
+
+      entryPoint: 'main',
+    },
+  });
+
+  const outputBuffer = t.device.createBuffer({
+    size: rep.componentOrder.length * 4,
+    usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
+  });
+
+  const bindGroup = t.device.createBindGroup({
+    layout: pipeline.getBindGroupLayout(0),
+    entries: [
+      {
+        binding: 0,
+        resource: texture.createView(),
+      },
+
+      {
+        binding: 1,
+        resource: {
+          buffer: outputBuffer,
+        },
+      },
+    ],
+  });
+
+  const encoder = t.device.createCommandEncoder();
+  const pass = encoder.beginComputePass();
+  pass.setPipeline(pipeline);
+  pass.setBindGroup(0, bindGroup);
+  pass.dispatch(1);
+  pass.endPass();
+  t.device.defaultQueue.submit([encoder.finish()]);
+
+  t.expectContents(
+    outputBuffer,
+    new ReadbackTypedArray(
+      rep.componentOrder.map(c => {
+        const value = rep.decode(componentData)[c];
+        assert(value !== undefined);
+        return value;
+      })
+    )
+  );
+}
+
+// Make a test parameter by mapping a format and each component to a texel component
+// data value.
+function makeParam(format, fn) {
+  const rep = getTexelDataRepresentation(format);
+  return {
+    R: rep.componentInfo.R ? fn(rep.componentInfo.R.bitLength, 0) : undefined,
+    G: rep.componentInfo.G ? fn(rep.componentInfo.G.bitLength, 1) : undefined,
+    B: rep.componentInfo.B ? fn(rep.componentInfo.B.bitLength, 2) : undefined,
+    A: rep.componentInfo.A ? fn(rep.componentInfo.A.bitLength, 3) : undefined,
+  };
+}
+
+g.test('unorm_texel_data_in_shader')
+  .params(
+    params()
+      .combine(poptions('format', kEncodableTextureFormats))
+      .filter(({ format }) => {
+        return (
+          kEncodableTextureFormatInfo[format].copyDst &&
+          kEncodableTextureFormatInfo[format].color &&
+          kEncodableTextureFormatInfo[format].dataType === 'unorm'
+        );
+      })
+      .expand(({ format }) => {
+        const max = bitLength => Math.pow(2, bitLength) - 1;
+        return [
+          // Test extrema
+          makeParam(format, () => 0),
+          makeParam(format, bitLength => max(bitLength)),
+
+          // Test a middle value
+          makeParam(format, bitLength => Math.floor(max(bitLength) / 2)),
+
+          // Test mixed values
+          makeParam(format, (bitLength, i) => {
+            const offset = [0.13, 0.63, 0.42, 0.89];
+            return Math.floor(offset[i] * max(bitLength));
+          }),
+        ];
+      })
+  )
+  .fn(doTest);
+
+g.test('snorm_texel_data_in_shader')
+  .params(
+    params()
+      .combine(poptions('format', kEncodableTextureFormats))
+      .filter(({ format }) => {
+        return (
+          kEncodableTextureFormatInfo[format].copyDst &&
+          kEncodableTextureFormatInfo[format].color &&
+          kEncodableTextureFormatInfo[format].dataType === 'snorm'
+        );
+      })
+      .expand(({ format }) => {
+        const max = bitLength => Math.pow(2, bitLength - 1) - 1;
+        return [
+          // Test extrema
+          makeParam(format, () => 0),
+          makeParam(format, bitLength => max(bitLength)),
+          makeParam(format, bitLength => -max(bitLength)),
+          makeParam(format, bitLength => -max(bitLength) - 1),
+
+          // Test a middle value
+          makeParam(format, bitLength => Math.floor(max(bitLength) / 2)),
+
+          // Test mixed values
+          makeParam(format, (bitLength, i) => {
+            const offset = [0.13, 0.63, 0.42, 0.89];
+            const range = 2 * max(bitLength);
+            return -max(bitLength) + Math.floor(offset[i] * range);
+          }),
+        ];
+      })
+  )
+  .fn(doTest);
+
+g.test('uint_texel_data_in_shader')
+  .params(
+    params()
+      .combine(poptions('format', kEncodableTextureFormats))
+      .filter(({ format }) => {
+        return (
+          kEncodableTextureFormatInfo[format].copyDst &&
+          kEncodableTextureFormatInfo[format].color &&
+          kEncodableTextureFormatInfo[format].dataType === 'uint'
+        );
+      })
+      .expand(({ format }) => {
+        const max = bitLength => Math.pow(2, bitLength) - 1;
+        return [
+          // Test extrema
+          makeParam(format, () => 0),
+          makeParam(format, bitLength => max(bitLength)),
+
+          // Test a middle value
+          makeParam(format, bitLength => Math.floor(max(bitLength) / 2)),
+
+          // Test mixed values
+          makeParam(format, (bitLength, i) => {
+            const offset = [0.13, 0.63, 0.42, 0.89];
+            return Math.floor(offset[i] * max(bitLength));
+          }),
+        ];
+      })
+  )
+  .fn(doTest);
+
+g.test('sint_texel_data_in_shader')
+  .params(
+    params()
+      .combine(poptions('format', kEncodableTextureFormats))
+      .filter(({ format }) => {
+        return (
+          kEncodableTextureFormatInfo[format].copyDst &&
+          kEncodableTextureFormatInfo[format].color &&
+          kEncodableTextureFormatInfo[format].dataType === 'sint'
+        );
+      })
+      .expand(({ format }) => {
+        const max = bitLength => Math.pow(2, bitLength - 1) - 1;
+        return [
+          // Test extrema
+          makeParam(format, () => 0),
+          makeParam(format, bitLength => max(bitLength)),
+          makeParam(format, bitLength => -max(bitLength) - 1),
+
+          // Test a middle value
+          makeParam(format, bitLength => Math.floor(max(bitLength) / 2)),
+
+          // Test mixed values
+          makeParam(format, (bitLength, i) => {
+            const offset = [0.13, 0.63, 0.42, 0.89];
+            const range = 2 * max(bitLength);
+            return -max(bitLength) + Math.floor(offset[i] * range);
+          }),
+        ];
+      })
+  )
+  .fn(doTest);
+
+g.test('float_texel_data_in_shader')
+  .params(
+    params()
+      .combine(poptions('format', kEncodableTextureFormats))
+      .filter(({ format }) => {
+        return (
+          kEncodableTextureFormatInfo[format].copyDst &&
+          kEncodableTextureFormatInfo[format].color &&
+          kEncodableTextureFormatInfo[format].dataType === 'float'
+        );
+      })
+      .expand(({ format }) => {
+        return [
+          // Test extrema
+          makeParam(format, () => 0),
+
+          // TODO: Test NaN, Infinity, -Infinity
+
+          // Test some values
+          makeParam(format, () => 0.1199951171875),
+          makeParam(format, () => 1.4072265625),
+          makeParam(format, () => 24928),
+          makeParam(format, () => -0.1319580078125),
+          makeParam(format, () => -323.25),
+          makeParam(format, () => -7440),
+
+          // Test mixed values
+          makeParam(format, (bitLength, i) => {
+            return [24896, -0.1319580078125, -323.25, -234.375][i];
+          }),
+        ];
+      })
+  )
+  .fn(doTest);
+
+g.test('ufloat_texel_data_in_shader')
+  .params(
+    params()
+      .combine(poptions('format', kEncodableTextureFormats))
+      .filter(({ format }) => {
+        return (
+          kEncodableTextureFormatInfo[format].copyDst &&
+          kEncodableTextureFormatInfo[format].color &&
+          kEncodableTextureFormatInfo[format].dataType === 'ufloat'
+        );
+      })
+      .expand(({ format }) => {
+        return [
+          // Test extrema
+          makeParam(format, () => 0),
+
+          // TODO: Test NaN, Infinity
+
+          // Test some values
+          makeParam(format, () => 0.119140625),
+          makeParam(format, () => 1.40625),
+          makeParam(format, () => 24896),
+
+          // Test scattered mixed values
+          makeParam(format, (bitLength, i) => {
+            return [24896, 1.40625, 0.119140625, 0.23095703125][i];
+          }),
+
+          // Test mixed values that are close in magnitude.
+          makeParam(format, (bitLength, i) => {
+            return [0.1337890625, 0.17919921875, 0.119140625, 0.125][i];
+          }),
+        ];
+      })
+  )
+  .fn(doTest);
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/canvas/context_creation.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/canvas/context_creation.spec.js
deleted file mode 100644
index 26dc5d8..0000000
--- a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/canvas/context_creation.spec.js
+++ /dev/null
@@ -1,24 +0,0 @@
-/**
- * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
- **/ export const description = '';
-import { Fixture } from '../../../common/framework/fixture.js';
-import { makeTestGroup } from '../../../common/framework/test_group.js';
-
-export const g = makeTestGroup(Fixture);
-
-g.test('canvas_element_getContext_returns_GPUCanvasContext').fn(async t => {
-  if (typeof document === 'undefined') {
-    // Skip if there is no document (Workers, Node)
-    t.skip('DOM is not available to create canvas element');
-  }
-
-  const canvas = document.createElement('canvas');
-  canvas.width = 10;
-  canvas.height = 10;
-
-  // TODO: fix types so these aren't necessary
-
-  const ctx = canvas.getContext('gpupresent');
-
-  t.expect(ctx instanceof window.GPUCanvasContext);
-});
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/canvas/context_creation.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/canvas/context_creation.spec.js
new file mode 100644
index 0000000..df32805
--- /dev/null
+++ b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/canvas/context_creation.spec.js
@@ -0,0 +1,32 @@
+/**
+ * AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
+ **/ export const description = '';
+import { Fixture } from '../../../common/framework/fixture.js';
+import { makeTestGroup } from '../../../common/framework/test_group.js';
+
+export const g = makeTestGroup(Fixture);
+
+g.test('return_type')
+  .desc(
+    `Test the return type of getContext for WebGPU.
+
+TODO: Test all combinations of context creation attributes.`
+  )
+  .fn(async t => {
+    if (typeof document === 'undefined') {
+      // Skip if there is no document (Workers, Node)
+      t.skip('DOM is not available to create canvas element');
+    }
+
+    const canvas = document.createElement('canvas');
+    canvas.width = 10;
+    canvas.height = 10;
+
+    // TODO: fix types so these aren't necessary
+
+    const ctx = canvas.getContext('gpupresent');
+
+    t.expect(ctx instanceof window.GPUCanvasContext);
+  });
+
+g.test('attributes_idl').desc('Tests invalid context creation attribute values.').unimplemented();
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/copyImageBitmapToTexture.spec.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/copyImageBitmapToTexture.spec.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/copyImageBitmapToTexture.spec.js
rename to third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/copyImageBitmapToTexture.spec.js
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_clear.html b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_clear.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_clear.html
rename to third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_clear.html
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_clear.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_clear.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_clear.js
rename to third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_clear.js
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_complex.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_complex.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_complex.js
rename to third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_complex.js
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_complex_bgra8unorm.html b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_complex_bgra8unorm.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/canvas_complex_bgra8unorm.html
rename to third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/canvas_complex_bgra8unorm.html
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/gpu_ref_test.js b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/gpu_ref_test.js
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/gpu_ref_test.js
rename to third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/gpu_ref_test.js
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/ref/canvas_clear-ref.html b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/ref/canvas_clear-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/ref/canvas_clear-ref.html
rename to third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/ref/canvas_clear-ref.html
diff --git a/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/ref/canvas_complex-ref.html b/third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/ref/canvas_complex-ref.html
similarity index 100%
rename from third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web-platform/reftests/ref/canvas_complex-ref.html
rename to third_party/blink/web_tests/wpt_internal/webgpu/webgpu/web_platform/reftests/ref/canvas_complex-ref.html
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index d1c630d..a17e0b8 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -37457,6 +37457,7 @@
 <enum name="IMEAutocorrectActions">
   <int value="0" label="WINDOW_SHOWN"/>
   <int value="1" label="UNDERLINED"/>
+  <int value="2" label="REVERTED"/>
 </enum>
 
 <enum name="IMECommitType">
@@ -50317,6 +50318,16 @@
       label="Histogram active sample wrapped 2^31 during accumulation."/>
 </enum>
 
+<enum name="NeighborLinkMonitorFailureType">
+  <int value="0" label="Unknown type of failure"/>
+  <int value="1" label="IPv4 gateway neighbor lost"/>
+  <int value="2" label="IPv4 DNS server neighbor lost"/>
+  <int value="3" label="IPv4 gateway and DNS server neighbor lost"/>
+  <int value="4" label="IPv6 gateway neighbor lost"/>
+  <int value="5" label="IPv6 DNS server neighbor lost"/>
+  <int value="6" label="IPv6 gateway and DNS server neighbor lost"/>
+</enum>
+
 <enum name="NetCacheState">
   <int value="0" label="FROM_CACHE"/>
   <int value="1" label="STILL_VALID"/>
diff --git a/tools/metrics/histograms/histograms_xml/cookie/histograms.xml b/tools/metrics/histograms/histograms_xml/cookie/histograms.xml
index 0c8ae0b..2b9f670f 100644
--- a/tools/metrics/histograms/histograms_xml/cookie/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/cookie/histograms.xml
@@ -297,9 +297,9 @@
   <owner>chlily@chromium.org</owner>
   <summary>
     This records if a cookie is being read by the same port value that set it
-    (the source port). See Cookie.Port.Set.{HostType} and
-    Cookie.Port.Read.{HostType} for more information on how the port value for
-    setting and reading (respectively) is obtained.
+    (the source port). See Cookie.Port.Set.* and Cookie.Port.Read.* for more
+    information on how the port value for setting and reading (respectively) is
+    obtained.
 
     If the source port is unspecified (due to a cookie already existing before
     we started to record this value) or invalid (due to corruption) then this
@@ -307,11 +307,16 @@
 
     The &quot;Localhost&quot; variant of this metric is recorded only for
     localhost origns. The &quot;RemoteHost&quot; variant is recorded for all
-    other origins.
+    other origins. The &quot;DomainSet&quot; variant of this metric is recorded
+    for all cookies which have the Domain attribute set (localhost and IP
+    addresses cannot set the Domain attribute and therefore will not trigger
+    this metric. Put technically, the origin must have a non-empty registrable
+    domain to set the Domain attribute).
 
     This metric is recorded once per included cookie on every read attempt.
   </summary>
   <token key="HostType">
+    <variant name="DomainSet"/>
     <variant name="Localhost"/>
     <variant name="RemoteHost"/>
   </token>
diff --git a/tools/metrics/histograms/histograms_xml/download/histograms.xml b/tools/metrics/histograms/histograms_xml/download/histograms.xml
index e75cc13..8a80ebf 100644
--- a/tools/metrics/histograms/histograms_xml/download/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/download/histograms.xml
@@ -489,6 +489,17 @@
   <summary>The number of unopened downloads, when one is opened.</summary>
 </histogram>
 
+<histogram name="Download.OverwrittenDownloadRemovedFromHistory"
+    units="downloads" expires_after="2021-06-01">
+  <owner>qinmin@chromium.org</owner>
+  <owner>chrome-downloads@google.com</owner>
+  <summary>
+    Records the number of overwritten downloads that are cleaned up from
+    Chrome://downloads history. Recorded after loading all the downloads from
+    history DB.
+  </summary>
+</histogram>
+
 <histogram name="Download.ParallelDownload.CreationEvent"
     enum="ParallelDownloadCreationEvent" expires_after="2020-12-06">
   <obsolete>
diff --git a/tools/metrics/histograms/histograms_xml/input/histograms.xml b/tools/metrics/histograms/histograms_xml/input/histograms.xml
index 0fa9e15..a366885f 100644
--- a/tools/metrics/histograms/histograms_xml/input/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/input/histograms.xml
@@ -399,6 +399,11 @@
 
 <histogram name="InputMethod.Mojo.Extension.ActivateIMELatency" units="ms"
     expires_after="2019-12-30">
+  <obsolete>
+    Obsolete since Q4 2019. Officially deprecated Nov 2020. This was meant for
+    rule-based input methods via extension and IME service, but as at circa Q4
+    2019, rule-based input methods stopped going through the extension.
+  </obsolete>
   <owner>googleo@chromium.org</owner>
   <owner>shuchen@chromium.org</owner>
   <owner>essential-inputs-team@google.com</owner>
@@ -419,6 +424,11 @@
 
 <histogram name="InputMethod.Mojo.Extension.Rulebased.ProcessLatency"
     units="ms" expires_after="2019-12-31">
+  <obsolete>
+    Obsolete since Q4 2019. Officially deprecated Nov 2020. This was meant for
+    rule-based input methods via extension and IME service, but as at circa Q4
+    2019, rule-based input methods stopped going through the extension.
+  </obsolete>
   <owner>shend@chromium.org</owner>
   <owner>essential-inputs-team@google.com</owner>
   <summary>
@@ -429,6 +439,11 @@
 
 <histogram name="InputMethod.Mojo.Extension.ServiceInitLatency" units="ms"
     expires_after="2019-12-31">
+  <obsolete>
+    Obsolete since Q4 2019. Officially deprecated Nov 2020. This was meant for
+    rule-based input methods via extension and IME service, but as at circa Q4
+    2019, rule-based input methods stopped going through the extension.
+  </obsolete>
   <owner>shend@chromium.org</owner>
   <owner>essential-inputs-team@google.com</owner>
   <summary>
diff --git a/tools/metrics/histograms/histograms_xml/network/histograms.xml b/tools/metrics/histograms/histograms_xml/network/histograms.xml
index c1b8e93..a0134d88 100644
--- a/tools/metrics/histograms/histograms_xml/network/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/network/histograms.xml
@@ -1386,6 +1386,17 @@
   </summary>
 </histogram>
 
+<histogram name="Network.Shill.Wifi.NeighborLinkMonitorFailure"
+    enum="NeighborLinkMonitorFailureType" expires_after="2021-12-01">
+  <owner>jiejiang@chromium.org</owner>
+  <owner>cros-network-metrics@google.com</owner>
+  <summary>
+    Chrome OS metric that signals the type of failure the NeighborLinkMonitor
+    detected on 802.11 wireless network. Recorded after the NeighborLinkMonitor
+    detects a layer 2 connectivity failure to a neighbor.
+  </summary>
+</histogram>
+
 <histogram name="Network.Shill.Wifi.NetworkConnectionIPType"
     enum="NetworkConnectionIPType" expires_after="2021-12-01">
   <owner>briannorris@chromium.org</owner>
diff --git a/tools/metrics/histograms/histograms_xml/others/histograms.xml b/tools/metrics/histograms/histograms_xml/others/histograms.xml
index 8533ad2e..a67a3eb 100644
--- a/tools/metrics/histograms/histograms_xml/others/histograms.xml
+++ b/tools/metrics/histograms/histograms_xml/others/histograms.xml
@@ -7684,25 +7684,43 @@
 
 <histogram name="LanguageUsage.AcceptLanguage" enum="LanguageCode"
     expires_after="2021-04-04">
-  <owner>anthonyvd@chromium.org</owner>
-  <owner>frechette@chromium.org</owner>
+  <owner>perrier@chromium.org</owner>
   <owner>chrome-language@google.com</owner>
-  <summary>Accept languages.</summary>
+  <summary>
+    Accept languages with country codes removed. Recorded once per profile
+    intitalization. Incognito profiles are ignored.
+  </summary>
 </histogram>
 
 <histogram name="LanguageUsage.AcceptLanguage.Count" units="units"
     expires_after="2021-06-01">
   <owner>dvallet@chromium.org</owner>
   <owner>chrome-language@google.com</owner>
-  <summary>The number of accepted languages in the user preferences.</summary>
+  <summary>
+    The number of accepted languages in the user preferences recored once per
+    profile initialization. Incognito profiles are ignored.
+  </summary>
 </histogram>
 
 <histogram name="LanguageUsage.ApplicationLanguage" enum="LanguageCode"
     expires_after="2021-04-04">
-  <owner>anthonyvd@chromium.org</owner>
-  <owner>frechette@chromium.org</owner>
+  <owner>perrier@chromium.org</owner>
   <owner>chrome-language@google.com</owner>
-  <summary>Application languages used for UI.</summary>
+  <summary>
+    Application languages used for UI recorded once per profile initialization.
+    Incognito profiles are ignored.
+  </summary>
+</histogram>
+
+<histogram name="LanguageUsage.MostFrequentPageLanguages" enum="LanguageCode"
+    expires_after="M90">
+  <owner>perrier@chromium.org</owner>
+  <owner>chrome-language@google.com</owner>
+  <summary>
+    Source page language from UrlLanguageHistogram recorded one per profile
+    during initialization. Each language with a frequency over 5% is recorded
+    once. Incognito profiles are ignored and not recorded on ChromeOS.
+  </summary>
 </histogram>
 
 <histogram name="Launch.FlagsAtStartup" enum="LoginCustomFlags"
@@ -14930,6 +14948,21 @@
   <token key="TextFragmentSource" variants="TextFragmentSource"/>
 </histogram>
 
+<histogram name="TextFragmentAnchor{TextFragmentSource}.SpansMultipleBlocks"
+    units="Boolean" expires_after="2021-05-20">
+  <owner>bokan@chromium.org</owner>
+  <owner>input-dev@chromium.org</owner>
+  <summary>
+    Whether or not a range-based text fragment match crosses any block
+    boundaries. That is, the start and end of the range are in different blocks
+    or in the same block but contain an intervening block. Only recorded for
+    range-based (start,end) text fragments. Only recorded on successful match.
+
+    Recorded from text fragment links followed from {TextFragmentSource}.
+  </summary>
+  <token key="TextFragmentSource" variants="TextFragmentSource"/>
+</histogram>
+
 <histogram name="TextFragmentAnchor{TextFragmentSource}.StartTextLength"
     units="characters" expires_after="2021-03-07">
   <owner>nburris@chromium.org</owner>
diff --git a/tools/metrics/structured/codegen.py b/tools/metrics/structured/codegen.py
index 20bb70c..8526d49 100644
--- a/tools/metrics/structured/codegen.py
+++ b/tools/metrics/structured/codegen.py
@@ -8,14 +8,18 @@
 import os
 import re
 import struct
-from model import _EVENT_TYPE, _EVENTS_TYPE
-from model import _PROJECT_TYPE, _PROJECTS_TYPE
+from model import _EVENT_TYPE
+from model import _PROJECT_TYPE
 from model import _METRIC_TYPE
 
 
 def sanitize_name(name):
-  s = re.sub('[^0-9a-zA-Z_]', '_', name)
-  return s
+  return re.sub('[^0-9a-zA-Z_]', '_', name)
+
+
+def camel_to_snake(name):
+  pat = '((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))'
+  return re.sub(pat, r'_\1', name).lower()
 
 
 def HashName(name):
@@ -30,28 +34,32 @@
     self.guard_path = sanitize_name(os.path.join(relpath, basename)).upper()
 
 
-class EventInfo(object):
-  def __init__(self, event_obj, project_obj):
-    self.raw_name = event_obj['name']
-    self.name = sanitize_name(event_obj['name'])
-    self.name_hash = HashName(event_obj['name'])
-
-    project_name = sanitize_name(project_obj['name'])
-    self.project_name_hash = HashName(project_name)
+class ProjectInfo(object):
+  def __init__(self, project_obj):
+    self.name = sanitize_name(project_obj['name'])
+    self.namespace = camel_to_snake(self.name)
+    self.name_hash = HashName(self.name)
 
     id_type = project_obj['id']['text']
     if id_type == 'uma':
-      self.project_id_type = 'kUmaId'
+      self.id_type = 'kUmaId'
     elif id_type == 'per-project':
-      self.project_id_type = 'kProjectId'
+      self.id_type = 'kProjectId'
     elif id_type == 'none':
-      self.project_id_type = 'kUnidentified'
+      self.id_type = 'kUnidentified'
     else:
       raise Exception(
-          "Structured metrics event '{}' has invalid id field '{}'".format(
+          "Structured metrics project '{}' has invalid id field '{}'".format(
               self.name, id_type))
 
 
+class EventInfo(object):
+  def __init__(self, event_obj):
+    self.raw_name = event_obj['name']
+    self.name = sanitize_name(event_obj['name'])
+    self.name_hash = HashName(event_obj['name'])
+
+
 class MetricInfo(object):
   def __init__(self, json_obj):
     self.raw_name = json_obj['name']
@@ -66,12 +74,15 @@
     else:
       raise Exception("Unexpected metric kind: " + json_obj['kind'])
 
+
 class Template(object):
   """Template for producing code from structured.xml."""
 
-  def __init__(self, basename, file_template, event_template, metric_template):
+  def __init__(self, basename, file_template, project_template, event_template,
+               metric_template):
     self.basename = basename
     self.file_template = file_template
+    self.project_template = project_template
     self.event_template = event_template
     self.metric_template = metric_template
 
@@ -83,47 +94,48 @@
         event=event_info,
         metric=MetricInfo(metric))
 
-  def _StampEventCode(self, file_info, event, project):
+  def _StampEventCode(self, file_info, project_info, event):
     """Stamp an event class by creating a skeleton of the class based on the
     event name, and then stamping code for each metric within it."""
-    event_info = EventInfo(event, project)
+    event_info = EventInfo(event)
     metric_code = ''.join(
         self._StampMetricCode(file_info, event_info, metric)
         for metric in event[_METRIC_TYPE.tag])
-    return self.event_template.format(
-        file=file_info,
-        event=event_info,
-        metric_code=metric_code)
+    return self.event_template.format(file=file_info,
+                                      project=project_info,
+                                      event=event_info,
+                                      metric_code=metric_code)
+
+  def _StampProjectCode(self, file_info, project):
+    """Stamp a project by stamping classes for all constituent events."""
+    project_info = ProjectInfo(project)
+    event_code = ''.join(
+        self._StampEventCode(file_info, project_info, event)
+        for event in project[_EVENT_TYPE.tag])
+    return self.project_template.format(file=file_info,
+                                        project=project_info,
+                                        event_code=event_code)
 
   def _StampFileCode(self, relpath, data):
-    """Stamp a file by creating a class for each event, and a list of all event
-    name hashes."""
+    """Stamp a file by creating a class for each event within each project, and
+    a list of all project name hashes."""
     file_info = FileInfo(relpath, self.basename)
-    event_code = []
 
-    project_name_hashes = set()
-    defined_projects = {
-        project['name']: project
-        for project in data[_PROJECTS_TYPE.tag][_PROJECT_TYPE.tag]
-    }
-    for event in data[_EVENTS_TYPE.tag][_EVENT_TYPE.tag]:
-      defined_project = defined_projects.get(event.get('project'))
-      event_code.append(self._StampEventCode(file_info, event, defined_project))
-      project_name_hashes.add(
-          defined_project['name'] if defined_project else event['name'])
+    project_code = [
+        self._StampProjectCode(file_info, project)
+        for project in data[_PROJECT_TYPE.tag]
+    ]
+    project_code = ''.join(project_code)
 
-    event_code = ''.join(event_code)
-
+    project_names = {project['name'] for project in data[_PROJECT_TYPE.tag]}
     project_name_hashes = [
-        'UINT64_C(%s)' % HashName(name)
-        for name in sorted(list(project_name_hashes))
+        'UINT64_C(%s)' % HashName(name) for name in sorted(list(project_names))
     ]
     project_name_hashes = '{' + ', '.join(project_name_hashes) + '}'
 
-    return self.file_template.format(
-        file=file_info,
-        event_code=event_code,
-        project_name_hashes=project_name_hashes)
+    return self.file_template.format(file=file_info,
+                                     project_code=project_code,
+                                     project_name_hashes=project_name_hashes)
 
   def WriteFile(self, outdir, relpath, data):
     """Generates code and writes it to a file.
diff --git a/tools/metrics/structured/compile_time_validation.py b/tools/metrics/structured/compile_time_validation.py
index c2f4e635..18255d4 100644
--- a/tools/metrics/structured/compile_time_validation.py
+++ b/tools/metrics/structured/compile_time_validation.py
@@ -5,69 +5,70 @@
 
 from collections import Counter
 from model import _METRIC_TYPE
-from model import _EVENT_TYPE, _EVENTS_TYPE
-from model import _PROJECT_TYPE, _PROJECTS_TYPE
+from model import _EVENT_TYPE
+from model import _PROJECT_TYPE
 
 
 def projectsHaveRequiredFields(data):
   """Check that projects have all fields required for compilation."""
-  for project in data[_PROJECTS_TYPE.tag][_PROJECT_TYPE.tag]:
+  valid_id_types = {'none', 'per-project', 'uma'}
+
+  for project in data[_PROJECT_TYPE.tag]:
     if 'name' not in project:
       raise Exception('Structured metrics project has no name')
+
     if 'id' not in project:
       raise Exception("Structured metrics project '{}' has no id field.".format(
           project['name']))
+    if project['id']['text'] not in valid_id_types:
+      raise Exception(
+          "Structured metrics project '{}' has invalid id field.".format(
+              project['name']))
 
   name_counts = Counter(
       project['name']
-      for project in data[_PROJECTS_TYPE.tag][_PROJECT_TYPE.tag])
+      for project in data[_PROJECT_TYPE.tag])
   for name, count in name_counts.items():
     if count != 1:
       raise Exception(
           "Structured metrics projects have duplicate name '{}'.".format(name))
 
 
-def eventsReferenceValidProjects(data):
-  """Check that any project referenced by an event exists."""
-  projects = {
-      project['name']: project
-      for project in data[_PROJECTS_TYPE.tag][_PROJECT_TYPE.tag]
-  }
-  for event in data[_EVENTS_TYPE.tag][_EVENT_TYPE.tag]:
-    project_name = event.get('project')
-    project = projects.get(project_name)
-    if project is None and project_name is not None:
-      raise Exception(("Structured metrics event '{}' references "
-                       "nonexistent project '{}'.").format(
-                           event['name'], project_name))
-
-
 def metricNamesUniqueWithinEvent(data):
   """Check that no two metrics within an event have the same name."""
-  for event in data[_EVENTS_TYPE.tag][_EVENT_TYPE.tag]:
-    name_counts = Counter(metric['name'] for metric in event[_METRIC_TYPE.tag])
-    for name, count in name_counts.items():
-      if count != 1:
-        raise Exception(("Structured metrics event '{}' has duplicated metric "
-                         "name '{}'.").format(event['name'], name))
+  for project in data[_PROJECT_TYPE.tag]:
+    for event in project[_EVENT_TYPE.tag]:
+      name_counts = Counter(
+        metric['name']
+        for metric in event[_METRIC_TYPE.tag])
+
+      for name, count in name_counts.items():
+        if count != 1:
+          raise Exception(("Structured metrics project '{}' and event '{}' has "
+                           "duplicated metric name '{}'.").format(
+                             project['name'], event['name'], name))
 
 
 def eventNamesUniqueWithinProject(data):
   """Check that no two events in a project have the same name."""
-  name_counts = Counter((event['project'], event['name'])
-                        for event in data[_EVENTS_TYPE.tag][_EVENT_TYPE.tag])
-  for (project, name), count in name_counts.items():
-    if count != 1:
-      raise Exception(
-          "Structured metrics project '{}' has events with duplicate "
-          "name '{}'.".format(project, name))
+  for project in data[_PROJECT_TYPE.tag]:
+    name_counts = Counter(
+      event['name']
+      for event in project[_EVENT_TYPE.tag])
+
+    for name, count in name_counts.items():
+      if count != 1:
+        raise Exception(
+            "Structured metrics project '{}' has events with duplicate "
+            "name '{}'.".format(project['name'], name))
 
 
 def projectNamesUnique(data):
   """Check that no two projects have the same name."""
   name_counts = Counter(
       project['name']
-      for project in data[_PROJECTS_TYPE.tag][_PROJECT_TYPE.tag])
+      for project in data[_PROJECT_TYPE.tag])
+
   for name, count in name_counts.items():
     if count != 1:
       raise Exception(
@@ -76,7 +77,6 @@
 
 def validate(data):
   projectsHaveRequiredFields(data)
-  eventsReferenceValidProjects(data)
-  metricNamesUniqueWithinEvent(data)
-  eventNamesUniqueWithinProject(data)
   projectNamesUnique(data)
+  eventNamesUniqueWithinProject(data)
+  metricNamesUniqueWithinEvent(data)
diff --git a/tools/metrics/structured/events_template.py b/tools/metrics/structured/events_template.py
index 2448d30..d1d35c1 100644
--- a/tools/metrics/structured/events_template.py
+++ b/tools/metrics/structured/events_template.py
@@ -26,8 +26,9 @@
 namespace structured {{
 namespace events {{
 
-constexpr uint64_t kProjectNameHashes[] = {project_name_hashes};\
-{event_code}
+constexpr uint64_t kProjectNameHashes[] = {project_name_hashes};
+
+{project_code}
 
 }}  // namespace events
 }}  // namespace structured
@@ -36,31 +37,40 @@
 #endif  // {file.guard_path}\
 """
 
-HEADER_EVENT_TEMPLATE = """
+HEADER_PROJECT_TEMPLATE = """\
+namespace {project.namespace} {{
 
+{event_code}\
+}}  // namespace {project.namespace}
+
+"""
+
+HEADER_EVENT_TEMPLATE = """\
 class {event.name} final : public ::metrics::structured::EventBase {{
  public:
   {event.name}();
   ~{event.name}() override;
 
   static constexpr uint64_t kEventNameHash = UINT64_C({event.name_hash});
-  static constexpr uint64_t kProjectNameHash = UINT64_C({event.project_name_hash});
-  static constexpr IdentifierType kIdType = IdentifierType::{event.project_id_type};\
-{metric_code}
-}};\
+  static constexpr uint64_t kProjectNameHash = UINT64_C({project.name_hash});
+  static constexpr IdentifierType kIdType = IdentifierType::{project.id_type};
+
+{metric_code}\
+}};
+
 """
 
-HEADER_METRIC_TEMPLATE = """
-
+HEADER_METRIC_TEMPLATE = """\
   static constexpr uint64_t k{metric.name}NameHash = UINT64_C({metric.hash});
-  {event.name}& Set{metric.name}(const {metric.type} value);\
+  {event.name}& Set{metric.name}(const {metric.type} value);
+
 """
 
-HEADER = codegen.Template(
-  basename="structured_events.h",
-  file_template=HEADER_FILE_TEMPLATE,
-  event_template=HEADER_EVENT_TEMPLATE,
-  metric_template=HEADER_METRIC_TEMPLATE)
+HEADER = codegen.Template(basename="structured_events.h",
+                          file_template=HEADER_FILE_TEMPLATE,
+                          project_template=HEADER_PROJECT_TEMPLATE,
+                          event_template=HEADER_EVENT_TEMPLATE,
+                          metric_template=HEADER_METRIC_TEMPLATE)
 
 ######
 # IMPL
@@ -74,35 +84,42 @@
 
 namespace metrics {{
 namespace structured {{
-namespace events {{\
-{event_code}
-
+namespace events {{
+{project_code}
 }}  // namespace events
 }}  // namespace structured
 }}  // namespace metrics\
 """
 
-IMPL_EVENT_TEMPLATE = """
+IMPL_PROJECT_TEMPLATE = """\
+namespace {project.namespace} {{
 
+{event_code}\
+}}  // namespace {project.namespace}
+
+"""
+
+IMPL_EVENT_TEMPLATE = """\
 {event.name}::{event.name}() :
   ::metrics::structured::EventBase(kEventNameHash, kProjectNameHash) {{}}
-{event.name}::~{event.name}() = default;\
+{event.name}::~{event.name}() = default;
 {metric_code}\
 """
 
-IMPL_METRIC_TEMPLATE = """
-
+IMPL_METRIC_TEMPLATE = """\
 {event.name}& {event.name}::Set{metric.name}(const {metric.type} value) {{
   {metric.setter}(k{metric.name}NameHash, value);
   return *this;
-}}\
+}}
+
 """
 
-IMPL = codegen.Template(
-  basename="structured_events.cc",
-  file_template=IMPL_FILE_TEMPLATE,
-  event_template=IMPL_EVENT_TEMPLATE,
-  metric_template=IMPL_METRIC_TEMPLATE)
+IMPL = codegen.Template(basename="structured_events.cc",
+                        file_template=IMPL_FILE_TEMPLATE,
+                        project_template=IMPL_PROJECT_TEMPLATE,
+                        event_template=IMPL_EVENT_TEMPLATE,
+                        metric_template=IMPL_METRIC_TEMPLATE)
+
 
 def WriteFiles(outdir, relpath, data):
   HEADER.WriteFile(outdir, relpath, data)
diff --git a/tools/metrics/structured/model.py b/tools/metrics/structured/model.py
index 18c769f..ef073cc 100644
--- a/tools/metrics/structured/model.py
+++ b/tools/metrics/structured/model.py
@@ -39,17 +39,14 @@
         models.ChildType(_SUMMARY_TYPE.tag, _SUMMARY_TYPE, multiple=False),
     ])
 
-_EVENT_TYPE = models.ObjectNodeType(
-    'event',
-    attributes=[
-        ('name', unicode, r'^[A-Z][A-Za-z0-9.]*$'),
-        ('project', unicode, r'^([A-Z][A-Za-z0-9.]*)?$'),
-    ],
+_EVENT_TYPE = models.ObjectNodeType('event',
+    attributes=[('name', unicode, r'^[A-Z][A-Za-z0-9.]*$'),],
     alphabetization=[
         (_OBSOLETE_TYPE.tag, lambda _: 1),
         (_OWNER_TYPE.tag, lambda _: 2),
         (_SUMMARY_TYPE.tag, lambda _: 3),
-        (_METRIC_TYPE.tag, _LOWERCASE_FN('name')),
+        (_METRIC_TYPE.tag,
+         _LOWERCASE_FN('name')),
     ],
     extra_newlines=(1, 1, 1),
     children=[
@@ -59,44 +56,27 @@
         models.ChildType(_METRIC_TYPE.tag, _METRIC_TYPE, multiple=True),
     ])
 
-_EVENTS_TYPE = models.ObjectNodeType(
-    'events',
-    alphabetization=[(_EVENT_TYPE.tag, _LOWERCASE_FN('name'))],
-    extra_newlines=(2, 1, 1),
-    indent=False,
+_PROJECT_TYPE = models.ObjectNodeType('project',
+    attributes=[
+        ('name', unicode, r'^[A-Z][A-Za-z0-9.]*$'),
+    ],
+    alphabetization=[
+        (_OBSOLETE_TYPE.tag, lambda _: 1),
+        (_OWNER_TYPE.tag, lambda _: 2),
+        (_ID_TYPE.tag, lambda _: 3),
+        (_SUMMARY_TYPE.tag, lambda _: 4),
+    ],
+    extra_newlines=(1, 1, 1),
     children=[
+        models.ChildType(_OBSOLETE_TYPE.tag, _OBSOLETE_TYPE, multiple=False),
+        models.ChildType(_OWNER_TYPE.tag, _OWNER_TYPE, multiple=True),
+        models.ChildType(_ID_TYPE.tag, _ID_TYPE, multiple=False),
+        models.ChildType(_SUMMARY_TYPE.tag, _SUMMARY_TYPE, multiple=False),
         models.ChildType(_EVENT_TYPE.tag, _EVENT_TYPE, multiple=True),
     ])
 
-_PROJECT_TYPE = models.ObjectNodeType('project',
-                                      attributes=[
-                                          ('name', unicode,
-                                           r'^[A-Z][A-Za-z0-9.]*$'),
-                                      ],
-                                      alphabetization=[
-                                          (_OBSOLETE_TYPE.tag, lambda _: 1),
-                                          (_OWNER_TYPE.tag, lambda _: 2),
-                                          (_ID_TYPE.tag, lambda _: 3),
-                                          (_SUMMARY_TYPE.tag, lambda _: 4),
-                                      ],
-                                      extra_newlines=(1, 1, 1),
-                                      children=[
-                                          models.ChildType(_OBSOLETE_TYPE.tag,
-                                                           _OBSOLETE_TYPE,
-                                                           multiple=False),
-                                          models.ChildType(_OWNER_TYPE.tag,
-                                                           _OWNER_TYPE,
-                                                           multiple=True),
-                                          models.ChildType(_ID_TYPE.tag,
-                                                           _ID_TYPE,
-                                                           multiple=False),
-                                          models.ChildType(_SUMMARY_TYPE.tag,
-                                                           _SUMMARY_TYPE,
-                                                           multiple=False),
-                                      ])
-
-_PROJECTS_TYPE = models.ObjectNodeType(
-    'projects',
+CONFIGURATION_TYPE = models.ObjectNodeType(
+    'structured-metrics',
     alphabetization=[(_PROJECT_TYPE.tag, _LOWERCASE_FN('name'))],
     extra_newlines=(2, 1, 1),
     indent=False,
@@ -104,19 +84,6 @@
         models.ChildType(_PROJECT_TYPE.tag, _PROJECT_TYPE, multiple=True),
     ])
 
-CONFIGURATION_TYPE = models.ObjectNodeType(
-    'structured-metrics',
-    alphabetization=[
-        (_EVENTS_TYPE.tag, lambda _: 1),
-        (_PROJECTS_TYPE.tag, lambda _: 2),
-    ],
-    extra_newlines=(2, 1, 1),
-    indent=False,
-    children=[
-        models.ChildType(_EVENTS_TYPE.tag, _EVENTS_TYPE, multiple=False),
-        models.ChildType(_PROJECTS_TYPE.tag, _PROJECTS_TYPE, multiple=False),
-    ])
-
 XML_TYPE = models.DocumentType(CONFIGURATION_TYPE)
 
 def PrettifyXML(original_xml):
diff --git a/tools/metrics/structured/structured.xml b/tools/metrics/structured/structured.xml
index 0a252f7..bf8c45b 100644
--- a/tools/metrics/structured/structured.xml
+++ b/tools/metrics/structured/structured.xml
@@ -2,275 +2,6 @@
 
 <structured-metrics>
 
-<events>
-
-<event name="CrOSActionEvent.FileOpened" project="Hindsight">
-  <summary>
-    Records whenever a file is opened in the File App on ChromeOS.
-  </summary>
-  <metric name="Filename" kind="hashed-string">
-    <summary>
-      The absolute path of the file.
-    </summary>
-  </metric>
-  <metric name="OpenType" kind="int">
-    <summary>
-      The kind of file open, defined in FileTaskObserver::OpenType.
-    </summary>
-  </metric>
-  <metric name="SequenceId" kind="int">
-    <summary>
-      Sequence of this action across all CrOSActionEvent.
-    </summary>
-  </metric>
-  <metric name="TimeSinceLastAction" kind="int">
-    <summary>
-      Time in milliseconds since last CrOSActionLogging.
-    </summary>
-  </metric>
-</event>
-
-<event name="CrOSActionEvent.SearchResultLaunched" project="Hindsight">
-  <summary>
-    Records information about the launch of an item from ChromeOS launcher.
-  </summary>
-  <metric name="Query" kind="hashed-string">
-    <summary>
-      The search query associated with this launch.
-    </summary>
-  </metric>
-  <metric name="ResultType" kind="int">
-    <summary>
-      Which kind of search provider the launched result was created by.
-    </summary>
-  </metric>
-  <metric name="SearchResultId" kind="hashed-string">
-    <summary>
-      The ID of the launched result result. For example, the app ID for app
-      results, or the URL for omnibox results.
-    </summary>
-  </metric>
-  <metric name="SequenceId" kind="int">
-    <summary>
-      Sequence of this action across all CrOSActionEvent.
-    </summary>
-  </metric>
-  <metric name="TimeSinceLastAction" kind="int"/>
-</event>
-
-<event name="CrOSActionEvent.SettingChanged" project="Hindsight">
-  <summary>
-    Records when a setting is changed; only records quick settings for now.
-  </summary>
-  <metric name="CurrentValue" kind="int">
-    <summary>
-      Value of the setting after the change.
-    </summary>
-  </metric>
-  <metric name="PreviousValue" kind="int">
-    <summary>
-      Value of the setting before the change.
-    </summary>
-  </metric>
-  <metric name="SequenceId" kind="int">
-    <summary>
-      Sequence of this action across all CrOSActionEvent.
-    </summary>
-  </metric>
-  <metric name="SettingId" kind="int">
-    <summary>
-      The setting id (in ash::ml::UserSettingsEvent::Event::SettingId) that
-      represents the type of the changed setting.
-    </summary>
-  </metric>
-  <metric name="SettingType" kind="int">
-    <summary>
-      Enum that represents where the settings event originated from (in
-      ash::ml::UserSettingsEvent::Event::SettingType).
-    </summary>
-  </metric>
-  <metric name="TimeSinceLastAction" kind="int">
-    <summary>
-      Time in milliseconds since last CrOSActionLogging.
-    </summary>
-  </metric>
-</event>
-
-<event name="CrOSActionEvent.TabEvent.TabNavigated" project="Hindsight">
-  <summary>
-    Records a tab activity of navigating to a new url.
-  </summary>
-  <metric name="PageTransition" kind="int">
-    <summary>
-      The types of transition between pages. See more on ui::PageTransition.
-    </summary>
-  </metric>
-  <metric name="SequenceId" kind="int">
-    <summary>
-      Sequence of this action across all CrOSActionEvent.
-    </summary>
-  </metric>
-  <metric name="TimeSinceLastAction" kind="int">
-    <summary>
-      Time in milliseconds since last CrOSActionLogging.
-    </summary>
-  </metric>
-  <metric name="URL" kind="hashed-string">
-    <summary>
-      The URL of the current event.
-    </summary>
-  </metric>
-  <metric name="Visibility" kind="int">
-    <summary>
-      The visibility of this url, see more on content::Visibility.
-    </summary>
-  </metric>
-</event>
-
-<event name="CrOSActionEvent.TabEvent.TabOpened" project="Hindsight">
-  <summary>
-    Records a tab activity of opening a new url with ctrl+click.
-  </summary>
-  <metric name="SequenceId" kind="int">
-    <summary>
-      Sequence of this action across all CrOSActionEvent.
-    </summary>
-  </metric>
-  <metric name="TimeSinceLastAction" kind="int">
-    <summary>
-      Time in milliseconds since last CrOSActionLogging.
-    </summary>
-  </metric>
-  <metric name="URL" kind="hashed-string">
-    <summary>
-      The URL of the current event.
-    </summary>
-  </metric>
-  <metric name="URLOpened" kind="hashed-string">
-    <summary>
-      The URL that is opened from the current url.
-    </summary>
-  </metric>
-  <metric name="WindowOpenDisposition" kind="int">
-    <summary>
-      Enum that indicates where the new tab is opened, see more on
-      WindowOpenDisposition.
-    </summary>
-  </metric>
-</event>
-
-<event name="CrOSActionEvent.TabEvent.TabReactivated" project="Hindsight">
-  <summary>
-    Records a tab activity of reactivating an existing tab.
-  </summary>
-  <metric name="SequenceId" kind="int">
-    <summary>
-      Sequence of this action across all CrOSActionEvent.
-    </summary>
-  </metric>
-  <metric name="TimeSinceLastAction" kind="int">
-    <summary>
-      Time in milliseconds since last CrOSActionLogging.
-    </summary>
-  </metric>
-  <metric name="URL" kind="hashed-string">
-    <summary>
-      The URL of the current event.
-    </summary>
-  </metric>
-</event>
-
-<event name="LauncherUsage" project="LauncherUsage">
-  <summary>
-    Records information about the launch of an item (such as an app or a file)
-    from the ChromeOS launcher. One event is recorded for every launch
-    originating from any launcher UI component, and this is the only
-    circumstance that records events.
-  </summary>
-  <metric name="App" kind="hashed-string">
-    <summary>
-      App ID of the most-recently-opened app when this launch occured. This can
-      be an app ID of a Chrome app, Arc++ app, or PWA.
-    </summary>
-  </metric>
-  <metric name="Domain" kind="hashed-string">
-    <summary>
-      The most-recently-visited domain when this launch ocurred.
-    </summary>
-  </metric>
-  <metric name="Hour" kind="int">
-    <summary>
-      The hour of launch. This is the user's local time rounded to the nearest
-      hour, 0 to 23 inclusive.
-    </summary>
-  </metric>
-  <metric name="ProviderType" kind="int">
-    <summary>
-      Which kind of search provider the launched result was created by. This
-      comes from the RankingItemType enum.
-    </summary>
-  </metric>
-  <metric name="SearchQuery" kind="hashed-string">
-    <summary>
-      The search query associated with this launch. Before hashing, the query is
-      the empty string if there was no search query.
-    </summary>
-  </metric>
-  <metric name="SearchQueryLength" kind="int">
-    <summary>
-      String length of the search query associated with this launch. If there
-      was no query, this is zero.
-    </summary>
-  </metric>
-  <metric name="Target" kind="hashed-string">
-    <summary>
-      The target item of this launch, eg. an app ID, filepath, or omnibox URL.
-    </summary>
-  </metric>
-</event>
-
-<event name="TestEventOne" project="TestProjectOne">
-  <summary>
-    Event for unit testing, do not use.
-  </summary>
-  <metric name="TestMetricOne" kind="hashed-string">
-    <summary>
-      A per-user keyed hashed value.
-    </summary>
-  </metric>
-  <metric name="TestMetricTwo" kind="int">
-    <summary>
-      An unhashed value, recorded as-is.
-    </summary>
-  </metric>
-</event>
-
-<event name="TestEventThree" project="TestProjectTwo">
-  <summary>
-    Event for unit testing, do not use.
-  </summary>
-  <metric name="TestMetricFour" kind="hashed-string">
-    <summary>
-      A per-user keyed hashed value.
-    </summary>
-  </metric>
-</event>
-
-<event name="TestEventTwo" project="TestProjectTwo">
-  <summary>
-    Event for unit testing, do not use.
-  </summary>
-  <metric name="TestMetricThree" kind="hashed-string">
-    <summary>
-      A per-user keyed hashed value.
-    </summary>
-  </metric>
-</event>
-
-</events>
-
-<projects>
-
 <project name="Hindsight">
   <owner>charleszhao@chromium.org</owner>
   <owner>tby@chromium.org</owner>
@@ -278,14 +9,239 @@
   <summary>
     Project for recording CrOSActions.
   </summary>
+  <event name="CrOSActionEvent.FileOpened">
+    <summary>
+      Records whenever a file is opened in the File App on ChromeOS.
+    </summary>
+    <metric name="Filename" kind="hashed-string">
+      <summary>
+        The absolute path of the file.
+      </summary>
+    </metric>
+    <metric name="OpenType" kind="int">
+      <summary>
+        The kind of file open, defined in FileTaskObserver::OpenType.
+      </summary>
+    </metric>
+    <metric name="SequenceId" kind="int">
+      <summary>
+        Sequence of this action across all CrOSActionEvent.
+      </summary>
+    </metric>
+    <metric name="TimeSinceLastAction" kind="int">
+      <summary>
+        Time in milliseconds since last CrOSActionLogging.
+      </summary>
+    </metric>
+  </event>
+
+  <event name="CrOSActionEvent.SearchResultLaunched">
+    <summary>
+      Records information about the launch of an item from ChromeOS launcher.
+    </summary>
+    <metric name="Query" kind="hashed-string">
+      <summary>
+        The search query associated with this launch.
+      </summary>
+    </metric>
+    <metric name="ResultType" kind="int">
+      <summary>
+        Which kind of search provider the launched result was created by.
+      </summary>
+    </metric>
+    <metric name="SearchResultId" kind="hashed-string">
+      <summary>
+        The ID of the launched result result. For example, the app ID for app
+        results, or the URL for omnibox results.
+      </summary>
+    </metric>
+    <metric name="SequenceId" kind="int">
+      <summary>
+        Sequence of this action across all CrOSActionEvent.
+      </summary>
+    </metric>
+    <metric name="TimeSinceLastAction" kind="int"/>
+  </event>
+
+  <event name="CrOSActionEvent.SettingChanged">
+    <summary>
+      Records when a setting is changed; only records quick settings for now.
+    </summary>
+    <metric name="CurrentValue" kind="int">
+      <summary>
+        Value of the setting after the change.
+      </summary>
+    </metric>
+    <metric name="PreviousValue" kind="int">
+      <summary>
+        Value of the setting before the change.
+      </summary>
+    </metric>
+    <metric name="SequenceId" kind="int">
+      <summary>
+        Sequence of this action across all CrOSActionEvent.
+      </summary>
+    </metric>
+    <metric name="SettingId" kind="int">
+      <summary>
+        The setting id (in ash::ml::UserSettingsEvent::Event::SettingId) that
+        represents the type of the changed setting.
+      </summary>
+    </metric>
+    <metric name="SettingType" kind="int">
+      <summary>
+        Enum that represents where the settings event originated from (in
+        ash::ml::UserSettingsEvent::Event::SettingType).
+      </summary>
+    </metric>
+    <metric name="TimeSinceLastAction" kind="int">
+      <summary>
+        Time in milliseconds since last CrOSActionLogging.
+      </summary>
+    </metric>
+  </event>
+
+  <event name="CrOSActionEvent.TabEvent.TabNavigated">
+    <summary>
+      Records a tab activity of navigating to a new url.
+    </summary>
+    <metric name="PageTransition" kind="int">
+      <summary>
+        The types of transition between pages. See more on ui::PageTransition.
+      </summary>
+    </metric>
+    <metric name="SequenceId" kind="int">
+      <summary>
+        Sequence of this action across all CrOSActionEvent.
+      </summary>
+    </metric>
+    <metric name="TimeSinceLastAction" kind="int">
+      <summary>
+        Time in milliseconds since last CrOSActionLogging.
+      </summary>
+    </metric>
+    <metric name="URL" kind="hashed-string">
+      <summary>
+        The URL of the current event.
+      </summary>
+    </metric>
+    <metric name="Visibility" kind="int">
+      <summary>
+        The visibility of this url, see more on content::Visibility.
+      </summary>
+    </metric>
+  </event>
+
+  <event name="CrOSActionEvent.TabEvent.TabOpened">
+    <summary>
+      Records a tab activity of opening a new url with ctrl+click.
+    </summary>
+    <metric name="SequenceId" kind="int">
+      <summary>
+        Sequence of this action across all CrOSActionEvent.
+      </summary>
+    </metric>
+    <metric name="TimeSinceLastAction" kind="int">
+      <summary>
+        Time in milliseconds since last CrOSActionLogging.
+      </summary>
+    </metric>
+    <metric name="URL" kind="hashed-string">
+      <summary>
+        The URL of the current event.
+      </summary>
+    </metric>
+    <metric name="URLOpened" kind="hashed-string">
+      <summary>
+        The URL that is opened from the current url.
+      </summary>
+    </metric>
+    <metric name="WindowOpenDisposition" kind="int">
+      <summary>
+        Enum that indicates where the new tab is opened, see more on
+        WindowOpenDisposition.
+      </summary>
+    </metric>
+  </event>
+
+  <event name="CrOSActionEvent.TabEvent.TabReactivated">
+    <summary>
+      Records a tab activity of reactivating an existing tab.
+    </summary>
+    <metric name="SequenceId" kind="int">
+      <summary>
+        Sequence of this action across all CrOSActionEvent.
+      </summary>
+    </metric>
+    <metric name="TimeSinceLastAction" kind="int">
+      <summary>
+        Time in milliseconds since last CrOSActionLogging.
+      </summary>
+    </metric>
+    <metric name="URL" kind="hashed-string">
+      <summary>
+        The URL of the current event.
+      </summary>
+    </metric>
+  </event>
+
 </project>
 
 <project name="LauncherUsage">
   <owner>tby@chromium.org</owner>
   <id>per-project</id>
   <summary>
-    Records information about search results launched from the launcher.
+    See event summary.
   </summary>
+  <event name="LauncherUsage">
+    <summary>
+      Records information about the launch of an item (such as an app or a file)
+      from the ChromeOS launcher. One event is recorded for every launch
+      originating from any launcher UI component, and this is the only
+      circumstance that records events.
+    </summary>
+    <metric name="App" kind="hashed-string">
+      <summary>
+        App ID of the most-recently-opened app when this launch occured. This
+        can be an app ID of a Chrome app, Arc++ app, or PWA.
+      </summary>
+    </metric>
+    <metric name="Domain" kind="hashed-string">
+      <summary>
+        The most-recently-visited domain when this launch ocurred.
+      </summary>
+    </metric>
+    <metric name="Hour" kind="int">
+      <summary>
+        The hour of launch. This is the user's local time rounded to the nearest
+        hour, 0 to 23 inclusive.
+      </summary>
+    </metric>
+    <metric name="ProviderType" kind="int">
+      <summary>
+        Which kind of search provider the launched result was created by. This
+        comes from the RankingItemType enum.
+      </summary>
+    </metric>
+    <metric name="SearchQuery" kind="hashed-string">
+      <summary>
+        The search query associated with this launch. Before hashing, the query
+        is the empty string if there was no search query.
+      </summary>
+    </metric>
+    <metric name="SearchQueryLength" kind="int">
+      <summary>
+        String length of the search query associated with this launch. If there
+        was no query, this is zero.
+      </summary>
+    </metric>
+    <metric name="Target" kind="hashed-string">
+      <summary>
+        The target item of this launch, eg. an app ID, filepath, or omnibox URL.
+      </summary>
+    </metric>
+  </event>
+
 </project>
 
 <project name="TestProjectOne">
@@ -294,6 +250,22 @@
   <summary>
     Project for unit testing, do not use.
   </summary>
+  <event name="TestEventOne">
+    <summary>
+      Event for unit testing, do not use.
+    </summary>
+    <metric name="TestMetricOne" kind="hashed-string">
+      <summary>
+        A per-user keyed hashed value.
+      </summary>
+    </metric>
+    <metric name="TestMetricTwo" kind="int">
+      <summary>
+        An unhashed value, recorded as-is.
+      </summary>
+    </metric>
+  </event>
+
 </project>
 
 <project name="TestProjectTwo">
@@ -302,8 +274,28 @@
   <summary>
     Project for unit testing, do not use.
   </summary>
-</project>
+  <event name="TestEventThree">
+    <summary>
+      Event for unit testing, do not use.
+    </summary>
+    <metric name="TestMetricFour" kind="hashed-string">
+      <summary>
+        A per-user keyed hashed value.
+      </summary>
+    </metric>
+  </event>
 
-</projects>
+  <event name="TestEventTwo">
+    <summary>
+      Event for unit testing, do not use.
+    </summary>
+    <metric name="TestMetricThree" kind="hashed-string">
+      <summary>
+        A per-user keyed hashed value.
+      </summary>
+    </metric>
+  </event>
+
+</project>
 
 </structured-metrics>
diff --git a/tools/metrics/structured/validate_format.py b/tools/metrics/structured/validate_format.py
index 03b1e005..1bb39c89 100755
--- a/tools/metrics/structured/validate_format.py
+++ b/tools/metrics/structured/validate_format.py
@@ -58,56 +58,18 @@
   return errors
 
 
-def checkMetricNamesWithinEventNotDuplicated(events):
-  errors = []
-
-  for node in events.getElementsByTagName('event'):
-    name = node.getAttribute('name')
-    metrics = set()
-    for metric_node in node.getElementsByTagName('metric'):
-      metric_name = metric_node.getAttribute('name')
-      if metric_name in metrics:
-        errors.append(
-            "duplicate metric name '%s' for event '%s'" % (metric_name, name))
-      metrics.add(metric_name)
-
-  return errors
-
-
-def checkEventsReferenceValidProjects(events, projects):
-  errors = []
-
-  projects = {
-      project.getAttribute('name')
-      for project in projects.getElementsByTagName('project')
-  }
-
-  for node in events.getElementsByTagName('event'):
-    name = node.getAttribute('name')
-    project = node.getAttribute('project')
-
-    # An event's project can either be empty (not specified), or must be a
-    # project listed in the projects section.
-    if project and project not in projects:
-      errors.append(
-          "event '%s' references nonexistent project '%s'" % (name, project))
-
-  return errors
-
-
 def main():
   with open(STRUCTURED_XML, 'r') as config_file:
     document = minidom.parse(config_file)
     [config] = document.getElementsByTagName('structured-metrics')
-    [events] = config.getElementsByTagName('events')
-    [projects] = config.getElementsByTagName('projects')
-
     errors = []
-    errors.extend(checkElementOwners(projects, 'project'))
-    errors.extend(checkElementsNotDuplicated(events, 'event'))
-    errors.extend(checkElementsNotDuplicated(projects, 'project'))
-    errors.extend(checkMetricNamesWithinEventNotDuplicated(events))
-    errors.extend(checkEventsReferenceValidProjects(events, projects))
+
+    errors.extend(checkElementOwners(config, 'project'))
+    errors.extend(checkElementsNotDuplicated(config, 'project'))
+    for project in document.getElementsByTagName('project'):
+      errors.extend(checkElementsNotDuplicated(project, 'event'))
+      for event in project.getElementsByTagName('event'):
+        errors.extend(checkElementsNotDuplicated(event, 'metric'))
 
     if errors:
       return 'ERRORS:' + ''.join('\n  ' + e for e in errors)
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index 17e43f6..8a1f95c05 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -3,7 +3,6 @@
 Googlers can view additional information about internal perf infrastructure at,https://goto.google.com/chrome-benchmarking-sheet
 Benchmark name,Individual owners,Component,Documentation,Tags
 UNSCHEDULED_blink_perf.service_worker,"shimazu@chromium.org, falken@chromium.org, ting.shao@intel.com",Blink>ServiceWorker,https://bit.ly/blink-perf-benchmarks,
-UNSCHEDULED_tab_search,"yuhengh@chromium.org, tluk@chromium.org, romanarora@chromium.org",UI>Browser>TabSearch,,
 base_perftests,"skyostil@chromium.org, gab@chromium.org",Internals>SequenceManager,https://chromium.googlesource.com/chromium/src/+/HEAD/base/README.md#performance-testing,
 blink_perf.accessibility,dmazzoni@chromium.org,Blink>Accessibility,https://bit.ly/blink-perf-benchmarks,all
 blink_perf.bindings,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org",Blink>Bindings,https://bit.ly/blink-perf-benchmarks,all
@@ -61,6 +60,7 @@
 system_health.memory_mobile,"pasko@chromium.org, lizeb@chromium.org",,https://bit.ly/system-health-benchmarks,"2016,2018,2019,2020,emerging_market,health_check,images,infinite_scroll,international,javascript_heavy"
 system_health.weblayer_startup,"cduvall@chromium.org, weblayer-team@chromium.org",Internals>WebLayer,https://bit.ly/36XBtpn,2016
 system_health.webview_startup,"oksamyt@chromium.org, torne@chromium.org, changwan@chromium.org",Mobile>WebView>Perf,,2016
+tab_search,"yuhengh@chromium.org, tluk@chromium.org, romanarora@chromium.org",UI>Browser>TabSearch,,
 tab_switching.typical_25,vovoy@chromium.org,OS>Performance,,"2016,tabs_switching"
 tracing.tracing_with_background_memory_infra,ssid@chromium.org,,,
 tracing_perftests,"eseckler@chromium.org, oysteine@chromium.org",Speed>Tracing,,
diff --git a/tools/perf/benchmarks/tab_search.py b/tools/perf/benchmarks/tab_search.py
index 1e8f6e0..8ae4aef 100644
--- a/tools/perf/benchmarks/tab_search.py
+++ b/tools/perf/benchmarks/tab_search.py
@@ -57,4 +57,4 @@
 
   @classmethod
   def Name(cls):
-    return 'UNSCHEDULED_tab_search'
+    return 'tab_search'
diff --git a/tools/perf/core/bot_platforms.py b/tools/perf/core/bot_platforms.py
index 4cf872df..ce9909c 100644
--- a/tools/perf/core/bot_platforms.py
+++ b/tools/perf/core/bot_platforms.py
@@ -345,6 +345,7 @@
 
 _WIN_10_BENCHMARK_CONFIGS = PerfSuite(OFFICIAL_BENCHMARK_CONFIGS).Remove([
     'blink_perf.display_locking',
+    'tab_search',
     'v8.runtime_stats.top_25',
 ])
 _WIN_10_EXECUTABLE_CONFIGS = frozenset([
@@ -357,6 +358,7 @@
 _WIN_10_LOW_END_BENCHMARK_CONFIGS = PerfSuite(
     OFFICIAL_BENCHMARK_CONFIGS).Remove([
         'blink_perf.display_locking',
+        'tab_search',
     ])
 _WIN_10_LOW_END_HP_CANDIDATE_BENCHMARK_CONFIGS = PerfSuite([
     _GetBenchmarkConfig('v8.browsing_desktop'),
diff --git a/tools/perf/core/shard_maps/linux-perf_map.json b/tools/perf/core/shard_maps/linux-perf_map.json
index d020f35..cf061302 100644
--- a/tools/perf/core/shard_maps/linux-perf_map.json
+++ b/tools/perf/core/shard_maps/linux-perf_map.json
@@ -353,6 +353,9 @@
     },
     "25": {
         "benchmarks": {
+            "tab_search": {
+                "abridged": false
+            },
             "v8.browsing_desktop-future": {
                 "begin": 14,
                 "abridged": false
diff --git a/tools/perf/core/shard_maps/mac-10_12_laptop_low_end-perf_map.json b/tools/perf/core/shard_maps/mac-10_12_laptop_low_end-perf_map.json
index 2d03194a..7003b8a 100644
--- a/tools/perf/core/shard_maps/mac-10_12_laptop_low_end-perf_map.json
+++ b/tools/perf/core/shard_maps/mac-10_12_laptop_low_end-perf_map.json
@@ -344,6 +344,9 @@
     },
     "25": {
         "benchmarks": {
+            "tab_search": {
+                "abridged": false
+            },
             "v8.browsing_desktop-future": {
                 "begin": 10,
                 "abridged": false
diff --git a/tools/perf/core/shard_maps/mac-10_13_laptop_high_end-perf_map.json b/tools/perf/core/shard_maps/mac-10_13_laptop_high_end-perf_map.json
index 0a191903..1d6f31d 100644
--- a/tools/perf/core/shard_maps/mac-10_13_laptop_high_end-perf_map.json
+++ b/tools/perf/core/shard_maps/mac-10_13_laptop_high_end-perf_map.json
@@ -355,6 +355,9 @@
     },
     "25": {
         "benchmarks": {
+            "tab_search": {
+                "abridged": false
+            },
             "v8.browsing_desktop-future": {
                 "begin": 11,
                 "abridged": false
diff --git a/tools/perf/core/shard_maps/mac-arm_dtk_arm-perf_map.json b/tools/perf/core/shard_maps/mac-arm_dtk_arm-perf_map.json
index e2dbe2e..ca5b7d8 100644
--- a/tools/perf/core/shard_maps/mac-arm_dtk_arm-perf_map.json
+++ b/tools/perf/core/shard_maps/mac-arm_dtk_arm-perf_map.json
@@ -197,6 +197,9 @@
                 "begin": 2,
                 "abridged": false
             },
+            "tab_search": {
+                "abridged": false
+            },
             "tab_switching.typical_25": {
                 "abridged": false
             },
diff --git a/tools/perf/core/undocumented_benchmarks.py b/tools/perf/core/undocumented_benchmarks.py
index 2eb2c38..841e7acf 100644
--- a/tools/perf/core/undocumented_benchmarks.py
+++ b/tools/perf/core/undocumented_benchmarks.py
@@ -24,7 +24,7 @@
     'speedometer2-future',
     'startup.mobile',
     'system_health.webview_startup',
-    'UNSCHEDULED_tab_search',
+    'tab_search',
     'tab_switching.typical_25',
     'tracing.tracing_with_background_memory_infra',
     'tracing_perftests',
diff --git a/tools/privacy_budget/blink_apis/blink_api_proto.py b/tools/privacy_budget/blink_apis/blink_api_proto.py
index f45e5e4..6830e93 100644
--- a/tools/privacy_budget/blink_apis/blink_api_proto.py
+++ b/tools/privacy_budget/blink_apis/blink_api_proto.py
@@ -14,7 +14,6 @@
     """BlinkApiProto converts a WebIdlDatabase to
     a identifiability.blink_apis.Snapshot proto defined in
     proto/blink_apis.proto"""
-
     def __init__(self, web_idl_pickle, proto_out_file, chromium_revision):
         self.web_idl_database = web_idl.Database.read_from_file(web_idl_pickle)
         self.proto_out_file = proto_out_file
@@ -132,6 +131,7 @@
         dest.is_readonly = attr.is_readonly
         self._ConvertExtendedAttributes(dest.extended_attributes, attr)
         self._ConvertIdlType(dest.idl_type, attr.idl_type)
+        self._ConvertSourceLocation(dest.source_location, attr.debug_info)
 
     def _GetSpecialOperationType(self, op):
         if not isinstance(op, web_idl.Operation):
@@ -149,24 +149,28 @@
         dest.static = op.is_static
         dest.special_op_type = self._GetSpecialOperationType(op)
         self._ConvertIdlType(dest.return_type, op.return_type)
+        self._ConvertSourceLocation(dest.source_location, op.debug_info)
         for arg in op.arguments:
             self._ConvertIdlType(dest.arguments.add(), arg.idl_type)
 
     def _ConvertIdlEnumeration(self, dest, enumer):
         dest.name = enumer.identifier
         dest.values[:] = enumer.values
+        self._ConvertSourceLocation(dest.source_location, enumer.debug_info)
 
     def _ConvertIdlConstant(self, dest, constant):
         dest.name = constant.identifier
         dest.value = constant.value.literal
         self._ConvertExtendedAttributes(dest.extended_attributes, constant)
         self._ConvertIdlType(dest.idl_type, constant.idl_type)
+        self._ConvertSourceLocation(dest.source_location, constant.debug_info)
 
     def _ConvertIdlInterfaceLike(self, dest, interface):
         dest.name = interface.identifier
         if hasattr(interface, 'inherited') and interface.inherited:
             dest.inherits_from = interface.inherited.identifier
         self._ConvertExtendedAttributes(dest.extended_attributes, interface)
+        self._ConvertSourceLocation(dest.source_location, interface.debug_info)
         for attr in interface.attributes:
             self._ConvertIdlAttribute(dest.attributes.add(), attr)
         for op in interface.operations:
@@ -179,10 +183,13 @@
         dest.name = member.identifier
         self._ConvertExtendedAttributes(dest.extended_attributes, member)
         self._ConvertIdlType(dest.idl_type, member.idl_type)
+        self._ConvertSourceLocation(dest.source_location, member.debug_info)
 
     def _ConvertIdlDictionary(self, dest, dictionary):
         assert isinstance(dictionary, web_idl.Dictionary)
         dest.name = dictionary.identifier
+        self._ConvertSourceLocation(dest.source_location,
+                                    dictionary.debug_info)
         if dictionary.inherited:
             dest.inherits_from = dictionary.inherited.identifier
         for member in dictionary.members:
@@ -192,3 +199,22 @@
         assert isinstance(typedef, web_idl.Typedef)
         dest.name = typedef.identifier
         self._ConvertIdlType(dest.idl_type, typedef.idl_type)
+
+    def _ConvertSourceLocation(self, dest, debug_info):
+        source_file = None
+        line_no = 0
+
+        if not debug_info or not hasattr(debug_info, 'all_locations'):
+            return
+
+        for loc in list(debug_info.all_locations):
+            if loc.filepath and loc.line_number:
+                source_file = loc.filepath
+                line_no = loc.line_number
+                break
+            if loc.filepath:
+                source_file = loc.filepath
+
+        if source_file:
+            dest.filename = source_file
+            dest.line = line_no
diff --git a/tools/privacy_budget/blink_apis/proto/blink_apis.proto b/tools/privacy_budget/blink_apis/proto/blink_apis.proto
index eda0404d..87272e5 100644
--- a/tools/privacy_budget/blink_apis/proto/blink_apis.proto
+++ b/tools/privacy_budget/blink_apis/proto/blink_apis.proto
@@ -50,8 +50,8 @@
   }
 
   // https://heycam.github.io/webidl/#Exposed
-  repeated Exposed exposed =
-      2;  // One value for each interface/partial interface/etc..
+  // One value for each interface/partial interface/etc..
+  repeated Exposed exposed = 2;
 
   // https://heycam.github.io/webidl/#Global
   bool global = 3;
@@ -119,6 +119,8 @@
   repeated Attribute attributes = 4;
   repeated Operation operations = 5;
   repeated Constant constants = 6;
+
+  SourceLocation source_location = 30;
 }
 
 message IDLType {
@@ -162,9 +164,12 @@
     string name = 1;
     ExtendedAttributes extended_attributes = 2;
     IDLType idl_type = 3;
+    SourceLocation source_location = 30;
   }
 
   repeated Member members = 7;
+
+  SourceLocation source_location = 30;
 }
 
 // Special operation types.
@@ -193,6 +198,8 @@
   // The following fields are only applicable to special operations.
   // https://heycam.github.io/webidl/#dfn-special-operation
   SpecialOperationType special_op_type = 5;
+
+  SourceLocation source_location = 30;
 }
 
 // An interface member or a namespace member declaring a data field.
@@ -203,6 +210,8 @@
   IDLType idl_type = 3;
   bool is_static = 4;
   bool is_readonly = 5;
+
+  SourceLocation source_location = 30;
 }
 
 // A declaration binding a value to a name.
@@ -216,6 +225,8 @@
   // `type`. There should be no expectation that this representation is
   // unambiguously parsable. It's intended solely for human consumption.
   string value = 4;
+
+  SourceLocation source_location = 30;
 }
 
 // Defines a type who's valid values are a set of strings.
@@ -225,6 +236,8 @@
 
   // Enum values are strings.
   repeated string values = 2;
+
+  SourceLocation source_location = 30;
 }
 
 // Declares a new name for a type.
@@ -233,4 +246,15 @@
 message Typedef {
   string name = 1;
   IDLType idl_type = 2;
+
+  SourceLocation source_location = 30;
+}
+
+message SourceLocation {
+  // Relative to the root of the Chromium source tree. So pretty much all
+  // strings start with 'third_party/blink/...'
+  string filename = 1;
+
+  // 1-based line number. 0 means there's no line-number information.
+  int32 line = 2;
 }
diff --git a/tools/style_variable_generator/PRESUBMIT.py b/tools/style_variable_generator/PRESUBMIT.py
index 15ae508..1b0d0ba 100644
--- a/tools/style_variable_generator/PRESUBMIT.py
+++ b/tools/style_variable_generator/PRESUBMIT.py
@@ -7,7 +7,7 @@
 for more details about the presubmit API built into depot_tools.
 """
 
-TEST_ALLOWLIST = [r'.+_test.py$']
+TEST_PATTERNS = [r'.+_test.py$']
 STYLE_VAR_GEN_INPUTS = [
     r'^tools[\\\/]style_variable_generator[\\\/].+\.json5$'
 ]
@@ -15,7 +15,7 @@
 
 def _CommonChecks(input_api, output_api):
     results = input_api.canned_checks.RunUnitTestsInDirectory(
-        input_api, output_api, '.', allowlist=TEST_ALLOWLIST)
+        input_api, output_api, '.', files_to_check=TEST_PATTERNS)
     try:
         import sys
         old_sys_path = sys.path[:]
diff --git a/tools/style_variable_generator/color.py b/tools/style_variable_generator/color.py
index 0414482b..c0a2f00 100644
--- a/tools/style_variable_generator/color.py
+++ b/tools/style_variable_generator/color.py
@@ -25,9 +25,9 @@
         # TODO(calamity): Add opacity-only values
         self.var = None
         self.rgb_var = None
-        self.r = 0
-        self.g = 0
-        self.b = 0
+        self.r = -1
+        self.g = -1
+        self.b = -1
         self.a = 1
         self.Parse(value_str)
 
@@ -38,12 +38,27 @@
 
         (self.r, self.g, self.b) = rgb
 
+    # Attempts to parse special variables, returns True if successful.
+    def _ParseWhiteBlack(self, var):
+        if var == 'white':
+            self._AssignRGB([255, 255, 255])
+            return True
+
+        if var == 'black':
+            self._AssignRGB([0, 0, 0])
+            return True
+
+        return False
+
     def _ParseRGBRef(self, rgb_ref):
-        match = re.match('^\$([a-z0-9_]+_rgb)$', rgb_ref)
+        match = re.match('^\$([\w\d_]+)_rgb$', rgb_ref)
         if not match:
             raise ValueError('Expected a reference to an RGB variable')
 
-        self.rgb_var = match.group(1)
+        rgb_var = match.group(1)
+
+        if not self._ParseWhiteBlack(rgb_var):
+            self.rgb_var = rgb_var + '_rgb'
 
     def _ParseAlpha(self, alpha_value):
         self.a = float(alpha_value)
@@ -105,15 +120,20 @@
                              '1 reference + alpha, or 3 ints + alpha')
 
         def ParseVariableReference(value):
-            match = re.match('^\$(.*)$', value)
+            match = re.match('^\$([\w\d_]+)$', value)
             if not match:
                 return False
 
+            var = match.group(1)
+
+            if self._ParseWhiteBlack(var):
+                return True
+
             if value.endswith('_rgb'):
                 raise ValueError(
                     'color reference cannot resolve to an rgb reference')
 
-            self.var = match.group(1)
+            self.var = var
             return True
 
         parsers = [
diff --git a/tools/style_variable_generator/color_test.py b/tools/style_variable_generator/color_test.py
index 6860079..0300b1a7 100644
--- a/tools/style_variable_generator/color_test.py
+++ b/tools/style_variable_generator/color_test.py
@@ -40,6 +40,19 @@
         c = Color('$some_color')
         self.assertEqual(c.var, 'some_color')
 
+    def testWhiteBlackColor(self):
+        c = Color('$white')
+        self.assertEqual((c.r, c.g, c.b, c.a), (255, 255, 255, 1))
+
+        c = Color('rgba($white_rgb, 0.5)')
+        self.assertEqual((c.r, c.g, c.b, c.a), (255, 255, 255, 0.5))
+
+        c = Color('$black')
+        self.assertEqual((c.r, c.g, c.b, c.a), (0, 0, 0, 1))
+
+        c = Color('rgba($black_rgb, 0.5)')
+        self.assertEqual((c.r, c.g, c.b, c.a), (0, 0, 0, 0.5))
+
     def testMalformedColors(self):
         with self.assertRaises(ValueError):
             # #RRGGBBAA not supported.
@@ -75,6 +88,14 @@
             # Color reference points to rgb reference.
             Color('$some_color_rgb')
 
+        with self.assertRaises(ValueError):
+            # Variable reference with accidental space.
+            print(Color('$some_color_rgb '))
+
+        with self.assertRaises(ValueError):
+            # Variable reference with accidental space.
+            Color('rgba($non_ rgb_var, 0.4)')
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/tools/style_variable_generator/colors_test.json5 b/tools/style_variable_generator/colors_test.json5
index 948ac1e..65d3b5cf 100644
--- a/tools/style_variable_generator/colors_test.json5
+++ b/tools/style_variable_generator/colors_test.json5
@@ -7,7 +7,7 @@
   colors: {
     text_color_primary: {
       light: "$google_grey_900",
-      dark: "rgb(255, 255, 255)",
+      dark: "$white",
     },
     toggle_color: {
       light: "rgba($text_color_primary_rgb, 0.1)"
diff --git a/ui/base/BUILD.gn b/ui/base/BUILD.gn
index 108800f..b195874 100644
--- a/ui/base/BUILD.gn
+++ b/ui/base/BUILD.gn
@@ -786,8 +786,6 @@
 
   if (is_chromeos_ash) {
     sources += [
-      "ime/chromeos/input_method_allowlist.cc",
-      "ime/chromeos/input_method_allowlist.h",
       "ime/chromeos/mock_component_extension_ime_manager.cc",
       "ime/chromeos/mock_component_extension_ime_manager.h",
       "ime/chromeos/mock_component_extension_ime_manager_delegate.cc",
@@ -802,7 +800,7 @@
       "ime/chromeos/mock_input_method_manager.h",
     ]
     deps += [
-      # Generates a header used by input_method_allowlist.cc
+      # Generates a header used by component_extension_ime_manager.cc
       "//chromeos/ime:gencode",
       "//ui/base/ime/chromeos",
     ]
diff --git a/ui/base/ime/chromeos/ime_input_context_handler_interface.h b/ui/base/ime/chromeos/ime_input_context_handler_interface.h
index 9b8d31e..0fd0f092 100644
--- a/ui/base/ime/chromeos/ime_input_context_handler_interface.h
+++ b/ui/base/ime/chromeos/ime_input_context_handler_interface.h
@@ -37,11 +37,8 @@
       const std::vector<ui::ImeTextSpan>& text_spans) = 0;
   virtual gfx::Range GetAutocorrectRange() = 0;
   virtual gfx::Rect GetAutocorrectCharacterBounds() = 0;
-  // Set the autocorrect range with text.
-  virtual bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                                   uint32_t start,
-                                   uint32_t end) = 0;
-  virtual void ClearAutocorrectRange() = 0;
+  // Sets the autocorrect range to be `range`.
+  virtual bool SetAutocorrectRange(const gfx::Range& range) = 0;
 
   // Called when the engine changes the selection range.
   // Returns true if the operation was successful.
diff --git a/ui/base/ime/chromeos/input_method_allowlist.cc b/ui/base/ime/chromeos/input_method_allowlist.cc
deleted file mode 100644
index 2f0a38c1..0000000
--- a/ui/base/ime/chromeos/input_method_allowlist.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/base/ime/chromeos/input_method_allowlist.h"
-
-#include <stddef.h>
-
-#include <vector>
-
-#include "base/stl_util.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "chromeos/ime/input_methods.h"
-#include "ui/base/ime/chromeos/extension_ime_util.h"
-#include "ui/base/ime/chromeos/input_method_descriptor.h"
-
-namespace chromeos {
-namespace input_method {
-namespace allowlist {
-
-const char kLanguageDelimiter[] = ",";
-
-std::unique_ptr<InputMethodDescriptors> GetSupportedInputMethods() {
-  std::unique_ptr<InputMethodDescriptors> input_methods(
-      new InputMethodDescriptors);
-  input_methods->reserve(base::size(kInputMethods));
-  for (const auto& input_method : kInputMethods) {
-    std::vector<std::string> layouts;
-    layouts.emplace_back(input_method.xkb_layout_id);
-
-    std::vector<std::string> languages =
-        base::SplitString(input_method.language_code, kLanguageDelimiter,
-                          base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
-    DCHECK(!languages.empty());
-
-    input_methods->push_back(InputMethodDescriptor(
-        extension_ime_util::GetInputMethodIDByEngineID(
-            input_method.input_method_id),
-        "", input_method.indicator, layouts, languages,
-        input_method.is_login_keyboard,
-        GURL(),  // options page url.
-        GURL()   // input view page url.
-        ));
-  }
-  return input_methods;
-}
-
-}  // namespace allowlist
-}  // namespace input_method
-}  // namespace chromeos
diff --git a/ui/base/ime/chromeos/input_method_allowlist.h b/ui/base/ime/chromeos/input_method_allowlist.h
deleted file mode 100644
index 4f80b00..0000000
--- a/ui/base/ime/chromeos/input_method_allowlist.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_BASE_IME_CHROMEOS_INPUT_METHOD_ALLOWLIST_H_
-#define UI_BASE_IME_CHROMEOS_INPUT_METHOD_ALLOWLIST_H_
-
-#include <vector>
-
-#include "base/component_export.h"
-#include "base/macros.h"
-
-namespace chromeos {
-namespace input_method {
-
-class InputMethodDescriptor;
-using InputMethodDescriptors = std::vector<InputMethodDescriptor>;
-
-namespace allowlist {
-
-// Returns all input methods that are supported, including ones not active.
-// Based on the list generated by gen_input_methods.py from input_methods.txt.
-// This function never returns nullptr. Note that input method extensions are
-// not included in the result.
-std::unique_ptr<InputMethodDescriptors> COMPONENT_EXPORT(UI_BASE_IME_CHROMEOS)
-    GetSupportedInputMethods();
-
-}  // namespace allowlist
-}  // namespace input_method
-}  // namespace chromeos
-
-#endif  // UI_BASE_IME_CHROMEOS_INPUT_METHOD_ALLOWLIST_H_
diff --git a/ui/base/ime/chromeos/input_method_chromeos.cc b/ui/base/ime/chromeos/input_method_chromeos.cc
index 841fa63f..d963378 100644
--- a/ui/base/ime/chromeos/input_method_chromeos.cc
+++ b/ui/base/ime/chromeos/input_method_chromeos.cc
@@ -314,11 +314,10 @@
     TextInputClient* focused) {
   ConfirmCompositionText(/* reset_engine */ true, /* keep_selection */ false);
 
-  // Removes any autocorrect range in the unfocused TextInputClient.
+  // Remove any autocorrect range in the unfocused TextInputClient.
   gfx::Range text_range;
   if (focused_before && focused_before->GetTextRange(&text_range)) {
-    // This is currently only implemented in RenderWidgetHostViewAura.
-    focused_before->ClearAutocorrectRange();
+    focused_before->SetAutocorrectRange(gfx::Range());
   }
 
   if (GetEngine())
@@ -407,21 +406,10 @@
   return GetTextInputClient()->GetAutocorrectCharacterBounds();
 }
 
-bool InputMethodChromeOS::SetAutocorrectRange(
-    const base::string16& autocorrect_text,
-    uint32_t start,
-    uint32_t end) {
+bool InputMethodChromeOS::SetAutocorrectRange(const gfx::Range& range) {
   if (IsTextInputTypeNone())
     return false;
-  return GetTextInputClient()->SetAutocorrectRange(autocorrect_text,
-                                                   gfx::Range(start, end));
-}
-
-void InputMethodChromeOS::ClearAutocorrectRange() {
-  if (IsTextInputTypeNone())
-    return;
-  // This is currently only implemented in RenderWidgetHostViewAura.
-  return GetTextInputClient()->ClearAutocorrectRange();
+  return GetTextInputClient()->SetAutocorrectRange(range);
 }
 
 bool InputMethodChromeOS::SetSelectionRange(uint32_t start, uint32_t end) {
diff --git a/ui/base/ime/chromeos/input_method_chromeos.h b/ui/base/ime/chromeos/input_method_chromeos.h
index 161b4c7..02507ba0 100644
--- a/ui/base/ime/chromeos/input_method_chromeos.h
+++ b/ui/base/ime/chromeos/input_method_chromeos.h
@@ -64,10 +64,7 @@
       const std::vector<ui::ImeTextSpan>& text_spans) override;
   gfx::Range GetAutocorrectRange() override;
   gfx::Rect GetAutocorrectCharacterBounds() override;
-  bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                           uint32_t start,
-                           uint32_t end) override;
-  void ClearAutocorrectRange() override;
+  bool SetAutocorrectRange(const gfx::Range& range) override;
   bool SetSelectionRange(uint32_t start, uint32_t end) override;
   void UpdateCompositionText(const CompositionText& text,
                              uint32_t cursor_pos,
diff --git a/ui/base/ime/chromeos/input_method_chromeos_unittest.cc b/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
index 09ec204..2b90fcb 100644
--- a/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
+++ b/ui/base/ime/chromeos/input_method_chromeos_unittest.cc
@@ -421,7 +421,7 @@
        OnWillChangeFocusedClientClearAutocorrectRange) {
   input_type_ = TEXT_INPUT_TYPE_TEXT;
   ime_->SetFocusedTextInputClient(this);
-  ime_->SetAutocorrectRange(base::UTF8ToUTF16("text"), 0, 5);
+  ime_->SetAutocorrectRange(gfx::Range(0, 5));
   EXPECT_EQ(gfx::Range(0, 5), this->GetAutocorrectRange());
 
   ime_->SetFocusedTextInputClient(nullptr);
diff --git a/ui/base/ime/chromeos/input_method_manager.h b/ui/base/ime/chromeos/input_method_manager.h
index 815b29b..88a785e 100644
--- a/ui/base/ime/chromeos/input_method_manager.h
+++ b/ui/base/ime/chromeos/input_method_manager.h
@@ -287,12 +287,6 @@
       CandidateWindowObserver* observer) = 0;
   virtual void RemoveImeMenuObserver(ImeMenuObserver* observer) = 0;
 
-  // Returns all input methods that are supported, including ones not active.
-  // This function never returns NULL. Note that input method extensions are NOT
-  // included in the result.
-  virtual std::unique_ptr<InputMethodDescriptors> GetSupportedInputMethods()
-      const = 0;
-
   // Activates the input method property specified by the |key|.
   virtual void ActivateInputMethodMenuItem(const std::string& key) = 0;
 
diff --git a/ui/base/ime/chromeos/mock_ime_input_context_handler.cc b/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
index 0ed9db2..41f39c6e8 100644
--- a/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
+++ b/ui/base/ime/chromeos/mock_ime_input_context_handler.cc
@@ -64,18 +64,11 @@
   return gfx::Rect();
 }
 
-bool MockIMEInputContextHandler::SetAutocorrectRange(
-    const base::string16& autocorrect_text,
-    uint32_t start,
-    uint32_t end) {
-  autocorrect_range_ = gfx::Range(start, end);
+bool MockIMEInputContextHandler::SetAutocorrectRange(const gfx::Range& range) {
+  autocorrect_range_ = range;
   return true;
 }
 
-void MockIMEInputContextHandler::ClearAutocorrectRange() {
-  autocorrect_range_ = gfx::Range();
-}
-
 bool MockIMEInputContextHandler::SetSelectionRange(uint32_t start,
                                                    uint32_t end) {
   ++set_selection_range_call_count_;
diff --git a/ui/base/ime/chromeos/mock_ime_input_context_handler.h b/ui/base/ime/chromeos/mock_ime_input_context_handler.h
index f4b30ca..e4dcda2 100644
--- a/ui/base/ime/chromeos/mock_ime_input_context_handler.h
+++ b/ui/base/ime/chromeos/mock_ime_input_context_handler.h
@@ -48,10 +48,7 @@
       const std::vector<ui::ImeTextSpan>& text_spans) override;
   gfx::Range GetAutocorrectRange() override;
   gfx::Rect GetAutocorrectCharacterBounds() override;
-  bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                           uint32_t start,
-                           uint32_t end) override;
-  void ClearAutocorrectRange() override;
+  bool SetAutocorrectRange(const gfx::Range& range) override;
   bool SetSelectionRange(uint32_t start, uint32_t end) override;
   void DeleteSurroundingText(int32_t offset, uint32_t length) override;
   SurroundingTextInfo GetSurroundingTextInfo() override;
diff --git a/ui/base/ime/chromeos/mock_input_method_manager.cc b/ui/base/ime/chromeos/mock_input_method_manager.cc
index eefa8b6..89327ab 100644
--- a/ui/base/ime/chromeos/mock_input_method_manager.cc
+++ b/ui/base/ime/chromeos/mock_input_method_manager.cc
@@ -147,11 +147,6 @@
 void MockInputMethodManager::RemoveImeMenuObserver(
     InputMethodManager::ImeMenuObserver* observer) {}
 
-std::unique_ptr<InputMethodDescriptors>
-MockInputMethodManager::GetSupportedInputMethods() const {
-  return nullptr;
-}
-
 void MockInputMethodManager::ActivateInputMethodMenuItem(
     const std::string& key) {}
 
diff --git a/ui/base/ime/chromeos/mock_input_method_manager.h b/ui/base/ime/chromeos/mock_input_method_manager.h
index b5197867..89ba2210 100644
--- a/ui/base/ime/chromeos/mock_input_method_manager.h
+++ b/ui/base/ime/chromeos/mock_input_method_manager.h
@@ -99,8 +99,6 @@
       InputMethodManager::CandidateWindowObserver* observer) override;
   void RemoveImeMenuObserver(
       InputMethodManager::ImeMenuObserver* observer) override;
-  std::unique_ptr<InputMethodDescriptors> GetSupportedInputMethods()
-      const override;
   void ActivateInputMethodMenuItem(const std::string& key) override;
   void ConnectInputEngineManager(
       mojo::PendingReceiver<chromeos::ime::mojom::InputEngineManager> receiver)
diff --git a/ui/base/ime/dummy_text_input_client.cc b/ui/base/ime/dummy_text_input_client.cc
index 6a1565c..6eace70 100644
--- a/ui/base/ime/dummy_text_input_client.cc
+++ b/ui/base/ime/dummy_text_input_client.cc
@@ -164,19 +164,11 @@
 }
 
 bool DummyTextInputClient::SetAutocorrectRange(
-    const base::string16& autocorrect_text,
     const gfx::Range& range) {
-  if (autocorrect_text.empty() || range.is_empty())
-    return false;
-
   autocorrect_range_ = range;
   return true;
 }
 
-void DummyTextInputClient::ClearAutocorrectRange() {
-  autocorrect_range_ = gfx::Range();
-}
-
 #endif
 
 #if defined(OS_WIN)
diff --git a/ui/base/ime/dummy_text_input_client.h b/ui/base/ime/dummy_text_input_client.h
index b54a52c..0f2e9568 100644
--- a/ui/base/ime/dummy_text_input_client.h
+++ b/ui/base/ime/dummy_text_input_client.h
@@ -66,9 +66,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   gfx::Range GetAutocorrectRange() const override;
   gfx::Rect GetAutocorrectCharacterBounds() const override;
-  bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                           const gfx::Range& range) override;
-  void ClearAutocorrectRange() override;
+  bool SetAutocorrectRange(const gfx::Range& range) override;
 #endif
 
 #if defined(OS_WIN)
diff --git a/ui/base/ime/text_input_client.h b/ui/base/ime/text_input_client.h
index 59f6df90..dfbdb51 100644
--- a/ui/base/ime/text_input_client.h
+++ b/ui/base/ime/text_input_client.h
@@ -242,15 +242,12 @@
   // These bounds are in screen coordinates.
   virtual gfx::Rect GetAutocorrectCharacterBounds() const = 0;
 
-  // Sets the autocorrect range and returns if it has been set correctly as a
-  // boolean value. Returns false if text or range is empty. Out of range
-  // results in failure and no modification will be made.
-  virtual bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                                   const gfx::Range& range) = 0;
-
-  // Clear the autocorrect range and remove the underline under the
-  // autocorrect text.
-  virtual void ClearAutocorrectRange() = 0;
+  // Sets the autocorrect range to |range|. Clients should show some visual
+  // indication of the range, such as flashing or underlining. If |range| is
+  // empty, then the autocorrect range is cleared.
+  // Returns true if the operation was successful. If |range| is invalid, then
+  // no modifications are made and this function returns false.
+  virtual bool SetAutocorrectRange(const gfx::Range& range) = 0;
 #endif
 
 #if defined(OS_WIN)
diff --git a/ui/base/models/dialog_model_field.h b/ui/base/models/dialog_model_field.h
index 98774ba..54b50c76 100644
--- a/ui/base/models/dialog_model_field.h
+++ b/ui/base/models/dialog_model_field.h
@@ -116,6 +116,7 @@
       base::PassKey<DialogModelHost>) const {
     return accelerators_;
   }
+  int unique_id(base::PassKey<DialogModelHost>) const { return unique_id_; }
   DialogModelButton* AsButton(base::PassKey<DialogModelHost>);
   DialogModelBodyText* AsBodyText(base::PassKey<DialogModelHost>);
   DialogModelCheckbox* AsCheckbox(base::PassKey<DialogModelHost>);
diff --git a/ui/base/models/dialog_model_host.h b/ui/base/models/dialog_model_host.h
index c0de748b..73e0a49b 100644
--- a/ui/base/models/dialog_model_host.h
+++ b/ui/base/models/dialog_model_host.h
@@ -19,11 +19,6 @@
   // or DialogModelHost.
   virtual void Close() = 0;
 
-  // Selects all text of a textfield.
-  // TODO(pbos): Reconsider whether this should be implied by if the textfield
-  // is initially focused.
-  virtual void SelectAllText(int unique_id) = 0;
-
  protected:
   friend class DialogModel;
   friend class DialogModelField;
diff --git a/ui/chromeos/colors/cros_colors.json5 b/ui/chromeos/colors/cros_colors.json5
index dfcdda5..6309b84 100644
--- a/ui/chromeos/colors/cros_colors.json5
+++ b/ui/chromeos/colors/cros_colors.json5
@@ -40,7 +40,7 @@
     },
 
     bg_color: {
-      light: "#ffffff",
+      light: "$white",
       dark: "$google_grey_900",
     },
 
@@ -73,7 +73,7 @@
     /*
      * Component colors.
      */
-    toolbar_bg_color: "#ffffff",
+    toolbar_bg_color: "$white",
     toolbar_search_bg_color: "$google_grey_100",
 
     // TODO(crbug/1122767): Rename menu_button_* to app sidebar menu items.
@@ -82,17 +82,17 @@
     menu_button_outline_color_focused: "$google_blue_600",
 
     menu_item_bg_color_focus: {
-      light: "rgba(0, 0, 0, 0.06)",
-      dark: "rgba(255, 255, 255, 0.08)",
+      light: "rgba($black_rgb, 0.06)",
+      dark: "rgba($white_rgb, 0.08)",
     },
     menu_item_ripple_color: {
-      light: "rgba(0, 0, 0, 0.06)",
-      dark: "rgba(255, 255, 255, 0.08)",
+      light: "rgba($black_rgb, 0.06)",
+      dark: "rgba($white_rgb, 0.08)",
     },
 
     toggle_color: "$icon_color_prominent",
     toggle_bg_color_inactive: "$google_grey_400",
-    toggle_button_color_inactive: "#ffffff",
+    toggle_button_color_inactive: "$white",
     toggle_ripple_color: "rgba($toggle_color_rgb, .2)",
     toggle_ripple_color_inactive: "rgba($google_grey_600_rgb, .15)",
 
@@ -101,7 +101,7 @@
     radio_button_color_unchecked: "$google_grey_700",
     radio_button_ripple_color_unchecked: "rgba($google_grey_600_rgb, .15)",
 
-    separator_color: "rgba(0, 0, 0, 0.12)",
+    separator_color: "rgba($black_rgb, 0.12)",
 
     link_color: "$google_blue_700",
 
@@ -115,8 +115,8 @@
     /* TODO(calamity): Generate a linear-gradient() to use for compositing
        backgrounds */
     button_background_color_primary_hover_overlay: {
-      light: "rgba(255, 255, 255, 0.08)",
-      dark: "rgba(0, 0, 0, 0.08)",
+      light: "rgba($white_rgb, 0.08)",
+      dark: "rgba($black_rgb, 0.08)",
     },
     /* button-primary[disabled] */
     button_background_color_primary_disabled: {
@@ -150,15 +150,15 @@
     /* textfield */
     textfield_background_color: {
       light: "$google_grey_100",
-      dark: "rgba(0, 0, 0, 0.3)",
+      dark: "rgba($black_rgb, 0.3)",
     },
     textfield_label_color: {
       light: "$google_grey_700",
-      dark: "rgba(255, 255, 255, 0.6)",
+      dark: "rgba($white_rgb, 0.6)",
     },
     textfield_input_color: {
       light: "$google_grey_900",
-      dark: "rgba(255, 255, 255, 0.87)",
+      dark: "rgba($white_rgb, 0.87)",
     },
     /* textfield:focus */
     textfield_label_color_focus: "$icon_color_prominent",
@@ -170,15 +170,15 @@
     /* textfield[disabled] */
     textfield_background_color_disabled: {
       light: "rgba($google_grey_100_rgb, 0.38)",
-      dark: "rgba(0, 0, 0, 0.11)",
+      dark: "rgba($black_rgb, 0.11)",
     },
     textfield_label_color_disabled: {
       light: "rgba($google_grey_700_rgb, 0.38)",
-      dark: "rgba(0, 0, 0, 0.23)",
+      dark: "rgba($black_rgb, 0.23)",
     },
     textfield_input_color_disabled: {
       light: "rgba($google_grey_900_rgb, 0.38)",
-      dark: "rgba(255, 255, 255, 0.33)",
+      dark: "rgba($white_rgb, 0.33)",
     },
 
     /*
diff --git a/ui/file_manager/image_loader/piex_loader.js b/ui/file_manager/image_loader/piex_loader.js
index 635bfda..e344f08 100644
--- a/ui/file_manager/image_loader/piex_loader.js
+++ b/ui/file_manager/image_loader/piex_loader.js
@@ -641,15 +641,13 @@
   return readSourceData(source)
       .then((buffer) => {
         if (piexModuleFailed()) {
-          // Just reject here: handle in the .catch() clause below.
-          return Promise.reject('piex wasm module failed');
+          throw new Error('piex wasm module failed');
         }
         imageBuffer = new ImageBuffer(buffer);
         return imageBuffer.process();
       })
       .then((/** !PiexWasmImageResult */ result) => {
         const buffer = /** @type {!ImageBuffer} */ (imageBuffer);
-        buffer.close();
         return new PiexLoaderResponse(buffer.preview(result));
       })
       .catch((error) => {
@@ -657,8 +655,10 @@
           setTimeout(onPiexModuleFailed, 0);
           return Promise.reject('piex wasm module failed');
         }
-        imageBuffer && imageBuffer.close();
         console.error('[PiexLoader] ' + error);
         return Promise.reject(error);
+      })
+      .finally(() => {
+        imageBuffer && imageBuffer.close();
       });
 };
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
index 067cd6e..ab23bce 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.cc
@@ -13,7 +13,6 @@
 #include "ui/base/dragdrop/drag_drop_types.h"
 #include "ui/base/dragdrop/os_exchange_data.h"
 #include "ui/base/dragdrop/os_exchange_data_provider_non_backed.h"
-#include "ui/gfx/geometry/point_f.h"
 #include "ui/ozone/platform/wayland/common/data_util.h"
 #include "ui/ozone/platform/wayland/common/wayland_util.h"
 #include "ui/ozone/platform/wayland/host/wayland_connection.h"
@@ -145,22 +144,35 @@
     data_offer_->Accept(serial, mime);
   }
 
-  std::unique_ptr<OSExchangeData> dragged_data;
-  // If the DND session was initiated from a Chromium window, |data_| already
-  // holds the data to be exchanged, so no needed to read it through Wayland,
-  // thus just copy it here.
-  if (IsDragSource())
-    dragged_data = std::make_unique<OSExchangeData>(data_->provider().Clone());
-
-  int available_operations =
-      DndActionsToDragOperations(data_offer_->source_actions());
-  window_->OnDragEnter(location, std::move(dragged_data), available_operations);
+  if (IsDragSource()) {
+    // If the DND session was initiated from a Chromium window, |data_| already
+    // holds the data to be exchanged, so we don't need to read it through
+    // Wayland and can just copy it here.
+    DCHECK(data_);
+    PropagateOnDragEnter(
+        location, std::make_unique<OSExchangeData>(data_->provider().Clone()));
+  } else {
+    // Otherwise, we are about to accept data dragged from another application.
+    // Reading the data may take some time so set |state_| to |kTrasferring|,
+    // which will defer sending OnDragEnter to the client until the data
+    // is ready.
+    state_ = State::kTransferring;
+    received_data_ = std::make_unique<OSExchangeData>(
+        std::make_unique<OSExchangeDataProviderNonBacked>());
+    last_drag_location_ = location;
+    HandleUnprocessedMimeTypes();
+  }
 }
 
 void WaylandDataDragController::OnDragMotion(const gfx::PointF& location) {
   if (!window_)
     return;
 
+  if (state_ == State::kTransferring) {
+    last_drag_location_ = location;
+    return;
+  }
+
   DCHECK(data_offer_);
   int available_operations =
       DndActionsToDragOperations(data_offer_->source_actions());
@@ -173,9 +185,8 @@
   if (!window_)
     return;
 
-  // Leave event can arrive while data is being transferred. As it cannot be
-  // handled right away, just mark it to be processed when the data is ready.
   if (state_ == State::kTransferring) {
+    // We cannot leave until the transfer is finished.  Postponing.
     is_leave_pending_ = true;
     return;
   }
@@ -190,21 +201,13 @@
   if (!window_)
     return;
 
-  if (IsDragSource()) {
-    // This means the data is being exchanged between Chromium windows. In this
-    // case, data is supposed to have already been sent to the drop handler
-    // before (see OnDragEnter()), expecting to receive null at this stage.
-    OnDataTransferFinished(nullptr);
-    return;
-  }
+  window_->OnDragDrop();
 
-  // Otherwise, we are about to accept data dragged from another application.
-  // Reading the data may take some time so set |state_| to |kTrasfering|, which
-  // will make final "leave" event handling to be postponed until data is ready.
-  state_ = State::kTransferring;
-  received_data_ = std::make_unique<OSExchangeData>(
-      std::make_unique<OSExchangeDataProviderNonBacked>());
-  HandleUnprocessedMimeTypes();
+  // Offer must be finished and destroyed here as some compositors may delay to
+  // send wl_data_source::finished|cancelled until owning client destroys the
+  // drag offer. e.g: Exosphere.
+  data_offer_->FinishOffer();
+  data_offer_.reset();
 }
 
 void WaylandDataDragController::OnDataSourceFinish(bool completed) {
@@ -223,7 +226,6 @@
   data_offer_.reset();
   data_.reset();
   data_device_->ResetDragDelegate();
-
   state_ = State::kIdle;
 }
 
@@ -282,7 +284,7 @@
 void WaylandDataDragController::HandleUnprocessedMimeTypes() {
   DCHECK_EQ(state_, State::kTransferring);
   std::string mime_type = GetNextUnprocessedMimeType();
-  if (mime_type.empty()) {
+  if (mime_type.empty() || is_leave_pending_) {
     OnDataTransferFinished(std::move(received_data_));
   } else {
     DCHECK(data_offer_);
@@ -309,21 +311,25 @@
 
 void WaylandDataDragController::OnDataTransferFinished(
     std::unique_ptr<OSExchangeData> received_data) {
-  window_->OnDragDrop(std::move(received_data));
-
-  // Offer must be finished and destroyed here as some compositors may delay to
-  // send wl_data_source::finished|cancelled until owning client destroys the
-  // drag offer. e.g: Exosphere.
-  data_offer_->FinishOffer();
-  data_offer_.reset();
-
   unprocessed_mime_types_.clear();
   state_ = State::kIdle;
 
   // If |is_leave_pending_| is set, it means a 'leave' event was fired while
-  // data was on transit, so process it here (See OnDragLeave for more context).
-  if (is_leave_pending_)
-    OnDragLeave();
+  // data was on transit (see OnDragLeave for more context).  Sending
+  // OnDragEnter to the window makes no sense anymore because the drag is no
+  // longer over it.  Reset and exit.
+  if (is_leave_pending_) {
+    if (data_offer_) {
+      data_offer_->FinishOffer();
+      data_offer_.reset();
+    }
+    data_.reset();
+    data_device_->ResetDragDelegate();
+    is_leave_pending_ = false;
+    return;
+  }
+
+  PropagateOnDragEnter(last_drag_location_, std::move(received_data));
 }
 
 // Returns the next MIME type to be received from the source process, or an
@@ -342,4 +348,15 @@
   return {};
 }
 
+void WaylandDataDragController::PropagateOnDragEnter(
+    const gfx::PointF& location,
+    std::unique_ptr<OSExchangeData> data) {
+  DCHECK(window_);
+
+  window_->OnDragEnter(
+      location, std::move(data),
+      DndActionsToDragOperations(data_offer_->source_actions()));
+  OnDragMotion(location);
+}
+
 }  // namespace ui
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
index 9ddd0c8..79589467 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller.h
@@ -11,6 +11,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/weak_ptr.h"
+#include "ui/gfx/geometry/point_f.h"
 #include "ui/ozone/platform/wayland/common/wayland_object.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_device.h"
 #include "ui/ozone/platform/wayland/host/wayland_data_source.h"
@@ -28,15 +29,40 @@
 class WaylandWindowManager;
 class WaylandShmBuffer;
 
-// WaylandDataDragController implements regular data exchanging between Chromium
-// and other client applications on top of the Wayland Drag and Drop protocol.
-// By implementing both DataDevice::DragDelegate and DataSource::Delegate,
-// it is responsible for handling both DND sessions initiated from Chromium
-// windows as well as those triggered by other clients.
+// WaylandDataDragController implements regular data exchange on top of the
+// Wayland Drag and Drop protocol.  The data can be dragged within the Chromium
+// window, or between Chromium and other application in both directions.
+//
+// The outgoing drag starts via the StartSession() method.  For more context,
+// see WaylandTopLevelWindow::StartDrag().
+//
+// The incoming drag starts with the call to OnDragEnter() from the Wayland side
+// (the data device), and ends up in call to WaylandWindow::OnDragEnter(), but
+// two ways of coming there are possible:
+//
+// 1.  The drag has been initiated by a Chromium window.  In this case, the data
+// that is being dragged is available right away, and therefore the controller
+// can forward the data to the window immediately.
+//
+// 2.  The data is being dragged from another application.  Before notifying the
+// window, the controller requests the data from the source side, which results
+// in a number of requests to Wayland and data transfers from it.  Only after
+// data records of all supported MIME types have been received, the window will
+// be notified.
+//
+// It is possible that further drag events come while the data is still being
+// transferred.  The drag motion event is ignored; the window will first receive
+// OnDragEnter, and any OnDragMotion that comes after that.  The drag leave
+// event stops the transfer and cancels the operation; the window will not
+// receive anything at all.
 class WaylandDataDragController : public WaylandDataDevice::DragDelegate,
                                   public WaylandDataSource::Delegate {
  public:
-  enum class State { kIdle, kStarted, kTransferring };
+  enum class State {
+    kIdle,          // Doing nothing special
+    kStarted,       // The outgoing drag is in progress.
+    kTransferring,  // The incoming data is transferred from the source.
+  };
 
   WaylandDataDragController(WaylandConnection* connection,
                             WaylandDataDeviceManager* data_device_manager);
@@ -84,6 +110,10 @@
   void OnDataTransferFinished(
       std::unique_ptr<ui::OSExchangeData> received_data);
   std::string GetNextUnprocessedMimeType();
+  // Calls the window's OnDragEnter with the given location and data,
+  // then immediately calls OnDragMotion to get the actual operation.
+  void PropagateOnDragEnter(const gfx::PointF& location,
+                            std::unique_ptr<OSExchangeData> data);
 
   WaylandConnection* const connection_;
   WaylandDataDeviceManager* const data_device_manager_;
@@ -92,6 +122,7 @@
 
   State state_ = State::kIdle;
 
+  // Data offered by us to the other side.
   std::unique_ptr<WaylandDataSource> data_source_;
 
   // When dragging is started from Chromium, |data_| holds the data to be sent
@@ -116,6 +147,9 @@
   // Current window under pointer.
   WaylandWindow* window_ = nullptr;
 
+  // The most recent location received while dragging the data.
+  gfx::PointF last_drag_location_;
+
   // The data delivered from Wayland
   std::unique_ptr<ui::OSExchangeData> received_data_;
 
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
index aeae253..50e2c95 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
@@ -78,11 +78,7 @@
   MockDropHandler() = default;
   ~MockDropHandler() override = default;
 
-  MOCK_METHOD4(OnDragEnter,
-               void(const gfx::PointF& point,
-                    std::unique_ptr<OSExchangeData> data,
-                    int operation,
-                    int modifiers));
+  MOCK_METHOD0(MockOnDragEnter, void());
   MOCK_METHOD3(MockDragMotion,
                int(const gfx::PointF& point, int operation, int modifiers));
   MOCK_METHOD0(MockOnDragDrop, void());
@@ -101,9 +97,15 @@
   int available_operations() const { return available_operations_; }
 
  protected:
+  void OnDragEnter(const gfx::PointF& point,
+                   std::unique_ptr<ui::OSExchangeData> data,
+                   int operation,
+                   int modifiers) override {
+    dropped_data_ = std::move(data);
+    MockOnDragEnter();
+  }
   void OnDragDrop(std::unique_ptr<OSExchangeData> data,
                   int modifiers) override {
-    dropped_data_ = std::move(data);
     MockOnDragDrop();
     on_drop_closure_.Run();
     on_drop_closure_.Reset();
@@ -302,6 +304,8 @@
       1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
       wl_fixed_from_int(entered_point.y()), data_offer);
 
+  Sync();
+
   int64_t time =
       (EventTimeForNow() - base::TimeTicks()).InMilliseconds() & UINT32_MAX;
   gfx::Point motion_point(11, 11);
@@ -339,27 +343,27 @@
       kMimeTypeURIList,
       ToClipboardData(std::string("file:///home/user/file\r\n")));
 
-  EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _, _)).Times(1);
+  EXPECT_CALL(*drop_handler_, MockOnDragEnter()).Times(1);
   gfx::Point entered_point(10, 10);
   data_device_manager_->data_device()->OnEnter(
       1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
       wl_fixed_from_int(entered_point.y()), data_offer);
+  // Here we are expecting three data items, so there will be three roundtrips
+  // to the Wayland and back.  Hence Sync() three times.
   Sync();
-  Mock::VerifyAndClearExpectations(drop_handler_.get());
+  Sync();
+  Sync();
 
   EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
   base::RunLoop loop;
   drop_handler_->SetOnDropClosure(loop.QuitClosure());
   data_device_manager_->data_device()->OnDrop();
 
-  // Here we are expecting three data items, so there will be three roundtrips
-  // to the Wayland and back.  Hence Sync() three times.
-  Sync();
-  Sync();
   Sync();
   loop.Run();
   Mock::VerifyAndClearExpectations(drop_handler_.get());
 
+  ASSERT_NE(drop_handler_->dropped_data(), nullptr);
   EXPECT_TRUE(drop_handler_->dropped_data()->HasString());
   EXPECT_TRUE(drop_handler_->dropped_data()->HasFile());
   EXPECT_TRUE(drop_handler_->dropped_data()->HasURL(kFilenameToURLPolicy));
@@ -386,13 +390,12 @@
     auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
     data_offer->OnOffer(kMimeTypeURIList, ToClipboardData(kCase.content));
 
-    EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _, _)).Times(1);
+    EXPECT_CALL(*drop_handler_, MockOnDragEnter()).Times(1);
     gfx::Point entered_point(10, 10);
     data_device_manager_->data_device()->OnEnter(
         1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
         wl_fixed_from_int(entered_point.y()), data_offer);
     Sync();
-    Mock::VerifyAndClearExpectations(drop_handler_.get());
 
     EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
     base::RunLoop loop;
@@ -441,13 +444,12 @@
     data_offer->OnOffer(kMimeTypeMozillaURL,
                         ToClipboardData(base::UTF8ToUTF16(kCase.content)));
 
-    EXPECT_CALL(*drop_handler_, OnDragEnter(_, _, _, _)).Times(1);
+    EXPECT_CALL(*drop_handler_, MockOnDragEnter()).Times(1);
     gfx::Point entered_point(10, 10);
     data_device_manager_->data_device()->OnEnter(
         1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
         wl_fixed_from_int(entered_point.y()), data_offer);
     Sync();
-    Mock::VerifyAndClearExpectations(drop_handler_.get());
 
     EXPECT_CALL(*drop_handler_, MockOnDragDrop()).Times(1);
     base::RunLoop loop;
@@ -520,6 +522,7 @@
   data_device_manager_->data_device()->OnEnter(
       1002, surface_->resource(), wl_fixed_from_int(entered_point.x()),
       wl_fixed_from_int(entered_point.y()), data_offer);
+  Sync();
 
   int64_t time = 1;
   gfx::Point motion_point(11, 11);
diff --git a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
index caedaf7..3aaca26c 100644
--- a/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_toplevel_window.cc
@@ -352,12 +352,12 @@
       /*modifiers=*/0);
 }
 
-void WaylandToplevelWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {
+void WaylandToplevelWindow::OnDragDrop() {
   WmDropHandler* drop_handler = GetWmDropHandler(*this);
   if (!drop_handler)
     return;
   // TODO(crbug.com/1102857): get the real event modifier here.
-  drop_handler->OnDragDrop(std::move(data), /*modifiers=*/0);
+  drop_handler->OnDragDrop({}, /*modifiers=*/0);
 }
 
 void WaylandToplevelWindow::OnDragLeave() {
diff --git a/ui/ozone/platform/wayland/host/wayland_toplevel_window.h b/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
index 08ac254..5de398a 100644
--- a/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_toplevel_window.h
@@ -74,7 +74,7 @@
                    std::unique_ptr<OSExchangeData> data,
                    int operation) override;
   int OnDragMotion(const gfx::PointF& point, int operation) override;
-  void OnDragDrop(std::unique_ptr<OSExchangeData> data) override;
+  void OnDragDrop() override;
   void OnDragLeave() override;
   void OnDragSessionClose(uint32_t dnd_action) override;
   bool OnInitialize(PlatformWindowInitProperties properties) override;
diff --git a/ui/ozone/platform/wayland/host/wayland_window.cc b/ui/ozone/platform/wayland/host/wayland_window.cc
index a79947e..aeb12a5f 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window.cc
@@ -358,7 +358,7 @@
   return -1;
 }
 
-void WaylandWindow::OnDragDrop(std::unique_ptr<OSExchangeData> data) {}
+void WaylandWindow::OnDragDrop() {}
 
 void WaylandWindow::OnDragLeave() {}
 
diff --git a/ui/ozone/platform/wayland/host/wayland_window.h b/ui/ozone/platform/wayland/host/wayland_window.h
index e719914f..860ca85d 100644
--- a/ui/ozone/platform/wayland/host/wayland_window.h
+++ b/ui/ozone/platform/wayland/host/wayland_window.h
@@ -165,7 +165,7 @@
                            std::unique_ptr<OSExchangeData> data,
                            int operation);
   virtual int OnDragMotion(const gfx::PointF& point, int operation);
-  virtual void OnDragDrop(std::unique_ptr<OSExchangeData> data);
+  virtual void OnDragDrop();
   virtual void OnDragLeave();
   virtual void OnDragSessionClose(uint32_t dnd_action);
 
diff --git a/ui/views/bubble/bubble_dialog_model_host.cc b/ui/views/bubble/bubble_dialog_model_host.cc
index 77652cea..ae244917 100644
--- a/ui/views/bubble/bubble_dialog_model_host.cc
+++ b/ui/views/bubble/bubble_dialog_model_host.cc
@@ -321,15 +321,6 @@
   model_.reset();
 }
 
-void BubbleDialogModelHost::SelectAllText(int unique_id) {
-  const DialogModelHostField& field_view_info =
-      FindDialogModelHostField(model_->GetFieldByUniqueId(unique_id));
-
-  DCHECK(field_view_info.focusable_view);
-  static_cast<views::Textfield*>(field_view_info.focusable_view)
-      ->SelectAll(false);
-}
-
 void BubbleDialogModelHost::OnFieldAdded(ui::DialogModelField* field) {
   switch (field->type(GetPassKey())) {
     case ui::DialogModelField::kButton:
@@ -491,6 +482,15 @@
           : model_field->accessible_name(GetPassKey()));
   textfield->SetText(model_field->text());
 
+  // If this textfield is initially focused the text should be initially
+  // selected as well.
+  base::Optional<int> initially_focused_field_id =
+      model_->initially_focused_field(GetPassKey());
+  if (initially_focused_field_id &&
+      model_field->unique_id(GetPassKey()) == initially_focused_field_id) {
+    textfield->SelectAll(true);
+  }
+
   property_changed_subscriptions_.push_back(
       textfield->AddTextChangedCallback(base::BindRepeating(
           [](ui::DialogModelTextfield* model_field,
diff --git a/ui/views/bubble/bubble_dialog_model_host.h b/ui/views/bubble/bubble_dialog_model_host.h
index 78e870c..9f05a03c 100644
--- a/ui/views/bubble/bubble_dialog_model_host.h
+++ b/ui/views/bubble/bubble_dialog_model_host.h
@@ -51,7 +51,6 @@
 
   // ui::DialogModelHost:
   void Close() override;
-  void SelectAllText(int unique_id) override;
   void OnFieldAdded(ui::DialogModelField* field) override;
 
  private:
diff --git a/ui/views/controls/prefix_selector.cc b/ui/views/controls/prefix_selector.cc
index 6659ea1d..8356b8a 100644
--- a/ui/views/controls/prefix_selector.cc
+++ b/ui/views/controls/prefix_selector.cc
@@ -185,16 +185,11 @@
   return gfx::Rect();
 }
 
-bool PrefixSelector::SetAutocorrectRange(const base::string16& autocorrect_text,
-                                         const gfx::Range& range) {
-  // TODO(crbug.com/1091088) Implement setAutocorrectRange.
+bool PrefixSelector::SetAutocorrectRange(const gfx::Range& range) {
+  // TODO(crbug.com/1091088): Implement SetAutocorrectRange.
   NOTIMPLEMENTED_LOG_ONCE();
   return false;
 }
-
-void PrefixSelector::ClearAutocorrectRange() {
-  // TODO(crbug.com/1091088) Implement ClearAutocorrectRange.
-}
 #endif
 
 #if defined(OS_WIN)
diff --git a/ui/views/controls/prefix_selector.h b/ui/views/controls/prefix_selector.h
index 8bbb455..3699c3a 100644
--- a/ui/views/controls/prefix_selector.h
+++ b/ui/views/controls/prefix_selector.h
@@ -86,9 +86,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   gfx::Range GetAutocorrectRange() const override;
   gfx::Rect GetAutocorrectCharacterBounds() const override;
-  bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                           const gfx::Range& range) override;
-  void ClearAutocorrectRange() override;
+  bool SetAutocorrectRange(const gfx::Range& range) override;
 #endif
 
 #if defined(OS_WIN)
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc
index dd71b2b..251dc3f 100644
--- a/ui/views/controls/textfield/textfield.cc
+++ b/ui/views/controls/textfield/textfield.cc
@@ -1877,15 +1877,12 @@
   return rect;
 }
 
-bool Textfield::SetAutocorrectRange(const base::string16& autocorrect_text,
-                                    const gfx::Range& range) {
-  base::UmaHistogramEnumeration("InputMethod.Assistive.Autocorrect.Count",
-                                TextInputClient::SubClass::kTextField);
-  return model_->SetAutocorrectRange(autocorrect_text, range);
-}
-
-void Textfield::ClearAutocorrectRange() {
-  model_->ClearAutocorrectRange();
+bool Textfield::SetAutocorrectRange(const gfx::Range& range) {
+  if (!range.is_empty()) {
+    base::UmaHistogramEnumeration("InputMethod.Assistive.Autocorrect.Count",
+                                  TextInputClient::SubClass::kTextField);
+  }
+  return model_->SetAutocorrectRange(range);
 }
 #endif
 
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h
index 20f7cd7a..3ee726a 100644
--- a/ui/views/controls/textfield/textfield.h
+++ b/ui/views/controls/textfield/textfield.h
@@ -419,9 +419,7 @@
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   gfx::Range GetAutocorrectRange() const override;
   gfx::Rect GetAutocorrectCharacterBounds() const override;
-  bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                           const gfx::Range& range) override;
-  void ClearAutocorrectRange() override;
+  bool SetAutocorrectRange(const gfx::Range& range) override;
 #endif
 
 #if defined(OS_WIN)
diff --git a/ui/views/controls/textfield/textfield_model.cc b/ui/views/controls/textfield/textfield_model.cc
index c470f28b..82e865e 100644
--- a/ui/views/controls/textfield/textfield_model.cc
+++ b/ui/views/controls/textfield/textfield_model.cc
@@ -755,44 +755,14 @@
 }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-bool TextfieldModel::SetAutocorrectRange(const base::string16& autocorrect_text,
-                                         const gfx::Range& autocorrect_range) {
-  if (autocorrect_text.empty() || autocorrect_range.is_empty())
+bool TextfieldModel::SetAutocorrectRange(const gfx::Range& range) {
+  // TODO(crbug.com/1108170): Add an underline to |range|.
+  if (range.GetMax() > render_text()->text().length()) {
     return false;
-
-  // TODO(crbug.com/1108170): Use original text to create the Undo window.
-  base::string16 current_text =
-      render_text_->GetTextFromRange(autocorrect_range);
-  // current text should always be valid.
-  if (current_text.empty())
-    return false;
-
-  original_text_ = std::move(current_text);
-  uint32_t autocorrect_range_start = autocorrect_range.start();
-
-  // TODO(crbug.com/1108170): Update the autocorrect range when the
-  // composition changes for ChromeOS. The current autocorrect_range_ does not
-  // get updated when composition changes or more text is committed.
-  autocorrect_range_ =
-      gfx::Range(autocorrect_range_start,
-                 autocorrect_text.length() + autocorrect_range_start);
-
-  base::string16 before_text =
-      render_text_->GetTextFromRange(gfx::Range(0, autocorrect_range.start()));
-  base::string16 after_text = render_text_->GetTextFromRange(gfx::Range(
-      autocorrect_range.end(),
-      std::max(autocorrect_range.end(),
-               static_cast<uint32_t>(render_text_->text().length()))));
-  base::string16 new_text =
-      before_text.append(autocorrect_text).append(after_text);
-  SetRenderTextText(new_text);
+  }
+  autocorrect_range_ = range;
   return true;
 }
-
-void TextfieldModel::ClearAutocorrectRange() {
-  autocorrect_range_ = gfx::Range();
-  original_text_ = base::EmptyString16();
-}
 #endif
 
 void TextfieldModel::SetCompositionFromExistingText(const gfx::Range& range) {
diff --git a/ui/views/controls/textfield/textfield_model.h b/ui/views/controls/textfield/textfield_model.h
index 9bfa2f0..5050309 100644
--- a/ui/views/controls/textfield/textfield_model.h
+++ b/ui/views/controls/textfield/textfield_model.h
@@ -238,13 +238,10 @@
   // Return the text range corresponding to the autocorrected text.
   const gfx::Range& autocorrect_range() const { return autocorrect_range_; }
 
-  // Replace the text in the specified range with the autocorrect text and
-  // store necessary metadata (The size of the new text + the original text)
-  // to be able to undo this change if needed.
-  bool SetAutocorrectRange(const base::string16& autocorrect_text,
-                           const gfx::Range& range);
-
-  void ClearAutocorrectRange();
+  // Sets the autocorrect range to |range|. If |range| is empty, then the
+  // autocorrect range is cleared. Returns true if the range was set or cleared
+  // successfully.
+  bool SetAutocorrectRange(const gfx::Range& range);
 #endif
 
   // Puts the text in the specified range into composition mode.
@@ -340,10 +337,6 @@
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
   gfx::Range autocorrect_range_;
-  // Original text is the text that was replaced by the autocorrect feature.
-  // This should be restored if the Undo button corresponding to the Autocorrect
-  // window is pressed.
-  base::string16 original_text_;
 #endif
 
   // The list of Edits. The oldest Edits are at the front of the list, and the
diff --git a/ui/views/controls/textfield/textfield_unittest.cc b/ui/views/controls/textfield/textfield_unittest.cc
index efa9d15..de03610 100644
--- a/ui/views/controls/textfield/textfield_unittest.cc
+++ b/ui/views/controls/textfield/textfield_unittest.cc
@@ -3089,99 +3089,42 @@
 }
 
 #if BUILDFLAG(IS_CHROMEOS_ASH)
-TEST_F(TextfieldTest, SetAutocorrectRangeText) {
+TEST_F(TextfieldTest, SetAutocorrectRange) {
   InitTextfield();
 
-  ui::CompositionText composition;
-  composition.text = UTF8ToUTF16("Initial txt");
-  textfield_->SetCompositionText(composition);
-  textfield_->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
-                                  gfx::Range(8, 11));
+  textfield_->SetText(ASCIIToUTF16("abc def ghi"));
+  textfield_->SetAutocorrectRange(gfx::Range(4, 7));
 
   gfx::Range autocorrect_range = textfield_->GetAutocorrectRange();
-  EXPECT_EQ(autocorrect_range, gfx::Range(8, 24));
-
-  base::string16 text;
-  textfield_->GetTextFromRange(gfx::Range(0, 24), &text);
-  EXPECT_EQ(text, UTF8ToUTF16("Initial text replacement"));
-}
-
-TEST_F(TextfieldTest, SetAutocorrectRangeExplicitlySet) {
-  InitTextfield();
-  textfield_->InsertText(UTF8ToUTF16("Initial txt"));
-  textfield_->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
-                                  gfx::Range(8, 11));
-
-  gfx::Range autocorrectRange = textfield_->GetAutocorrectRange();
-  EXPECT_EQ(autocorrectRange, gfx::Range(8, 24));
-
-  base::string16 text;
-  textfield_->GetTextFromRange(gfx::Range(0, 24), &text);
-  EXPECT_EQ(text, UTF8ToUTF16("Initial text replacement"));
+  EXPECT_EQ(autocorrect_range, gfx::Range(4, 7));
 }
 
 TEST_F(TextfieldTest, DoesNotSetAutocorrectRangeWhenRangeGivenIsInvalid) {
   InitTextfield();
 
-  ui::CompositionText composition;
-  composition.text = UTF8ToUTF16("Initial");
-  textfield_->SetCompositionText(composition);
+  textfield_->SetText(ASCIIToUTF16("abc"));
 
-  EXPECT_FALSE(textfield_->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
-                                               gfx::Range(8, 11)));
-  EXPECT_EQ(gfx::Range(0, 0), textfield_->GetAutocorrectRange());
-  gfx::Range range;
-  textfield_->GetTextRange(&range);
-  base::string16 text;
-  textfield_->GetTextFromRange(range, &text);
-  EXPECT_EQ(composition.text, text);
-}
-
-TEST_F(TextfieldTest, ReturnsFalseWhenSetAutocorrectRangeWithEmptyText) {
-  InitTextfield();
-
-  ui::CompositionText composition;
-  composition.text = UTF8ToUTF16("Initial");
-  textfield_->SetCompositionText(composition);
-
-  EXPECT_FALSE(
-      textfield_->SetAutocorrectRange(base::EmptyString16(), gfx::Range(0, 2)));
+  EXPECT_FALSE(textfield_->SetAutocorrectRange(gfx::Range(8, 11)));
+  EXPECT_TRUE(textfield_->GetAutocorrectRange().is_empty());
 }
 
 TEST_F(TextfieldTest,
        ClearsAutocorrectRangeWhenSetAutocorrectRangeWithEmptyRange) {
   InitTextfield();
 
-  ui::CompositionText composition;
-  composition.text = UTF8ToUTF16("Initial");
-  textfield_->SetCompositionText(composition);
+  textfield_->SetText(ASCIIToUTF16("abc"));
 
-  EXPECT_FALSE(
-      textfield_->SetAutocorrectRange(UTF8ToUTF16("Test"), gfx::Range(0, 0)));
-}
-
-TEST_F(TextfieldTest, ClearAutocorrectRange) {
-  InitTextfield();
-  textfield_->InsertText(UTF8ToUTF16("Initial txt"));
-  textfield_->SetAutocorrectRange(ASCIIToUTF16("text replacement"),
-                                  gfx::Range(8, 11));
-
-  EXPECT_EQ(textfield_->GetText(), UTF8ToUTF16("Initial text replacement"));
-  EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range(8, 24));
-
-  textfield_->ClearAutocorrectRange();
-
-  EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range());
+  EXPECT_TRUE(textfield_->SetAutocorrectRange(gfx::Range()));
+  EXPECT_TRUE(textfield_->GetAutocorrectRange().is_empty());
 }
 
 TEST_F(TextfieldTest, GetAutocorrectCharacterBoundsTest) {
   InitTextfield();
 
   textfield_->InsertText(UTF8ToUTF16("hello placeholder text"));
-  textfield_->SetAutocorrectRange(ASCIIToUTF16("longlonglongtext"),
-                                  gfx::Range(3, 10));
+  textfield_->SetAutocorrectRange(gfx::Range(3, 10));
 
-  EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range(3, 19));
+  EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range(3, 10));
 
   gfx::Rect rect_for_long_text = textfield_->GetAutocorrectCharacterBounds();
 
@@ -3189,7 +3132,7 @@
   textfield_->DeleteRange(gfx::Range(0, 99));
 
   textfield_->InsertText(UTF8ToUTF16("hello placeholder text"));
-  textfield_->SetAutocorrectRange(ASCIIToUTF16("short"), gfx::Range(3, 10));
+  textfield_->SetAutocorrectRange(gfx::Range(3, 8));
 
   EXPECT_EQ(textfield_->GetAutocorrectRange(), gfx::Range(3, 8));