diff --git a/DEPS b/DEPS
index c4a4202..044308b 100644
--- a/DEPS
+++ b/DEPS
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'd4db58fa238a3e6f80fc87bc7fe539cd9f54aa7f',
+  'pdfium_revision': '9a785afee976e60fa2bd3d462cdcb1c3636d97dd',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '2098afcc067c739c573144d79af4bb25f8abfddf',
+  'catapult_revision': '95c33d94d5efa5157c45c96cb7f2279c655568a7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -109,6 +109,10 @@
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
   'scanbuild_revision': '15bd7ca2934162c51654ddffc52933e45f95e7ef',
+  # Three lines of non-changing comments so that
+  # the commit queue can handle CLs rolling libprotobuf-mutator
+  # and whatever else without interference from each other.
+  'libprotobuf-mutator': '9f19110ef75ff7e8c50428247a262a131f312c3c',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -305,6 +309,9 @@
   'src/third_party/libFuzzer/src':
     Var('chromium_git') + '/chromium/llvm-project/llvm/lib/Fuzzer.git' + '@' +  Var('libfuzzer_revision'),
 
+  'src/third_party/libprotobuf-mutator/src':
+    Var('chromium_git') + '/external/github.com/google/libprotobuf-mutator.git' + '@' +  Var('libprotobuf-mutator'),
+
   'src/third_party/visualmetrics/src':
     Var('chromium_git') + '/external/github.com/WPO-Foundation/visualmetrics.git' + '@' +  '1edde9d2fe203229c895b648fdec355917200ad6',
 
diff --git a/WATCHLISTS b/WATCHLISTS
index 671e845..0b141fe 100644
--- a/WATCHLISTS
+++ b/WATCHLISTS
@@ -441,9 +441,6 @@
                   'media/cdm/|' \
                   'third_party/widevine/cdm/'
     },
-    'events': {
-      'filepath': 'ui/events/',
-    },
     'extension': {
       'filepath': 'extension',
     },
@@ -1011,6 +1008,9 @@
     'task_manager': {
       'filepath': 'task_manager'
     },
+    'tbmv2_metrics': {
+      'filepath': 'third_party/catapult/tracing/tracing/metrics'
+    },
     'tcmalloc': {
       'filepath': 'third_party/tcmalloc'
     },
@@ -1891,7 +1891,6 @@
     'drive': ['tfarina@chromium.org'],
     'drive_resource_metadata': ['hashimoto+watch@chromium.org'],
     'eme': ['eme-reviews@chromium.org'],
-    'events': ['tdresser+watch@chromium.org'],
     'extension': ['chromium-apps-reviews@chromium.org',
                   'extensions-reviews@chromium.org'],
     'feature_policy': ['lunalu@chromium.org',
@@ -2043,7 +2042,8 @@
     'ozone': ['kalyan.kondapally@intel.com',
               'ozone-reviews@chromium.org'],
     'page_load_metrics' : ['csharrison+watch@chromium.org',
-                           'loading-reviews+metrics@chromium.org'],
+                           'loading-reviews+metrics@chromium.org',
+                           'speed-metrics-reviews@chromium.org'],
     'panels': ['dcheng@chromium.org',
                'dimich@chromium.org',
                'jennb@chromium.org',
@@ -2120,6 +2120,7 @@
     'tab_contents': ['ajwong+watch@chromium.org',
                      'avi@chromium.org',
                      'creis+watch@chromium.org'],
+    'tbmv2_metrics': ['speed-metrics-reviews@chromium.org'],
     'tcmalloc': ['dmikurube@chromium.org'],
     'telemetry': ['telemetry-reviews@chromium.org'],
     'test_runner': ['jochen+watch@chromium.org',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 45a817b..df0b83b 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -587,7 +587,6 @@
     "common/wm_transient_window_observer.h",
     "common/wm_window.cc",
     "common/wm_window.h",
-    "common/wm_window_property.h",
     "common/wm_window_user_data.h",
     "debug.cc",
     "debug.h",
diff --git a/ash/common/accelerators/debug_commands.cc b/ash/common/accelerators/debug_commands.cc
index 1b7d3b20..c84d84f 100644
--- a/ash/common/accelerators/debug_commands.cc
+++ b/ash/common/accelerators/debug_commands.cc
@@ -14,8 +14,8 @@
 #include "ash/common/wm/maximize_mode/maximize_mode_controller.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/root_window_controller.h"
+#include "ash/wm/window_properties.h"
 #include "base/command_line.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
@@ -63,8 +63,7 @@
        << ((window == active_window) ? " [active] " : " ")
        << (window->IsVisible() ? " visible " : " ")
        << window->GetBounds().ToString()
-       << (window->GetBoolProperty(
-               WmWindowProperty::SNAP_CHILDREN_TO_PIXEL_BOUNDARY)
+       << (window->aura_window()->GetProperty(kSnapChildrenToPixelBoundary)
                ? " [snapped] "
                : "")
        << ", subpixel offset="
diff --git a/ash/common/frame/custom_frame_view_ash.cc b/ash/common/frame/custom_frame_view_ash.cc
index 43d55bef..470dd01 100644
--- a/ash/common/frame/custom_frame_view_ash.cc
+++ b/ash/common/frame/custom_frame_view_ash.cc
@@ -15,9 +15,9 @@
 #include "ash/common/wm/window_state_observer.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/shared/immersive_fullscreen_controller.h"
 #include "ash/shared/immersive_fullscreen_controller_delegate.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_observer.h"
 #include "ui/gfx/geometry/rect.h"
@@ -195,8 +195,8 @@
   // |header_view_| is set as the non client view's overlay view so that it can
   // overlay the web contents in immersive fullscreen.
   frame->non_client_view()->SetOverlayView(new OverlayView(header_view_));
-  frame_window->SetColorProperty(WmWindowProperty::TOP_VIEW_COLOR,
-                                 header_view_->GetInactiveFrameColor());
+  frame_window->aura_window()->SetProperty(
+      aura::client::kTopViewColor, header_view_->GetInactiveFrameColor());
 
   // A delegate for a more complex way of fullscreening the window may already
   // be set. This is the case for packaged apps.
@@ -220,8 +220,8 @@
                                         SkColor inactive_frame_color) {
   header_view_->SetFrameColors(active_frame_color, inactive_frame_color);
   WmWindow* frame_window = WmWindow::Get(frame_->GetNativeWindow());
-  frame_window->SetColorProperty(WmWindowProperty::TOP_VIEW_COLOR,
-                                 header_view_->GetInactiveFrameColor());
+  frame_window->aura_window()->SetProperty(
+      aura::client::kTopViewColor, header_view_->GetInactiveFrameColor());
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -283,8 +283,8 @@
 void CustomFrameViewAsh::Layout() {
   views::NonClientFrameView::Layout();
   WmWindow* frame_window = WmWindow::Get(frame_->GetNativeWindow());
-  frame_window->SetIntProperty(WmWindowProperty::TOP_VIEW_INSET,
-                               NonClientTopBorderHeight());
+  frame_window->aura_window()->SetProperty(aura::client::kTopViewInset,
+                                           NonClientTopBorderHeight());
 }
 
 const char* CustomFrameViewAsh::GetClassName() const {
diff --git a/ash/common/shelf/shelf_widget.cc b/ash/common/shelf/shelf_widget.cc
index 797c9cfd..248b4d5 100644
--- a/ash/common/shelf/shelf_widget.cc
+++ b/ash/common/shelf/shelf_widget.cc
@@ -19,8 +19,8 @@
 #include "ash/common/system/status_area_widget.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/root_window_controller.h"
+#include "ash/wm/window_properties.h"
 #include "base/memory/ptr_util.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/scoped_layer_animation_settings.h"
@@ -307,7 +307,7 @@
 
   WmWindow* shelf_window = WmWindow::Get(this->GetNativeWindow());
   shelf_view_->UpdatePanelIconPosition(
-      panel->GetIntProperty(WmWindowProperty::SHELF_ID),
+      panel->aura_window()->GetProperty(kShelfIDKey),
       shelf_window->ConvertRectFromScreen(panel->GetBoundsInScreen())
           .CenterPoint());
 }
@@ -318,7 +318,7 @@
   if (!shelf_view_)
     return gfx::Rect();
 
-  ShelfID id = window->GetIntProperty(WmWindowProperty::SHELF_ID);
+  ShelfID id = window->aura_window()->GetProperty(kShelfIDKey);
   gfx::Rect bounds(shelf_view_->GetIdealBoundsOfItemIcon(id));
   gfx::Point screen_origin;
   views::View::ConvertPointToScreen(shelf_view_, &screen_origin);
diff --git a/ash/common/shelf/shelf_window_watcher_item_delegate.cc b/ash/common/shelf/shelf_window_watcher_item_delegate.cc
index 262e606d..01f4bd4 100644
--- a/ash/common/shelf/shelf_window_watcher_item_delegate.cc
+++ b/ash/common/shelf/shelf_window_watcher_item_delegate.cc
@@ -9,8 +9,9 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/wm/window_util.h"
+#include "ui/aura/window.h"
 #include "ui/events/event_constants.h"
 
 namespace ash {
@@ -41,7 +42,7 @@
     ShelfLaunchSource source) {
   // Move panels attached on another display to the current display.
   if (GetShelfItemType(id_) == TYPE_APP_PANEL &&
-      window_->GetBoolProperty(WmWindowProperty::PANEL_ATTACHED) &&
+      window_->aura_window()->GetProperty(kPanelAttachedKey) &&
       wm::MoveWindowToDisplay(window_->aura_window(), display_id)) {
     window_->Activate();
     return SHELF_ACTION_WINDOW_ACTIVATED;
diff --git a/ash/common/shelf/shelf_window_watcher_unittest.cc b/ash/common/shelf/shelf_window_watcher_unittest.cc
index e055328..f88eaa1 100644
--- a/ash/common/shelf/shelf_window_watcher_unittest.cc
+++ b/ash/common/shelf/shelf_window_watcher_unittest.cc
@@ -11,8 +11,8 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/root_window_controller.h"
 #include "ash/test/ash_test_base.h"
 #include "ui/base/hit_test.h"
@@ -37,7 +37,8 @@
 
   static ShelfID CreateShelfItem(WmWindow* window) {
     ShelfID id = WmShell::Get()->shelf_model()->next_id();
-    window->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_DIALOG);
+    window->aura_window()->SetProperty(kShelfItemTypeKey,
+                                       static_cast<int32_t>(TYPE_DIALOG));
     return id;
   }
 
@@ -102,12 +103,15 @@
   EXPECT_EQ(STATUS_ACTIVE, model_->items()[index_w2].status);
 
   // ShelfItem is removed when the item type window property is cleared.
-  window1->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_UNDEFINED);
+  window1->aura_window()->SetProperty(kShelfItemTypeKey,
+                                      static_cast<int32_t>(TYPE_UNDEFINED));
   EXPECT_EQ(2, model_->item_count());
-  window2->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_UNDEFINED);
+  window2->aura_window()->SetProperty(kShelfItemTypeKey,
+                                      static_cast<int32_t>(TYPE_UNDEFINED));
   EXPECT_EQ(1, model_->item_count());
   // Clearing twice doesn't do anything.
-  window2->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_UNDEFINED);
+  window2->aura_window()->SetProperty(kShelfItemTypeKey,
+                                      static_cast<int32_t>(TYPE_UNDEFINED));
   EXPECT_EQ(1, model_->item_count());
 }
 
@@ -169,7 +173,8 @@
   EXPECT_EQ(STATUS_ACTIVE, model_->items()[index].status);
 
   // Update the ShelfItemType for |window|.
-  window->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_APP);
+  window->aura_window()->SetProperty(kShelfItemTypeKey,
+                                     static_cast<int32_t>(TYPE_APP));
   // No new item is created after updating a launcher item.
   EXPECT_EQ(2, model_->item_count());
   // index and id are not changed after updating a launcher item.
@@ -302,12 +307,14 @@
   std::unique_ptr<views::Widget> widget1 =
       CreateTestWidget(nullptr, kShellWindowId_PanelContainer, gfx::Rect());
   WmWindow* window1 = WmWindow::Get(widget1->GetNativeWindow());
-  window1->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_APP_PANEL);
+  window1->aura_window()->SetProperty(kShelfItemTypeKey,
+                                      static_cast<int32_t>(TYPE_APP_PANEL));
   EXPECT_EQ(2, model_->item_count());
   std::unique_ptr<views::Widget> widget2 =
       CreateTestWidget(nullptr, kShellWindowId_DefaultContainer, gfx::Rect());
   WmWindow* window2 = WmWindow::Get(widget2->GetNativeWindow());
-  window2->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_APP_PANEL);
+  window2->aura_window()->SetProperty(kShelfItemTypeKey,
+                                      static_cast<int32_t>(TYPE_APP_PANEL));
   EXPECT_EQ(3, model_->item_count());
 
   // Create a panel-type widget to mimic Chrome's app panel windows.
@@ -322,8 +329,8 @@
   panel_widget.Init(panel_params);
   panel_widget.Show();
   WmWindow* panel_window = WmWindow::Get(panel_widget.GetNativeWindow());
-  panel_window->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE,
-                               TYPE_APP_PANEL);
+  panel_window->aura_window()->SetProperty(
+      kShelfItemTypeKey, static_cast<int32_t>(TYPE_APP_PANEL));
   EXPECT_EQ(4, model_->item_count());
 
   // Each ShelfItem is removed when the associated window is destroyed.
@@ -340,7 +347,8 @@
 
   WmWindow* window = WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL,
                                                ui::LAYER_NOT_DRAWN);
-  window->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_APP);
+  window->aura_window()->SetProperty(kShelfItemTypeKey,
+                                     static_cast<int32_t>(TYPE_APP));
   WmShell::Get()
       ->GetPrimaryRootWindow()
       ->GetChildByShellWindowId(kShellWindowId_DefaultContainer)
@@ -350,7 +358,8 @@
 
   WmWindow* child_window = WmShell::Get()->NewWindow(ui::wm::WINDOW_TYPE_NORMAL,
                                                      ui::LAYER_NOT_DRAWN);
-  child_window->SetIntProperty(WmWindowProperty::SHELF_ITEM_TYPE, TYPE_APP);
+  child_window->aura_window()->SetProperty(kShelfItemTypeKey,
+                                           static_cast<int32_t>(TYPE_APP));
   window->AddChild(child_window);
   child_window->Show();
   // |child_window| should not result in adding a new entry.
diff --git a/ash/common/test/test_shelf_delegate.cc b/ash/common/test/test_shelf_delegate.cc
index 24a1ad5..ee762fd 100644
--- a/ash/common/test/test_shelf_delegate.cc
+++ b/ash/common/test/test_shelf_delegate.cc
@@ -12,8 +12,8 @@
 #include "ash/common/test/test_shelf_item_delegate.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/root_window_controller.h"
+#include "ash/wm/window_properties.h"
 #include "base/memory/ptr_util.h"
 #include "ui/aura/window.h"
 
@@ -62,7 +62,7 @@
 void TestShelfDelegate::AddShelfItem(WmWindow* window,
                                      const std::string& app_id) {
   AddShelfItem(window, STATUS_CLOSED);
-  ShelfID shelf_id = window->GetIntProperty(WmWindowProperty::SHELF_ID);
+  ShelfID shelf_id = window->aura_window()->GetProperty(kShelfIDKey);
   AddShelfIDToAppIDMapping(shelf_id, app_id);
 }
 
@@ -80,11 +80,11 @@
 
   model->SetShelfItemDelegate(id,
                               base::MakeUnique<TestShelfItemDelegate>(window));
-  window->SetIntProperty(WmWindowProperty::SHELF_ID, id);
+  window->aura_window()->SetProperty(kShelfIDKey, id);
 }
 
 void TestShelfDelegate::RemoveShelfItemForWindow(WmWindow* window) {
-  ShelfID shelf_id = window->GetIntProperty(WmWindowProperty::SHELF_ID);
+  ShelfID shelf_id = window->aura_window()->GetProperty(kShelfIDKey);
   if (shelf_id == 0)
     return;
   ShelfModel* model = WmShell::Get()->shelf_model();
diff --git a/ash/common/wm/always_on_top_controller.cc b/ash/common/wm/always_on_top_controller.cc
index 0758e8a5..d115f01 100644
--- a/ash/common/wm/always_on_top_controller.cc
+++ b/ash/common/wm/always_on_top_controller.cc
@@ -6,7 +6,6 @@
 
 #include "ash/common/wm/workspace/workspace_layout_manager.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "base/memory/ptr_util.h"
 #include "ui/aura/client/aura_constants.h"
@@ -31,7 +30,7 @@
 
 WmWindow* AlwaysOnTopController::GetContainer(WmWindow* window) const {
   DCHECK(always_on_top_container_);
-  if (window->GetBoolProperty(WmWindowProperty::ALWAYS_ON_TOP))
+  if (window->aura_window()->GetProperty(aura::client::kAlwaysOnTopKey))
     return always_on_top_container_;
   return always_on_top_container_->GetRootWindow()->GetChildByShellWindowId(
       kShellWindowId_DefaultContainer);
diff --git a/ash/common/wm/container_finder.cc b/ash/common/wm/container_finder.cc
index f859279..ece5ca95 100644
--- a/ash/common/wm/container_finder.cc
+++ b/ash/common/wm/container_finder.cc
@@ -10,8 +10,8 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/root_window_controller.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -92,7 +92,7 @@
       return target_root->GetChildByShellWindowId(
           kShellWindowId_UnparentedControlContainer);
     case ui::wm::WINDOW_TYPE_PANEL:
-      if (window->GetBoolProperty(WmWindowProperty::PANEL_ATTACHED))
+      if (window->aura_window()->GetProperty(kPanelAttachedKey))
         return target_root->GetChildByShellWindowId(
             kShellWindowId_PanelContainer);
       return GetContainerFromAlwaysOnTopController(target_root, window);
diff --git a/ash/common/wm/dock/docked_window_resizer.cc b/ash/common/wm/dock/docked_window_resizer.cc
index 9379452..f2ea238 100644
--- a/ash/common/wm/dock/docked_window_resizer.cc
+++ b/ash/common/wm/dock/docked_window_resizer.cc
@@ -10,8 +10,8 @@
 #include "ash/common/wm/wm_event.h"
 #include "ash/common/wm/workspace/magnetism_matcher.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ui/base/hit_test.h"
@@ -205,7 +205,7 @@
   WmWindow* window = GetTarget();
   const bool is_attached_panel =
       window->GetType() == ui::wm::WINDOW_TYPE_PANEL &&
-      window->GetBoolProperty(WmWindowProperty::PANEL_ATTACHED);
+      window->aura_window()->GetProperty(kPanelAttachedKey);
   const bool is_resized =
       (details().bounds_change & WindowResizer::kBoundsChange_Resizes) != 0;
 
diff --git a/ash/common/wm/drag_details.cc b/ash/common/wm/drag_details.cc
index 73815a4..4a91826 100644
--- a/ash/common/wm/drag_details.cc
+++ b/ash/common/wm/drag_details.cc
@@ -6,7 +6,8 @@
 
 #include "ash/common/wm/window_resizer.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
+#include "ash/public/cpp/window_properties.h"
+#include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
 #include "ui/compositor/layer.h"
 
@@ -66,7 +67,7 @@
       source(source),
       should_attach_to_shelf(
           window->GetType() == ui::wm::WINDOW_TYPE_PANEL &&
-          window->GetBoolProperty(WmWindowProperty::PANEL_ATTACHED)) {
+          window->aura_window()->GetProperty(kPanelAttachedKey)) {
   wm::WindowState* window_state = window->GetWindowState();
   if ((window_state->IsNormalOrSnapped() || window_state->IsDocked()) &&
       window_state->HasRestoreBounds() && window_component == HTCAPTION) {
diff --git a/ash/common/wm/maximize_mode/maximize_mode_window_manager.cc b/ash/common/wm/maximize_mode/maximize_mode_window_manager.cc
index cea2689b..9cafa32 100644
--- a/ash/common/wm/maximize_mode/maximize_mode_window_manager.cc
+++ b/ash/common/wm/maximize_mode/maximize_mode_window_manager.cc
@@ -16,7 +16,6 @@
 #include "ash/common/wm/workspace_controller.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
diff --git a/ash/common/wm/overview/scoped_transform_overview_window.cc b/ash/common/wm/overview/scoped_transform_overview_window.cc
index f6172e7..db63b3d 100644
--- a/ash/common/wm/overview/scoped_transform_overview_window.cc
+++ b/ash/common/wm/overview/scoped_transform_overview_window.cc
@@ -13,12 +13,12 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/root_window_controller.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
@@ -275,7 +275,7 @@
       return SK_ColorTRANSPARENT;
     }
   }
-  return window_->GetColorProperty(WmWindowProperty::TOP_VIEW_COLOR);
+  return window_->aura_window()->GetProperty(aura::client::kTopViewColor);
 }
 
 int ScopedTransformOverviewWindow::GetTopInset() const {
@@ -290,7 +290,7 @@
       return 0;
     }
   }
-  return window_->GetIntProperty(WmWindowProperty::TOP_VIEW_INSET);
+  return window_->aura_window()->GetProperty(aura::client::kTopViewInset);
 }
 
 void ScopedTransformOverviewWindow::OnWindowDestroyed() {
diff --git a/ash/common/wm/overview/window_selector_item.cc b/ash/common/wm/overview/window_selector_item.cc
index 5fbf9ce..f6a7b94 100644
--- a/ash/common/wm/overview/window_selector_item.cc
+++ b/ash/common/wm/overview/window_selector_item.cc
@@ -19,7 +19,6 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/resources/vector_icons/vector_icons.h"
 #include "ash/root_window_controller.h"
diff --git a/ash/common/wm/panels/panel_frame_view.cc b/ash/common/wm/panels/panel_frame_view.cc
index b2fdbce..67ef90c 100644
--- a/ash/common/wm/panels/panel_frame_view.cc
+++ b/ash/common/wm/panels/panel_frame_view.cc
@@ -9,7 +9,8 @@
 #include "ash/common/frame/frame_border_hit_test.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
+#include "ui/aura/client/aura_constants.h"
+#include "ui/aura/window.h"
 #include "ui/base/hit_test.h"
 #include "ui/gfx/canvas.h"
 #include "ui/views/controls/image_view.h"
@@ -37,8 +38,8 @@
 void PanelFrameView::SetFrameColors(SkColor active_frame_color,
                                     SkColor inactive_frame_color) {
   header_painter_->SetFrameColors(active_frame_color, inactive_frame_color);
-  GetWidgetWindow()->SetColorProperty(WmWindowProperty::TOP_VIEW_COLOR,
-                                      header_painter_->GetInactiveFrameColor());
+  GetWidgetWindow()->aura_window()->SetProperty(
+      aura::client::kTopViewColor, header_painter_->GetInactiveFrameColor());
 }
 
 const char* PanelFrameView::GetClassName() const {
@@ -47,8 +48,8 @@
 
 void PanelFrameView::InitHeaderPainter() {
   header_painter_.reset(new DefaultHeaderPainter);
-  GetWidgetWindow()->SetColorProperty(WmWindowProperty::TOP_VIEW_COLOR,
-                                      header_painter_->GetInactiveFrameColor());
+  GetWidgetWindow()->aura_window()->SetProperty(
+      aura::client::kTopViewColor, header_painter_->GetInactiveFrameColor());
 
   caption_button_container_ = new FrameCaptionButtonContainerView(frame_);
   AddChildView(caption_button_container_);
@@ -85,8 +86,8 @@
   if (!header_painter_)
     return;
   header_painter_->LayoutHeader();
-  GetWidgetWindow()->SetIntProperty(WmWindowProperty::TOP_VIEW_INSET,
-                                    NonClientTopBorderHeight());
+  GetWidgetWindow()->aura_window()->SetProperty(aura::client::kTopViewInset,
+                                                NonClientTopBorderHeight());
 }
 
 void PanelFrameView::GetWindowMask(const gfx::Size&, gfx::Path*) {
diff --git a/ash/common/wm/panels/panel_layout_manager.cc b/ash/common/wm/panels/panel_layout_manager.cc
index 4ab47592..eb8dd67 100644
--- a/ash/common/wm/panels/panel_layout_manager.cc
+++ b/ash/common/wm/panels/panel_layout_manager.cc
@@ -16,8 +16,8 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/root_window_controller.h"
 #include "ash/wm/window_properties.h"
 #include "base/auto_reset.h"
@@ -339,7 +339,7 @@
   if (in_add_window_)
     return;
   base::AutoReset<bool> auto_reset_in_add_window(&in_add_window_, true);
-  if (!child->GetBoolProperty(WmWindowProperty::PANEL_ATTACHED)) {
+  if (!child->aura_window()->GetProperty(kPanelAttachedKey)) {
     // This should only happen when a window is added to panel container as a
     // result of bounds change from within the application during a drag.
     // If so we have already stopped the drag and should reparent the panel
diff --git a/ash/common/wm/panels/panel_window_resizer.cc b/ash/common/wm/panels/panel_window_resizer.cc
index 2a18c81..e4047eb8 100644
--- a/ash/common/wm/panels/panel_window_resizer.cc
+++ b/ash/common/wm/panels/panel_window_resizer.cc
@@ -9,8 +9,8 @@
 #include "ash/common/wm/window_parenting_utils.h"
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/public/cpp/window_properties.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ui/base/hit_test.h"
@@ -105,8 +105,7 @@
       panel_container_(NULL),
       initial_panel_container_(NULL),
       did_move_or_resize_(false),
-      was_attached_(
-          GetTarget()->GetBoolProperty(WmWindowProperty::PANEL_ATTACHED)),
+      was_attached_(GetTarget()->aura_window()->GetProperty(kPanelAttachedKey)),
       weak_ptr_factory_(this) {
   DCHECK(details().is_resizable);
   panel_container_ = GetTarget()->GetRootWindow()->GetChildByShellWindowId(
@@ -158,7 +157,7 @@
   if (!was_attached_) {
     // Attach the panel while dragging, placing it in front of other panels.
     WmWindow* target = GetTarget();
-    target->SetBoolProperty(WmWindowProperty::PANEL_ATTACHED, true);
+    target->aura_window()->SetProperty(kPanelAttachedKey, true);
     // We use root window coordinates to ensure that during the drag the panel
     // is reparented to a container in the root window that has that window.
     WmWindow* target_root = target->GetRootWindow();
@@ -173,10 +172,10 @@
 void PanelWindowResizer::FinishDragging() {
   if (!did_move_or_resize_)
     return;
-  if (GetTarget()->GetBoolProperty(WmWindowProperty::PANEL_ATTACHED) !=
+  if (GetTarget()->aura_window()->GetProperty(kPanelAttachedKey) !=
       details().should_attach_to_shelf) {
-    GetTarget()->SetBoolProperty(WmWindowProperty::PANEL_ATTACHED,
-                                 details().should_attach_to_shelf);
+    GetTarget()->aura_window()->SetProperty(kPanelAttachedKey,
+                                            details().should_attach_to_shelf);
     // We use last known location to ensure that after the drag the panel
     // is reparented to a container in the root window that has that location.
     WmWindow* target = GetTarget();
diff --git a/ash/common/wm/system_modal_container_layout_manager.cc b/ash/common/wm/system_modal_container_layout_manager.cc
index ad52259..d6d8d040 100644
--- a/ash/common/wm/system_modal_container_layout_manager.cc
+++ b/ash/common/wm/system_modal_container_layout_manager.cc
@@ -10,7 +10,6 @@
 #include "ash/common/wm/window_dimmer.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
@@ -27,7 +26,7 @@
 
 ui::ModalType GetModalType(WmWindow* window) {
   return static_cast<ui::ModalType>(
-      window->GetIntProperty(WmWindowProperty::MODAL_TYPE));
+      window->aura_window()->GetProperty(aura::client::kModalKey));
 }
 
 bool HasTransientAncestor(const WmWindow* window, const WmWindow* ancestor) {
diff --git a/ash/common/wm/wm_snap_to_pixel_layout_manager.cc b/ash/common/wm/wm_snap_to_pixel_layout_manager.cc
index 295bc4c..79afc89 100644
--- a/ash/common/wm/wm_snap_to_pixel_layout_manager.cc
+++ b/ash/common/wm/wm_snap_to_pixel_layout_manager.cc
@@ -5,9 +5,10 @@
 #include "ash/common/wm/wm_snap_to_pixel_layout_manager.h"
 
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
+#include "ash/wm/window_properties.h"
 #include "base/memory/ptr_util.h"
+#include "ui/aura/window.h"
 
 namespace ash {
 namespace wm {
@@ -22,8 +23,7 @@
     if (child->GetShellWindowId() < kShellWindowId_Min ||
         child->GetShellWindowId() > kShellWindowId_Max)  // not a container
       continue;
-    if (child->GetBoolProperty(
-            WmWindowProperty::SNAP_CHILDREN_TO_PIXEL_BOUNDARY)) {
+    if (child->aura_window()->GetProperty(kSnapChildrenToPixelBoundary)) {
       if (!child->GetLayoutManager())
         child->SetLayoutManager(base::MakeUnique<WmSnapToPixelLayoutManager>());
     } else {
diff --git a/ash/common/wm/workspace/workspace_layout_manager.cc b/ash/common/wm/workspace/workspace_layout_manager.cc
index 4d7ef88..055ff85 100644
--- a/ash/common/wm/workspace/workspace_layout_manager.cc
+++ b/ash/common/wm/workspace/workspace_layout_manager.cc
@@ -17,9 +17,9 @@
 #include "ash/common/wm/workspace/workspace_layout_manager_backdrop_delegate.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
+#include "ash/wm/window_properties.h"
 #include "ash/wm/window_state_aura.h"
 #include "base/command_line.h"
 #include "ui/aura/client/aura_constants.h"
@@ -43,8 +43,7 @@
   shell_->AddActivationObserver(this);
   root_window_->aura_window()->AddObserver(this);
   display::Screen::GetScreen()->AddObserver(this);
-  DCHECK(window->GetBoolProperty(
-      WmWindowProperty::SNAP_CHILDREN_TO_PIXEL_BOUNDARY));
+  DCHECK(window->aura_window()->GetProperty(kSnapChildrenToPixelBoundary));
 }
 
 WorkspaceLayoutManager::~WorkspaceLayoutManager() {
diff --git a/ash/common/wm_window.cc b/ash/common/wm_window.cc
index 0162092..cb4018c 100644
--- a/ash/common/wm_window.cc
+++ b/ash/common/wm_window.cc
@@ -11,7 +11,6 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_layout_manager.h"
 #include "ash/common/wm_transient_window_observer.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/root_window_controller.h"
@@ -297,126 +296,6 @@
   return window_->GetProperty(aura::client::kModalKey) == ui::MODAL_TYPE_SYSTEM;
 }
 
-bool WmWindow::GetBoolProperty(WmWindowProperty key) {
-  switch (key) {
-    case WmWindowProperty::DRAW_ATTENTION:
-      return window_->GetProperty(aura::client::kDrawAttentionKey);
-
-    case WmWindowProperty::PANEL_ATTACHED:
-      return window_->GetProperty(kPanelAttachedKey);
-
-    case WmWindowProperty::SNAP_CHILDREN_TO_PIXEL_BOUNDARY:
-      return window_->GetProperty(kSnapChildrenToPixelBoundary);
-
-    case WmWindowProperty::ALWAYS_ON_TOP:
-      return window_->GetProperty(aura::client::kAlwaysOnTopKey);
-
-    default:
-      NOTREACHED();
-      break;
-  }
-
-  return false;
-}
-
-void WmWindow::SetBoolProperty(WmWindowProperty key, bool value) {
-  switch (key) {
-    case WmWindowProperty::PANEL_ATTACHED:
-      window_->SetProperty(kPanelAttachedKey, value);
-      break;
-    default:
-      NOTREACHED();
-      break;
-  }
-}
-
-SkColor WmWindow::GetColorProperty(WmWindowProperty key) {
-  if (key == WmWindowProperty::TOP_VIEW_COLOR)
-    return window_->GetProperty(aura::client::kTopViewColor);
-
-  NOTREACHED();
-  return 0;
-}
-
-void WmWindow::SetColorProperty(WmWindowProperty key, SkColor value) {
-  if (key == WmWindowProperty::TOP_VIEW_COLOR) {
-    window_->SetProperty(aura::client::kTopViewColor, value);
-    return;
-  }
-
-  NOTREACHED();
-}
-
-int WmWindow::GetIntProperty(WmWindowProperty key) {
-  if (key == WmWindowProperty::MODAL_TYPE)
-    return window_->GetProperty(aura::client::kModalKey);
-
-  if (key == WmWindowProperty::SHELF_ID)
-    return window_->GetProperty(kShelfIDKey);
-
-  if (key == WmWindowProperty::SHELF_ITEM_TYPE) {
-    if (aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL ||
-        window_->GetProperty(kShelfItemTypeKey) != TYPE_UNDEFINED) {
-      return window_->GetProperty(kShelfItemTypeKey);
-    }
-    // Mash provides a default shelf item type for non-ignored windows.
-    return GetWindowState()->ignored_by_shelf() ? TYPE_UNDEFINED : TYPE_APP;
-  }
-
-  if (key == WmWindowProperty::TOP_VIEW_INSET)
-    return window_->GetProperty(aura::client::kTopViewInset);
-
-  NOTREACHED();
-  return 0;
-}
-
-void WmWindow::SetIntProperty(WmWindowProperty key, int value) {
-  if (key == WmWindowProperty::SHELF_ID) {
-    window_->SetProperty(kShelfIDKey, value);
-    return;
-  }
-  if (key == WmWindowProperty::SHELF_ITEM_TYPE) {
-    window_->SetProperty(kShelfItemTypeKey, value);
-    return;
-  }
-  if (key == WmWindowProperty::TOP_VIEW_INSET) {
-    window_->SetProperty(aura::client::kTopViewInset, value);
-    return;
-  }
-
-  NOTREACHED();
-}
-
-std::string WmWindow::GetStringProperty(WmWindowProperty key) {
-  if (key == WmWindowProperty::APP_ID) {
-    std::string* value = window_->GetProperty(aura::client::kAppIdKey);
-    return value ? *value : std::string();
-  }
-
-  NOTREACHED();
-  return std::string();
-}
-
-void WmWindow::SetStringProperty(WmWindowProperty key,
-                                 const std::string& value) {
-  if (key == WmWindowProperty::APP_ID) {
-    window_->SetProperty(aura::client::kAppIdKey, new std::string(value));
-    return;
-  }
-
-  NOTREACHED();
-}
-
-gfx::ImageSkia WmWindow::GetWindowIcon() {
-  gfx::ImageSkia* image = window_->GetProperty(aura::client::kWindowIconKey);
-  return image ? *image : gfx::ImageSkia();
-}
-
-gfx::ImageSkia WmWindow::GetAppIcon() {
-  gfx::ImageSkia* image = window_->GetProperty(aura::client::kAppIconKey);
-  return image ? *image : gfx::ImageSkia();
-}
-
 const wm::WindowState* WmWindow::GetWindowState() const {
   return ash::wm::GetWindowState(window_);
 }
diff --git a/ash/common/wm_window.h b/ash/common/wm_window.h
index 078dd0172..4b08cb3 100644
--- a/ash/common/wm_window.h
+++ b/ash/common/wm_window.h
@@ -25,7 +25,6 @@
 }
 
 namespace gfx {
-class ImageSkia;
 class Point;
 class Rect;
 class Size;
@@ -168,18 +167,6 @@
 
   bool IsSystemModal() const;
 
-  bool GetBoolProperty(WmWindowProperty key);
-  void SetBoolProperty(WmWindowProperty key, bool value);
-  SkColor GetColorProperty(WmWindowProperty key);
-  void SetColorProperty(WmWindowProperty key, SkColor value);
-  int GetIntProperty(WmWindowProperty key);
-  void SetIntProperty(WmWindowProperty key, int value);
-  std::string GetStringProperty(WmWindowProperty key);
-  void SetStringProperty(WmWindowProperty key, const std::string& value);
-
-  gfx::ImageSkia GetWindowIcon();
-  gfx::ImageSkia GetAppIcon();
-
   wm::WindowState* GetWindowState() {
     return const_cast<wm::WindowState*>(
         const_cast<const WmWindow*>(this)->GetWindowState());
diff --git a/ash/common/wm_window_property.h b/ash/common/wm_window_property.h
deleted file mode 100644
index fde7b151..0000000
--- a/ash/common/wm_window_property.h
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_COMMON_WM_WINDOW_PROPERTY_H_
-#define ASH_COMMON_WM_WINDOW_PROPERTY_H_
-
-namespace ash {
-
-// See ui/aura/client/aura_constants.h for some more detailed descriptions.
-enum class WmWindowProperty {
-  // Not a valid property; used for property key translation purposes.
-  INVALID_PROPERTY,
-
-  // Type bool.
-  ALWAYS_ON_TOP,
-
-  // Type ImageSkia.
-  APP_ICON,
-
-  // Type std::string.
-  APP_ID,
-
-  // Type bool.
-  DRAW_ATTENTION,
-
-  // Type int, but cast to ui::ModalType.
-  MODAL_TYPE,
-
-  // Type bool. See ash::kPanelAttachedKey for details.
-  PANEL_ATTACHED,
-
-  // Type int.
-  SHELF_ID,
-
-  // Type int, but cast to ShelfItemType.
-  SHELF_ITEM_TYPE,
-
-  // Type bool.
-  SNAP_CHILDREN_TO_PIXEL_BOUNDARY,
-
-  // Type SkColor. See aura::client::kTopViewColor for details.
-  TOP_VIEW_COLOR,
-
-  // Type int. See aura::client::kTopViewInset for details.
-  TOP_VIEW_INSET,
-
-  // Type ImageSkia.
-  WINDOW_ICON,
-};
-
-}  // namespace ash
-
-#endif  // ASH_COMMON_WM_WINDOW_PROPERTY_H_
diff --git a/ash/shell/window_watcher.cc b/ash/shell/window_watcher.cc
index 167e6eb..23cf1d3 100644
--- a/ash/shell/window_watcher.cc
+++ b/ash/shell/window_watcher.cc
@@ -10,11 +10,11 @@
 #include "ash/common/shelf/shelf_widget.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/shell.h"
 #include "ash/shell/window_watcher_shelf_item_delegate.h"
+#include "ash/wm/window_properties.h"
 #include "ash/wm/window_util.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_event_dispatcher.h"
@@ -117,7 +117,7 @@
   std::unique_ptr<ShelfItemDelegate> delegate(
       new WindowWatcherShelfItemDelegate(id, this));
   model->SetShelfItemDelegate(id, std::move(delegate));
-  WmWindow::Get(new_window)->SetIntProperty(WmWindowProperty::SHELF_ID, id);
+  new_window->SetProperty(kShelfIDKey, id);
 }
 
 void WindowWatcher::OnWillRemoveWindow(aura::Window* window) {
diff --git a/ash/wm/overview/window_selector_unittest.cc b/ash/wm/overview/window_selector_unittest.cc
index 73fb5a6..0629a5d 100644
--- a/ash/wm/overview/window_selector_unittest.cc
+++ b/ash/wm/overview/window_selector_unittest.cc
@@ -26,7 +26,6 @@
 #include "ash/common/wm/workspace/workspace_window_resizer.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/drag_drop/drag_drop_controller.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
@@ -160,7 +159,8 @@
     widget->Init(params);
     widget->Show();
     WmWindow* window = WmWindow::Get(widget->GetNativeWindow());
-    window->SetIntProperty(WmWindowProperty::TOP_VIEW_INSET, kHeaderHeight);
+    window->aura_window()->SetProperty(aura::client::kTopViewInset,
+                                       kHeaderHeight);
     ParentWindowInPrimaryRootWindow(widget->GetNativeWindow());
     return widget;
   }
@@ -1130,7 +1130,8 @@
   widget->Init(params);
   widget->Show();
   WmWindow* window = WmWindow::Get(widget->GetNativeWindow());
-  window->SetIntProperty(WmWindowProperty::TOP_VIEW_INSET, kHeaderHeight);
+  window->aura_window()->SetProperty(aura::client::kTopViewInset,
+                                     kHeaderHeight);
 
   ASSERT_EQ(root_windows[1], window1->GetRootWindow());
 
diff --git a/ash/wm/panels/panel_layout_manager_unittest.cc b/ash/wm/panels/panel_layout_manager_unittest.cc
index 01f0bbc0..3b11ebba 100644
--- a/ash/wm/panels/panel_layout_manager_unittest.cc
+++ b/ash/wm/panels/panel_layout_manager_unittest.cc
@@ -16,13 +16,13 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/root_window_controller.h"
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/test/shelf_view_test_api.h"
+#include "ash/wm/window_properties.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
@@ -220,7 +220,7 @@
     test_api.SetAnimationDuration(1);
     test_api.RunMessageLoopUntilAnimationsDone();
     int index = WmShell::Get()->shelf_model()->ItemIndexByID(
-        WmWindow::Get(window)->GetIntProperty(WmWindowProperty::SHELF_ID));
+        window->GetProperty(kShelfIDKey));
     gfx::Rect bounds = test_api.GetButton(index)->GetBoundsInScreen();
 
     ui::test::EventGenerator& event_generator = GetEventGenerator();
diff --git a/ash/wm/panels/panel_window_resizer_unittest.cc b/ash/wm/panels/panel_window_resizer_unittest.cc
index 12164ac..f81bd502 100644
--- a/ash/wm/panels/panel_window_resizer_unittest.cc
+++ b/ash/wm/panels/panel_window_resizer_unittest.cc
@@ -13,7 +13,6 @@
 #include "ash/common/wm/wm_event.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shelf_types.h"
 #include "ash/public/cpp/shell_window_ids.h"
 #include "ash/public/cpp/window_properties.h"
@@ -22,6 +21,7 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/test/cursor_manager_test_api.h"
 #include "ash/wm/drag_window_resizer.h"
+#include "ash/wm/window_properties.h"
 #include "ash/wm/window_state_aura.h"
 #include "base/i18n/rtl.h"
 #include "ui/aura/client/aura_constants.h"
@@ -132,8 +132,7 @@
     for (std::vector<aura::Window *>::const_iterator
              iter = window_order.begin();
          iter != window_order.end(); ++iter, ++panel_index) {
-      ShelfID id =
-          WmWindow::Get(*iter)->GetIntProperty(WmWindowProperty::SHELF_ID);
+      ShelfID id = (*iter)->GetProperty(kShelfIDKey);
       EXPECT_EQ(id, model_->items()[panel_index].id);
     }
   }
diff --git a/ash/wm/window_mirror_view.cc b/ash/wm/window_mirror_view.cc
index 7b67803..94dd847 100644
--- a/ash/wm/window_mirror_view.cc
+++ b/ash/wm/window_mirror_view.cc
@@ -6,7 +6,6 @@
 
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/wm/window_state_aura.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/window.h"
@@ -105,7 +104,7 @@
 }
 
 gfx::Rect WindowMirrorView::GetClientAreaBounds() const {
-  int insets = target_->GetIntProperty(WmWindowProperty::TOP_VIEW_INSET);
+  int insets = target_->aura_window()->GetProperty(aura::client::kTopViewInset);
   if (insets > 0) {
     gfx::Rect bounds(target_->GetBounds().size());
     bounds.Inset(0, insets, 0, 0);
diff --git a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
index 63033d7..75be549 100644
--- a/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
+++ b/build/secondary/third_party/crashpad/crashpad/util/BUILD.gn
@@ -120,6 +120,8 @@
     "posix/drop_privileges.h",
     "posix/process_info.h",
     "posix/process_info_mac.cc",
+    "posix/signals.cc",
+    "posix/signals.h",
     "posix/symbolic_constants_posix.cc",
     "posix/symbolic_constants_posix.h",
     "stdlib/aligned_allocator.cc",
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index ec96802..93c4856 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -9,7 +9,6 @@
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "build/build_config.h"
 #include "cc/animation/animation_host.h"
 #include "cc/base/completion_event.h"
 #include "cc/input/main_thread_scrolling_reason.h"
@@ -2072,20 +2071,12 @@
 
 SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostScrollTestPropertyTreeUpdate);
 
-// Disabled due to flakes/crashes on Linux TSan Tests and on
-// linux_chromium_asan_rel; see https://crbug.com/697652.
-#if defined(OS_LINUX)
-#define MAYBE_LayerTreeHostScrollTestImplSideInvalidation \
-  DISABLED_LayerTreeHostScrollTestImplSideInvalidation
-#else
-#define MAYBE_LayerTreeHostScrollTestImplSideInvalidation \
-  LayerTreeHostScrollTestImplSideInvalidation
-#endif
-class MAYBE_LayerTreeHostScrollTestImplSideInvalidation
+// Disabled due to flakes/crashes, see https://crbug.com/697652.
+class DISABLED_LayerTreeHostScrollTestImplSideInvalidation
     : public LayerTreeHostScrollTest {
   void BeginTest() override {
     layer_tree_host()->outer_viewport_scroll_layer()->set_did_scroll_callback(
-        base::Bind(&MAYBE_LayerTreeHostScrollTestImplSideInvalidation::
+        base::Bind(&DISABLED_LayerTreeHostScrollTestImplSideInvalidation::
                        DidScrollOuterViewport,
                    base::Unretained(this)));
     PostSetNeedsCommitToMainThread();
@@ -2098,7 +2089,7 @@
       CompletionEvent completion;
       task_runner_provider()->ImplThreadTaskRunner()->PostTask(
           FROM_HERE,
-          base::Bind(&MAYBE_LayerTreeHostScrollTestImplSideInvalidation::
+          base::Bind(&DISABLED_LayerTreeHostScrollTestImplSideInvalidation::
                          WaitForInvalidationOnImplThread,
                      base::Unretained(this), &completion));
       completion.Wait();
@@ -2249,7 +2240,7 @@
   int num_of_deltas_ = 0;
 };
 
-MULTI_THREAD_TEST_F(MAYBE_LayerTreeHostScrollTestImplSideInvalidation);
+MULTI_THREAD_TEST_F(DISABLED_LayerTreeHostScrollTestImplSideInvalidation);
 
 }  // namespace
 }  // namespace cc
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java
index 0d83afb..139889c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/downloads/OfflinePageDownloadBridge.java
@@ -138,8 +138,16 @@
 
     @Override
     public void resumeDownload(DownloadItem item, boolean hasUserGesture) {
+        // If the resumption was an user action then we have to resume the specific download item.
+        // Otherwise it can only be called when Chrome starts and we would like to resume all
+        // pending requests.
+        // TODO(romax): it's based on the assumption that if this method is called with
+        // |hasUserGesture| == false then we're trying to resume all pending requests. This
+        // assumption may change.
         if (hasUserGesture) {
             resumeDownload(item.getId());
+        } else {
+            nativeResumePendingRequestImmediately(mNativeOfflinePageDownloadBridge);
         }
     }
 
@@ -297,4 +305,5 @@
     native void nativeDeleteItemByGuid(long nativeOfflinePageDownloadBridge, String guid);
     native long nativeGetOfflineIdByGuid(long nativeOfflinePageDownloadBridge, String guid);
     native void nativeStartDownload(long nativeOfflinePageDownloadBridge, Tab tab);
+    native void nativeResumePendingRequestImmediately(long nativeOfflinePageDownloadBridge);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
index 0a3b11c..7407041 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBar.java
@@ -250,6 +250,8 @@
         boolean hasNonEmptyText = false;
         Editable text = getText();
         if (!TextUtils.isEmpty(text)) {
+            // Make sure the setText in this block does not affect the suggestions.
+            setIgnoreTextChangesForAutocomplete(true);
             setText("");
             hasNonEmptyText = true;
         }
@@ -258,7 +260,10 @@
         } else {
             setHintTextColor(mLightHintColor);
         }
-        if (hasNonEmptyText) setText(text);
+        if (hasNonEmptyText) {
+            setText(text);
+            setIgnoreTextChangesForAutocomplete(false);
+        }
 
         if (!hasFocus()) {
             deEmphasizeUrl();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionChecker.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionChecker.java
index a6fb8b395..e6f6fbf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionChecker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionChecker.java
@@ -23,6 +23,8 @@
     @IntDef({VR_NOT_AVAILABLE, VR_OUT_OF_DATE, VR_READY})
     public @interface VrCoreCompatibility {}
 
+    public static final String VR_CORE_PACKAGE_ID = "com.google.vr.vrcore";
+
     /**
      * Check if VrCore is installed or if installed version is compatible with Chromium.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionCheckerImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionCheckerImpl.java
index dfb25f3..6ab0169 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionCheckerImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrCoreVersionCheckerImpl.java
@@ -12,6 +12,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
+import org.chromium.base.PackageUtils;
 
 import org.chromium.chrome.browser.ChromeFeatureList;
 
@@ -45,6 +46,15 @@
             return VrCoreVersionChecker.VR_READY;
         } catch (VrCoreNotAvailableException e) {
             Log.i(TAG, "Unable to find VrCore.");
+            // Old versions of VrCore are not integrated with the sdk library version check and will
+            // trigger this exception even though VrCore is installed.
+            // Double check package manager to make sure we are not telling user to install
+            // when it should just be an update.
+            if (PackageUtils.getPackageVersion(
+                        ContextUtils.getApplicationContext(), VR_CORE_PACKAGE_ID)
+                    != -1) {
+                return VrCoreVersionChecker.VR_OUT_OF_DATE;
+            }
             return VrCoreVersionChecker.VR_NOT_AVAILABLE;
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index 9ac366c..2c36264 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -84,8 +84,6 @@
     private static final String VR_ACTIVITY_ALIAS =
             "org.chromium.chrome.browser.VRChromeTabbedActivity";
 
-    private static final String VR_CORE_PACKAGE_ID = "com.google.vr.vrcore";
-
     private static final long REENTER_VR_TIMEOUT_MS = 1000;
 
     private static VrShellDelegate sInstance;
@@ -703,7 +701,8 @@
                     @Override
                     public boolean onInfoBarButtonClicked(boolean isPrimary) {
                         activity.startActivity(new Intent(Intent.ACTION_VIEW,
-                                Uri.parse("market://details?id=" + VR_CORE_PACKAGE_ID)));
+                                Uri.parse("market://details?id="
+                                        + VrCoreVersionChecker.VR_CORE_PACKAGE_ID)));
                         return false;
                     }
                 },
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index b6cbea8..8cb8591 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -236,6 +236,8 @@
     "component_updater/component_updater_resource_throttle.h",
     "component_updater/component_updater_utils.cc",
     "component_updater/component_updater_utils.h",
+    "component_updater/cros_component_installer.cc",
+    "component_updater/cros_component_installer.h",
     "component_updater/ev_whitelist_component_installer.cc",
     "component_updater/ev_whitelist_component_installer.h",
     "component_updater/file_type_policies_component_installer.cc",
@@ -520,6 +522,8 @@
     "mac/exception_processor.mm",
     "mac/install_from_dmg.h",
     "mac/install_from_dmg.mm",
+    "mac/keychain_reauthorize.h",
+    "mac/keychain_reauthorize.mm",
     "mac/keystone_glue.h",
     "mac/keystone_glue.mm",
     "mac/keystone_registration.h",
diff --git a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
index c7c7242..b78235c6 100644
--- a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
+++ b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
@@ -440,6 +440,17 @@
   }
 }
 
+void OfflinePageDownloadBridge::ResumePendingRequestImmediately(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  RequestCoordinator* coordinator =
+      RequestCoordinatorFactory::GetForBrowserContext(browser_context_);
+  if (coordinator)
+    coordinator->StartImmediateProcessing(base::Bind([](bool result) {}));
+  else
+    LOG(WARNING) << "ResumePendingRequestImmediately has no valid coordinator.";
+}
+
 void OfflinePageDownloadBridge::ItemsLoaded() {
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobject> obj = weak_java_ref_.get(env);
diff --git a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.h b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.h
index 7ac42bc..16478717 100644
--- a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.h
+++ b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.h
@@ -75,6 +75,10 @@
                       const base::android::JavaParamRef<jobject>& obj,
                       const base::android::JavaParamRef<jstring>& j_guid);
 
+  void ResumePendingRequestImmediately(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj);
+
   // DownloadUIAdapter::Observer implementation.
   void ItemsLoaded() override;
   void ItemAdded(const DownloadUIItem& item) override;
diff --git a/chrome/browser/component_updater/cros_component_installer.cc b/chrome/browser/component_updater/cros_component_installer.cc
new file mode 100644
index 0000000..0aa0886
--- /dev/null
+++ b/chrome/browser/component_updater/cros_component_installer.cc
@@ -0,0 +1,168 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/component_updater/cros_component_installer.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/component_updater/component_installer_errors.h"
+#include "components/component_updater/component_updater_paths.h"
+#include "content/public/browser/browser_thread.h"
+
+#if defined(OS_CHROMEOS)
+#include "chromeos/dbus/dbus_method_call_status.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/image_loader_client.h"
+#endif  // defined(OS_CHROMEOS)
+
+using content::BrowserThread;
+
+namespace component_updater {
+
+#if defined(OS_CHROMEOS)
+void LogRegistrationResult(chromeos::DBusMethodCallStatus call_status,
+                           bool result) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (call_status != chromeos::DBUS_METHOD_CALL_SUCCESS) {
+    DVLOG(1) << "Call to imageloader service failed.";
+    return;
+  }
+  if (!result) {
+    DVLOG(1) << "Component registration failed";
+    return;
+  }
+}
+void ImageLoaderRegistration(const std::string& version,
+                             const base::FilePath& install_dir,
+                             const std::string& name) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  chromeos::ImageLoaderClient* loader =
+      chromeos::DBusThreadManager::Get()->GetImageLoaderClient();
+
+  if (loader) {
+    loader->RegisterComponent(name, version, install_dir.value(),
+                              base::Bind(&LogRegistrationResult));
+  } else {
+    DVLOG(1) << "Failed to get ImageLoaderClient object.";
+  }
+}
+ComponentConfig::ComponentConfig(const std::string& name,
+                                 const std::string& dir,
+                                 const std::string& sha2hashstr)
+    : name(name), dir(dir), sha2hashstr(sha2hashstr) {}
+ComponentConfig::~ComponentConfig() {}
+
+CrOSComponentInstallerTraits::CrOSComponentInstallerTraits(
+    const ComponentConfig& config)
+    : dir_name(config.dir), name(config.name) {
+  if (config.sha2hashstr.length() != 64)
+    return;
+  auto strstream = config.sha2hashstr;
+  for (auto& cell : kSha2Hash_) {
+    cell = stoul(strstream.substr(0, 2), nullptr, 16);
+    strstream.erase(0, 2);
+  }
+}
+
+bool CrOSComponentInstallerTraits::SupportsGroupPolicyEnabledComponentUpdates()
+    const {
+  return true;
+}
+
+bool CrOSComponentInstallerTraits::RequiresNetworkEncryption() const {
+  return true;
+}
+
+update_client::CrxInstaller::Result
+CrOSComponentInstallerTraits::OnCustomInstall(
+    const base::DictionaryValue& manifest,
+    const base::FilePath& install_dir) {
+  DVLOG(1) << "[CrOSComponentInstallerTraits::OnCustomInstall]";
+  std::string version;
+  if (!manifest.GetString("version", &version)) {
+    return ToInstallerResult(update_client::InstallError::GENERIC_ERROR);
+  }
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&ImageLoaderRegistration, version, install_dir, name));
+  return update_client::CrxInstaller::Result(update_client::InstallError::NONE);
+}
+
+void CrOSComponentInstallerTraits::ComponentReady(
+    const base::Version& version,
+    const base::FilePath& path,
+    std::unique_ptr<base::DictionaryValue> manifest) {}
+
+bool CrOSComponentInstallerTraits::VerifyInstallation(
+    const base::DictionaryValue& manifest,
+    const base::FilePath& install_dir) const {
+  return true;
+}
+
+base::FilePath CrOSComponentInstallerTraits::GetRelativeInstallDir() const {
+  return base::FilePath(dir_name);
+}
+
+void CrOSComponentInstallerTraits::GetHash(std::vector<uint8_t>* hash) const {
+  hash->assign(kSha2Hash_, kSha2Hash_ + arraysize(kSha2Hash_));
+}
+
+std::string CrOSComponentInstallerTraits::GetName() const {
+  return name;
+}
+
+update_client::InstallerAttributes
+CrOSComponentInstallerTraits::GetInstallerAttributes() const {
+  return update_client::InstallerAttributes();
+}
+
+std::vector<std::string> CrOSComponentInstallerTraits::GetMimeTypes() const {
+  std::vector<std::string> mime_types;
+  return mime_types;
+}
+
+void RegisterCrOSComponentInternal(ComponentUpdateService* cus,
+                                   const ComponentConfig& config) {
+  std::unique_ptr<ComponentInstallerTraits> traits(
+      new CrOSComponentInstallerTraits(config));
+  // |cus| will take ownership of |installer| during
+  // installer->Register(cus).
+  DefaultComponentInstaller* installer =
+      new DefaultComponentInstaller(std::move(traits));
+  installer->Register(cus, base::Closure());
+}
+
+bool RegisterCrOSComponentInternal(ComponentUpdateService* cus,
+                                   const std::string& name) {
+  if (name.empty()) {
+    DVLOG(1) << "[RegisterCrOSComponents] name is empty.";
+    return false;
+  }
+  const std::map<std::string, std::map<std::string, std::string>> components = {
+      {"escpr",
+       {{"dir", "epson-inkjet-printer-escpr"},
+        {"sha2hashstr",
+         "1913a5e0a6cad30b6f03e176177e0d7ed62c5d6700a9c66da556d7c3f5d6a47e"}}}};
+  const auto it = components.find(name);
+  if (it == components.end()) {
+    DVLOG(1) << "[RegisterCrOSComponents] component " << name
+             << " is not in configuration.";
+    return false;
+  }
+  ComponentConfig config(it->first, it->second.find("dir")->second,
+                         it->second.find("sha2hashstr")->second);
+  RegisterCrOSComponentInternal(cus, config);
+  return true;
+}
+
+#endif  // defined(OS_CHROMEOS)
+
+bool RegisterCrOSComponent(ComponentUpdateService* cus,
+                           const std::string& name) {
+#if defined(OS_CHROMEOS)
+  return RegisterCrOSComponentInternal(cus, name);
+#else
+  return false;
+#endif  // defined(OS_CHROMEOS)
+}
+
+}  // namespace component_updater
diff --git a/chrome/browser/component_updater/cros_component_installer.h b/chrome/browser/component_updater/cros_component_installer.h
new file mode 100644
index 0000000..9339574
--- /dev/null
+++ b/chrome/browser/component_updater/cros_component_installer.h
@@ -0,0 +1,66 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_COMPONENT_UPDATER_CROS_COMPONENT_INSTALLER_H_
+#define CHROME_BROWSER_COMPONENT_UPDATER_CROS_COMPONENT_INSTALLER_H_
+
+#include <string>
+
+#include "build/build_config.h"
+#include "components/component_updater/default_component_installer.h"
+#include "crypto/sha2.h"
+
+namespace component_updater {
+
+class ComponentUpdateService;
+
+#if defined(OS_CHROMEOS)
+struct ComponentConfig {
+  std::string name;
+  std::string dir;
+  std::string sha2hashstr;
+  ComponentConfig(const std::string& name,
+                  const std::string& dir,
+                  const std::string& sha2hashstr);
+  ~ComponentConfig();
+};
+
+class CrOSComponentInstallerTraits : public ComponentInstallerTraits {
+ public:
+  explicit CrOSComponentInstallerTraits(const ComponentConfig& config);
+  ~CrOSComponentInstallerTraits() override {}
+
+ private:
+  // The following methods override ComponentInstallerTraits.
+  bool SupportsGroupPolicyEnabledComponentUpdates() const override;
+  bool RequiresNetworkEncryption() const override;
+  update_client::CrxInstaller::Result OnCustomInstall(
+      const base::DictionaryValue& manifest,
+      const base::FilePath& install_dir) override;
+  bool VerifyInstallation(const base::DictionaryValue& manifest,
+                          const base::FilePath& install_dir) const override;
+  void ComponentReady(const base::Version& version,
+                      const base::FilePath& path,
+                      std::unique_ptr<base::DictionaryValue> manifest) override;
+  base::FilePath GetRelativeInstallDir() const override;
+  void GetHash(std::vector<uint8_t>* hash) const override;
+  std::string GetName() const override;
+  update_client::InstallerAttributes GetInstallerAttributes() const override;
+  std::vector<std::string> GetMimeTypes() const override;
+  std::string dir_name;
+  std::string name;
+  uint8_t kSha2Hash_[crypto::kSHA256Length] = {};
+
+  DISALLOW_COPY_AND_ASSIGN(CrOSComponentInstallerTraits);
+};
+#endif  // defined(OS_CHROMEOS)
+
+// Register a CrOS component.
+// It must be called on UI thread.
+bool RegisterCrOSComponent(ComponentUpdateService* cus,
+                           const std::string& name);
+
+}  // namespace component_updater
+
+#endif  // CHROME_BROWSER_COMPONENT_UPDATER_CROS_COMPONENT_INSTALLER_H_
diff --git a/chrome/browser/component_updater/cros_component_installer_unittest.cc b/chrome/browser/component_updater/cros_component_installer_unittest.cc
new file mode 100644
index 0000000..a9373ad
--- /dev/null
+++ b/chrome/browser/component_updater/cros_component_installer_unittest.cc
@@ -0,0 +1,61 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/component_updater/cros_component_installer.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/test/test_simple_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "components/component_updater/mock_component_updater_service.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/platform_test.h"
+
+namespace component_updater {
+
+class CrOSMockComponentUpdateService
+    : public component_updater::MockComponentUpdateService {
+ public:
+  CrOSMockComponentUpdateService() {}
+  ~CrOSMockComponentUpdateService() override {}
+
+  scoped_refptr<base::SequencedTaskRunner> GetSequencedTaskRunner() override {
+    return base::ThreadTaskRunnerHandle::Get();
+  }
+
+ private:
+  content::TestBrowserThreadBundle thread_bundle_;
+  DISALLOW_COPY_AND_ASSIGN(CrOSMockComponentUpdateService);
+};
+
+class CrOSComponentInstallerTest : public PlatformTest {
+ public:
+  CrOSComponentInstallerTest() {}
+
+  void SetUp() override { PlatformTest::SetUp(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CrOSComponentInstallerTest);
+};
+
+#if defined(OS_CHROMEOS)
+TEST_F(CrOSComponentInstallerTest, RegisterESCPR) {
+  std::unique_ptr<CrOSMockComponentUpdateService> cus =
+      base::MakeUnique<CrOSMockComponentUpdateService>();
+  EXPECT_CALL(*cus, RegisterComponent(testing::_)).Times(1);
+  component_updater::RegisterCrOSComponent(cus.get(), "escpr");
+  base::RunLoop().RunUntilIdle();
+}
+TEST_F(CrOSComponentInstallerTest, RegisterFakeComponent) {
+  std::unique_ptr<CrOSMockComponentUpdateService> cus =
+      base::MakeUnique<CrOSMockComponentUpdateService>();
+  EXPECT_CALL(*cus, RegisterComponent(testing::_)).Times(0);
+  RegisterCrOSComponent(cus.get(), "arandomname");
+  base::RunLoop().RunUntilIdle();
+}
+#endif  // defined(OS_CHROMEOS)
+
+}  // namespace component_updater
diff --git a/chrome/browser/extensions/api/settings_private/OWNERS b/chrome/browser/extensions/api/settings_private/OWNERS
index e07a545..879a522d 100644
--- a/chrome/browser/extensions/api/settings_private/OWNERS
+++ b/chrome/browser/extensions/api/settings_private/OWNERS
@@ -1,3 +1,5 @@
 michaelpg@chromium.org
 stevenjb@chromium.org
 dbeam@chromium.org
+
+# COMPONENT: UI>Settings
diff --git a/chrome/browser/mac/keychain_reauthorize.h b/chrome/browser/mac/keychain_reauthorize.h
new file mode 100644
index 0000000..3b2b456
--- /dev/null
+++ b/chrome/browser/mac/keychain_reauthorize.h
@@ -0,0 +1,34 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MAC_KEYCHAIN_REAUTHORIZE_H_
+#define CHROME_BROWSER_MAC_KEYCHAIN_REAUTHORIZE_H_
+
+#ifdef __OBJC__
+@class NSString;
+#else
+class NSString;
+#endif
+
+namespace chrome {
+
+// Reauthorizes the keychain entry, but only if it's determined that it's
+// necessary. pref_key is looked up in the system's standard user defaults
+// (preferences) and it is associated with both the number of previous attempts,
+// and whether a previous attempt succeeded. Only if a previous attempt did not
+// succeed, and the number of previous tries is less than max_tries, is
+// reauthorization attempted. Before the attempt, the preference is
+// incremented, allowing a finite number of incomplete attempts at performing
+// the operation.
+
+// The system's standard user defaults for the application are used
+// (~/Library/Preferences/com.google.Chrome.plist,
+// com.google.Chrome.canary.plist, etc.) instead of Chrome preferences because
+// Keychain access is tied more closely to the bundle identifier and signed
+// product than it is to any specific profile (--user-data-dir).
+void KeychainReauthorizeIfNeeded(NSString* pref_key, int max_tries);
+
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_MAC_KEYCHAIN_REAUTHORIZE_H_
diff --git a/chrome/browser/mac/keychain_reauthorize.mm b/chrome/browser/mac/keychain_reauthorize.mm
new file mode 100644
index 0000000..aa611a24
--- /dev/null
+++ b/chrome/browser/mac/keychain_reauthorize.mm
@@ -0,0 +1,137 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/mac/keychain_reauthorize.h"
+
+#import <Foundation/Foundation.h>
+#include <Security/Security.h>
+
+#include <string.h>
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/mac/foundation_util.h"
+#include "base/mac/mac_logging.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/scoped_generic.h"
+#include "components/os_crypt/keychain_password_mac.h"
+#include "crypto/apple_keychain.h"
+
+namespace chrome {
+
+namespace {
+
+struct VectorScramblerTraits {
+  static std::vector<uint8_t>* InvalidValue() { return nullptr; }
+
+  static void Free(std::vector<uint8_t>* buf) {
+    memset(buf->data(), 0x11, buf->size());
+    delete buf;
+  }
+};
+
+typedef base::ScopedGeneric<std::vector<uint8_t>*, VectorScramblerTraits>
+    ScopedVectorScrambler;
+
+// Reauthorizes the Safe Storage keychain item, which protects the randomly
+// generated password that encrypts the user's saved passwords. This reads out
+// the keychain item, deletes it, and re-adds it to the keychain. This works
+// because the keychain uses an app's designated requirement as the ACL for
+// reading an item. Chrome will be signed with a designated requirement that
+// accepts both the old and new certificates.
+bool KeychainReauthorize() {
+  base::ScopedCFTypeRef<SecKeychainItemRef> storage_item;
+  UInt32 pw_length = 0;
+  void* password_data = nullptr;
+
+  crypto::AppleKeychain keychain;
+  OSStatus error = keychain.FindGenericPassword(
+      nullptr, strlen(KeychainPassword::service_name),
+      KeychainPassword::service_name, strlen(KeychainPassword::account_name),
+      KeychainPassword::account_name, &pw_length, &password_data,
+      storage_item.InitializeInto());
+
+  if (error != noErr) {
+    OSSTATUS_LOG(ERROR, error)
+        << "KeychainReauthorize failed. Cannot retrieve item.";
+    return false;
+  }
+
+  ScopedVectorScrambler password;
+  password.reset(new std::vector<uint8_t>(
+      static_cast<uint8_t*>(password_data),
+      static_cast<uint8_t*>(password_data) + pw_length));
+  memset(password_data, 0x11, pw_length);
+  keychain.ItemFreeContent(nullptr, password_data);
+
+  error = keychain.ItemDelete(storage_item);
+  if (error != noErr) {
+    OSSTATUS_LOG(ERROR, error)
+        << "KeychainReauthorize failed. Cannot delete item.";
+    return false;
+  }
+
+  error = keychain.AddGenericPassword(
+      NULL, strlen(KeychainPassword::service_name),
+      KeychainPassword::service_name, strlen(KeychainPassword::account_name),
+      KeychainPassword::account_name, password.get()->size(),
+      password.get()->data(), nullptr);
+
+  if (error != noErr) {
+    OSSTATUS_LOG(ERROR, error) << "Failed to re-add storage password.";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace
+
+void KeychainReauthorizeIfNeeded(NSString* pref_key, int max_tries) {
+  NSUserDefaults* user_defaults = [NSUserDefaults standardUserDefaults];
+  int pref_value = [user_defaults integerForKey:pref_key];
+
+  if (pref_value >= max_tries)
+    return;
+
+  NSString* success_pref_key = [pref_key stringByAppendingString:@"Success"];
+  BOOL success_value = [user_defaults boolForKey:success_pref_key];
+  if (success_value)
+    return;
+
+  if (pref_value > 0) {
+    // Logs the number of previous tries that didn't complete.
+    if (base::mac::AmIBundled()) {
+      UMA_HISTOGRAM_SPARSE_SLOWLY("OSX.KeychainReauthorizeIfNeeded",
+                                  pref_value);
+    } else {
+      UMA_HISTOGRAM_SPARSE_SLOWLY("OSX.KeychainReauthorizeIfNeededAtUpdate",
+                                  pref_value);
+    }
+  }
+
+  ++pref_value;
+  [user_defaults setInteger:pref_value forKey:pref_key];
+  [user_defaults synchronize];
+
+  bool success = KeychainReauthorize();
+
+  if (!success)
+    return;
+
+  [user_defaults setBool:YES forKey:success_pref_key];
+  [user_defaults synchronize];
+
+  // Logs the try number (1, 2) that succeeded.
+  if (base::mac::AmIBundled()) {
+    UMA_HISTOGRAM_SPARSE_SLOWLY("OSX.KeychainReauthorizeIfNeededSuccess",
+                                pref_value);
+  } else {
+    UMA_HISTOGRAM_SPARSE_SLOWLY(
+        "OSX.KeychainReauthorizeIfNeededAtUpdateSuccess", pref_value);
+  }
+}
+
+}  // namespace chrome
diff --git a/chrome/browser/resources/extensions/OWNERS b/chrome/browser/resources/extensions/OWNERS
index ccdcd27..b4ef953 100644
--- a/chrome/browser/resources/extensions/OWNERS
+++ b/chrome/browser/resources/extensions/OWNERS
@@ -1,3 +1,6 @@
 dbeam@chromium.org
 finnur@chromium.org
 rdevlin.cronin@chromium.org
+
+# TEAM: extensions-dev@chromium.org
+# COMPONENT: Platform>Extensions
diff --git a/chrome/browser/resources/md_bookmarks/OWNERS b/chrome/browser/resources/md_bookmarks/OWNERS
index 793f7b9d..d0663e0 100644
--- a/chrome/browser/resources/md_bookmarks/OWNERS
+++ b/chrome/browser/resources/md_bookmarks/OWNERS
@@ -1,3 +1,5 @@
 calamity@chromium.org
 dbeam@chromium.org
 tsergeant@chromium.org
+
+# COMPONENT: UI>Browser>Bookmarks
diff --git a/chrome/browser/resources/md_downloads/OWNERS b/chrome/browser/resources/md_downloads/OWNERS
index cba869d..455bfb5 100644
--- a/chrome/browser/resources/md_downloads/OWNERS
+++ b/chrome/browser/resources/md_downloads/OWNERS
@@ -1 +1,3 @@
 dbeam@chromium.org
+
+# COMPONENT: UI>Browser>Downloads
diff --git a/chrome/browser/resources/md_extensions/OWNERS b/chrome/browser/resources/md_extensions/OWNERS
index 209719e..9f01114 100644
--- a/chrome/browser/resources/md_extensions/OWNERS
+++ b/chrome/browser/resources/md_extensions/OWNERS
@@ -1,2 +1,5 @@
 rdevlin.cronin@chromium.org
 dbeam@chromium.org
+
+# TEAM: extensions-dev@chromium.org
+# COMPONENT: Platform>Extensions
diff --git a/chrome/browser/resources/md_history/OWNERS b/chrome/browser/resources/md_history/OWNERS
index 793f7b9d..68e023a6 100644
--- a/chrome/browser/resources/md_history/OWNERS
+++ b/chrome/browser/resources/md_history/OWNERS
@@ -1,3 +1,5 @@
 calamity@chromium.org
 dbeam@chromium.org
 tsergeant@chromium.org
+
+# COMPONENT: UI>Browser>History
diff --git a/chrome/browser/resources/ntp4/OWNERS b/chrome/browser/resources/ntp4/OWNERS
index 387af30..f4065b63 100644
--- a/chrome/browser/resources/ntp4/OWNERS
+++ b/chrome/browser/resources/ntp4/OWNERS
@@ -1,3 +1,6 @@
 estade@chromium.org
 rbyers@chromium.org
 dbeam@chromium.org
+
+# TEAM: ntp-dev@chromium.org
+# COMPONENT: UI>Browser>NewTabPage
diff --git a/chrome/browser/resources/options/i18n_setup.html b/chrome/browser/resources/options/i18n_setup.html
new file mode 100644
index 0000000..cec2322
--- /dev/null
+++ b/chrome/browser/resources/options/i18n_setup.html
@@ -0,0 +1,6 @@
+<!-- This file is intentionally empty.
+  settings-lock-screen element will import i18n_setup.html file in settings.
+  The scripts included by i18n_setup.html is already included in options.html,
+  including the same script again seems to throw some errors. So creating an
+  empty file here just for options.
+-->
diff --git a/chrome/browser/resources/options/options.html b/chrome/browser/resources/options/options.html
index efb9633f..948096d 100644
--- a/chrome/browser/resources/options/options.html
+++ b/chrome/browser/resources/options/options.html
@@ -72,7 +72,7 @@
 <link rel="stylesheet" href="certificate_manager.css">
 <link rel="stylesheet" href="certificate_tree.css">
 </if>
-<script src="chrome://resources/js/action_link.js"></script>
+<link rel="import" href="chrome://resources/html/action_link.html">
 <script src="chrome://resources/js/cr.js"></script>
 <script src="chrome://resources/js/event_tracker.js"></script>
 <script src="chrome://resources/js/cr/event_target.js"></script>
diff --git a/chrome/browser/resources/options_resources.grd b/chrome/browser/resources/options_resources.grd
index 71abcdae..b6d776f 100644
--- a/chrome/browser/resources/options_resources.grd
+++ b/chrome/browser/resources/options_resources.grd
@@ -21,49 +21,39 @@
         <structure name="IDR_OPTIONS_ICONS_HTML"
                    file="settings/icons.html"
                    type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   preprocess="true" />
         <structure name="IDR_OPTIONS_PIN_KEYBOARD_HTML"
                    file="chromeos/quick_unlock/pin_keyboard.html"
                    type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   preprocess="true" />
         <structure name="IDR_OPTIONS_PIN_KEYBOARD_JS"
                    file="chromeos/quick_unlock/pin_keyboard.js"
                    type="chrome_html"
-                   flattenhtml="true" />
+                   preprocess="true" />
         <structure name="IDR_OPTIONS_PASSWORD_PROMPT_DIALOG_JS"
                    file="settings/people_page/password_prompt_dialog.js"
                    type="chrome_html" />
         <structure name="IDR_OPTIONS_PASSWORD_PROMPT_DIALOG_HTML"
                    file="settings/people_page/password_prompt_dialog.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_OPTIONS_LOCK_SCREEN_CONSTANTS_JS"
                    file="settings/people_page/lock_screen_constants.js"
                    type="chrome_html" />
         <structure name="IDR_OPTIONS_LOCK_SCREEN_CONSTANTS_HTML"
                    file="settings/people_page/lock_screen_constants.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_OPTIONS_LOCK_STATE_BEHAVIOR_JS"
                    file="settings/people_page/lock_state_behavior.js"
                    type="chrome_html" />
         <structure name="IDR_OPTIONS_LOCK_STATE_BEHAVIOR_HTML"
                    file="settings/people_page/lock_state_behavior.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_OPTIONS_SETUP_PIN_DIALOG_JS"
                    file="settings/people_page/setup_pin_dialog.js"
                    type="chrome_html" />
         <structure name="IDR_OPTIONS_SETUP_PIN_DIALOG_HTML"
                    file="settings/people_page/setup_pin_dialog.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_OPTIONS_FINGERPRINT_LIST_JS"
                    file="settings/people_page/fingerprint_list.js"
                    type="chrome_html" />
@@ -93,78 +83,62 @@
                    type="chrome_html" />
         <structure name="IDR_OPTIONS_LOCK_SCREEN_HTML"
                    file="settings/people_page/lock_screen.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_OPTIONS_ROUTE_HTML"
                    file="settings/route.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_OPTIONS_ROUTE_JS"
                    file="settings/route.js"
                    type="chrome_html"
-                   flattenhtml="true" />
+                   preprocess="true" />
         <structure name="IDR_SETTINGS_SHARED_CSS_HTML"
                    file="settings/settings_shared_css.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_TOGGLE_BUTTON_HTML"
                    file="settings/controls/settings_toggle_button.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_TOGGLE_BUTTON_JS"
                    file="settings/controls/settings_toggle_button.js"
-                   type="chrome_html"
-                   flattenhtml="true" />
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_BOOLEAN_CONTROL_BEHAVIOR_HTML"
                    file="settings/controls/settings_boolean_control_behavior.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_BOOLEAN_CONTROL_BEHAVIOR_JS"
                    file="settings/controls/settings_boolean_control_behavior.js"
-                   type="chrome_html"
-                   flattenhtml="true" />
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_PREF_CONTROL_BEHAVIOR_HTML"
                    file="settings/controls/pref_control_behavior.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_PREF_CONTROL_BEHAVIOR_JS"
                    file="settings/controls/pref_control_behavior.js"
-                   type="chrome_html"
-                   flattenhtml="true" />
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_VARS_CSS_HTML"
                    file="settings/settings_vars_css.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_PREFS_BEHAVIOR_HTML"
                    file="settings/prefs/prefs_behavior.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_PREFS_BEHAVIOR_JS"
                    file="settings/prefs/prefs_behavior.js"
-                   type="chrome_html"
-                   flattenhtml="true" />
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_PREFS_TYPES_HTML"
                    file="settings/prefs/prefs_types.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
         <structure name="IDR_SETTINGS_PREFS_TYPES_JS"
                    file="settings/prefs/prefs_types.js"
-                   type="chrome_html"
-                   flattenhtml="true" />
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_PREFS_HTML"
+                   file="settings/prefs/prefs.html"
+                   type="chrome_html" />
+        <structure name="IDR_SETTINGS_PREFS_JS"
+                   file="settings/prefs/prefs.js"
+                   type="chrome_html" />
+        <structure name="IDR_OPTIONS_I18N_SETUP_HTML"
+                   file="options/i18n_setup.html"
+                   type="chrome_html" />
         <structure name="IDR_OPTIONS_POLYMER_ELEMENTS_HTML"
                    file="options/options_polymer.html"
-                   type="chrome_html"
-                   flattenhtml="true"
-                   allowexternalscript="true" />
+                   type="chrome_html" />
       </if>
     </structures>
   </release>
diff --git a/chrome/browser/resources/settings/OWNERS b/chrome/browser/resources/settings/OWNERS
index 7786353..a34bf8b 100644
--- a/chrome/browser/resources/settings/OWNERS
+++ b/chrome/browser/resources/settings/OWNERS
@@ -5,3 +5,5 @@
 michaelpg@chromium.org
 stevenjb@chromium.org
 tommycli@chromium.org
+
+# COMPONENT: UI>Settings
diff --git a/chrome/browser/resources/settings/people_page/lock_screen.js b/chrome/browser/resources/settings/people_page/lock_screen.js
index 70365d1..419671a 100644
--- a/chrome/browser/resources/settings/people_page/lock_screen.js
+++ b/chrome/browser/resources/settings/people_page/lock_screen.js
@@ -89,11 +89,8 @@
 
   /** @override */
   attached: function() {
-    // currentRouteChanged is not called during the initial navigation. If the
-    // user navigates directly to the lockScreen page, we still want to show the
-    // password prompt page.
-    this.currentRouteChanged(settings.Route.LOCK_SCREEN,
-        settings.Route.LOCK_SCREEN);
+    if (this.shouldAskForPassword_(settings.getCurrentRoute()))
+      this.$.passwordPrompt.open();
     this.browserProxy_ = settings.FingerprintBrowserProxyImpl.getInstance();
   },
 
@@ -113,7 +110,7 @@
           }.bind(this));
     }
 
-    if (newRoute == settings.Route.LOCK_SCREEN && !this.setModes_) {
+    if (this.shouldAskForPassword_(newRoute)) {
       this.$.passwordPrompt.open();
     } else if (newRoute != settings.Route.FINGERPRINT &&
         oldRoute != settings.Route.FINGERPRINT) {
@@ -142,8 +139,7 @@
 
   /** @private */
   onSetModesChanged_: function() {
-    if (settings.getCurrentRoute() == settings.Route.LOCK_SCREEN &&
-        !this.setModes_) {
+    if (this.shouldAskForPassword_(settings.getCurrentRoute())) {
       this.$.setupPin.close();
       this.$.passwordPrompt.open();
     }
@@ -201,4 +197,13 @@
   onEditFingerprints_: function() {
     settings.navigateTo(settings.Route.FINGERPRINT);
   },
+
+  /**
+   * @param {!settings.Route} route
+   * @return {boolean} Whether the password dialog should be shown.
+   * @private
+   */
+  shouldAskForPassword_: function(route) {
+    return route == settings.Route.LOCK_SCREEN && !this.setModes_;
+  },
 });
diff --git a/chrome/browser/resources/uber/OWNERS b/chrome/browser/resources/uber/OWNERS
index 262db99..8624e36 100644
--- a/chrome/browser/resources/uber/OWNERS
+++ b/chrome/browser/resources/uber/OWNERS
@@ -1,2 +1,4 @@
 dbeam@chromium.org
 estade@chromium.org
+
+# COMPONENT: UI>Browser>WebUI
diff --git a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
index b6608fa..548531a3 100644
--- a/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_navigation_observer_manager.cc
@@ -175,6 +175,11 @@
 
 void NavigationEventList::RecordNavigationEvent(
     std::unique_ptr<NavigationEvent> nav_event) {
+  // Skip page refresh.
+  if (nav_event->source_url == nav_event->GetDestinationUrl() &&
+      nav_event->source_tab_id == nav_event->target_tab_id)
+    return;
+
   if (navigation_events_.size() == size_limit_)
     navigation_events_.pop_front();
   navigation_events_.push_back(std::move(nav_event));
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
index d744202..f20d0993 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/arc_app_window_launcher_controller.cc
@@ -10,10 +10,10 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/display/screen_orientation_controller_chromeos.h"
 #include "ash/shared/app_types.h"
 #include "ash/shell.h"
+#include "ash/wm/window_properties.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
 #include "base/bind.h"
@@ -422,8 +422,7 @@
       base::MakeUnique<AppWindow>(task_id, info->app_shelf_id(), widget, this));
   RegisterApp(info);
   DCHECK(info->app_window()->controller());
-  ash::WmWindow::Get(window)->SetIntProperty(ash::WmWindowProperty::SHELF_ID,
-                                             info->app_window()->shelf_id());
+  window->SetProperty(ash::kShelfIDKey, info->app_window()->shelf_id());
   if (ash::WmShell::Get()
           ->maximize_mode_controller()
           ->IsMaximizeModeWindowManagerEnabled()) {
diff --git a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
index a1612bed..dc3ddfd 100644
--- a/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
+++ b/chrome/browser/ui/ash/launcher/browser_shortcut_launcher_item_controller.cc
@@ -11,9 +11,9 @@
 #include "ash/common/shelf/shelf_model.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/shelf_application_menu_item.h"
 #include "ash/resources/grit/ash_resources.h"
+#include "ash/wm/window_properties.h"
 #include "ash/wm/window_util.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -178,10 +178,9 @@
       IsSettingsBrowser(browser))
     return;
 
-  ash::WmWindow::Get(browser->window()->GetNativeWindow())
-      ->SetIntProperty(
-          ash::WmWindowProperty::SHELF_ID,
-          launcher_controller()->GetShelfIDForWebContents(web_contents));
+  browser->window()->GetNativeWindow()->SetProperty(
+      ash::kShelfIDKey,
+      launcher_controller()->GetShelfIDForWebContents(web_contents));
 }
 
 ash::ShelfAction BrowserShortcutLauncherItemController::ItemSelected(
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
index f77b2af..7a473e0 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller_impl_browsertest.cc
@@ -16,10 +16,10 @@
 #include "ash/common/wm/window_state.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
 #include "ash/public/cpp/window_properties.h"
 #include "ash/shell.h"
 #include "ash/test/shelf_view_test_api.h"
+#include "ash/wm/window_properties.h"
 #include "ash/wm/window_state_aura.h"
 #include "ash/wm/window_util.h"
 #include "base/macros.h"
@@ -2162,7 +2162,7 @@
 
   int browser_index = GetIndexOfShelfItemType(ash::TYPE_BROWSER_SHORTCUT);
   ash::ShelfID browser_id = model_->items()[browser_index].id;
-  ash::ShelfID id = window->GetIntProperty(ash::WmWindowProperty::SHELF_ID);
+  ash::ShelfID id = window->aura_window()->GetProperty(ash::kShelfIDKey);
   EXPECT_EQ(browser_id, id);
 
   ash::ShelfID app_id = CreateShortcut("app1");
@@ -2172,13 +2172,13 @@
   WmShelf::ActivateShelfItem(model_->ItemIndexByID(app_id));
   EXPECT_EQ(2, browser()->tab_strip_model()->count());
   EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
-  id = window->GetIntProperty(ash::WmWindowProperty::SHELF_ID);
+  id = window->aura_window()->GetProperty(ash::kShelfIDKey);
   EXPECT_EQ(app_id, id);
 
   // Activate the tab at index 0 (NTP) and expect a browser ShelfID.
   browser()->tab_strip_model()->ActivateTabAt(0, false);
   EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
-  id = window->GetIntProperty(ash::WmWindowProperty::SHELF_ID);
+  id = window->aura_window()->GetProperty(ash::kShelfIDKey);
   EXPECT_EQ(browser_id, id);
 }
 
diff --git a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
index 180ef58..dd059dc 100644
--- a/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/extension_app_window_launcher_controller.cc
@@ -7,7 +7,7 @@
 #include "ash/common/shelf/shelf_delegate.h"
 #include "ash/common/wm_shell.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
+#include "ash/wm/window_properties.h"
 #include "ash/wm/window_util.h"
 #include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
@@ -192,8 +192,8 @@
     app_controller_map_[app_shelf_id] = controller;
   }
   owner()->SetItemStatus(shelf_id, status);
-  ash::WmWindow::Get(window)->SetIntProperty(ash::WmWindowProperty::SHELF_ID,
-                                             shelf_id);
+  ash::WmWindow::Get(window)->aura_window()->SetProperty(ash::kShelfIDKey,
+                                                         shelf_id);
 }
 
 void ExtensionAppWindowLauncherController::UnregisterApp(aura::Window* window) {
diff --git a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
index bd6bb91..30e3df69 100644
--- a/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
+++ b/chrome/browser/ui/ash/launcher/multi_profile_browser_status_monitor.cc
@@ -6,7 +6,7 @@
 
 #include "ash/common/shelf/shelf_item_types.h"
 #include "ash/common/wm_window.h"
-#include "ash/common/wm_window_property.h"
+#include "ash/public/cpp/window_properties.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
@@ -17,6 +17,7 @@
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/settings_window_manager.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "ui/aura/window.h"
 
 MultiProfileBrowserStatusMonitor::MultiProfileBrowserStatusMonitor(
     ChromeLauncherController* launcher_controller)
@@ -77,12 +78,12 @@
     if (chrome::SettingsWindowManager::GetInstance()->IsSettingsBrowser(
             browser)) {
       aura::Window* aura_window = browser->window()->GetNativeWindow();
-      ash::WmWindow::Get(aura_window)
-          ->SetIntProperty(
-              ash::WmWindowProperty::SHELF_ITEM_TYPE,
+      aura_window->SetProperty(
+          ash::kShelfItemTypeKey,
+          static_cast<int32_t>(
               multi_user_util::IsProfileFromActiveUser(browser->profile())
                   ? ash::TYPE_DIALOG
-                  : ash::TYPE_UNDEFINED);
+                  : ash::TYPE_UNDEFINED));
     }
   }
 
diff --git a/chrome/browser/ui/views/payments/payment_method_view_controller.cc b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
index d7a9b86..383f0382 100644
--- a/chrome/browser/ui/views/payments/payment_method_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_method_view_controller.cc
@@ -190,8 +190,7 @@
   std::unique_ptr<views::View> extra_view = base::MakeUnique<views::View>();
 
   extra_view->SetLayoutManager(new views::BoxLayout(
-      views::BoxLayout::kHorizontal, kPaymentRequestRowHorizontalInsets,
-      kPaymentRequestRowVerticalInsets, kPaymentRequestButtonSpacing));
+      views::BoxLayout::kHorizontal, 0, 0, kPaymentRequestButtonSpacing));
 
   views::LabelButton* button = views::MdTextButton::CreateSecondaryUiButton(
       this, l10n_util::GetStringUTF16(IDS_AUTOFILL_ADD_CREDITCARD_CAPTION));
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
index 6eb407d..0fc3bb6 100644
--- a/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller.cc
@@ -123,8 +123,7 @@
       base::MakeUnique<views::View>();
 
   trailing_buttons_container->SetLayoutManager(new views::BoxLayout(
-      views::BoxLayout::kHorizontal, kPaymentRequestRowHorizontalInsets,
-      kPaymentRequestRowVerticalInsets, kPaymentRequestButtonSpacing));
+      views::BoxLayout::kHorizontal, 0, 0, kPaymentRequestButtonSpacing));
 
   std::unique_ptr<views::Button> primary_button = CreatePrimaryButton();
   if (primary_button)
diff --git a/chrome/browser/ui/views/payments/payment_request_sheet_controller.h b/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
index ba313dc..d722992 100644
--- a/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
+++ b/chrome/browser/ui/views/payments/payment_request_sheet_controller.h
@@ -57,7 +57,8 @@
   // extra view is to be displayed.The caller takes ownership of the view but
   // the view is guaranteed to be outlived by the controller so subclasses may
   // retain a raw pointer to the returned view (for example to control its
-  // enabled state).
+  // enabled state). The horizontal and vertical insets (to the left and bottom
+  // borders) is taken care of by the caller, so can be set to 0.
   // +---------------------------+
   // | EXTRA VIEW | PAY | CANCEL |
   // +---------------------------+
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.cc b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
index 3bf349ed..e74b938 100644
--- a/chrome/browser/ui/webui/help/version_updater_chromeos.cc
+++ b/chrome/browser/ui/webui/help/version_updater_chromeos.cc
@@ -174,16 +174,31 @@
   UpdateEngineClient* update_engine_client =
       DBusThreadManager::Get()->GetUpdateEngineClient();
 
-  // Request the channel information.
-  update_engine_client->GetChannel(get_current_channel, cb);
+  // Request the channel information. Bind to a weak_ptr bound method rather
+  // than passing |cb| directly so that |cb| does not outlive |this|.
+  update_engine_client->GetChannel(
+      get_current_channel, base::Bind(&VersionUpdaterCros::OnGetChannel,
+                                      weak_ptr_factory_.GetWeakPtr(), cb));
+}
+
+void VersionUpdaterCros::OnGetChannel(const ChannelCallback& cb,
+                                      const std::string& current_channel) {
+  cb.Run(current_channel);
 }
 
 void VersionUpdaterCros::GetEolStatus(const EolStatusCallback& cb) {
   UpdateEngineClient* update_engine_client =
       DBusThreadManager::Get()->GetUpdateEngineClient();
 
-  // Request the Eol Status.
-  update_engine_client->GetEolStatus(cb);
+  // Request the Eol Status. Bind to a weak_ptr bound method rather than passing
+  // |cb| directly so that |cb| does not outlive |this|.
+  update_engine_client->GetEolStatus(base::Bind(
+      &VersionUpdaterCros::OnGetEolStatus, weak_ptr_factory_.GetWeakPtr(), cb));
+}
+
+void VersionUpdaterCros::OnGetEolStatus(const EolStatusCallback& cb,
+                                        update_engine::EndOfLifeStatus status) {
+  cb.Run(status);
 }
 
 VersionUpdaterCros::VersionUpdaterCros(content::WebContents* web_contents)
diff --git a/chrome/browser/ui/webui/help/version_updater_chromeos.h b/chrome/browser/ui/webui/help/version_updater_chromeos.h
index 44d4ee8..b9f50dd 100644
--- a/chrome/browser/ui/webui/help/version_updater_chromeos.h
+++ b/chrome/browser/ui/webui/help/version_updater_chromeos.h
@@ -47,6 +47,14 @@
   // Callback from UpdateEngineClient::RequestUpdateCheck().
   void OnUpdateCheck(chromeos::UpdateEngineClient::UpdateCheckResult result);
 
+  // Callback from UpdateEngineClient::GetChannel().
+  void OnGetChannel(const ChannelCallback& cb,
+                    const std::string& current_channel);
+
+  // Callback from UpdateEngineClient::GetEolStatus().
+  void OnGetEolStatus(const EolStatusCallback& cb,
+                      update_engine::EndOfLifeStatus status);
+
   // BrowserContext in which the class was instantiated.
   content::BrowserContext* context_;
 
diff --git a/chrome/browser/ui/webui/md_bookmarks/OWNERS b/chrome/browser/ui/webui/md_bookmarks/OWNERS
index 793f7b9d..d0663e0 100644
--- a/chrome/browser/ui/webui/md_bookmarks/OWNERS
+++ b/chrome/browser/ui/webui/md_bookmarks/OWNERS
@@ -1,3 +1,5 @@
 calamity@chromium.org
 dbeam@chromium.org
 tsergeant@chromium.org
+
+# COMPONENT: UI>Browser>Bookmarks
diff --git a/chrome/browser/ui/webui/md_downloads/OWNERS b/chrome/browser/ui/webui/md_downloads/OWNERS
index cd46f8d..8eefb55 100644
--- a/chrome/browser/ui/webui/md_downloads/OWNERS
+++ b/chrome/browser/ui/webui/md_downloads/OWNERS
@@ -1,2 +1,4 @@
 asanka@chromium.org
 dbeam@chromium.org
+
+# COMPONENT: UI>Browser>Downloads
diff --git a/chrome/browser/ui/webui/ntp/OWNERS b/chrome/browser/ui/webui/ntp/OWNERS
index 66c06dfd..3abb43de 100644
--- a/chrome/browser/ui/webui/ntp/OWNERS
+++ b/chrome/browser/ui/webui/ntp/OWNERS
@@ -3,3 +3,6 @@
 
 per-file ntp_user_data_logger*=beaudoin@chromium.org
 per-file ntp_user_data_logger*=file://chrome/browser/search/OWNERS
+
+# TEAM: ntp-dev@chromium.org
+# COMPONENT: UI>Browser>NewTabPage
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc
index e581069..c711347 100644
--- a/chrome/browser/ui/webui/options/browser_options_handler.cc
+++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -814,6 +814,8 @@
                      chromeos::quick_unlock::IsPinEnabled(profile->GetPrefs()));
   values->SetBoolean("fingerprintUnlockEnabled",
                      chromeos::quick_unlock::IsFingerprintEnabled());
+  values->SetBoolean("pinUnlockEnabled",
+                     chromeos::quick_unlock::IsPinEnabled(profile->GetPrefs()));
   if (chromeos::quick_unlock::IsPinEnabled(profile->GetPrefs())) {
     values->SetString(
         "enableScreenlock",
diff --git a/chrome/browser/ui/webui/options/options_ui.cc b/chrome/browser/ui/webui/options/options_ui.cc
index b6bc1383..02b02a8 100644
--- a/chrome/browser/ui/webui/options/options_ui.cc
+++ b/chrome/browser/ui/webui/options/options_ui.cc
@@ -145,6 +145,14 @@
     "people_page/setup_fingerprint_dialog.html";
 constexpr char kSetupFingerprintJSPath[] =
     "people_page/setup_fingerprint_dialog.js";
+constexpr char kFingerprintBrowserProxyHTMLPath[] =
+    "people_page/fingerprint_browser_proxy.html";
+constexpr char kFingerprintBrowserProxyJSPath[] =
+    "people_page/fingerprint_browser_proxy.js";
+constexpr char kFingerprintProgressArcHTMLPath[] =
+    "people_page/fingerprint_progress_arc.html";
+constexpr char kFingerprintProgressArcJSPath[] =
+    "people_page/fingerprint_progress_arc.js";
 constexpr char kSettingsRouteHTMLPath[] = "route.html";
 constexpr char kSettingsRouteJSPath[] = "route.js";
 constexpr char kSettingsSharedCSSHTMLPath[] = "settings_shared_css.html";
@@ -165,6 +173,9 @@
 constexpr char kSettingsPrefsBehaviorJSPath[] = "prefs/prefs_behavior.js";
 constexpr char kSettingsPrefsTypesHTMLPath[] = "prefs/prefs_types.html";
 constexpr char kSettingsPrefsTypesJSPath[] = "prefs/prefs_types.js";
+constexpr char kSettingsPrefsHTMLPath[] = "prefs/prefs.html";
+constexpr char kSettingsPrefsJSPath[] = "prefs/prefs.js";
+constexpr char kSettingsI18nHTMLPath[] = "i18n_setup.html";
 constexpr char kOptionsPolymerHTMLPath[] = "options_polymer.html";
 #endif
 
@@ -325,6 +336,17 @@
   path_to_idr_map_[kSettingsPrefsTypesHTMLPath] = IDR_SETTINGS_PREFS_TYPES_HTML;
   path_to_idr_map_[kSettingsPrefsTypesJSPath] = IDR_SETTINGS_PREFS_TYPES_JS;
   path_to_idr_map_[kOptionsPolymerHTMLPath] = IDR_OPTIONS_POLYMER_ELEMENTS_HTML;
+  path_to_idr_map_[kSettingsPrefsHTMLPath] = IDR_SETTINGS_PREFS_HTML;
+  path_to_idr_map_[kSettingsPrefsJSPath] = IDR_SETTINGS_PREFS_JS;
+  path_to_idr_map_[kSettingsI18nHTMLPath] = IDR_OPTIONS_I18N_SETUP_HTML;
+  path_to_idr_map_[kFingerprintBrowserProxyHTMLPath] =
+      IDR_OPTIONS_FINGERPRINT_BROWSER_PROXY_HTML;
+  path_to_idr_map_[kFingerprintBrowserProxyJSPath] =
+      IDR_OPTIONS_FINGERPRINT_BROWSER_PROXY_JS;
+  path_to_idr_map_[kFingerprintProgressArcHTMLPath] =
+      IDR_OPTIONS_FINGERPRINT_PROGRESS_ARC_HTML;
+  path_to_idr_map_[kFingerprintProgressArcJSPath] =
+      IDR_OPTIONS_FINGERPRINT_PROGRESS_ARC_JS;
 #endif
 }
 
diff --git a/chrome/browser/ui/webui/settings/OWNERS b/chrome/browser/ui/webui/settings/OWNERS
index 7786353..a34bf8b 100644
--- a/chrome/browser/ui/webui/settings/OWNERS
+++ b/chrome/browser/ui/webui/settings/OWNERS
@@ -5,3 +5,5 @@
 michaelpg@chromium.org
 stevenjb@chromium.org
 tommycli@chromium.org
+
+# COMPONENT: UI>Settings
diff --git a/chrome/browser/ui/zoom/OWNERS b/chrome/browser/ui/zoom/OWNERS
index aede306..17b9bbe9 100644
--- a/chrome/browser/ui/zoom/OWNERS
+++ b/chrome/browser/ui/zoom/OWNERS
@@ -1,2 +1,4 @@
 dbeam@chromium.org
 wjmaclean@chromium.org
+
+# COMPONENT: UI>Browser>Toolbar
diff --git a/chrome/browser/win/jumplist.cc b/chrome/browser/win/jumplist.cc
index 14b6f87..3c114ee 100644
--- a/chrome/browser/win/jumplist.cc
+++ b/chrome/browser/win/jumplist.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/macros.h"
@@ -265,27 +266,39 @@
   // This variable records the status of three folder operations.
   uint32_t folder_operation_status = FolderOperationResult::SUCCESS;
 
+  base::ScopedClosureRunner log_operation_status_when_done(base::Bind(
+      [](uint32_t* folder_operation_status_ptr) {
+        UMA_HISTOGRAM_ENUMERATION("WinJumplist.DetailedFolderResults",
+                                  *folder_operation_status_ptr,
+                                  FolderOperationResult::END);
+      },
+      base::Unretained(&folder_operation_status)));
+
+  // If deletion of |icon_dir_old| fails, do not move |icon_dir| to
+  // |icon_dir_old|, instead, delete |icon_dir| directly to avoid bloating
+  // |icon_dir_old| by moving more things to it.
   if (!base::DeleteFile(icon_dir_old, true)) {
     folder_operation_status |= FolderOperationResult::DELETE_DEST_FAILED;
-    // If deletion of |icon_dir_old| fails, do not move |icon_dir| to
-    // |icon_dir_old|, instead, delete |icon_dir| directly to avoid bloating
-    // |icon_dir_old| by moving more things to it.
-    if (!base::DeleteFile(icon_dir, true))
+    // If deletion of |icon_dir| fails, exit early. This skips creating the same
+    // directory and updating jumplist icons to avoid bloating the JumplistIcons
+    // folder.
+    if (!base::DeleteFile(icon_dir, true)) {
       folder_operation_status |= FolderOperationResult::DELETE_SRC_FAILED;
+      return;
+    }
   } else if (!base::Move(icon_dir, icon_dir_old)) {
     folder_operation_status |= FolderOperationResult::MOVE_FAILED;
     // If Move() fails, delete |icon_dir| to avoid file accumulation in this
     // directory, which can eventually lead the folder to be huge.
-    if (!base::DeleteFile(icon_dir, true))
+    if (!base::DeleteFile(icon_dir, true)) {
       folder_operation_status |= FolderOperationResult::DELETE_SRC_FAILED;
+      return;
+    }
   }
+
   if (!base::CreateDirectory(icon_dir))
     folder_operation_status |= FolderOperationResult::CREATE_SRC_FAILED;
 
-  UMA_HISTOGRAM_ENUMERATION("WinJumplist.DetailedFolderResults",
-                            folder_operation_status,
-                            FolderOperationResult::END);
-
   // Create temporary icon files for shortcuts in the "Most Visited" category.
   CreateIconFiles(icon_dir, local_most_visited_pages);
 
@@ -296,10 +309,8 @@
   // We finished collecting all resources needed for updating an application
   // JumpList. So, create a new JumpList and replace the current JumpList
   // with it.
-  UpdateJumpList(app_id.c_str(),
-                 local_most_visited_pages,
-                 local_recently_closed_pages,
-                 incognito_availability);
+  UpdateJumpList(app_id.c_str(), local_most_visited_pages,
+                 local_recently_closed_pages, incognito_availability);
 }
 
 }  // namespace
diff --git a/chrome/installer/mac/sign_app.sh.in b/chrome/installer/mac/sign_app.sh.in
index 7a027727..c5118ab 100644
--- a/chrome/installer/mac/sign_app.sh.in
+++ b/chrome/installer/mac/sign_app.sh.in
@@ -48,7 +48,8 @@
 requirement_string="\
 designated => \
 (identifier \"com.google.Chrome\" or identifier \"com.google.Chrome.canary\") \
-and certificate leaf = H\"85cee8254216185620ddc8851c7a9fc4dfe120ef\"\
+and (certificate leaf = H\"85cee8254216185620ddc8851c7a9fc4dfe120ef\" or \
+certificate leaf = H\"34f0bdf7f87d4f3a955862c351472e52250e4c2b\") \
 "
 
 enforcement_flags="restrict"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 9bf8134..a5f5007e 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -3799,6 +3799,8 @@
   }
 
   if (is_chromeos) {
+    sources +=
+        [ "../browser/component_updater/cros_component_installer_unittest.cc" ]
     sources -= [ "../browser/signin/chrome_signin_status_metrics_provider_delegate_unittest.cc" ]
   }
   if (enable_background) {
diff --git a/chrome/test/data/webui/OWNERS b/chrome/test/data/webui/OWNERS
index 0e971c4f..d4423e5 100644
--- a/chrome/test/data/webui/OWNERS
+++ b/chrome/test/data/webui/OWNERS
@@ -1,3 +1,5 @@
 dbeam@chromium.org
 dpapad@chromium.org
 michaelpg@chromium.org
+
+# COMPONENT: UI>Browser>WebUI
diff --git a/chrome/test/data/webui/settings/OWNERS b/chrome/test/data/webui/settings/OWNERS
index 7786353..a34bf8b 100644
--- a/chrome/test/data/webui/settings/OWNERS
+++ b/chrome/test/data/webui/settings/OWNERS
@@ -5,3 +5,5 @@
 michaelpg@chromium.org
 stevenjb@chromium.org
 tommycli@chromium.org
+
+# COMPONENT: UI>Settings
diff --git a/components/about_ui/OWNERS b/components/about_ui/OWNERS
index c4cf1964..e87625e1 100644
--- a/components/about_ui/OWNERS
+++ b/components/about_ui/OWNERS
@@ -1 +1,3 @@
 file://ui/webui/OWNERS
+
+# COMPONENT: UI>Browser>WebUI
diff --git a/components/cronet/ios/BUILD.gn b/components/cronet/ios/BUILD.gn
index e455f652..ac1dfe0 100644
--- a/components/cronet/ios/BUILD.gn
+++ b/components/cronet/ios/BUILD.gn
@@ -33,6 +33,7 @@
 source_set("cronet_sources") {
   deps = [
     ":cronet_version_header",
+    ":generate_accept_languages",
     "//base:base",
     "//components/grpc_support",
     "//components/metrics:metrics",
@@ -70,77 +71,11 @@
   info_plist = "Info.plist"
 }
 
-bundle_data("cronet_framework_resources") {
-  # This bundle contains "Accept-Languages" header values for known locales.
-  # TODO(mef): These strings should be auto-generated from chrome's .xtb
-  # files, not hardcoded.
-  sources = [
-    "Resources/Localization/am.lproj",
-    "Resources/Localization/ar.lproj",
-    "Resources/Localization/bg.lproj",
-    "Resources/Localization/bn.lproj",
-    "Resources/Localization/ca.lproj",
-    "Resources/Localization/cs.lproj",
-    "Resources/Localization/da.lproj",
-    "Resources/Localization/de.lproj",
-    "Resources/Localization/el.lproj",
-    "Resources/Localization/en-GB.lproj",
-    "Resources/Localization/en.lproj",
-    "Resources/Localization/es-419.lproj",
-    "Resources/Localization/es.lproj",
-    "Resources/Localization/fa.lproj",
-    "Resources/Localization/fi.lproj",
-    "Resources/Localization/fil.lproj",
-    "Resources/Localization/fr.lproj",
-    "Resources/Localization/gu.lproj",
-    "Resources/Localization/he.lproj",
-    "Resources/Localization/hi.lproj",
-    "Resources/Localization/hr.lproj",
-    "Resources/Localization/hu.lproj",
-    "Resources/Localization/id.lproj",
-    "Resources/Localization/it.lproj",
-    "Resources/Localization/ja.lproj",
-    "Resources/Localization/kn.lproj",
-    "Resources/Localization/ko.lproj",
-    "Resources/Localization/lt.lproj",
-    "Resources/Localization/lv.lproj",
-    "Resources/Localization/ml.lproj",
-    "Resources/Localization/mr.lproj",
-    "Resources/Localization/ms.lproj",
-    "Resources/Localization/nb.lproj",
-    "Resources/Localization/nl.lproj",
-    "Resources/Localization/pl.lproj",
-    "Resources/Localization/pt-BR.lproj",
-    "Resources/Localization/pt-PT.lproj",
-    "Resources/Localization/pt.lproj",
-    "Resources/Localization/ro.lproj",
-    "Resources/Localization/ru.lproj",
-    "Resources/Localization/sk.lproj",
-    "Resources/Localization/sl.lproj",
-    "Resources/Localization/sr.lproj",
-    "Resources/Localization/sv.lproj",
-    "Resources/Localization/sw.lproj",
-    "Resources/Localization/ta.lproj",
-    "Resources/Localization/te.lproj",
-    "Resources/Localization/th.lproj",
-    "Resources/Localization/tr.lproj",
-    "Resources/Localization/uk.lproj",
-    "Resources/Localization/vi.lproj",
-    "Resources/Localization/zh-Hans.lproj",
-    "Resources/Localization/zh-Hant.lproj",
-    "Resources/Localization/zh.lproj",
-  ]
-  outputs = [
-    "{{bundle_resources_dir}}/cronet_resources.bundle/{{source_file_part}}",
-  ]
-}
-
 ios_framework_bundle("cronet_framework") {
   output_name = "Cronet"
   info_plist_target = ":tweak_cronet_plist"
 
   deps = [
-    ":cronet_framework_resources",
     ":cronet_sources",
     "//base",
     "//net:net",
@@ -189,6 +124,17 @@
   ]
 }
 
+action("generate_accept_languages") {
+  script = "//components/cronet/tools/generate_accept_languages.py"
+  args = [
+    rebase_path("$target_gen_dir"),
+    rebase_path("//"),
+  ]
+  outputs = [
+    "$target_gen_dir/accept_languages_table.h",
+  ]
+}
+
 if (additional_toolchains == [] || current_toolchain == default_toolchain) {
   _package_dir = "$root_out_dir/cronet"
 
diff --git a/components/cronet/ios/Cronet.h b/components/cronet/ios/Cronet.h
index 52f81d9f..4a29721 100644
--- a/components/cronet/ios/Cronet.h
+++ b/components/cronet/ios/Cronet.h
@@ -31,6 +31,10 @@
 GRPC_SUPPORT_EXPORT
 @interface Cronet : NSObject
 
+// Sets the HTTP Accept-Language header.  This method only has any effect before
+// |start| is called.
++ (void)setAcceptLanguages:(NSString*)acceptLanguages;
+
 // Sets whether HTTP/2 should be supported by CronetEngine. This method only has
 // any effect before |start| is called.
 + (void)setHttp2Enabled:(BOOL)http2Enabled;
diff --git a/components/cronet/ios/Cronet.mm b/components/cronet/ios/Cronet.mm
index 135398a..d4217ab 100644
--- a/components/cronet/ios/Cronet.mm
+++ b/components/cronet/ios/Cronet.mm
@@ -14,6 +14,7 @@
 #include "base/memory/scoped_vector.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/synchronization/lock.h"
+#include "components/cronet/ios/accept_languages_table.h"
 #include "components/cronet/ios/cronet_environment.h"
 #include "components/cronet/url_request_context_config.h"
 #include "ios/net/crn_http_protocol_handler.h"
@@ -43,6 +44,7 @@
 std::unique_ptr<CronetHttpProtocolHandlerDelegate> gHttpProtocolHandlerDelegate;
 NSURLCache* gPreservedSharedURLCache = nil;
 BOOL gEnableTestCertVerifierForTesting = FALSE;
+NSString* gAcceptLanguages = nil;
 
 // CertVerifier, which allows any certificates for testing.
 class TestCertVerifier : public net::CertVerifier {
@@ -116,20 +118,34 @@
   }
 }
 
++ (NSString*)getAcceptLanguagesFromPreferredLanguages:
+    (NSArray<NSString*>*)languages {
+  NSMutableArray* acceptLanguages = [NSMutableArray new];
+  for (NSString* lang_region in languages) {
+    NSString* lang = [lang_region componentsSeparatedByString:@"-"][0];
+    NSString* localeAcceptLangs = acceptLangs[lang_region] ?: acceptLangs[lang];
+    if (localeAcceptLangs)
+      [acceptLanguages
+          addObjectsFromArray:[localeAcceptLangs
+                                  componentsSeparatedByString:@","]];
+  }
+
+  NSString* acceptLanguageString =
+      [[[NSOrderedSet orderedSetWithArray:acceptLanguages] array]
+          componentsJoinedByString:@","];
+
+  return [acceptLanguageString length] != 0 ? acceptLanguageString
+                                            : @"en-US,en";
+}
+
 + (NSString*)getAcceptLanguages {
-  // Use the framework bundle to search for resources.
-  NSBundle* frameworkBundle = [NSBundle bundleForClass:self];
-  NSString* bundlePath =
-      [frameworkBundle pathForResource:@"cronet_resources" ofType:@"bundle"];
-  NSBundle* bundle = [NSBundle bundleWithPath:bundlePath];
-  NSString* acceptLanguages = NSLocalizedStringWithDefaultValue(
-      @"IDS_ACCEPT_LANGUAGES", @"Localizable", bundle, @"en-US,en",
-      @"These values are copied from Chrome's .xtb files, so the same "
-       "values are used in the |Accept-Language| header. Key name matches "
-       "Chrome's.");
-  if (acceptLanguages == Nil)
-    acceptLanguages = @"";
-  return acceptLanguages;
+  return [self
+      getAcceptLanguagesFromPreferredLanguages:[NSLocale preferredLanguages]];
+}
+
++ (void)setAcceptLanguages:(NSString*)acceptLanguages {
+  [self checkNotStarted];
+  gAcceptLanguages = acceptLanguages;
 }
 
 + (void)checkNotStarted {
@@ -193,7 +209,7 @@
   gChromeNet.Get().reset(
       new cronet::CronetEnvironment(user_agent, gUserAgentPartial));
   gChromeNet.Get()->set_accept_language(
-      base::SysNSStringToUTF8([self getAcceptLanguages]));
+      base::SysNSStringToUTF8(gAcceptLanguages ?: [self getAcceptLanguages]));
 
   gChromeNet.Get()->set_http2_enabled(gHttp2Enabled);
   gChromeNet.Get()->set_quic_enabled(gQuicEnabled);
diff --git a/components/cronet/ios/Resources/Localization/am.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/am.lproj/Localizable.strings
deleted file mode 100644
index ba55b06..0000000
--- a/components/cronet/ios/Resources/Localization/am.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "am,en-GB,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/ar.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/ar.lproj/Localizable.strings
deleted file mode 100644
index dcd3304..0000000
--- a/components/cronet/ios/Resources/Localization/ar.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "ar,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/bg.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/bg.lproj/Localizable.strings
deleted file mode 100644
index 407c27b5..0000000
--- a/components/cronet/ios/Resources/Localization/bg.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "bg-BG,bg";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/bn.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/bn.lproj/Localizable.strings
deleted file mode 100644
index 08a6464..0000000
--- a/components/cronet/ios/Resources/Localization/bn.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "bn-IN,bn,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/ca.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/ca.lproj/Localizable.strings
deleted file mode 100644
index bec5e211..0000000
--- a/components/cronet/ios/Resources/Localization/ca.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "ca-ES,ca";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/cs.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/cs.lproj/Localizable.strings
deleted file mode 100644
index 665a4e3a..0000000
--- a/components/cronet/ios/Resources/Localization/cs.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "cs-CZ,cs";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/da.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/da.lproj/Localizable.strings
deleted file mode 100644
index 428e5f7..0000000
--- a/components/cronet/ios/Resources/Localization/da.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "da-DK,da,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/de.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/de.lproj/Localizable.strings
deleted file mode 100644
index ca69ecb4..0000000
--- a/components/cronet/ios/Resources/Localization/de.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "de-DE,de,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/el.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/el.lproj/Localizable.strings
deleted file mode 100644
index 450fd28..0000000
--- a/components/cronet/ios/Resources/Localization/el.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "el-GR,el";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/en-GB.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/en-GB.lproj/Localizable.strings
deleted file mode 100644
index 790ff2c..0000000
--- a/components/cronet/ios/Resources/Localization/en-GB.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "en-GB,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/en.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/en.lproj/Localizable.strings
deleted file mode 100644
index b379815..0000000
--- a/components/cronet/ios/Resources/Localization/en.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. DO NOT TRANSLATE. */
-"IDS_ACCEPT_LANGUAGES" = "en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/es-419.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/es-419.lproj/Localizable.strings
deleted file mode 100644
index 347bc579..0000000
--- a/components/cronet/ios/Resources/Localization/es-419.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "es-419,es";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/es.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/es.lproj/Localizable.strings
deleted file mode 100644
index 1ed553b7..0000000
--- a/components/cronet/ios/Resources/Localization/es.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "es-ES,es";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/et.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/et.lproj/Localizable.strings
deleted file mode 100644
index 6260779..0000000
--- a/components/cronet/ios/Resources/Localization/et.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "et-EE,et,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/fa.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/fa.lproj/Localizable.strings
deleted file mode 100644
index 69d343f..0000000
--- a/components/cronet/ios/Resources/Localization/fa.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "fa,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/fi.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/fi.lproj/Localizable.strings
deleted file mode 100644
index 3c35a79..0000000
--- a/components/cronet/ios/Resources/Localization/fi.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "fi-FI,fi,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/fil.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/fil.lproj/Localizable.strings
deleted file mode 100644
index 6a90add..0000000
--- a/components/cronet/ios/Resources/Localization/fil.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "fil,fil-PH,tl,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/fr.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/fr.lproj/Localizable.strings
deleted file mode 100644
index 1cf4700..0000000
--- a/components/cronet/ios/Resources/Localization/fr.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "fr-FR,fr,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/gu.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/gu.lproj/Localizable.strings
deleted file mode 100644
index b8439e85..0000000
--- a/components/cronet/ios/Resources/Localization/gu.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "gu-IN,gu,hi-IN,hi,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/he.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/he.lproj/Localizable.strings
deleted file mode 100644
index 23c6a0d..0000000
--- a/components/cronet/ios/Resources/Localization/he.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "he-IL,he,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/hi.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/hi.lproj/Localizable.strings
deleted file mode 100644
index 28466ff..0000000
--- a/components/cronet/ios/Resources/Localization/hi.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "hi-IN,hi,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/hr.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/hr.lproj/Localizable.strings
deleted file mode 100644
index db8c1e6..0000000
--- a/components/cronet/ios/Resources/Localization/hr.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "hr-HR,hr,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/hu.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/hu.lproj/Localizable.strings
deleted file mode 100644
index 3b86667..0000000
--- a/components/cronet/ios/Resources/Localization/hu.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "hu-HU,hu,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/id.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/id.lproj/Localizable.strings
deleted file mode 100644
index 7af26cef..0000000
--- a/components/cronet/ios/Resources/Localization/id.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "id-ID,id,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/it.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/it.lproj/Localizable.strings
deleted file mode 100644
index fd855c0..0000000
--- a/components/cronet/ios/Resources/Localization/it.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "it-IT,it,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/ja.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/ja.lproj/Localizable.strings
deleted file mode 100644
index 6a1779e..0000000
--- a/components/cronet/ios/Resources/Localization/ja.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "ja,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/kn.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/kn.lproj/Localizable.strings
deleted file mode 100644
index 167d19ca..0000000
--- a/components/cronet/ios/Resources/Localization/kn.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "kn-IN,kn,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/ko.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/ko.lproj/Localizable.strings
deleted file mode 100644
index c5e8d4f2..0000000
--- a/components/cronet/ios/Resources/Localization/ko.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "ko-KR,ko,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/lt.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/lt.lproj/Localizable.strings
deleted file mode 100644
index 857146a..0000000
--- a/components/cronet/ios/Resources/Localization/lt.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "lt,en-US,en,ru,pl";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/lv.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/lv.lproj/Localizable.strings
deleted file mode 100644
index 1efd5e84..0000000
--- a/components/cronet/ios/Resources/Localization/lv.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "lv-LV,lv,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/ml.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/ml.lproj/Localizable.strings
deleted file mode 100644
index 4382668..0000000
--- a/components/cronet/ios/Resources/Localization/ml.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "ml-IN,ml,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/mr.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/mr.lproj/Localizable.strings
deleted file mode 100644
index fbf98d7..0000000
--- a/components/cronet/ios/Resources/Localization/mr.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "mr-IN,mr,hi-IN,hi,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/ms.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/ms.lproj/Localizable.strings
deleted file mode 100644
index a8b6d58..0000000
--- a/components/cronet/ios/Resources/Localization/ms.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. DO NOT TRANSLATE. */
-"IDS_ACCEPT_LANGUAGES" = "ms,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/nb.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/nb.lproj/Localizable.strings
deleted file mode 100644
index 4e3271b6..0000000
--- a/components/cronet/ios/Resources/Localization/nb.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "nb-NO,nb,no,nn,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/nl.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/nl.lproj/Localizable.strings
deleted file mode 100644
index dca54fe..0000000
--- a/components/cronet/ios/Resources/Localization/nl.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "nl-NL,nl,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/pl.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/pl.lproj/Localizable.strings
deleted file mode 100644
index f9ea84e1..0000000
--- a/components/cronet/ios/Resources/Localization/pl.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "pl-PL,pl,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/pt-BR.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/pt-BR.lproj/Localizable.strings
deleted file mode 100644
index 8b04250..0000000
--- a/components/cronet/ios/Resources/Localization/pt-BR.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "pt-BR,pt,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/pt-PT.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/pt-PT.lproj/Localizable.strings
deleted file mode 100644
index 2e0d86c..0000000
--- a/components/cronet/ios/Resources/Localization/pt-PT.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "pt-PT,pt,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/pt.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/pt.lproj/Localizable.strings
deleted file mode 100644
index fb3c1ebd..0000000
--- a/components/cronet/ios/Resources/Localization/pt.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. DO NOT TRANSLATE. */
-"IDS_ACCEPT_LANGUAGES" = "pt-PT,pt,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/ro.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/ro.lproj/Localizable.strings
deleted file mode 100644
index 7428ce5..0000000
--- a/components/cronet/ios/Resources/Localization/ro.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "ro-RO,ro,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/ru.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/ru.lproj/Localizable.strings
deleted file mode 100644
index 2d56449..0000000
--- a/components/cronet/ios/Resources/Localization/ru.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "ru-RU,ru,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/sk.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/sk.lproj/Localizable.strings
deleted file mode 100644
index 5dff353f..0000000
--- a/components/cronet/ios/Resources/Localization/sk.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "sk-SK,sk,cs,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/sl.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/sl.lproj/Localizable.strings
deleted file mode 100644
index 811ab06f..0000000
--- a/components/cronet/ios/Resources/Localization/sl.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "sl-SI,sl,en-GB,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/sr.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/sr.lproj/Localizable.strings
deleted file mode 100644
index ff18f14..0000000
--- a/components/cronet/ios/Resources/Localization/sr.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "sr-RS,sr,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/sv.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/sv.lproj/Localizable.strings
deleted file mode 100644
index 3daf55fc..0000000
--- a/components/cronet/ios/Resources/Localization/sv.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "sv-SE,sv,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/sw.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/sw.lproj/Localizable.strings
deleted file mode 100644
index ef6b492..0000000
--- a/components/cronet/ios/Resources/Localization/sw.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "sw,en-GB,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/ta.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/ta.lproj/Localizable.strings
deleted file mode 100644
index 2bde0146..0000000
--- a/components/cronet/ios/Resources/Localization/ta.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "ta-IN,ta,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/te.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/te.lproj/Localizable.strings
deleted file mode 100644
index 38fb4a4..0000000
--- a/components/cronet/ios/Resources/Localization/te.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "te-IN,te,hi-IN,hi,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/th.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/th.lproj/Localizable.strings
deleted file mode 100644
index 464b6370..0000000
--- a/components/cronet/ios/Resources/Localization/th.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "th-TH,th";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/tr.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/tr.lproj/Localizable.strings
deleted file mode 100644
index b5289e2a..0000000
--- a/components/cronet/ios/Resources/Localization/tr.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "tr-TR,tr,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/uk.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/uk.lproj/Localizable.strings
deleted file mode 100644
index 1fe6381..0000000
--- a/components/cronet/ios/Resources/Localization/uk.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "uk-UA,uk,ru,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/vi.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/vi.lproj/Localizable.strings
deleted file mode 100644
index 082f76da..0000000
--- a/components/cronet/ios/Resources/Localization/vi.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. */
-"IDS_ACCEPT_LANGUAGES" = "vi-VN,vi,fr-FR,fr,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/zh-Hans.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/zh-Hans.lproj/Localizable.strings
deleted file mode 100644
index 0a14ff7..0000000
--- a/components/cronet/ios/Resources/Localization/zh-Hans.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. DO NOT TRANSLATE. */
-"IDS_ACCEPT_LANGUAGES" = "zh-CN,zh";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/zh-Hant.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/zh-Hant.lproj/Localizable.strings
deleted file mode 100644
index fadad918..0000000
--- a/components/cronet/ios/Resources/Localization/zh-Hant.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. DO NOT TRANSLATE. */
-"IDS_ACCEPT_LANGUAGES" = "zh-TW,zh,en-US,en";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/Localization/zh.lproj/Localizable.strings b/components/cronet/ios/Resources/Localization/zh.lproj/Localizable.strings
deleted file mode 100644
index 0a14ff7..0000000
--- a/components/cronet/ios/Resources/Localization/zh.lproj/Localizable.strings
+++ /dev/null
@@ -1,2 +0,0 @@
-/* These values are copied from Chrome's .xtb files, this is so the same values are used in the |Accept-Language| header. Key name matches Chrome's. DO NOT TRANSLATE. */
-"IDS_ACCEPT_LANGUAGES" = "zh-CN,zh";
\ No newline at end of file
diff --git a/components/cronet/ios/Resources/README b/components/cronet/ios/Resources/README
deleted file mode 100644
index 681b853..0000000
--- a/components/cronet/ios/Resources/README
+++ /dev/null
@@ -1,9 +0,0 @@
-This localization directory contains language strings taken from Chrome. These
-language strings are taken from Chrome's *.xtb files with the key
-IDS_ACCEPT_LANGUAGES.
-
-DO NOT translate strings with a IDS_ACCEPT_LANGUAGES key from these .strings
-files in the translation console.
-
-On top of Chrome's language list, the following languages were added:
-"pt" "ms" "zh"
diff --git a/components/cronet/ios/test/BUILD.gn b/components/cronet/ios/test/BUILD.gn
index db793b56..fc515a5 100644
--- a/components/cronet/ios/test/BUILD.gn
+++ b/components/cronet/ios/test/BUILD.gn
@@ -8,6 +8,7 @@
 test("cronet_test") {
   testonly = true
   sources = [
+    "cronet_acceptlang_test.mm",
     "cronet_http_test.mm",
     "cronet_netlog_test.mm",
     "cronet_test_runner.mm",
diff --git a/components/cronet/ios/test/cronet_acceptlang_test.mm b/components/cronet/ios/test/cronet_acceptlang_test.mm
new file mode 100644
index 0000000..d19ace6
--- /dev/null
+++ b/components/cronet/ios/test/cronet_acceptlang_test.mm
@@ -0,0 +1,57 @@
+// 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.
+
+// These tests are somewhat dependent on the exact contents of the
+// accept languages table generated at build-time.
+
+#import <Cronet/Cronet.h>
+#import <Foundation/Foundation.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+@interface Cronet (ExposedForTesting)
++ (NSString*)getAcceptLanguagesFromPreferredLanguages:
+    (NSArray<NSString*>*)languages;
+@end
+
+namespace cronet {
+
+#define EXPECT_NSEQ(a, b) EXPECT_TRUE([(a) isEqual:(b)])
+
+TEST(AcceptLangTest, Region) {
+  NSString* acceptLangs =
+      [Cronet getAcceptLanguagesFromPreferredLanguages:@[ @"en-GB" ]];
+
+  EXPECT_NSEQ(acceptLangs, @"en-GB,en-US,en");
+}
+
+TEST(AcceptLangTest, Lang) {
+  NSString* acceptLangs =
+      [Cronet getAcceptLanguagesFromPreferredLanguages:@[ @"ja-JP" ]];
+
+  EXPECT_NSEQ(acceptLangs, @"ja,en-US,en");
+}
+
+TEST(AcceptLangTest, Default) {
+  NSString* acceptLangs =
+      [Cronet getAcceptLanguagesFromPreferredLanguages:@[ @"lol-LOL" ]];
+
+  EXPECT_NSEQ(acceptLangs, @"en-US,en");
+}
+
+TEST(AcceptLangTest, Append) {
+  NSString* acceptLangs =
+      [Cronet getAcceptLanguagesFromPreferredLanguages:@[ @"ja-JP", @"en-GB" ]];
+
+  EXPECT_NSEQ(acceptLangs, @"ja,en-US,en,en-GB");
+}
+
+TEST(AcceptLangTest, NoDefaultAppend) {
+  NSString* acceptLangs = [Cronet
+      getAcceptLanguagesFromPreferredLanguages:@[ @"en-GB", @"lol-LOL" ]];
+
+  NSLog(@"%@", acceptLangs);
+  EXPECT_NSEQ(acceptLangs, @"en-GB,en-US,en");
+}
+}
diff --git a/components/cronet/ios/test/start_cronet.mm b/components/cronet/ios/test/start_cronet.mm
index 4af4d223..148fe533 100644
--- a/components/cronet/ios/test/start_cronet.mm
+++ b/components/cronet/ios/test/start_cronet.mm
@@ -20,6 +20,7 @@
     [Cronet setUserAgent:@"CronetTest/1.0.0.0" partial:NO];
     [Cronet setHttp2Enabled:true];
     [Cronet setQuicEnabled:true];
+    [Cronet setAcceptLanguages:@"en-US,en"];
     [Cronet setSslKeyLogFileName:@"SSLKEYLOGFILE"];
     [Cronet addQuicHint:@"test.example.com" port:443 altPort:443];
     [Cronet enableTestCertVerifierForTesting];
diff --git a/components/cronet/tools/generate_accept_languages.py b/components/cronet/tools/generate_accept_languages.py
new file mode 100644
index 0000000..f192058d
--- /dev/null
+++ b/components/cronet/tools/generate_accept_languages.py
@@ -0,0 +1,45 @@
+# 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.
+
+# This script generates a header containing a dictionary from locales to
+# accept language strings from chromium's .xtb files.  It is not very
+# robust at the moment, and makes some assumptions about the format of
+# the files, including at least the following:
+#   * assumes necessary data is contained only with files of the form
+#     components/strings/components_locale_settings_${LANG}.xtb
+#   * assumes ${LANG} is identified in the lang attribute of the root
+#     element of the file's xml data
+#   * assumes that there is only one relevant element with the
+#     IDS_ACCEPT_LANGUAGES attribute
+
+import os, re, sys
+from xml.etree import ElementTree
+
+STRINGS_DIR = sys.argv[2] + 'components/strings/'
+
+def extract_accept_langs(filename):
+  tree = ElementTree.parse(STRINGS_DIR + filename).getroot()
+  for child in tree:
+    if child.get('id') == 'IDS_ACCEPT_LANGUAGES':
+      return tree.get('lang'), child.text
+
+def gen_accept_langs_table():
+  return dict(filter(None, (extract_accept_langs(filename)
+    for filename in os.listdir(STRINGS_DIR)
+    if re.match(r'components_locale_settings_\S+.xtb', filename))))
+
+HEADER = "NSDictionary* acceptLangs = @{"
+def LINE(locale, accept_langs):
+  return '  @"' + locale + '" : @"' + accept_langs + '",'
+FOOTER = "};"
+
+def main():
+  with open(sys.argv[1] + "/accept_languages_table.h", "w+") as f:
+    print >>f, HEADER
+    for (locale, accept_langs) in gen_accept_langs_table().items():
+      print >>f, LINE(locale, accept_langs)
+    print >>f, FOOTER
+
+if __name__ == "__main__":
+  main()
diff --git a/components/flags_ui/OWNERS b/components/flags_ui/OWNERS
index 61dccf7..506ff92 100644
--- a/components/flags_ui/OWNERS
+++ b/components/flags_ui/OWNERS
@@ -1,3 +1,5 @@
 file://ui/webui/OWNERS
 
 asvitkine@chromium.org
+
+# COMPONENT: UI>Browser>WebUI
diff --git a/components/network_session_configurator/network_session_configurator.cc b/components/network_session_configurator/network_session_configurator.cc
index 91a2b15..fba5a01 100644
--- a/components/network_session_configurator/network_session_configurator.cc
+++ b/components/network_session_configurator/network_session_configurator.cc
@@ -324,6 +324,13 @@
       GetVariationParam(quic_trial_params, "quic_version"));
 }
 
+bool ShouldEnableServerPushCancelation(
+    const VariationParameters& quic_trial_params) {
+  return base::LowerCaseEqualsASCII(
+      GetVariationParam(quic_trial_params, "enable_server_push_cancellation"),
+      "true");
+}
+
 void ConfigureQuicParams(base::StringPiece quic_trial_group,
                          const VariationParameters& quic_trial_params,
                          bool is_quic_force_disabled,
@@ -335,6 +342,8 @@
       is_quic_force_enabled);
   params->disable_quic_on_timeout_with_open_streams =
       ShouldDisableQuicWhenConnectionTimesOutWithOpenStreams(quic_trial_params);
+  params->enable_server_push_cancellation =
+      ShouldEnableServerPushCancelation(quic_trial_params);
 
   params->enable_quic_alternative_service_with_different_host =
       ShouldQuicEnableAlternativeServicesForDifferentHost(quic_trial_params);
diff --git a/components/network_session_configurator/network_session_configurator_unittest.cc b/components/network_session_configurator/network_session_configurator_unittest.cc
index 1832dfd..4d24564 100644
--- a/components/network_session_configurator/network_session_configurator_unittest.cc
+++ b/components/network_session_configurator/network_session_configurator_unittest.cc
@@ -74,6 +74,7 @@
   EXPECT_FALSE(params_.quic_disable_connection_pooling);
   EXPECT_EQ(0.25f, params_.quic_load_server_info_timeout_srtt_multiplier);
   EXPECT_FALSE(params_.quic_enable_connection_racing);
+  EXPECT_FALSE(params_.enable_server_push_cancellation);
   EXPECT_FALSE(params_.quic_enable_non_blocking_io);
   EXPECT_FALSE(params_.quic_disable_disk_cache);
   EXPECT_FALSE(params_.quic_prefer_aes);
@@ -210,6 +211,17 @@
   EXPECT_TRUE(params_.quic_race_cert_verification);
 }
 
+TEST_F(NetworkSessionConfiguratorTest, EnableServerPushCancellation) {
+  std::map<std::string, std::string> field_trial_params;
+  field_trial_params["enable_server_push_cancellation"] = "true";
+  variations::AssociateVariationParams("QUIC", "Enabled", field_trial_params);
+  base::FieldTrialList::CreateFieldTrial("QUIC", "Enabled");
+
+  ParseFieldTrials();
+
+  EXPECT_TRUE(params_.enable_server_push_cancellation);
+}
+
 TEST_F(NetworkSessionConfiguratorTest, QuicDoNotFragment) {
   std::map<std::string, std::string> field_trial_params;
   field_trial_params["do_not_fragment"] = "true";
diff --git a/components/omnibox/browser/zero_suggest_provider.cc b/components/omnibox/browser/zero_suggest_provider.cc
index 1a5d022..f6e3863 100644
--- a/components/omnibox/browser/zero_suggest_provider.cc
+++ b/components/omnibox/browser/zero_suggest_provider.cc
@@ -19,6 +19,7 @@
 #include "components/data_use_measurement/core/data_use_user_data.h"
 #include "components/history/core/browser/history_types.h"
 #include "components/history/core/browser/top_sites.h"
+#include "components/metrics/proto/omnibox_event.pb.h"
 #include "components/metrics/proto/omnibox_input_type.pb.h"
 #include "components/omnibox/browser/autocomplete_classifier.h"
 #include "components/omnibox/browser/autocomplete_input.h"
@@ -43,19 +44,30 @@
 
 namespace {
 
+// Represents whether ZeroSuggestProvider is allowed to display contextual
+// suggestions on focus, and if not, why not.
+// These values are written to logs.  New enum values can be added, but existing
+// enums must never be renumbered or deleted and reused.
+enum class ZeroSuggestEligibility {
+  ELIGIBLE = 0,
+  // URL_INELIGIBLE would be ELIGIBLE except some property of the current URL
+  // itself prevents ZeroSuggest from triggering.
+  URL_INELIGIBLE = 1,
+  GENERALLY_INELIGIBLE = 2,
+  ELIGIBLE_MAX_VALUE
+};
+
 // TODO(hfung): The histogram code was copied and modified from
 // search_provider.cc.  Refactor and consolidate the code.
 // We keep track in a histogram how many suggest requests we send, how
 // many suggest requests we invalidate (e.g., due to a user typing
 // another character), and how many replies we receive.
-// *** ADD NEW ENUMS AFTER ALL PREVIOUSLY DEFINED ONES! ***
-//     (excluding the end-of-list enum value)
-// We do not want values of existing enums to change or else it screws
-// up the statistics.
+// These values are written to logs.  New enum values can be added, but existing
+// enums must never be renumbered or deleted and reused.
 enum ZeroSuggestRequestsHistogramValue {
   ZERO_SUGGEST_REQUEST_SENT = 1,
-  ZERO_SUGGEST_REQUEST_INVALIDATED,
-  ZERO_SUGGEST_REPLY_RECEIVED,
+  ZERO_SUGGEST_REQUEST_INVALIDATED = 2,
+  ZERO_SUGGEST_REPLY_RECEIVED = 3,
   ZERO_SUGGEST_MAX_REQUEST_HISTOGRAM_VALUE
 };
 
@@ -68,6 +80,9 @@
 // Relevance value to use if it was not set explicitly by the server.
 const int kDefaultZeroSuggestRelevance = 100;
 
+// Used for testing whether zero suggest is ever available.
+const char kArbitraryInsecureUrlString[] = "http://www.google.com/";
+
 }  // namespace
 
 // static
@@ -101,32 +116,37 @@
   current_query_ = input.current_url().spec();
   current_page_classification_ = input.current_page_classification();
   current_url_match_ = MatchForCurrentURL();
-  TemplateURLService* template_url_service = client()->GetTemplateURLService();
 
-  const TemplateURL* default_provider =
-      template_url_service->GetDefaultSearchProvider();
-  if (default_provider == NULL)
-    return;
-
-  base::string16 prefix;
-  TemplateURLRef::SearchTermsArgs search_term_args(prefix);
-  std::string url_string;
-  if (OmniboxFieldTrial::InZeroSuggestRedirectToChromeFieldTrial()) {
-    url_string = OmniboxFieldTrial::ZeroSuggestRedirectToChromeServerAddress();
-  } else {
-    url_string = default_provider->suggestions_url_ref().ReplaceSearchTerms(
-        search_term_args, template_url_service->search_terms_data());
-  }
+  std::string url_string = GetContextualSuggestionsUrl();
   GURL suggest_url(url_string);
-
   if (!suggest_url.is_valid())
     return;
 
   // No need to send the current page URL in personalized suggest or
   // most visited field trials.
-  if (CanSendURL(input.current_url(), suggest_url, default_provider,
+  const TemplateURLService* template_url_service =
+      client()->GetTemplateURLService();
+  const TemplateURL* default_provider =
+      template_url_service->GetDefaultSearchProvider();
+  const bool can_send_current_url =
+      CanSendURL(input.current_url(), suggest_url, default_provider,
                  current_page_classification_,
-                 template_url_service->search_terms_data(), client()) &&
+                 template_url_service->search_terms_data(), client());
+  GURL arbitrary_insecure_url(kArbitraryInsecureUrlString);
+  ZeroSuggestEligibility eligibility = ZeroSuggestEligibility::ELIGIBLE;
+  if (!can_send_current_url) {
+    const bool can_send_ordinary_url =
+        CanSendURL(arbitrary_insecure_url, suggest_url, default_provider,
+                   current_page_classification_,
+                   template_url_service->search_terms_data(), client());
+    eligibility = can_send_ordinary_url
+                      ? ZeroSuggestEligibility::URL_INELIGIBLE
+                      : ZeroSuggestEligibility::GENERALLY_INELIGIBLE;
+  }
+  UMA_HISTOGRAM_ENUMERATION(
+      "Omnibox.ZeroSuggest.Eligible.OnFocus", static_cast<int>(eligibility),
+      static_cast<int>(ZeroSuggestEligibility::ELIGIBLE_MAX_VALUE));
+  if (can_send_current_url &&
       !OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial() &&
       !OmniboxFieldTrial::InZeroSuggestMostVisitedFieldTrial()) {
     // Update suggest_url to include the current_page_url.
@@ -136,6 +156,8 @@
           OmniboxFieldTrial::ZeroSuggestRedirectToChromeAdditionalFields();
       suggest_url = GURL(url_string);
     } else {
+      base::string16 prefix;
+      TemplateURLRef::SearchTermsArgs search_term_args(prefix);
       search_term_args.current_page_url = current_query_;
       suggest_url =
           GURL(default_provider->suggestions_url_ref().ReplaceSearchTerms(
@@ -209,6 +231,23 @@
       results_from_cache_(false),
       waiting_for_most_visited_urls_request_(false),
       weak_ptr_factory_(this) {
+  // Record whether contextual zero suggest is possible for this user / profile.
+  const TemplateURLService* template_url_service =
+      client->GetTemplateURLService();
+  // Template URL service can be null in tests.
+  if (template_url_service != nullptr) {
+    GURL suggest_url(GetContextualSuggestionsUrl());
+    // To check whether this is allowed, use an arbitrary insecure (http) URL
+    // as the URL we'd want suggestions for.  The value of OTHER as the current
+    // page classification is to correspond with that URL.
+    UMA_HISTOGRAM_BOOLEAN(
+        "Omnibox.ZeroSuggest.Eligible.OnProfileOpen",
+        suggest_url.is_valid() &&
+            CanSendURL(GURL(kArbitraryInsecureUrlString), suggest_url,
+                       template_url_service->GetDefaultSearchProvider(),
+                       metrics::OmniboxEventProto::OTHER,
+                       template_url_service->search_terms_data(), client));
+  }
 }
 
 ZeroSuggestProvider::~ZeroSuggestProvider() {
@@ -479,6 +518,24 @@
   return true;
 }
 
+std::string ZeroSuggestProvider::GetContextualSuggestionsUrl() const {
+  // Without a default search provider, refuse to do anything (even if the user
+  // is in the redirect-to-chrome field trial).
+  const TemplateURLService* template_url_service =
+      client()->GetTemplateURLService();
+  const TemplateURL* default_provider =
+      template_url_service->GetDefaultSearchProvider();
+  if (default_provider == nullptr)
+    return std::string();
+
+  if (OmniboxFieldTrial::InZeroSuggestRedirectToChromeFieldTrial())
+    return OmniboxFieldTrial::ZeroSuggestRedirectToChromeServerAddress();
+  base::string16 prefix;
+  TemplateURLRef::SearchTermsArgs search_term_args(prefix);
+  return default_provider->suggestions_url_ref().ReplaceSearchTerms(
+      search_term_args, template_url_service->search_terms_data());
+}
+
 void ZeroSuggestProvider::MaybeUseCachedSuggestions() {
   if (!OmniboxFieldTrial::InZeroSuggestPersonalizedFieldTrial())
     return;
diff --git a/components/omnibox/browser/zero_suggest_provider.h b/components/omnibox/browser/zero_suggest_provider.h
index d4cf416..b682e7b7 100644
--- a/components/omnibox/browser/zero_suggest_provider.h
+++ b/components/omnibox/browser/zero_suggest_provider.h
@@ -122,6 +122,12 @@
   bool ShouldShowNonContextualZeroSuggest(const GURL& suggest_url,
                                           const GURL& current_page_url) const;
 
+  // Returns a URL string that should be used to to request contextual
+  // suggestions from the default provider.  Does not take into account whether
+  // sending this request is prohibited (e.g., in an incognito window).  Returns
+  // an empty string in case of an error.
+  std::string GetContextualSuggestionsUrl() const;
+
   // Checks whether we have a set of zero suggest results cached, and if so
   // populates |matches_| with cached results.
   void MaybeUseCachedSuggestions();
diff --git a/components/os_crypt/keychain_password_mac.h b/components/os_crypt/keychain_password_mac.h
index f044f04..2de865114 100644
--- a/components/os_crypt/keychain_password_mac.h
+++ b/components/os_crypt/keychain_password_mac.h
@@ -27,6 +27,10 @@
   // empty string is returned.
   std::string GetPassword() const;
 
+  // The service and account names used in Chrome's Safe Storage keychain item.
+  static const char service_name[];
+  static const char account_name[];
+
  private:
   const crypto::AppleKeychain& keychain_;
 
diff --git a/components/os_crypt/keychain_password_mac.mm b/components/os_crypt/keychain_password_mac.mm
index 1f60b9f..2b38db2 100644
--- a/components/os_crypt/keychain_password_mac.mm
+++ b/components/os_crypt/keychain_password_mac.mm
@@ -47,28 +47,23 @@
 
 }  // namespace
 
-std::string KeychainPassword::GetPassword() const {
-  // These two strings ARE indeed user facing.  But they are used to access
-  // the encryption keyword.  So as to not lose encrypted data when system
-  // locale changes we DO NOT LOCALIZE.
+// These two strings ARE indeed user facing.  But they are used to access
+// the encryption keyword.  So as to not lose encrypted data when system
+// locale changes we DO NOT LOCALIZE.
 #if defined(GOOGLE_CHROME_BUILD)
-  const std::string service_name = "Chrome Safe Storage";
-  const std::string account_name = "Chrome";
+const char KeychainPassword::service_name[] = "Chrome Safe Storage";
+const char KeychainPassword::account_name[] = "Chrome";
 #else
-  const std::string service_name = "Chromium Safe Storage";
-  const std::string account_name = "Chromium";
+const char KeychainPassword::service_name[] = "Chromium Safe Storage";
+const char KeychainPassword::account_name[] = "Chromium";
 #endif
 
+std::string KeychainPassword::GetPassword() const {
   UInt32 password_length = 0;
   void* password_data = NULL;
-  OSStatus error = keychain_.FindGenericPassword(NULL,
-                                                 service_name.size(),
-                                                 service_name.data(),
-                                                 account_name.size(),
-                                                 account_name.data(),
-                                                 &password_length,
-                                                 &password_data,
-                                                 NULL);
+  OSStatus error = keychain_.FindGenericPassword(
+      nullptr, strlen(service_name), service_name, strlen(account_name),
+      account_name, &password_length, &password_data, NULL);
 
   if (error == noErr) {
     std::string password =
diff --git a/components/version_ui/OWNERS b/components/version_ui/OWNERS
index c4cf1964..e87625e1 100644
--- a/components/version_ui/OWNERS
+++ b/components/version_ui/OWNERS
@@ -1 +1,3 @@
 file://ui/webui/OWNERS
+
+# COMPONENT: UI>Browser>WebUI
diff --git a/components/zoom/OWNERS b/components/zoom/OWNERS
index aede306..2cd925c 100644
--- a/components/zoom/OWNERS
+++ b/components/zoom/OWNERS
@@ -1,2 +1,4 @@
 dbeam@chromium.org
 wjmaclean@chromium.org
+
+# COMPONENT: UI>Browser>Zoom
diff --git a/content/browser/frame_host/debug_urls.cc b/content/browser/frame_host/debug_urls.cc
index c693078..a3fae24 100644
--- a/content/browser/frame_host/debug_urls.cc
+++ b/content/browser/frame_host/debug_urls.cc
@@ -17,7 +17,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/thread_restrictions.h"
 #include "cc/base/switches.h"
-#include "content/browser/gpu/gpu_process_host_ui_shim.h"
+#include "content/browser/gpu/gpu_process_host.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_constants.h"
 #include "content/public/common/url_constants.h"
@@ -167,32 +167,36 @@
   }
 
   if (url == kChromeUIGpuCleanURL) {
-    GpuProcessHostUIShim* shim = GpuProcessHostUIShim::GetOneInstance();
-    if (shim)
-      shim->SimulateRemoveAllContext();
+    GpuProcessHost::CallOnIO(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+                             false /* force_create */,
+                             base::Bind([](GpuProcessHost* host) {
+                               host->gpu_service()->DestroyAllChannels();
+                             }));
     return true;
   }
 
   if (url == kChromeUIGpuCrashURL) {
-    GpuProcessHostUIShim* shim = GpuProcessHostUIShim::GetOneInstance();
-    if (shim)
-      shim->SimulateCrash();
+    GpuProcessHost::CallOnIO(
+        GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, false /* force_create */,
+        base::Bind([](GpuProcessHost* host) { host->gpu_service()->Crash(); }));
     return true;
   }
 
 #if defined(OS_ANDROID)
   if (url == kChromeUIGpuJavaCrashURL) {
-    GpuProcessHostUIShim* shim = GpuProcessHostUIShim::GetOneInstance();
-    if (shim)
-      shim->SimulateJavaCrash();
+    GpuProcessHost::CallOnIO(GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED,
+                             false /* force_create */,
+                             base::Bind([](GpuProcessHost* host) {
+                               host->gpu_service()->ThrowJavaException();
+                             }));
     return true;
   }
 #endif
 
   if (url == kChromeUIGpuHangURL) {
-    GpuProcessHostUIShim* shim = GpuProcessHostUIShim::GetOneInstance();
-    if (shim)
-      shim->SimulateHang();
+    GpuProcessHost::CallOnIO(
+        GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, false /* force_create */,
+        base::Bind([](GpuProcessHost* host) { host->gpu_service()->Hang(); }));
     return true;
   }
 
diff --git a/content/browser/gpu/gpu_ipc_browsertests.cc b/content/browser/gpu/gpu_ipc_browsertests.cc
index 367ed032..458e847d 100644
--- a/content/browser/gpu/gpu_ipc_browsertests.cc
+++ b/content/browser/gpu/gpu_ipc_browsertests.cc
@@ -8,10 +8,11 @@
 #include "build/build_config.h"
 #include "content/browser/compositor/image_transport_factory.h"
 #include "content/browser/gpu/browser_gpu_channel_host_factory.h"
-#include "content/browser/gpu/gpu_process_host_ui_shim.h"
+#include "content/browser/gpu/gpu_process_host.h"
 #include "content/public/browser/gpu_data_manager.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/content_browser_test.h"
+#include "services/ui/gpu/interfaces/gpu_service.mojom.h"
 #include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkPaint.h"
@@ -283,10 +284,9 @@
       base::Bind(&BrowserGpuChannelHostFactoryTest::OnContextLost,
                  base::Unretained(this), run_loop.QuitClosure(), &counter));
   EXPECT_TRUE(provider->BindToCurrentThread());
-  GpuProcessHostUIShim* shim =
-      GpuProcessHostUIShim::FromID(GetFactory()->GpuProcessHostId());
-  EXPECT_TRUE(shim != NULL);
-  shim->SimulateCrash();
+  GpuProcessHost::CallOnIO(
+      GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, false /* force_create */,
+      base::Bind([](GpuProcessHost* host) { host->gpu_service()->Crash(); }));
   run_loop.Run();
 
   EXPECT_EQ(1, counter);
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index 20322999..167b4d2 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -103,9 +103,10 @@
   // Helper function to run a callback on the IO thread. The callback receives
   // the appropriate GpuProcessHost instance. If |force_create| is false, and no
   // GpuProcessHost instance exists, then the callback is never called.
-  static void CallOnIO(GpuProcessKind kind,
-                       bool force_create,
-                       const base::Callback<void(GpuProcessHost*)>& callback);
+  CONTENT_EXPORT static void CallOnIO(
+      GpuProcessKind kind,
+      bool force_create,
+      const base::Callback<void(GpuProcessHost*)>& callback);
 
   service_manager::InterfaceProvider* GetRemoteInterfaces();
 
diff --git a/content/browser/gpu/gpu_process_host_ui_shim.cc b/content/browser/gpu/gpu_process_host_ui_shim.cc
index f8fe86b..a662106 100644
--- a/content/browser/gpu/gpu_process_host_ui_shim.cc
+++ b/content/browser/gpu/gpu_process_host_ui_shim.cc
@@ -43,14 +43,6 @@
 base::LazyInstance<IDMap<GpuProcessHostUIShim*>> g_hosts_by_id =
     LAZY_INSTANCE_INITIALIZER;
 
-void SendOnIOThreadTask(int host_id, IPC::Message* msg) {
-  GpuProcessHost* host = GpuProcessHost::FromID(host_id);
-  if (host)
-    host->Send(msg);
-  else
-    delete msg;
-}
-
 void StopGpuProcessOnIO(int host_id) {
   GpuProcessHost* host = GpuProcessHost::FromID(host_id);
   if (host)
@@ -113,24 +105,6 @@
   return g_hosts_by_id.Pointer()->Lookup(host_id);
 }
 
-// static
-GpuProcessHostUIShim* GpuProcessHostUIShim::GetOneInstance() {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  if (g_hosts_by_id.Pointer()->IsEmpty())
-    return NULL;
-  IDMap<GpuProcessHostUIShim*>::iterator it(g_hosts_by_id.Pointer());
-  return it.GetCurrentValue();
-}
-
-bool GpuProcessHostUIShim::Send(IPC::Message* msg) {
-  DCHECK(CalledOnValidThread());
-  return BrowserThread::PostTask(BrowserThread::IO,
-                                 FROM_HERE,
-                                 base::Bind(&SendOnIOThreadTask,
-                                            host_id_,
-                                            msg));
-}
-
 bool GpuProcessHostUIShim::OnMessageReceived(const IPC::Message& message) {
   DCHECK(CalledOnValidThread());
 
@@ -154,24 +128,6 @@
       BrowserThread::IO, FROM_HERE, base::Bind(&StopGpuProcessOnIO, host_id_));
 }
 
-void GpuProcessHostUIShim::SimulateRemoveAllContext() {
-  Send(new GpuMsg_Clean());
-}
-
-void GpuProcessHostUIShim::SimulateCrash() {
-  Send(new GpuMsg_Crash());
-}
-
-void GpuProcessHostUIShim::SimulateHang() {
-  Send(new GpuMsg_Hang());
-}
-
-#if defined(OS_ANDROID)
-void GpuProcessHostUIShim::SimulateJavaCrash() {
-  Send(new GpuMsg_JavaCrash());
-}
-#endif
-
 GpuProcessHostUIShim::~GpuProcessHostUIShim() {
   DCHECK(CalledOnValidThread());
   if (!close_callback_.is_null())
diff --git a/content/browser/gpu/gpu_process_host_ui_shim.h b/content/browser/gpu/gpu_process_host_ui_shim.h
index e8605b8..2032134 100644
--- a/content/browser/gpu/gpu_process_host_ui_shim.h
+++ b/content/browser/gpu/gpu_process_host_ui_shim.h
@@ -35,7 +35,6 @@
 void RouteToGpuProcessHostUIShimTask(int host_id, const IPC::Message& msg);
 
 class GpuProcessHostUIShim : public IPC::Listener,
-                             public IPC::Sender,
                              public base::NonThreadSafe {
  public:
   // Create a GpuProcessHostUIShim with the given ID.  The object can be found
@@ -52,29 +51,15 @@
 
   CONTENT_EXPORT static GpuProcessHostUIShim* FromID(int host_id);
 
-  // Get a GpuProcessHostUIShim instance; it doesn't matter which one.
-  // Return NULL if none has been created.
-  CONTENT_EXPORT static GpuProcessHostUIShim* GetOneInstance();
-
   // Stops the GPU process.
   CONTENT_EXPORT void StopGpuProcess(const base::Closure& callback);
 
-  // IPC::Sender implementation.
-  bool Send(IPC::Message* msg) override;
-
   // IPC::Listener implementation.
   // The GpuProcessHost causes this to be called on the UI thread to
   // dispatch the incoming messages from the GPU process, which are
   // actually received on the IO thread.
   bool OnMessageReceived(const IPC::Message& message) override;
 
-  CONTENT_EXPORT void SimulateRemoveAllContext();
-  CONTENT_EXPORT void SimulateCrash();
-  CONTENT_EXPORT void SimulateHang();
-#if defined(OS_ANDROID)
-  CONTENT_EXPORT void SimulateJavaCrash();
-#endif
-
  private:
   explicit GpuProcessHostUIShim(int host_id);
   ~GpuProcessHostUIShim() override;
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 073ffc5..1bd1839 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -636,6 +636,7 @@
   if (!vulkan_context_provider)
     return;
 
+  // TODO(crbug.com/582558): Need to match GL and implement DidSwapBuffers.
   auto vulkan_surface = base::MakeUnique<VulkanOutputSurface>(
       vulkan_context_provider, base::ThreadTaskRunnerHandle::Get());
   if (!vulkan_surface->Initialize(window_))
diff --git a/content/browser/webui/OWNERS b/content/browser/webui/OWNERS
index 3aee59d..e49cb53 100644
--- a/content/browser/webui/OWNERS
+++ b/content/browser/webui/OWNERS
@@ -3,3 +3,5 @@
 
 # Emeritus
 estade@chromium.org
+
+# COMPONENT: UI>Browser>WebUI
diff --git a/content/common/gpu_host_messages.h b/content/common/gpu_host_messages.h
index 0cee493d..f56899b 100644
--- a/content/common/gpu_host_messages.h
+++ b/content/common/gpu_host_messages.h
@@ -106,20 +106,6 @@
 // information.
 IPC_MESSAGE_CONTROL0(GpuMsg_CollectGraphicsInfo)
 
-// Tells the GPU process to remove all contexts.
-IPC_MESSAGE_CONTROL0(GpuMsg_Clean)
-
-// Tells the GPU process to crash.
-IPC_MESSAGE_CONTROL0(GpuMsg_Crash)
-
-// Tells the GPU process to hang.
-IPC_MESSAGE_CONTROL0(GpuMsg_Hang)
-
-#if defined(OS_ANDROID)
-// Tells the GPU process to throw a java exception
-IPC_MESSAGE_CONTROL0(GpuMsg_JavaCrash)
-#endif
-
 // Tells the GPU process that the browser has seen a GPU switch.
 IPC_MESSAGE_CONTROL0(GpuMsg_GpuSwitched)
 
diff --git a/content/gpu/gpu_child_thread.cc b/content/gpu/gpu_child_thread.cc
index e1e5fd4..4d8a952 100644
--- a/content/gpu/gpu_child_thread.cc
+++ b/content/gpu/gpu_child_thread.cc
@@ -51,7 +51,6 @@
 #endif
 
 #if defined(OS_ANDROID)
-#include "base/android/throw_uncaught_exception.h"
 #include "media/base/android/media_client_android.h"
 #endif
 
@@ -249,12 +248,6 @@
   IPC_BEGIN_MESSAGE_MAP(GpuChildThread, msg)
     IPC_MESSAGE_HANDLER(GpuMsg_Finalize, OnFinalize)
     IPC_MESSAGE_HANDLER(GpuMsg_CollectGraphicsInfo, OnCollectGraphicsInfo)
-    IPC_MESSAGE_HANDLER(GpuMsg_Clean, OnClean)
-    IPC_MESSAGE_HANDLER(GpuMsg_Crash, OnCrash)
-    IPC_MESSAGE_HANDLER(GpuMsg_Hang, OnHang)
-#if defined(OS_ANDROID)
-    IPC_MESSAGE_HANDLER(GpuMsg_JavaCrash, OnJavaCrash)
-#endif
     IPC_MESSAGE_HANDLER(GpuMsg_GpuSwitched, OnGpuSwitched)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
@@ -413,33 +406,6 @@
 #endif  // OS_WIN
 }
 
-void GpuChildThread::OnClean() {
-  DVLOG(1) << "GPU: Removing all contexts";
-  if (gpu_channel_manager())
-    gpu_channel_manager()->DestroyAllChannels();
-}
-
-void GpuChildThread::OnCrash() {
-  DVLOG(1) << "GPU: Simulating GPU crash";
-  // Good bye, cruel world.
-  volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL;
-  *it_s_the_end_of_the_world_as_we_know_it = 0xdead;
-}
-
-void GpuChildThread::OnHang() {
-  DVLOG(1) << "GPU: Simulating GPU hang";
-  for (;;) {
-    // Do not sleep here. The GPU watchdog timer tracks the amount of user
-    // time this thread is using and it doesn't use much while calling Sleep.
-  }
-}
-
-#if defined(OS_ANDROID)
-void GpuChildThread::OnJavaCrash() {
-  base::android::ThrowUncaughtException();
-}
-#endif
-
 void GpuChildThread::OnGpuSwitched() {
   DVLOG(1) << "GPU: GPU has switched";
   // Notify observers in the GPU process.
diff --git a/content/gpu/gpu_child_thread.h b/content/gpu/gpu_child_thread.h
index c4f539f..d967925b 100644
--- a/content/gpu/gpu_child_thread.h
+++ b/content/gpu/gpu_child_thread.h
@@ -114,12 +114,6 @@
   void OnCollectGraphicsInfo();
   void OnSetVideoMemoryWindowCount(uint32_t window_count);
 
-  void OnClean();
-  void OnCrash();
-  void OnHang();
-#if defined(OS_ANDROID)
-  void OnJavaCrash();
-#endif
   void OnGpuSwitched();
 
   void OnDestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index ccdc8d7..56ed319 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -741,6 +741,7 @@
     "//ppapi/features",
     "//services/catalog:lib",
     "//services/service_manager/public/cpp",
+    "//services/ui/gpu/interfaces",
     "//services/ui/public/cpp/gpu",
     "//storage/browser",
     "//testing/gmock",
diff --git a/ios/chrome/browser/ui/util/i18n_string.mm b/ios/chrome/browser/ui/util/i18n_string.mm
index 5242053c0..6aaf6816b 100644
--- a/ios/chrome/browser/ui/util/i18n_string.mm
+++ b/ios/chrome/browser/ui/util/i18n_string.mm
@@ -15,5 +15,5 @@
   if (has_changed) {
     return base::SysUTF16ToNSString(converted_text);
   }
-  return text;
+  return [[text copy] autorelease];
 }
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index e162b1a..7004abe1 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1080,7 +1080,7 @@
 
 // NativeControllerDelegate method, called to inform that title has changed.
 - (void)nativeContent:(id)content titleDidChange:(NSString*)title {
-  _webStateImpl->OnTitleChanged();
+  [self setNavigationItemTitle:title];
 }
 
 - (void)setNativeControllerWebUsageEnabled:(BOOL)webUsageEnabled {
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 63e6426..2b3820f 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -2116,6 +2116,10 @@
   visibility = [ ":test_support" ]
   testonly = true
   sources = [
+    "data/quic_http_response_cache_data_with_push/test.example.com/favicon.ico",
+    "data/quic_http_response_cache_data_with_push/test.example.com/index.html",
+    "data/quic_http_response_cache_data_with_push/test.example.com/index2.html",
+    "data/quic_http_response_cache_data_with_push/test.example.com/kitten-1.jpg",
     "data/ssl/certificates/1024-rsa-ee-by-1024-rsa-intermediate.pem",
     "data/ssl/certificates/1024-rsa-ee-by-2048-rsa-intermediate.pem",
     "data/ssl/certificates/1024-rsa-ee-by-768-rsa-intermediate.pem",
diff --git a/net/http/http_cache.cc b/net/http/http_cache.cc
index 1dc390a..904797a1 100644
--- a/net/http/http_cache.cc
+++ b/net/http/http_cache.cc
@@ -38,6 +38,7 @@
 #include "net/base/upload_data_stream.h"
 #include "net/disk_cache/disk_cache.h"
 #include "net/http/disk_cache_based_quic_server_info.h"
+#include "net/http/http_cache_lookup_manager.h"
 #include "net/http/http_cache_transaction.h"
 #include "net/http/http_network_layer.h"
 #include "net/http/http_network_session.h"
@@ -343,14 +344,20 @@
   // Session may be NULL in unittests.
   // TODO(mmenke): Seems like tests could be changed to provide a session,
   // rather than having logic only used in unit tests here.
-  if (session) {
-    net_log_ = session->net_log();
-    if (is_main_cache &&
-        !session->quic_stream_factory()->has_quic_server_info_factory()) {
-      // QuicStreamFactory takes ownership of QuicServerInfoFactoryAdaptor.
-      session->quic_stream_factory()->set_quic_server_info_factory(
-          new QuicServerInfoFactoryAdaptor(this));
-    }
+  if (!session)
+    return;
+
+  net_log_ = session->net_log();
+  if (!is_main_cache)
+    return;
+
+  session->SetServerPushDelegate(
+      base::MakeUnique<HttpCacheLookupManager>(this));
+
+  if (!session->quic_stream_factory()->has_quic_server_info_factory()) {
+    // QuicStreamFactory takes ownership of QuicServerInfoFactoryAdaptor.
+    session->quic_stream_factory()->set_quic_server_info_factory(
+        new QuicServerInfoFactoryAdaptor(this));
   }
 }
 
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index b57653a..cd58bb60 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -105,6 +105,7 @@
     : client_socket_factory(nullptr),
       host_resolver(nullptr),
       cert_verifier(nullptr),
+      enable_server_push_cancellation(false),
       channel_id_service(nullptr),
       transport_security_state(nullptr),
       cert_transparency_verifier(nullptr),
@@ -398,7 +399,9 @@
 
 void HttpNetworkSession::SetServerPushDelegate(
     std::unique_ptr<ServerPushDelegate> push_delegate) {
-  DCHECK(!push_delegate_ && push_delegate);
+  DCHECK(push_delegate);
+  if (!params_.enable_server_push_cancellation || push_delegate_)
+    return;
 
   push_delegate_ = std::move(push_delegate);
   spdy_session_pool_.set_server_push_delegate(push_delegate_.get());
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index b0ed8c0..47543fb1 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -85,6 +85,7 @@
     ClientSocketFactory* client_socket_factory;
     HostResolver* host_resolver;
     CertVerifier* cert_verifier;
+    bool enable_server_push_cancellation;
     ChannelIDService* channel_id_service;
     TransportSecurityState* transport_security_state;
     CTVerifier* cert_transparency_verifier;
diff --git a/net/nqe/network_quality_estimator.cc b/net/nqe/network_quality_estimator.cc
index b8861b3..9ca1e18 100644
--- a/net/nqe/network_quality_estimator.cc
+++ b/net/nqe/network_quality_estimator.cc
@@ -906,7 +906,8 @@
 
 void NetworkQualityEstimator::UpdateSignalStrength() {
 #if defined(OS_ANDROID)
-  if (!android::cellular_signal_strength::GetSignalStrengthDbm(
+  if (!NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type) ||
+      !android::cellular_signal_strength::GetSignalStrengthDbm(
           &signal_strength_dbm_)) {
     signal_strength_dbm_ = INT32_MIN;
   }
diff --git a/net/quic/core/quic_server_session_base_test.cc b/net/quic/core/quic_server_session_base_test.cc
index 6e18cd5..ec05f6ab 100644
--- a/net/quic/core/quic_server_session_base_test.cc
+++ b/net/quic/core/quic_server_session_base_test.cc
@@ -210,6 +210,7 @@
   // Send a reset (and expect the peer to send a RST in response).
   QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM,
                           0);
+  EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
   EXPECT_CALL(*connection_,
               SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
   visitor_->OnRstStream(rst1);
@@ -227,6 +228,7 @@
   // Send a reset (and expect the peer to send a RST in response).
   QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM,
                           0);
+  EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
   EXPECT_CALL(*connection_,
               SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
   visitor_->OnRstStream(rst1);
@@ -253,6 +255,7 @@
 
   // Send a reset (and expect the peer to send a RST in response).
   QuicRstStreamFrame rst(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, 0);
+  EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
   EXPECT_CALL(*connection_,
               SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
   visitor_->OnRstStream(rst);
diff --git a/net/quic/core/quic_session.cc b/net/quic/core/quic_session.cc
index 6160cdd..b4d73481 100644
--- a/net/quic/core/quic_session.cc
+++ b/net/quic/core/quic_session.cc
@@ -95,6 +95,10 @@
     return;
   }
 
+  if (visitor_) {
+    visitor_->OnRstStreamReceived(frame);
+  }
+
   QuicStream* stream = GetOrCreateDynamicStream(frame.stream_id);
   if (!stream) {
     HandleRstOnValidNonexistentStream(frame);
diff --git a/net/quic/core/quic_session.h b/net/quic/core/quic_session.h
index 283f55f..2f80010 100644
--- a/net/quic/core/quic_session.h
+++ b/net/quic/core/quic_session.h
@@ -53,6 +53,9 @@
 
     // Called when the session has become write blocked.
     virtual void OnWriteBlocked(QuicBlockedWriterInterface* blocked_writer) = 0;
+
+    // Called when the session receives reset on a stream from the peer.
+    virtual void OnRstStreamReceived(const QuicRstStreamFrame& frame) = 0;
   };
 
   // CryptoHandshakeEvent enumerates the events generated by a QuicCryptoStream.
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index 9fb1811..9749457 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -147,6 +147,7 @@
     g_time_delta = base::TimeDelta();
     g_time_now = base::TimeTicks::Now();
     session_deps_.net_log = log_.bound().net_log();
+    session_deps_.enable_server_push_cancellation = true;
   }
 
   void CreateNetworkSession() {
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index 1b2ef247..0729125 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -341,6 +341,7 @@
       enable_ping(false),
       enable_user_alternate_protocol_ports(false),
       enable_quic(false),
+      enable_server_push_cancellation(false),
       session_max_recv_window_size(kDefaultInitialWindowSize),
       time_func(&base::TimeTicks::Now),
       enable_http2_alternative_service_with_different_host(false),
@@ -402,6 +403,8 @@
   params.enable_user_alternate_protocol_ports =
       session_deps->enable_user_alternate_protocol_ports;
   params.enable_quic = session_deps->enable_quic;
+  params.enable_server_push_cancellation =
+      session_deps->enable_server_push_cancellation;
   params.spdy_session_max_recv_window_size =
       session_deps->session_max_recv_window_size;
   params.http2_settings = session_deps->http2_settings;
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h
index 62a0564..727145c8 100644
--- a/net/spdy/spdy_test_util_common.h
+++ b/net/spdy/spdy_test_util_common.h
@@ -207,6 +207,7 @@
   bool enable_ping;
   bool enable_user_alternate_protocol_ports;
   bool enable_quic;
+  bool enable_server_push_cancellation;
   size_t session_max_recv_window_size;
   SettingsMap http2_settings;
   SpdySession::TimeFunc time_func;
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index c99ea93..4a1df9c 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -524,6 +524,8 @@
   write_blocked_list_.insert(std::make_pair(blocked_writer, true));
 }
 
+void QuicDispatcher::OnRstStreamReceived(const QuicRstStreamFrame& frame) {}
+
 void QuicDispatcher::OnConnectionAddedToTimeWaitList(
     QuicConnectionId connection_id) {
   QUIC_DLOG(INFO) << "Connection " << connection_id
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h
index 266e3e4..a95fd8ab 100644
--- a/net/tools/quic/quic_dispatcher.h
+++ b/net/tools/quic/quic_dispatcher.h
@@ -85,6 +85,11 @@
   // Queues the blocked writer for later resumption.
   void OnWriteBlocked(QuicBlockedWriterInterface* blocked_writer) override;
 
+  // QuicSession::Visitor interface implementation (via inheritance of
+  // QuicTimeWaitListManager::Visitor):
+  // Collects reset error code received on streams.
+  void OnRstStreamReceived(const QuicRstStreamFrame& frame) override;
+
   // QuicTimeWaitListManager::Visitor interface implementation
   // Called whenever the time wait list manager adds a new connection to the
   // time-wait list.
diff --git a/net/tools/quic/quic_simple_dispatcher.cc b/net/tools/quic/quic_simple_dispatcher.cc
index cab2925..e173624 100644
--- a/net/tools/quic/quic_simple_dispatcher.cc
+++ b/net/tools/quic/quic_simple_dispatcher.cc
@@ -26,6 +26,26 @@
 
 QuicSimpleDispatcher::~QuicSimpleDispatcher() {}
 
+int QuicSimpleDispatcher::GetRstErrorCount(
+    QuicRstStreamErrorCode error_code) const {
+  auto it = rst_error_map_.find(error_code);
+  if (it == rst_error_map_.end()) {
+    return 0;
+  } else {
+    return it->second;
+  }
+}
+
+void QuicSimpleDispatcher::OnRstStreamReceived(
+    const QuicRstStreamFrame& frame) {
+  auto it = rst_error_map_.find(frame.error_code);
+  if (it == rst_error_map_.end()) {
+    rst_error_map_.insert(std::make_pair(frame.error_code, 1));
+  } else {
+    it->second++;
+  }
+}
+
 QuicServerSessionBase* QuicSimpleDispatcher::CreateQuicSession(
     QuicConnectionId connection_id,
     const QuicSocketAddress& client_address) {
diff --git a/net/tools/quic/quic_simple_dispatcher.h b/net/tools/quic/quic_simple_dispatcher.h
index b9df6d9..41d24cf 100644
--- a/net/tools/quic/quic_simple_dispatcher.h
+++ b/net/tools/quic/quic_simple_dispatcher.h
@@ -24,6 +24,10 @@
 
   ~QuicSimpleDispatcher() override;
 
+  int GetRstErrorCount(QuicRstStreamErrorCode rst_error_code) const;
+
+  void OnRstStreamReceived(const QuicRstStreamFrame& frame) override;
+
  protected:
   QuicServerSessionBase* CreateQuicSession(
       QuicConnectionId connection_id,
@@ -33,6 +37,9 @@
 
  private:
   QuicHttpResponseCache* response_cache_;  // Unowned.
+
+  // The map of the reset error code with its counter.
+  std::map<QuicRstStreamErrorCode, int> rst_error_map_;
 };
 
 }  // namespace net
diff --git a/net/tools/quic/quic_simple_server_session_test.cc b/net/tools/quic/quic_simple_server_session_test.cc
index 5d1cac2..35db616 100644
--- a/net/tools/quic/quic_simple_server_session_test.cc
+++ b/net/tools/quic/quic_simple_server_session_test.cc
@@ -235,6 +235,7 @@
   // Receive a reset (and send a RST in response).
   QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM,
                           0);
+  EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
   EXPECT_CALL(*connection_,
               SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
   visitor_->OnRstStream(rst1);
@@ -252,6 +253,7 @@
   // Send a reset (and expect the peer to send a RST in response).
   QuicRstStreamFrame rst1(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM,
                           0);
+  EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
   EXPECT_CALL(*connection_,
               SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
   visitor_->OnRstStream(rst1);
@@ -278,6 +280,7 @@
 
   // Send a reset (and expect the peer to send a RST in response).
   QuicRstStreamFrame rst(kClientDataStreamId1, QUIC_ERROR_PROCESSING_STREAM, 0);
+  EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
   EXPECT_CALL(*connection_,
               SendRstStream(kClientDataStreamId1, QUIC_RST_ACKNOWLEDGEMENT, 0));
   visitor_->OnRstStream(rst);
@@ -569,6 +572,7 @@
   // Reset the last stream in the queue. It should be marked cancelled.
   QuicStreamId stream_got_reset = num_resources * 2;
   QuicRstStreamFrame rst(stream_got_reset, QUIC_STREAM_CANCELLED, 0);
+  EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
   EXPECT_CALL(*connection_,
               SendRstStream(stream_got_reset, QUIC_RST_ACKNOWLEDGEMENT, 0));
   visitor_->OnRstStream(rst);
@@ -613,6 +617,7 @@
       .WillOnce(Return(QuicConsumedData(kStreamFlowControlWindowSize, false)));
 
   EXPECT_CALL(*connection_, SendBlocked(stream_to_open));
+  EXPECT_CALL(owner_, OnRstStreamReceived(_)).Times(1);
   QuicRstStreamFrame rst(stream_got_reset, QUIC_STREAM_CANCELLED, 0);
   visitor_->OnRstStream(rst);
 }
diff --git a/net/tools/quic/test_tools/mock_quic_session_visitor.h b/net/tools/quic/test_tools/mock_quic_session_visitor.h
index ee1a6c7..793be8d4 100644
--- a/net/tools/quic/test_tools/mock_quic_session_visitor.h
+++ b/net/tools/quic/test_tools/mock_quic_session_visitor.h
@@ -23,6 +23,7 @@
                     const std::string& error_details));
   MOCK_METHOD1(OnWriteBlocked,
                void(QuicBlockedWriterInterface* blocked_writer));
+  MOCK_METHOD1(OnRstStreamReceived, void(const QuicRstStreamFrame& frame));
   MOCK_METHOD1(OnConnectionAddedToTimeWaitList,
                void(QuicConnectionId connection_id));
 
diff --git a/net/url_request/url_request_quic_unittest.cc b/net/url_request/url_request_quic_unittest.cc
index 7532196..f435d61 100644
--- a/net/url_request/url_request_quic_unittest.cc
+++ b/net/url_request/url_request_quic_unittest.cc
@@ -15,12 +15,17 @@
 #include "net/cert/mock_cert_verifier.h"
 #include "net/dns/mapped_host_resolver.h"
 #include "net/dns/mock_host_resolver.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/test_net_log.h"
+#include "net/log/test_net_log_entry.h"
 #include "net/quic/chromium/crypto/proof_source_chromium.h"
 #include "net/quic/test_tools/crypto_test_utils.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/gtest_util.h"
 #include "net/test/test_data_directory.h"
+#include "net/tools/quic/quic_dispatcher.h"
 #include "net/tools/quic/quic_http_response_cache.h"
+#include "net/tools/quic/quic_simple_dispatcher.h"
 #include "net/tools/quic/quic_simple_server.h"
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_test_util.h"
@@ -64,9 +69,11 @@
     params->origins_to_force_quic_on.insert(HostPortPair(kTestServerHost, 443));
     params->cert_verifier = &cert_verifier_;
     params->enable_quic = true;
+    params->enable_server_push_cancellation = true;
     context_->set_host_resolver(host_resolver_.get());
     context_->set_http_network_session_params(std::move(params));
     context_->set_cert_verifier(&cert_verifier_);
+    context_->set_net_log(&net_log_);
   }
 
   void TearDown() override {
@@ -88,11 +95,29 @@
     return context_->CreateRequest(url, priority, delegate);
   }
 
+  void ExtractNetLog(NetLogEventType type,
+                     TestNetLogEntry::List* entry_list) const {
+    net::TestNetLogEntry::List entries;
+    net_log_.GetEntries(&entries);
+
+    for (const auto& entry : entries) {
+      if (entry.type == type)
+        entry_list->push_back(entry);
+    }
+  }
+
+  unsigned int GetRstErrorCountReceivedByServer(
+      QuicRstStreamErrorCode error_code) const {
+    return (static_cast<QuicSimpleDispatcher*>(server_->dispatcher()))
+        ->GetRstErrorCount(error_code);
+  }
+
  private:
   void StartQuicServer() {
     // Set up in-memory cache.
     response_cache_.AddSimpleResponse(kTestServerHost, kHelloPath, kHelloStatus,
                                       kHelloBodyValue);
+    response_cache_.InitializeFromDirectory(ServerPushCacheDirectory());
     net::QuicConfig config;
     // Set up server certs.
     std::unique_ptr<net::ProofSourceChromium> proof_source(
@@ -120,9 +145,19 @@
     EXPECT_TRUE(host_resolver_->AddRuleFromString(map_rule));
   }
 
+  std::string ServerPushCacheDirectory() {
+    base::FilePath path;
+    PathService::Get(base::DIR_SOURCE_ROOT, &path);
+    path = path.AppendASCII("net").AppendASCII("data").AppendASCII(
+        "quic_http_response_cache_data_with_push");
+    // The file path is known to be an ascii string.
+    return path.MaybeAsASCII();
+  }
+
   std::unique_ptr<MappedHostResolver> host_resolver_;
   std::unique_ptr<QuicSimpleServer> server_;
   std::unique_ptr<TestURLRequestContext> context_;
+  TestNetLog net_log_;
   QuicHttpResponseCache response_cache_;
   MockCertVerifier cert_verifier_;
 };
@@ -211,6 +246,201 @@
   EXPECT_EQ(kHelloBodyValue, delegate.data_received());
 }
 
+TEST_F(URLRequestQuicTest, CancelPushIfCached) {
+  base::RunLoop run_loop;
+  WaitForCompletionNetworkDelegate network_delegate(
+      run_loop.QuitClosure(), /*num_expected_requests=*/2);
+  SetNetworkDelegate(&network_delegate);
+
+  Init();
+  {
+    // Send a request to the pushed url: /kitten-1.jpg to pull the resource into
+    // cache.
+    CheckLoadTimingDelegate delegate(false);
+    std::string url =
+        base::StringPrintf("https://%s%s", kTestServerHost, "/kitten-1.jpg");
+    std::unique_ptr<URLRequest> request =
+        CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
+
+    request->Start();
+    ASSERT_TRUE(request->is_pending());
+    base::RunLoop().Run();
+
+    EXPECT_TRUE(request->status().is_success());
+  }
+
+  // Send a request to /index2.html which pushes /kitten-1.jpg and /favicon.ico.
+  // Should cancel push for /kitten-1.jpg.
+  CheckLoadTimingDelegate delegate(true);
+  std::string url =
+      base::StringPrintf("https://%s%s", kTestServerHost, "/index2.html");
+  std::unique_ptr<URLRequest> request =
+      CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
+
+  request->Start();
+  ASSERT_TRUE(request->is_pending());
+  base::RunLoop().Run();
+
+  // Extract net logs on client side to verify push lookup transactions.
+  net::TestNetLogEntry::List entries;
+  ExtractNetLog(NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION, &entries);
+
+  EXPECT_EQ(4u, entries.size());
+
+  std::string value;
+  int net_error;
+  std::string push_url_1 =
+      base::StringPrintf("https://%s%s", kTestServerHost, "/kitten-1.jpg");
+  std::string push_url_2 =
+      base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
+
+  EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
+  EXPECT_EQ(value, push_url_1);
+  // No net error code for this lookup transaction, the push is found.
+  EXPECT_FALSE(entries[1].GetIntegerValue("net_error", &net_error));
+
+  EXPECT_TRUE(entries[2].GetStringValue("push_url", &value));
+  EXPECT_EQ(value, push_url_2);
+  // Net error code -400 is found for this lookup transaction, the push is not
+  // found in the cache.
+  EXPECT_TRUE(entries[3].GetIntegerValue("net_error", &net_error));
+  EXPECT_EQ(net_error, -400);
+
+  EXPECT_TRUE(request->status().is_success());
+
+  // Verify the reset error count received on the server side.
+  EXPECT_EQ(1u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED));
+}
+
+TEST_F(URLRequestQuicTest, CancelPushIfCached2) {
+  base::RunLoop run_loop;
+  WaitForCompletionNetworkDelegate network_delegate(
+      run_loop.QuitClosure(), /*num_expected_requests=*/3);
+  SetNetworkDelegate(&network_delegate);
+
+  Init();
+  {
+    // Send a request to the pushed url: /kitten-1.jpg to pull the resource into
+    // cache.
+    CheckLoadTimingDelegate delegate(false);
+    std::string url =
+        base::StringPrintf("https://%s%s", kTestServerHost, "/kitten-1.jpg");
+    std::unique_ptr<URLRequest> request =
+        CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
+
+    request->Start();
+    ASSERT_TRUE(request->is_pending());
+    base::RunLoop().Run();
+
+    EXPECT_TRUE(request->status().is_success());
+    EXPECT_NE(network_delegate.total_network_bytes_sent(), 0u);
+  }
+
+  {
+    // Send a request to the pushed url: /favicon.ico to pull the resource into
+    // cache.
+    CheckLoadTimingDelegate delegate(true);
+    std::string url =
+        base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
+    std::unique_ptr<URLRequest> request =
+        CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
+
+    request->Start();
+    ASSERT_TRUE(request->is_pending());
+    base::RunLoop().Run();
+
+    EXPECT_TRUE(request->status().is_success());
+  }
+
+  // Send a request to /index2.html which pushes /kitten-1.jpg and /favicon.ico.
+  // Should cancel push for /kitten-1.jpg.
+  CheckLoadTimingDelegate delegate(true);
+  std::string url =
+      base::StringPrintf("https://%s%s", kTestServerHost, "/index2.html");
+  std::unique_ptr<URLRequest> request =
+      CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
+
+  request->Start();
+  ASSERT_TRUE(request->is_pending());
+  base::RunLoop().Run();
+
+  // Extract net logs on client side to verify push lookup transactions.
+  net::TestNetLogEntry::List entries;
+  ExtractNetLog(NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION, &entries);
+
+  EXPECT_EQ(4u, entries.size());
+
+  std::string value;
+  int net_error;
+  std::string push_url_1 =
+      base::StringPrintf("https://%s%s", kTestServerHost, "/kitten-1.jpg");
+  std::string push_url_2 =
+      base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
+
+  EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
+  EXPECT_EQ(value, push_url_1);
+  // No net error code for this lookup transaction, the push is found.
+  EXPECT_FALSE(entries[1].GetIntegerValue("net_error", &net_error));
+
+  EXPECT_TRUE(entries[2].GetStringValue("push_url", &value));
+  EXPECT_EQ(value, push_url_2);
+  // No net error code for this lookup transaction, the push is found.
+  EXPECT_FALSE(entries[3].GetIntegerValue("net_error", &net_error));
+
+  EXPECT_TRUE(request->status().is_success());
+
+  // Verify the reset error count received on the server side.
+  EXPECT_EQ(2u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED));
+}
+
+TEST_F(URLRequestQuicTest, DoNotCancelPushIfNotFoundInCache) {
+  base::RunLoop run_loop;
+  WaitForCompletionNetworkDelegate network_delegate(
+      run_loop.QuitClosure(), /*num_expected_requests=*/1);
+  SetNetworkDelegate(&network_delegate);
+
+  Init();
+  // Send a request to /index2.hmtl which pushes /kitten-1.jpg and /favicon.ico
+  // and shouldn't cancel any since neither is in cache.
+  CheckLoadTimingDelegate delegate(false);
+  std::string url =
+      base::StringPrintf("https://%s%s", kTestServerHost, "/index2.html");
+  std::unique_ptr<URLRequest> request =
+      CreateRequest(GURL(url), DEFAULT_PRIORITY, &delegate);
+
+  request->Start();
+  ASSERT_TRUE(request->is_pending());
+  base::RunLoop().Run();
+
+  // Extract net logs on client side to verify push lookup transactions.
+  net::TestNetLogEntry::List entries;
+  ExtractNetLog(NetLogEventType::SERVER_PUSH_LOOKUP_TRANSACTION, &entries);
+
+  EXPECT_EQ(4u, entries.size());
+
+  std::string value;
+  int net_error;
+  std::string push_url_1 =
+      base::StringPrintf("https://%s%s", kTestServerHost, "/kitten-1.jpg");
+  std::string push_url_2 =
+      base::StringPrintf("https://%s%s", kTestServerHost, "/favicon.ico");
+
+  EXPECT_TRUE(entries[0].GetStringValue("push_url", &value));
+  EXPECT_EQ(value, push_url_1);
+  EXPECT_TRUE(entries[1].GetIntegerValue("net_error", &net_error));
+  EXPECT_EQ(net_error, -400);
+
+  EXPECT_TRUE(entries[2].GetStringValue("push_url", &value));
+  EXPECT_EQ(value, push_url_2);
+  EXPECT_TRUE(entries[3].GetIntegerValue("net_error", &net_error));
+  EXPECT_EQ(net_error, -400);
+
+  EXPECT_TRUE(request->status().is_success());
+
+  // Verify the reset error count received on the server side.
+  EXPECT_EQ(0u, GetRstErrorCountReceivedByServer(QUIC_STREAM_CANCELLED));
+}
+
 // Tests that if two requests use the same QUIC session, the second request
 // should not have |LoadTimingInfo::connect_timing|.
 TEST_F(URLRequestQuicTest, TestTwoRequests) {
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index 1e905fd..5f7f123 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -135,7 +135,7 @@
         base::MakeUnique<HttpNetworkSession>(params));
     context_storage_.set_http_transaction_factory(base::MakeUnique<HttpCache>(
         context_storage_.http_network_session(),
-        HttpCache::DefaultBackend::InMemory(0), false));
+        HttpCache::DefaultBackend::InMemory(0), true /* is_main_cache */));
   }
   if (!http_user_agent_settings()) {
     context_storage_.set_http_user_agent_settings(
diff --git a/remoting/test/chromoting_test_driver.cc b/remoting/test/chromoting_test_driver.cc
index abf7a77..1e7d73e 100644
--- a/remoting/test/chromoting_test_driver.cc
+++ b/remoting/test/chromoting_test_driver.cc
@@ -9,6 +9,7 @@
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
 #include "base/strings/stringprintf.h"
+#include "base/task_scheduler/task_scheduler.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
 #include "base/test/test_switches.h"
@@ -182,6 +183,9 @@
 #endif
   }
 
+  const int kMaxBackgroundThreads = 5;
+  base::TaskScheduler::CreateAndSetSimpleTaskScheduler(kMaxBackgroundThreads);
+
   // Update the logging verbosity level if user specified one.
   std::string verbosity_level(
       command_line->GetSwitchValueASCII(switches::kLoggingLevelSwitchName));
diff --git a/services/ui/gpu/gpu_service.cc b/services/ui/gpu/gpu_service.cc
index 73adbe3..f8a6a17e 100644
--- a/services/ui/gpu/gpu_service.cc
+++ b/services/ui/gpu/gpu_service.cc
@@ -36,6 +36,7 @@
 #include "url/gurl.h"
 
 #if defined(OS_ANDROID)
+#include "base/android/throw_uncaught_exception.h"
 #include "media/gpu/avda_codec_allocator.h"
 #endif
 
@@ -234,4 +235,34 @@
 #endif
 }
 
+void GpuService::DestroyAllChannels() {
+  if (!gpu_channel_manager_)
+    return;
+  DVLOG(1) << "GPU: Removing all contexts";
+  gpu_channel_manager_->DestroyAllChannels();
+}
+
+void GpuService::Crash() {
+  DVLOG(1) << "GPU: Simulating GPU crash";
+  // Good bye, cruel world.
+  volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL;
+  *it_s_the_end_of_the_world_as_we_know_it = 0xdead;
+}
+
+void GpuService::Hang() {
+  DVLOG(1) << "GPU: Simulating GPU hang";
+  for (;;) {
+    // Do not sleep here. The GPU watchdog timer tracks the amount of user
+    // time this thread is using and it doesn't use much while calling Sleep.
+  }
+}
+
+void GpuService::ThrowJavaException() {
+#if defined(OS_ANDROID)
+  base::android::ThrowUncaughtException();
+#else
+  NOTREACHED() << "Java exception not supported on this platform.";
+#endif
+}
+
 }  // namespace ui
diff --git a/services/ui/gpu/gpu_service.h b/services/ui/gpu/gpu_service.h
index 0e0355de..88dd9aa 100644
--- a/services/ui/gpu/gpu_service.h
+++ b/services/ui/gpu/gpu_service.h
@@ -130,6 +130,10 @@
       int32_t surface_id,
       const DestroyingVideoSurfaceCallback& callback) override;
   void WakeUpGpu() override;
+  void DestroyAllChannels() override;
+  void Crash() override;
+  void Hang() override;
+  void ThrowJavaException() override;
 
   scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
 
diff --git a/services/ui/gpu/interfaces/gpu_service.mojom b/services/ui/gpu/interfaces/gpu_service.mojom
index 46d3dc6..69bd9d4 100644
--- a/services/ui/gpu/interfaces/gpu_service.mojom
+++ b/services/ui/gpu/interfaces/gpu_service.mojom
@@ -47,4 +47,10 @@
 
   // Tells GPU to wake up the GPU because we're about to draw.
   WakeUpGpu();
+
+  DestroyAllChannels();
+
+  Crash();
+  Hang();
+  ThrowJavaException();
 };
diff --git a/third_party/.gitignore b/third_party/.gitignore
index e2abab4c..86127121 100644
--- a/third_party/.gitignore
+++ b/third_party/.gitignore
@@ -93,6 +93,7 @@
 /libevdev/src
 /libexif/sources
 /libFuzzer/src
+/libprotobuf-mutator/src
 /libjingle/source
 /libjpeg_turbo
 /liblouis/src
diff --git a/third_party/WebKit/LayoutTests/svg/dom/tooltip-title-with-use.html b/third_party/WebKit/LayoutTests/svg/dom/tooltip-title-with-use.html
new file mode 100644
index 0000000..6625e4f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/dom/tooltip-title-with-use.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<svg width="400" height="400">
+    <symbol id="greenSquare">
+        <title>Title in Symbol</title>
+        <rect width="50" height="50" fill="green">
+            <title>Title in Rect</title>
+        </rect>
+    </symbol>
+    <symbol id="blueSquare">
+        <rect width="50" height="50" fill="blue">
+            <title>Title in Rect</title>
+        </rect>
+    </symbol>
+    <use x="100" y="100" xlink:href="#greenSquare"></use>
+    <use x="200" y="100" xlink:href="#blueSquare"></use>
+    <use x="300" y="100" xlink:href="#greenSquare">
+        <title>Title in Use</title>
+    </use>
+</svg>
+<script>
+testTooltipText(125, 125, "Title in Symbol", "Tooltip title of title child under shadow root");
+testTooltipText(225, 125, "", "Tooltip title without any first level title child under shadow root. Should return empty string");
+testTooltipText(325, 125, "Title in Use", "Tooltip title under Use");
+
+function testTooltipText(x, y, expectedText, description) {
+    if (!window.eventSender || !window.testRunner)
+        return;
+    eventSender.dragMode = false;
+    eventSender.mouseMoveTo(x,y);
+    test(function () {
+        assert_equals(testRunner.tooltipText, expectedText);
+    }, description);
+}
+</script>
\ No newline at end of file
diff --git a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
index 9d99cfd4..0a35269 100644
--- a/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGUseElement.cpp
@@ -40,6 +40,7 @@
 #include "core/svg/SVGLengthContext.h"
 #include "core/svg/SVGSVGElement.h"
 #include "core/svg/SVGSymbolElement.h"
+#include "core/svg/SVGTitleElement.h"
 #include "core/svg/SVGTreeScopeResources.h"
 #include "core/xml/parser/XMLDocumentParser.h"
 #include "platform/loader/fetch/FetchRequest.h"
@@ -339,6 +340,22 @@
   ASSERT(!m_needsShadowTreeRecreation);
 }
 
+String SVGUseElement::title() const {
+  // Find the first <title> child in <use> which doesn't cover shadow tree.
+  if (Element* titleElement = Traversal<SVGTitleElement>::firstChild(*this))
+    return titleElement->innerText();
+
+  // If there is no <title> child in <use>, we lookup first <title> child in
+  // shadow tree.
+  if (m_targetElementInstance) {
+    if (Element* titleElement =
+            Traversal<SVGTitleElement>::firstChild(*m_targetElementInstance))
+      return titleElement->innerText();
+  }
+  // Otherwise return a null string.
+  return String();
+}
+
 static void associateCorrespondingElements(SVGElement& targetRoot,
                                            SVGElement& instanceRoot) {
   auto targetRange = Traversal<SVGElement>::inclusiveDescendantsOf(targetRoot);
diff --git a/third_party/WebKit/Source/core/svg/SVGUseElement.h b/third_party/WebKit/Source/core/svg/SVGUseElement.h
index 7621c56..4c0b5b4 100644
--- a/third_party/WebKit/Source/core/svg/SVGUseElement.h
+++ b/third_party/WebKit/Source/core/svg/SVGUseElement.h
@@ -54,6 +54,7 @@
   SVGAnimatedLength* height() const { return m_height.get(); }
 
   void buildPendingResource() override;
+  String title() const override;
 
   void dispatchPendingEvent();
   void toClipPath(Path&) const;
diff --git a/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp b/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp
index 6c327a3..b85a831 100644
--- a/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp
+++ b/third_party/WebKit/Source/modules/encryptedmedia/NavigatorRequestMediaKeySystemAccess.cpp
@@ -51,12 +51,12 @@
   for (size_t i = 0; i < capabilities.size(); ++i) {
     const WebString& contentType = capabilities[i].contentType();
     result[i].contentType = contentType;
-    if (ParsedContentType(contentType).isValid()) {
+    ParsedContentType type(contentType);
+    if (type.isValid()) {
       // FIXME: Fail if there are unrecognized parameters.
       // http://crbug.com/690131
-      ContentType type(capabilities[i].contentType());
-      result[i].mimeType = type.type();
-      result[i].codecs = type.parameter("codecs");
+      result[i].mimeType = type.mimeType();
+      result[i].codecs = type.parameterValueForName("codecs");
     }
     result[i].robustness = capabilities[i].robustness();
   }
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
index 13c240f..6b8397a 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
@@ -44,7 +44,6 @@
 #include "third_party/skia/include/core/SkData.h"
 #include "third_party/skia/include/core/SkRRect.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
-#include "third_party/skia/include/core/SkUnPreMultiply.h"
 #include "third_party/skia/include/effects/SkGradientShader.h"
 #include "third_party/skia/include/effects/SkLumaColorFilter.h"
 #include "third_party/skia/include/effects/SkPictureImageFilter.h"
diff --git a/third_party/crashpad/README.chromium b/third_party/crashpad/README.chromium
index e9d05e1e..a69e595 100644
--- a/third_party/crashpad/README.chromium
+++ b/third_party/crashpad/README.chromium
@@ -2,7 +2,7 @@
 Short Name: crashpad
 URL: https://crashpad.chromium.org/
 Version: unknown
-Revision: 4a2043ea65e2641ef1a921801c0aaa15ada02fc7
+Revision: 6128f38e28eb53721757d1faa5cbe3db27b61ca4
 License: Apache 2.0
 License File: crashpad/LICENSE
 Security Critical: yes
diff --git a/third_party/crashpad/crashpad/DEPS b/third_party/crashpad/crashpad/DEPS
index 4aa8dd5..a2def66 100644
--- a/third_party/crashpad/crashpad/DEPS
+++ b/third_party/crashpad/crashpad/DEPS
@@ -38,7 +38,7 @@
 
   'crashpad/third_party/mini_chromium/mini_chromium':
       Var('chromium_git') + '/chromium/mini_chromium@' +
-      'f65519e442d23498937251e680a3b113927613b0',
+      '3a2d52d74c9af5277bf6456cc00ae728f89c4898',
   'crashpad/third_party/zlib/zlib':
       Var('chromium_git') + '/chromium/src/third_party/zlib@' +
       '13dc246a58e4b72104d35f9b1809af95221ebda7',
@@ -72,6 +72,19 @@
     ],
   },
   {
+    'name': 'clang_format_linux',
+    'pattern': '.',
+    'action': [
+      'download_from_google_storage',
+      '--platform=^linux2?$',
+      '--no_resume',
+      '--no_auth',
+      '--bucket=chromium-clang-format',
+      '--sha1_file',
+      'buildtools/linux64/clang-format.sha1',
+    ],
+  },
+  {
     'name': 'gn_mac',
     'pattern': '.',
     'action': [
@@ -98,6 +111,19 @@
     ],
   },
   {
+    'name': 'gn_linux',
+    'pattern': '.',
+    'action': [
+      'download_from_google_storage',
+      '--platform=^linux2?$',
+      '--no_resume',
+      '--no_auth',
+      '--bucket=chromium-gn',
+      '--sha1_file',
+      'buildtools/linux64/gn.sha1',
+    ],
+  },
+  {
     'name': 'gyp',
     'pattern': '\.gypi?$',
     'action': ['python', 'crashpad/build/gyp_crashpad.py'],
diff --git a/third_party/crashpad/crashpad/client/crash_report_database_mac.mm b/third_party/crashpad/crashpad/client/crash_report_database_mac.mm
index f9c783e..0d074cb 100644
--- a/third_party/crashpad/crashpad/client/crash_report_database_mac.mm
+++ b/third_party/crashpad/crashpad/client/crash_report_database_mac.mm
@@ -299,9 +299,10 @@
       base_dir_.Append(kWriteDirectory)
           .Append(report->uuid.ToString() + "." + kCrashReportFileExtension);
 
-  report->handle = HANDLE_EINTR(open(report->path.value().c_str(),
-                                     O_CREAT | O_WRONLY | O_EXCL | O_EXLOCK,
-                                     0600));
+  report->handle = HANDLE_EINTR(
+      open(report->path.value().c_str(),
+           O_WRONLY | O_EXLOCK | O_CREAT | O_EXCL | O_NOCTTY | O_CLOEXEC,
+           0600));
   if (report->handle < 0) {
     PLOG(ERROR) << "open " << report->path.value();
     return kFileSystemError;
@@ -612,8 +613,9 @@
 // static
 base::ScopedFD CrashReportDatabaseMac::ObtainReportLock(
     const base::FilePath& path) {
-  int fd = HANDLE_EINTR(open(path.value().c_str(),
-                             O_RDONLY | O_EXLOCK | O_NONBLOCK));
+  int fd = HANDLE_EINTR(
+      open(path.value().c_str(),
+           O_RDONLY | O_NONBLOCK | O_EXLOCK | O_NOCTTY | O_CLOEXEC));
   PLOG_IF(ERROR, fd < 0) << "open lock " << path.value();
   return base::ScopedFD(fd);
 }
diff --git a/third_party/crashpad/crashpad/compat/non_win/dbghelp.h b/third_party/crashpad/crashpad/compat/non_win/dbghelp.h
index 78ec2952..dedd8ad 100644
--- a/third_party/crashpad/crashpad/compat/non_win/dbghelp.h
+++ b/third_party/crashpad/crashpad/compat/non_win/dbghelp.h
@@ -164,7 +164,7 @@
   UnloadedModuleListStream = 14,
 
   //! \brief The stream type for MINIDUMP_MISC_INFO, MINIDUMP_MISC_INFO_2,
-  //!     MINIDUMP_MISC_INFO_3, and MINIDUMP_MISC_INFO_4.
+  //!     MINIDUMP_MISC_INFO_3, MINIDUMP_MISC_INFO_4, and MINIDUMP_MISC_INFO_5.
   //!
   //! More recent versions of this stream are supersets of earlier versions.
   //!
@@ -753,6 +753,33 @@
   uint32_t NumberOfEntries;
 };
 
+//! \brief Information about XSAVE-managed state stored within CPU-specific
+//!     context structures.
+struct __attribute__((packed, aligned(4))) XSTATE_CONFIG_FEATURE_MSC_INFO {
+  //! \brief The size of this structure, in bytes. This value is
+  //!     `sizeof(XSTATE_CONFIG_FEATURE_MSC_INFO)`.
+  uint32_t SizeOfInfo;
+
+  //! \brief The size of a CPU-specific context structure carrying all XSAVE
+  //!     state components described by this structure.
+  //!
+  //! Equivalent to the value returned by `InitializeContext()` in \a
+  //! ContextLength.
+  uint32_t ContextSize;
+
+  //! \brief The XSAVE state-component bitmap, XSAVE_BV.
+  //!
+  //! See Intel Software Developer’s Manual, Volume 1: Basic Architecture
+  //! (253665-060), 13.4.2 “XSAVE Header”.
+  uint64_t EnabledFeatures;
+
+  //! \brief The location of each state component within a CPU-specific context
+  //!     structure.
+  //!
+  //! This array is indexed by bit position numbers used in #EnabledFeatures.
+  XSTATE_FEATURE Features[MAXIMUM_XSTATE_FEATURES];
+};
+
 //! \anchor MINIDUMP_MISCx
 //! \name MINIDUMP_MISC*
 //!
@@ -805,6 +832,10 @@
 //!  - MINIDUMP_MISC_INFO_4::BuildString
 //!  - MINIDUMP_MISC_INFO_4::DbgBldStr
 #define MINIDUMP_MISC4_BUILDSTRING 0x00000100
+
+//! \brief MINIDUMP_MISC_INFO_5::ProcessCookie is valid.
+#define MINIDUMP_MISC5_PROCESS_COOKIE 0x00000200
+
 //! \}
 
 //! \brief Information about the process that the minidump file contains a
@@ -814,6 +845,7 @@
 //! \sa MINIDUMP_MISC_INFO_2
 //! \sa MINIDUMP_MISC_INFO_3
 //! \sa MINIDUMP_MISC_INFO_4
+//! \sa MINIDUMP_MISC_INFO_5
 //! \sa MINIDUMP_MISC_INFO_N
 struct __attribute__((packed, aligned(4))) MINIDUMP_MISC_INFO {
   //! \brief The size of the structure.
@@ -854,6 +886,7 @@
 //! \sa MINIDUMP_MISC_INFO
 //! \sa MINIDUMP_MISC_INFO_3
 //! \sa MINIDUMP_MISC_INFO_4
+//! \sa MINIDUMP_MISC_INFO_5
 //! \sa MINIDUMP_MISC_INFO_N
 struct __attribute__((packed, aligned(4))) MINIDUMP_MISC_INFO_2
     : public MINIDUMP_MISC_INFO {
@@ -885,6 +918,7 @@
 //! \sa MINIDUMP_MISC_INFO
 //! \sa MINIDUMP_MISC_INFO_2
 //! \sa MINIDUMP_MISC_INFO_4
+//! \sa MINIDUMP_MISC_INFO_5
 //! \sa MINIDUMP_MISC_INFO_N
 struct __attribute__((packed, aligned(4))) MINIDUMP_MISC_INFO_3
     : public MINIDUMP_MISC_INFO_2 {
@@ -946,6 +980,7 @@
 //! \sa MINIDUMP_MISC_INFO
 //! \sa MINIDUMP_MISC_INFO_2
 //! \sa MINIDUMP_MISC_INFO_3
+//! \sa MINIDUMP_MISC_INFO_5
 //! \sa MINIDUMP_MISC_INFO_N
 struct __attribute__((packed, aligned(4))) MINIDUMP_MISC_INFO_4
     : public MINIDUMP_MISC_INFO_3 {
@@ -968,8 +1003,31 @@
   base::char16 DbgBldStr[40];
 };
 
+//! \brief Information about the process that the minidump file contains a
+//!     snapshot of, as well as the system that hosted that process.
+//!
+//! This structure variant is used on Windows 10 and later.
+//!
+//! \sa \ref MINIDUMP_MISCx "MINIDUMP_MISC*"
+//! \sa MINIDUMP_MISC_INFO
+//! \sa MINIDUMP_MISC_INFO_2
+//! \sa MINIDUMP_MISC_INFO_3
+//! \sa MINIDUMP_MISC_INFO_4
+//! \sa MINIDUMP_MISC_INFO_N
+struct __attribute__((packed, aligned(4))) MINIDUMP_MISC_INFO_5
+    : public MINIDUMP_MISC_INFO_4 {
+  //! \brief Information about XSAVE-managed state stored within CPU-specific
+  //!     context structures.
+  //!
+  //! This information can be used to locate state components within
+  //! CPU-specific context structures.
+  XSTATE_CONFIG_FEATURE_MSC_INFO XStateData;
+
+  uint32_t ProcessCookie;
+};
+
 //! \brief The latest known version of the MINIDUMP_MISC_INFO structure.
-typedef MINIDUMP_MISC_INFO_4 MINIDUMP_MISC_INFO_N;
+typedef MINIDUMP_MISC_INFO_5 MINIDUMP_MISC_INFO_N;
 
 //! \brief Describes a region of memory.
 struct __attribute__((packed, aligned(4))) MINIDUMP_MEMORY_INFO {
diff --git a/third_party/crashpad/crashpad/compat/non_win/winnt.h b/third_party/crashpad/crashpad/compat/non_win/winnt.h
index 5e46f53..f2ed6ac 100644
--- a/third_party/crashpad/crashpad/compat/non_win/winnt.h
+++ b/third_party/crashpad/crashpad/compat/non_win/winnt.h
@@ -112,6 +112,66 @@
 #define PF_RDTSCP_INSTRUCTION_AVAILABLE 32
 //! \}
 
+//! \anchor PAGE_x
+//! \name PAGE_*
+//!
+//! \brief Memory protection constants for MINIDUMP_MEMORY_INFO::Protect and
+//!     MINIDUMP_MEMORY_INFO::AllocationProtect.
+//! \{
+#define PAGE_NOACCESS 0x1
+#define PAGE_READONLY 0x2
+#define PAGE_READWRITE 0x4
+#define PAGE_WRITECOPY 0x8
+#define PAGE_EXECUTE 0x10
+#define PAGE_EXECUTE_READ 0x20
+#define PAGE_EXECUTE_READWRITE 0x40
+#define PAGE_EXECUTE_WRITECOPY 0x80
+#define PAGE_GUARD 0x100
+#define PAGE_NOCACHE 0x200
+#define PAGE_WRITECOMBINE 0x400
+//! \}
+
+//! \anchor MEM_x
+//! \name MEM_*
+//!
+//! \brief Memory state and type constants for MINIDUMP_MEMORY_INFO::State and
+//!     MINIDUMP_MEMORY_INFO::Type.
+//! \{
+#define MEM_COMMIT 0x1000
+#define MEM_RESERVE 0x2000
+#define MEM_DECOMMIT 0x4000
+#define MEM_RELEASE 0x8000
+#define MEM_FREE 0x10000
+#define MEM_PRIVATE 0x20000
+#define MEM_MAPPED 0x40000
+#define MEM_RESET 0x80000
+//! \}
+
+//! \brief The maximum number of distinct identifiable features that could
+//!     possibly be carried in an XSAVE area.
+//!
+//! This corresponds to the number of bits in the XSAVE state-component bitmap,
+//! XSAVE_BV. See Intel Software Developer’s Manual, Volume 1: Basic
+//! Architecture (253665-060), 13.4.2 “XSAVE Header”.
+#define MAXIMUM_XSTATE_FEATURES (64)
+
+//! \brief The location of a single state component within an XSAVE area.
+struct XSTATE_FEATURE {
+  //! \brief The location of a state component within a CPU-specific context
+  //!     structure.
+  //!
+  //! This is equivalent to the difference (`ptrdiff_t`) between the return
+  //! value of `LocateXStateFeature()` and its \a Context argument.
+  uint32_t Offset;
+
+  //! \brief The size of a state component with a CPU-specific context
+  //!     structure.
+  //!
+  //! This is equivalent to the size returned by `LocateXStateFeature()` in \a
+  //!     Length.
+  uint32_t Size;
+};
+
 //! \anchor IMAGE_DEBUG_MISC_x
 //! \name IMAGE_DEBUG_MISC_*
 //!
@@ -187,39 +247,4 @@
 #define VER_PLATFORM_WIN32_NT 2
 //! \}
 
-//! \anchor PAGE_x
-//! \name PAGE_*
-//!
-//! \brief Memory protection constants for MINIDUMP_MEMORY_INFO::Protect and
-//!     MINIDUMP_MEMORY_INFO::AllocationProtect.
-//! \{
-#define PAGE_NOACCESS 0x1
-#define PAGE_READONLY 0x2
-#define PAGE_READWRITE 0x4
-#define PAGE_WRITECOPY 0x8
-#define PAGE_EXECUTE 0x10
-#define PAGE_EXECUTE_READ 0x20
-#define PAGE_EXECUTE_READWRITE 0x40
-#define PAGE_EXECUTE_WRITECOPY 0x80
-#define PAGE_GUARD 0x100
-#define PAGE_NOCACHE 0x200
-#define PAGE_WRITECOMBINE 0x400
-//! \}
-
-//! \anchor MEM_x
-//! \name MEM_*
-//!
-//! \brief Memory state and type constants for MINIDUMP_MEMORY_INFO::State and
-//!     MINIDUMP_MEMORY_INFO::Type.
-//! \{
-#define MEM_COMMIT 0x1000
-#define MEM_RESERVE 0x2000
-#define MEM_DECOMMIT 0x4000
-#define MEM_RELEASE 0x8000
-#define MEM_FREE 0x10000
-#define MEM_PRIVATE 0x20000
-#define MEM_MAPPED 0x40000
-#define MEM_RESET 0x80000
-//! \}
-
 #endif  // CRASHPAD_COMPAT_NON_WIN_WINNT_H_
diff --git a/third_party/crashpad/crashpad/doc/support/crashpad.doxy b/third_party/crashpad/crashpad/doc/support/crashpad.doxy
index 198b717..d9fdc36 100644
--- a/third_party/crashpad/crashpad/doc/support/crashpad.doxy
+++ b/third_party/crashpad/crashpad/doc/support/crashpad.doxy
@@ -1,4 +1,4 @@
-# Doxyfile 1.8.12
+# Doxyfile 1.8.13
 
 # This file describes the settings to be used by the documentation system
 # doxygen (www.doxygen.org) for a project.
@@ -2362,6 +2362,11 @@
 
 PLANTUML_JAR_PATH      =
 
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE      =
+
 # When using plantuml, the specified paths are searched for files specified by
 # the !include statement in a plantuml block.
 
diff --git a/third_party/crashpad/crashpad/handler/handler_main.cc b/third_party/crashpad/crashpad/handler/handler_main.cc
index 5006cf6..16eb114 100644
--- a/third_party/crashpad/crashpad/handler/handler_main.cc
+++ b/third_party/crashpad/crashpad/handler/handler_main.cc
@@ -59,6 +59,7 @@
 #include "util/mach/child_port_handshake.h"
 #include "util/mach/mach_extensions.h"
 #include "util/posix/close_stdio.h"
+#include "util/posix/signals.h"
 #elif defined(OS_WIN)
 #include <windows.h>
 
@@ -145,29 +146,6 @@
 
 #if defined(OS_MACOSX)
 
-void InstallSignalHandler(const std::vector<int>& signals,
-                          void (*handler)(int, siginfo_t*, void*)) {
-  struct sigaction sa = {};
-  sigemptyset(&sa.sa_mask);
-  sa.sa_flags = SA_SIGINFO;
-  sa.sa_sigaction = handler;
-
-  for (int sig : signals) {
-    int rv = sigaction(sig, &sa, nullptr);
-    PCHECK(rv == 0) << "sigaction " << sig;
-  }
-}
-
-void RestoreDefaultSignalHandler(int sig) {
-  struct sigaction sa = {};
-  sigemptyset(&sa.sa_mask);
-  sa.sa_flags = 0;
-  sa.sa_handler = SIG_DFL;
-  int rv = sigaction(sig, &sa, nullptr);
-  DPLOG_IF(ERROR, rv != 0) << "sigaction " << sig;
-  ALLOW_UNUSED_LOCAL(rv);
-}
-
 void HandleCrashSignal(int sig, siginfo_t* siginfo, void* context) {
   MetricsRecordExit(Metrics::LifetimeMilestone::kCrashed);
 
@@ -202,99 +180,19 @@
   }
   Metrics::HandlerCrashed(metrics_code);
 
-  RestoreDefaultSignalHandler(sig);
-
-  // If the signal was received synchronously resulting from a hardware fault,
-  // returning from the signal handler will cause the kernel to re-raise it,
-  // because this handler hasn’t done anything to alleviate the condition that
-  // caused the signal to be raised in the first place. With the default signal
-  // handler in place, it will cause the same behavior to be taken as though
-  // this signal handler had never been installed at all (expected to be a
-  // crash). This is ideal, because the signal is re-raised with the same
-  // properties and from the same context that initially triggered it, providing
-  // the best debugging experience.
-
-  if ((sig != SIGILL && sig != SIGFPE && sig != SIGBUS && sig != SIGSEGV) ||
-      !si_code_valid) {
-    // Signals received other than via hardware faults, such as those raised
-    // asynchronously via kill() and raise(), and those arising via hardware
-    // traps such as int3 (resulting in SIGTRAP but advancing the instruction
-    // pointer), will not reoccur on their own when returning from the signal
-    // handler. Re-raise them.
-    //
-    // Unfortunately, when SIGBUS is received asynchronously via kill(),
-    // siginfo->si_code makes it appear as though it was actually received via a
-    // hardware fault. See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c
-    // sendsig(). An asynchronous SIGBUS will thus cause the handler-crashed
-    // metric to be logged but will not cause the process to terminate. This
-    // isn’t ideal, but asynchronous SIGBUS is an unexpected condition. The
-    // alternative, to re-raise here on any SIGBUS, is a bad idea because it
-    // would lose properties associated with the the original signal, which are
-    // very valuable for debugging and are visible to a Mach exception handler.
-    // Since SIGBUS is normally received synchronously in response to a hardware
-    // fault, don’t sweat the unexpected asynchronous case.
-    //
-    // Because this signal handler executes with the signal blocked, this
-    // raise() cannot immediately deliver the signal. Delivery is deferred until
-    // this signal handler returns and the signal becomes unblocked. The
-    // re-raised signal will appear with the same context as where it was
-    // initially triggered.
-    int rv = raise(sig);
-    DPLOG_IF(ERROR, rv != 0) << "raise";
-    ALLOW_UNUSED_LOCAL(rv);
-  }
+  Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
 }
 
 void HandleTerminateSignal(int sig, siginfo_t* siginfo, void* context) {
   MetricsRecordExit(Metrics::LifetimeMilestone::kTerminated);
-
-  RestoreDefaultSignalHandler(sig);
-
-  // Re-raise the signal. See the explanation in HandleCrashSignal(). Note that
-  // no checks for signals arising from synchronous hardware faults are made
-  // because termination signals never originate in that way.
-  int rv = raise(sig);
-  DPLOG_IF(ERROR, rv != 0) << "raise";
-  ALLOW_UNUSED_LOCAL(rv);
+  Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
 }
 
 void InstallCrashHandler() {
-  // These are the core-generating signals from 10.12.3
-  // xnu-3789.41.3/bsd/sys/signalvar.h sigprop: entries with SA_CORE are in the
-  // set.
-  const int kCrashSignals[] = {SIGQUIT,
-                               SIGILL,
-                               SIGTRAP,
-                               SIGABRT,
-                               SIGEMT,
-                               SIGFPE,
-                               SIGBUS,
-                               SIGSEGV,
-                               SIGSYS};
-  InstallSignalHandler(
-      std::vector<int>(&kCrashSignals[0],
-                       &kCrashSignals[arraysize(kCrashSignals)]),
-      HandleCrashSignal);
+  Signals::InstallCrashHandlers(HandleCrashSignal, 0, nullptr);
 
-  // Not a crash handler, but close enough. These are non-core-generating but
-  // terminating signals from 10.12.3 xnu-3789.41.3/bsd/sys/signalvar.h sigprop:
-  // entries with SA_KILL but not SA_CORE are in the set. SIGKILL is excluded
-  // because it is uncatchable.
-  const int kTerminateSignals[] = {SIGHUP,
-                                   SIGINT,
-                                   SIGPIPE,
-                                   SIGALRM,
-                                   SIGTERM,
-                                   SIGXCPU,
-                                   SIGXFSZ,
-                                   SIGVTALRM,
-                                   SIGPROF,
-                                   SIGUSR1,
-                                   SIGUSR2};
-  InstallSignalHandler(
-      std::vector<int>(&kTerminateSignals[0],
-                       &kTerminateSignals[arraysize(kTerminateSignals)]),
-      HandleTerminateSignal);
+  // Not a crash handler, but close enough.
+  Signals::InstallTerminateHandlers(HandleTerminateSignal, 0, nullptr);
 }
 
 struct ResetSIGTERMTraits {
@@ -617,7 +515,7 @@
   base::AutoReset<ExceptionHandlerServer*> reset_g_exception_handler_server(
       &g_exception_handler_server, &exception_handler_server);
 
-  struct sigaction old_sa;
+  struct sigaction old_sigterm_action;
   ScopedResetSIGTERM reset_sigterm;
   if (!options.mach_service.empty()) {
     // When running from launchd, no no-senders notification could ever be
@@ -627,13 +525,10 @@
     //
     // Set up a SIGTERM handler that will call exception_handler_server.Stop().
     // This replaces the HandleTerminateSignal handler for SIGTERM.
-    struct sigaction sa = {};
-    sigemptyset(&sa.sa_mask);
-    sa.sa_flags = SA_SIGINFO;
-    sa.sa_sigaction = HandleSIGTERM;
-    int rv = sigaction(SIGTERM, &sa, &old_sa);
-    PCHECK(rv == 0) << "sigaction";
-    reset_sigterm.reset(&old_sa);
+    if (Signals::InstallHandler(
+            SIGTERM, HandleSIGTERM, 0, &old_sigterm_action)) {
+      reset_sigterm.reset(&old_sigterm_action);
+    }
   }
 #elif defined(OS_WIN)
   // Shut down as late as possible relative to programs we're watching.
@@ -695,9 +590,6 @@
   upload_thread.Stop();
   prune_thread.Stop();
 
-  if (histogram_allocator)
-    histogram_allocator->DeletePersistentLocation();
-
   return EXIT_SUCCESS;
 }
 
diff --git a/third_party/crashpad/crashpad/infra/config/cq.cfg b/third_party/crashpad/crashpad/infra/config/cq.cfg
new file mode 100644
index 0000000..74aa1620
--- /dev/null
+++ b/third_party/crashpad/crashpad/infra/config/cq.cfg
@@ -0,0 +1,46 @@
+# Copyright 2017 The Crashpad Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# See https://luci-config.appspot.com/schemas/projects/refs:cq.cfg for the
+# documentation of this file format.
+
+version: 1
+cq_name: "crashpad"
+cq_status_url: "https://chromium-cq-status.appspot.com"
+
+# This is required for gerrit projects.
+git_repo_url: "https://chromium.googlesource.com/crashpad/crashpad"
+
+# Crashpad uses gerrit with no special options.
+gerrit {}
+
+verifiers {
+  gerrit_cq_ability {
+    committer_list: "project-crashpad-committers"
+    dry_run_access_list: "project-crashpad-committers"
+  }
+  try_job {
+    buckets {
+      name: "master.client.crashpad"
+      builders { name: "crashpad_try_mac_dbg" }
+      builders { name: "crashpad_try_mac_rel" }
+      builders { name: "crashpad_try_win_x64_dbg" }
+      builders { name: "crashpad_try_win_x64_rel" }
+      builders { name: "crashpad_try_win_x86_dbg" }
+      builders { name: "crashpad_try_win_x86_rel" }
+      builders { name: "crashpad_try_win_x86_wow64_dbg" }
+      builders { name: "crashpad_try_win_x86_wow64_rel" }
+    }
+  }
+}
diff --git a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
index ff4fdda..2ea8fa9 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.cc
@@ -145,7 +145,7 @@
 }  // namespace internal
 
 MinidumpMiscInfoWriter::MinidumpMiscInfoWriter()
-    : MinidumpStreamWriter(), misc_info_() {
+    : MinidumpStreamWriter(), misc_info_(), has_xstate_data_(false) {
 }
 
 MinidumpMiscInfoWriter::~MinidumpMiscInfoWriter() {
@@ -330,6 +330,21 @@
       debug_build_string);
 }
 
+void MinidumpMiscInfoWriter::SetXStateData(
+    const XSTATE_CONFIG_FEATURE_MSC_INFO& xstate_data) {
+  DCHECK_EQ(state(), kStateMutable);
+
+  misc_info_.XStateData = xstate_data;
+  has_xstate_data_ = true;
+}
+
+void MinidumpMiscInfoWriter::SetProcessCookie(uint32_t process_cookie) {
+  DCHECK_EQ(state(), kStateMutable);
+
+  misc_info_.ProcessCookie = process_cookie;
+  misc_info_.Flags1 |= MINIDUMP_MISC5_PROCESS_COOKIE;
+}
+
 bool MinidumpMiscInfoWriter::Freeze() {
   DCHECK_EQ(state(), kStateMutable);
 
@@ -365,6 +380,9 @@
 size_t MinidumpMiscInfoWriter::CalculateSizeOfObjectFromFlags() const {
   DCHECK_GE(state(), kStateFrozen);
 
+  if (has_xstate_data_ || (misc_info_.Flags1 & MINIDUMP_MISC5_PROCESS_COOKIE)) {
+    return sizeof(MINIDUMP_MISC_INFO_5);
+  }
   if (misc_info_.Flags1 & MINIDUMP_MISC4_BUILDSTRING) {
     return sizeof(MINIDUMP_MISC_INFO_4);
   }
diff --git a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.h b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.h
index a558fc3..ee90b0e 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.h
+++ b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer.h
@@ -51,10 +51,10 @@
 //!     minidump file.
 //!
 //! The actual stream written will be a MINIDUMP_MISC_INFO,
-//! MINIDUMP_MISC_INFO_2, MINIDUMP_MISC_INFO_3, or MINIDUMP_MISC_INFO_4 stream.
-//! Later versions of MINIDUMP_MISC_INFO are supersets of earlier versions. The
-//! earliest version that supports all of the information that an object of this
-//! class contains will be used.
+//! MINIDUMP_MISC_INFO_2, MINIDUMP_MISC_INFO_3, MINIDUMP_MISC_INFO_4, or
+//! MINIDUMP_MISC_INFO_5 stream. Later versions of MINIDUMP_MISC_INFO are
+//! supersets of earlier versions. The earliest version that supports all of the
+//! information that an object of this class contains will be used.
 class MinidumpMiscInfoWriter final : public internal::MinidumpStreamWriter {
  public:
   MinidumpMiscInfoWriter();
@@ -107,6 +107,15 @@
   void SetBuildString(const std::string& build_string,
                       const std::string& debug_build_string);
 
+  // TODO(mark): Provide a better interface than this. Don’t force callers to
+  // build their own XSTATE_CONFIG_FEATURE_MSC_INFO structure.
+  //
+  //! \brief Sets MINIDUMP_MISC_INFO_5::XStateData.
+  void SetXStateData(const XSTATE_CONFIG_FEATURE_MSC_INFO& xstate_data);
+
+  //! \brief Sets the field referenced by #MINIDUMP_MISC5_PROCESS_COOKIE.
+  void SetProcessCookie(uint32_t process_cookie);
+
  protected:
   // MinidumpWritable:
   bool Freeze() override;
@@ -123,6 +132,7 @@
   size_t CalculateSizeOfObjectFromFlags() const;
 
   MINIDUMP_MISC_INFO_N misc_info_;
+  bool has_xstate_data_;
 
   DISALLOW_COPY_AND_ASSIGN(MinidumpMiscInfoWriter);
 };
diff --git a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer_test.cc b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer_test.cc
index a184e2ad..9a0c7654 100644
--- a/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer_test.cc
+++ b/third_party/crashpad/crashpad/minidump/minidump_misc_info_writer_test.cc
@@ -21,9 +21,11 @@
 #include <utility>
 
 #include "base/compiler_specific.h"
+#include "base/format_macros.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "gtest/gtest.h"
 #include "minidump/minidump_file_writer.h"
@@ -164,6 +166,29 @@
   }
 }
 
+template <>
+void ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_5>(
+    const MINIDUMP_MISC_INFO_5* expected,
+    const MINIDUMP_MISC_INFO_5* observed) {
+  ExpectMiscInfoEqual<MINIDUMP_MISC_INFO_4>(
+      reinterpret_cast<const MINIDUMP_MISC_INFO_4*>(expected),
+      reinterpret_cast<const MINIDUMP_MISC_INFO_4*>(observed));
+  EXPECT_EQ(expected->XStateData.SizeOfInfo, observed->XStateData.SizeOfInfo);
+  EXPECT_EQ(expected->XStateData.ContextSize, observed->XStateData.ContextSize);
+  EXPECT_EQ(expected->XStateData.EnabledFeatures,
+            observed->XStateData.EnabledFeatures);
+  for (size_t feature_index = 0;
+       feature_index < arraysize(observed->XStateData.Features);
+       ++feature_index) {
+    SCOPED_TRACE(base::StringPrintf("feature_index %" PRIuS, feature_index));
+    EXPECT_EQ(expected->XStateData.Features[feature_index].Offset,
+              observed->XStateData.Features[feature_index].Offset);
+    EXPECT_EQ(expected->XStateData.Features[feature_index].Size,
+              observed->XStateData.Features[feature_index].Size);
+  }
+  EXPECT_EQ(expected->ProcessCookie, observed->ProcessCookie);
+}
+
 TEST(MinidumpMiscInfoWriter, Empty) {
   MinidumpFileWriter minidump_file_writer;
   auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
@@ -490,7 +515,7 @@
   MinidumpFileWriter minidump_file_writer;
   auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
 
-  MINIDUMP_MISC_INFO_4 tmp;
+  MINIDUMP_MISC_INFO_N tmp;
   ALLOW_UNUSED_LOCAL(tmp);
   std::string build_string(arraysize(tmp.BuildString) + 1, 'B');
   std::string debug_build_string(arraysize(tmp.DbgBldStr), 'D');
@@ -520,6 +545,63 @@
   ExpectMiscInfoEqual(&expected, observed);
 }
 
+TEST(MinidumpMiscInfoWriter, XStateData) {
+  MinidumpFileWriter minidump_file_writer;
+  auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
+
+  const XSTATE_CONFIG_FEATURE_MSC_INFO kXStateData = {
+      sizeof(XSTATE_CONFIG_FEATURE_MSC_INFO),
+      1024,
+      0x000000000000005f,
+      {
+          {0, 512},
+          {512, 256},
+          {768, 128},
+          {896, 64},
+          {960, 32},
+          {0, 0},
+          {992, 32},
+      }};
+
+  misc_info_writer->SetXStateData(kXStateData);
+
+  minidump_file_writer.AddStream(std::move(misc_info_writer));
+
+  StringFile string_file;
+  ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
+
+  const MINIDUMP_MISC_INFO_5* observed = nullptr;
+  ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed));
+
+  MINIDUMP_MISC_INFO_5 expected = {};
+  expected.XStateData = kXStateData;
+
+  ExpectMiscInfoEqual(&expected, observed);
+}
+
+TEST(MinidumpMiscInfoWriter, ProcessCookie) {
+  MinidumpFileWriter minidump_file_writer;
+  auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
+
+  const uint32_t kProcessCookie = 0x12345678;
+
+  misc_info_writer->SetProcessCookie(kProcessCookie);
+
+  minidump_file_writer.AddStream(std::move(misc_info_writer));
+
+  StringFile string_file;
+  ASSERT_TRUE(minidump_file_writer.WriteEverything(&string_file));
+
+  const MINIDUMP_MISC_INFO_5* observed = nullptr;
+  ASSERT_NO_FATAL_FAILURE(GetMiscInfoStream(string_file.string(), &observed));
+
+  MINIDUMP_MISC_INFO_5 expected = {};
+  expected.Flags1 = MINIDUMP_MISC5_PROCESS_COOKIE;
+  expected.ProcessCookie = kProcessCookie;
+
+  ExpectMiscInfoEqual(&expected, observed);
+}
+
 TEST(MinidumpMiscInfoWriter, Everything) {
   MinidumpFileWriter minidump_file_writer;
   auto misc_info_writer = base::WrapUnique(new MinidumpMiscInfoWriter());
diff --git a/third_party/crashpad/crashpad/package.h b/third_party/crashpad/crashpad/package.h
index 79f188e..ddf98c14 100644
--- a/third_party/crashpad/crashpad/package.h
+++ b/third_party/crashpad/crashpad/package.h
@@ -19,7 +19,7 @@
 #define PACKAGE_COPYRIGHT \
   "Copyright " PACKAGE_COPYRIGHT_YEAR " " PACKAGE_COPYRIGHT_OWNER
 #define PACKAGE_COPYRIGHT_OWNER "The Crashpad Authors"
-#define PACKAGE_COPYRIGHT_YEAR "2016"
+#define PACKAGE_COPYRIGHT_YEAR "2017"
 #define PACKAGE_NAME "Crashpad"
 #define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION
 #define PACKAGE_TARNAME "crashpad"
diff --git a/third_party/crashpad/crashpad/snapshot/snapshot.gyp b/third_party/crashpad/crashpad/snapshot/snapshot.gyp
index 5020073..667ca2c 100644
--- a/third_party/crashpad/crashpad/snapshot/snapshot.gyp
+++ b/third_party/crashpad/crashpad/snapshot/snapshot.gyp
@@ -127,7 +127,6 @@
           'link_settings': {
             'libraries': [
               '-lpowrprof.lib',
-              '-lversion.lib',
             ],
           },
         }],
diff --git a/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win.cc b/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win.cc
index 28d692bd..a8f6fcb 100644
--- a/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win.cc
+++ b/third_party/crashpad/crashpad/snapshot/win/system_snapshot_win.cc
@@ -106,17 +106,17 @@
     os_version_major_ = ffi.dwFileVersionMS >> 16;
     os_version_minor_ = ffi.dwFileVersionMS & 0xffff;
     os_version_bugfix_ = ffi.dwFileVersionLS >> 16;
-    os_version_build_ =
-        base::StringPrintf("%d", ffi.dwFileVersionLS & 0xffff);
+    os_version_build_ = base::StringPrintf("%u", ffi.dwFileVersionLS & 0xffff);
     os_version_full_ = base::StringPrintf(
-        "%s %d.%d.%d.%s%s",
+        "%s %u.%u.%u.%s%s",
         os_name.c_str(),
         os_version_major_,
         os_version_minor_,
         os_version_bugfix_,
         os_version_build_.c_str(),
-        flags_string.empty() ? "" : (std::string(" (") + flags_string + ")")
-                                        .c_str());
+        flags_string.empty()
+            ? ""
+            : (std::string(" (") + flags_string + ")").c_str());
   }
 
   INITIALIZATION_STATE_SET_VALID(initialized_);
diff --git a/third_party/crashpad/crashpad/tools/mac/catch_exception_tool.cc b/third_party/crashpad/crashpad/tools/mac/catch_exception_tool.cc
index afd738a..3a535cb 100644
--- a/third_party/crashpad/crashpad/tools/mac/catch_exception_tool.cc
+++ b/third_party/crashpad/crashpad/tools/mac/catch_exception_tool.cc
@@ -12,6 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <fcntl.h>
 #include <getopt.h>
 #include <libgen.h>
 #include <stdio.h>
@@ -279,6 +280,10 @@
       return EXIT_FAILURE;
     }
     options.file = file_owner.get();
+    if (fcntl(fileno(options.file), F_SETFD, FD_CLOEXEC) == -1) {
+      PLOG(ERROR) << "fcntl " << options.file_path;
+      return EXIT_FAILURE;
+    }
   }
 
   int exceptions_handled = 0;
diff --git a/third_party/crashpad/crashpad/util/file/file_io_posix.cc b/third_party/crashpad/crashpad/util/file/file_io_posix.cc
index 30eae53..1534db15 100644
--- a/third_party/crashpad/crashpad/util/file/file_io_posix.cc
+++ b/third_party/crashpad/crashpad/util/file/file_io_posix.cc
@@ -80,10 +80,11 @@
                              const base::FilePath& path,
                              FileWriteMode mode,
                              FilePermissions permissions) {
+  int flags = O_NOCTTY | O_CLOEXEC;
+
   DCHECK(rdwr_or_wronly & (O_RDWR | O_WRONLY));
   DCHECK_EQ(rdwr_or_wronly & ~(O_RDWR | O_WRONLY), 0);
-
-  int flags = rdwr_or_wronly;
+  flags |= rdwr_or_wronly;
 
   switch (mode) {
     case FileWriteMode::kReuseOrFail:
@@ -118,7 +119,8 @@
 }
 
 FileHandle OpenFileForRead(const base::FilePath& path) {
-  return HANDLE_EINTR(open(path.value().c_str(), O_RDONLY));
+  return HANDLE_EINTR(
+      open(path.value().c_str(), O_RDONLY | O_NOCTTY | O_CLOEXEC));
 }
 
 FileHandle OpenFileForWrite(const base::FilePath& path,
diff --git a/third_party/crashpad/crashpad/util/mac/xattr_test.cc b/third_party/crashpad/crashpad/util/mac/xattr_test.cc
index daaba30..c27ab4c 100644
--- a/third_party/crashpad/crashpad/util/mac/xattr_test.cc
+++ b/third_party/crashpad/crashpad/util/mac/xattr_test.cc
@@ -37,8 +37,10 @@
 
   void SetUp() override {
     path_ = temp_dir_.path().Append("xattr_file");
-    base::ScopedFD tmp(HANDLE_EINTR(
-          open(path_.value().c_str(), O_CREAT | O_TRUNC, 0644)));
+    base::ScopedFD tmp(
+        HANDLE_EINTR(open(path_.value().c_str(),
+                          O_WRONLY | O_CREAT | O_TRUNC | O_NOCTTY | O_CLOEXEC,
+                          0644)));
     EXPECT_GE(tmp.get(), 0) << ErrnoMessage("open");
   }
 
diff --git a/third_party/crashpad/crashpad/util/net/http_transport_mac.mm b/third_party/crashpad/crashpad/util/net/http_transport_mac.mm
index edabe9c6..5b4f18c 100644
--- a/third_party/crashpad/crashpad/util/net/http_transport_mac.mm
+++ b/third_party/crashpad/crashpad/util/net/http_transport_mac.mm
@@ -16,11 +16,14 @@
 
 #include <CoreFoundation/CoreFoundation.h>
 #import <Foundation/Foundation.h>
+#include <sys/utsname.h>
 
 #include "base/mac/foundation_util.h"
 #import "base/mac/scoped_nsobject.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
+#include "build/build_config.h"
+#include "package.h"
 #include "third_party/apple_cf/CFStreamAbstract.h"
 #include "util/file/file_io.h"
 #include "util/misc/implicit_cast.h"
@@ -30,6 +33,80 @@
 
 namespace {
 
+NSString* AppendEscapedFormat(NSString* base,
+                              NSString* format,
+                              NSString* data) {
+  return [base stringByAppendingFormat:
+                   format,
+                   [data stringByAddingPercentEncodingWithAllowedCharacters:
+                             [[NSCharacterSet
+                                 characterSetWithCharactersInString:
+                                     @"()<>@,;:\\\"/[]?={} \t"] invertedSet]]];
+}
+
+// This builds the same User-Agent string that CFNetwork would build internally,
+// but it uses PACKAGE_NAME and PACKAGE_VERSION in place of values obtained from
+// the main bundle’s Info.plist.
+NSString* UserAgentString() {
+  NSString* user_agent = [NSString string];
+
+  // CFNetwork would use the main bundle’s CFBundleName, or the main
+  // executable’s filename if none.
+  user_agent = AppendEscapedFormat(
+      user_agent, @"%@", [NSString stringWithUTF8String:PACKAGE_NAME]);
+
+  // CFNetwork would use the main bundle’s CFBundleVersion, or the string
+  // “(unknown version)” if none.
+  user_agent = AppendEscapedFormat(
+      user_agent, @"/%@", [NSString stringWithUTF8String:PACKAGE_VERSION]);
+
+  // Expected to be CFNetwork.
+  NSBundle* nsurl_bundle = [NSBundle bundleForClass:[NSURLRequest class]];
+  NSString* bundle_name = base::mac::ObjCCast<NSString>([nsurl_bundle
+      objectForInfoDictionaryKey:base::mac::CFToNSCast(kCFBundleNameKey)]);
+  if (bundle_name) {
+    user_agent = AppendEscapedFormat(user_agent, @" %@", bundle_name);
+
+    NSString* bundle_version = base::mac::ObjCCast<NSString>([nsurl_bundle
+        objectForInfoDictionaryKey:base::mac::CFToNSCast(kCFBundleVersionKey)]);
+    if (bundle_version) {
+      user_agent = AppendEscapedFormat(user_agent, @"/%@", bundle_version);
+    }
+  }
+
+  utsname os;
+  if (uname(&os) != 0) {
+    PLOG(WARNING) << "uname";
+  } else {
+    user_agent = AppendEscapedFormat(
+        user_agent, @" %@", [NSString stringWithUTF8String:os.sysname]);
+    user_agent = AppendEscapedFormat(
+        user_agent, @"/%@", [NSString stringWithUTF8String:os.release]);
+
+    // CFNetwork just uses the equivalent of os.machine to obtain the native
+    // (kernel) architecture. Here, give the process’ architecture as well as
+    // the native architecture. Use the same strings that the kernel would, so
+    // that they can be de-duplicated.
+#if defined(ARCH_CPU_X86)
+    NSString* arch = @"i386";
+#elif defined(ARCH_CPU_X86_64)
+    NSString* arch = @"x86_64";
+#else
+#error Port
+#endif
+    user_agent = AppendEscapedFormat(user_agent, @" (%@", arch);
+
+    NSString* machine = [NSString stringWithUTF8String:os.machine];
+    if (![machine isEqualToString:arch]) {
+      user_agent = AppendEscapedFormat(user_agent, @"; %@", machine);
+    }
+
+    user_agent = [user_agent stringByAppendingString:@")"];
+  }
+
+  return user_agent;
+}
+
 // An implementation of CFReadStream. This implements the V0 callback
 // scheme.
 class HTTPBodyStreamCFReadStream {
@@ -171,6 +248,13 @@
                             timeoutInterval:timeout()];
     [request setHTTPMethod:base::SysUTF8ToNSString(method())];
 
+    // If left to its own devices, CFNetwork would build a user-agent string
+    // based on keys in the main bundle’s Info.plist, giving ugly results if
+    // there is no Info.plist. Provide a User-Agent string similar to the one
+    // that CFNetwork would use, but with appropriate values in place of the
+    // Info.plist-derived strings.
+    [request setValue:UserAgentString() forHTTPHeaderField:@"User-Agent"];
+
     for (const auto& pair : headers()) {
       [request setValue:base::SysUTF8ToNSString(pair.second)
           forHTTPHeaderField:base::SysUTF8ToNSString(pair.first)];
diff --git a/third_party/crashpad/crashpad/util/net/http_transport_win.cc b/third_party/crashpad/crashpad/util/net/http_transport_win.cc
index 294048a..56fdaad1 100644
--- a/third_party/crashpad/crashpad/util/net/http_transport_win.cc
+++ b/third_party/crashpad/crashpad/util/net/http_transport_win.cc
@@ -28,15 +28,59 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "package.h"
 #include "util/file/file_io.h"
 #include "util/numeric/safe_assignment.h"
 #include "util/net/http_body.h"
+#include "util/win/module_version.h"
 
 namespace crashpad {
 
 namespace {
 
+const wchar_t kWinHttpDll[] = L"winhttp.dll";
+
+std::string UserAgent() {
+  std::string user_agent =
+      base::StringPrintf("%s/%s WinHTTP", PACKAGE_NAME, PACKAGE_VERSION);
+
+  VS_FIXEDFILEINFO version;
+  if (GetModuleVersionAndType(base::FilePath(kWinHttpDll), &version)) {
+    user_agent.append(base::StringPrintf("/%u.%u.%u.%u",
+                                         version.dwFileVersionMS >> 16,
+                                         version.dwFileVersionMS & 0xffff,
+                                         version.dwFileVersionLS >> 16,
+                                         version.dwFileVersionLS & 0xffff));
+  }
+
+  if (GetModuleVersionAndType(base::FilePath(L"kernel32.dll"), &version) &&
+      (version.dwFileOS & VOS_NT_WINDOWS32) == VOS_NT_WINDOWS32) {
+    user_agent.append(base::StringPrintf(" Windows_NT/%u.%u.%u.%u (",
+                                         version.dwFileVersionMS >> 16,
+                                         version.dwFileVersionMS & 0xffff,
+                                         version.dwFileVersionLS >> 16,
+                                         version.dwFileVersionLS & 0xffff));
+#if defined(ARCH_CPU_X86)
+    user_agent.append("x86");
+#elif defined(ARCH_CPU_X86_64)
+    user_agent.append("x64");
+#else
+#error Port
+#endif
+
+    BOOL is_wow64;
+    if (!IsWow64Process(GetCurrentProcess(), &is_wow64)) {
+      PLOG(WARNING) << "IsWow64Process";
+    } else if (is_wow64) {
+      user_agent.append("; WoW64");
+    }
+    user_agent.append(1, ')');
+  }
+
+  return user_agent;
+}
+
 // PLOG doesn't work for messages from WinHTTP, so we need to use
 // FORMAT_MESSAGE_FROM_HMODULE + the dll name manually here.
 std::string WinHttpMessage(const char* extra) {
@@ -45,7 +89,7 @@
   DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
                 FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_FROM_HMODULE;
   DWORD len = FormatMessageA(flags,
-                             GetModuleHandle(L"winhttp.dll"),
+                             GetModuleHandle(kWinHttpDll),
                              error_code,
                              0,
                              msgbuf,
@@ -93,12 +137,11 @@
 }
 
 bool HTTPTransportWin::ExecuteSynchronously(std::string* response_body) {
-  ScopedHINTERNET session(
-      WinHttpOpen(base::UTF8ToUTF16(PACKAGE_NAME "/" PACKAGE_VERSION).c_str(),
-                  WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
-                  WINHTTP_NO_PROXY_NAME,
-                  WINHTTP_NO_PROXY_BYPASS,
-                  0));
+  ScopedHINTERNET session(WinHttpOpen(base::UTF8ToUTF16(UserAgent()).c_str(),
+                                      WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
+                                      WINHTTP_NO_PROXY_NAME,
+                                      WINHTTP_NO_PROXY_BYPASS,
+                                      0));
   if (!session.get()) {
     LOG(ERROR) << WinHttpMessage("WinHttpOpen");
     return false;
@@ -136,6 +179,16 @@
   std::wstring extra_info(url_components.lpszExtraInfo,
                           url_components.dwExtraInfoLength);
 
+  // Use url_path, and get the query parameter from extra_info, up to the first
+  // #, if any. See RFC 7230 §5.3.1 and RFC 3986 §3.4. Beware that when this is
+  // used to POST data, the query parameters generally belong in the request
+  // body and not in the URL request target. It’s legal for them to be in both
+  // places, but the interpretation is subject to whatever the client and server
+  // agree on. This honors whatever was passed in, matching other platforms, but
+  // you’ve been warned!
+  std::wstring request_target(
+      url_path.append(extra_info.substr(0, extra_info.find(L'#'))));
+
   ScopedHINTERNET connect(WinHttpConnect(
       session.get(), host_name.c_str(), url_components.nPort, 0));
   if (!connect.get()) {
@@ -146,7 +199,7 @@
   ScopedHINTERNET request(WinHttpOpenRequest(
       connect.get(),
       base::UTF8ToUTF16(method()).c_str(),
-      url_path.c_str(),
+      request_target.c_str(),
       nullptr,
       WINHTTP_NO_REFERER,
       WINHTTP_DEFAULT_ACCEPT_TYPES,
diff --git a/third_party/crashpad/crashpad/util/posix/close_multiple.cc b/third_party/crashpad/crashpad/util/posix/close_multiple.cc
index f1d7773..172a8f0 100644
--- a/third_party/crashpad/crashpad/util/posix/close_multiple.cc
+++ b/third_party/crashpad/crashpad/util/posix/close_multiple.cc
@@ -211,7 +211,7 @@
   // do_prlimit() and kernel/sysctl.c fs_table. Inability to open this file is
   // not considered an error, because /proc may not be available or usable.
   {
-    base::ScopedFILE nr_open_file(fopen("/proc/sys/fs/nr_open", "r"));
+    base::ScopedFILE nr_open_file(fopen("/proc/sys/fs/nr_open", "re"));
     if (nr_open_file.get() != nullptr) {
       int nr_open;
       if (fscanf(nr_open_file.get(), "%d\n", &nr_open) == 1 &&
diff --git a/third_party/crashpad/crashpad/util/posix/close_stdio.cc b/third_party/crashpad/crashpad/util/posix/close_stdio.cc
index d589294..cc9cdac 100644
--- a/third_party/crashpad/crashpad/util/posix/close_stdio.cc
+++ b/third_party/crashpad/crashpad/util/posix/close_stdio.cc
@@ -27,7 +27,8 @@
 namespace {
 
 void CloseStdioStream(int desired_fd, int oflag) {
-  base::ScopedFD fd(HANDLE_EINTR(open(_PATH_DEVNULL, oflag)));
+  base::ScopedFD fd(
+      HANDLE_EINTR(open(_PATH_DEVNULL, oflag | O_NOCTTY | O_CLOEXEC)));
   if (fd == desired_fd) {
     // Weird, but play along.
     ignore_result(fd.release());
diff --git a/third_party/crashpad/crashpad/util/posix/process_info_test.cc b/third_party/crashpad/crashpad/util/posix/process_info_test.cc
index 7e28e5f4c..c07b1ef7 100644
--- a/third_party/crashpad/crashpad/util/posix/process_info_test.cc
+++ b/third_party/crashpad/crashpad/util/posix/process_info_test.cc
@@ -103,7 +103,7 @@
 #elif defined(OS_LINUX) || defined(OS_ANDROID)
   std::vector<std::string> expect_arg_vector;
   {
-    base::ScopedFILE cmdline(fopen("/proc/self/cmdline", "r"));
+    base::ScopedFILE cmdline(fopen("/proc/self/cmdline", "re"));
     ASSERT_NE(nullptr, cmdline.get()) << ErrnoMessage("fopen");
 
     int expect_arg_char;
diff --git a/third_party/crashpad/crashpad/util/posix/signals.cc b/third_party/crashpad/crashpad/util/posix/signals.cc
new file mode 100644
index 0000000..a19fbafb
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/posix/signals.cc
@@ -0,0 +1,281 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/posix/signals.h"
+
+#include <unistd.h>
+
+#include <vector>
+
+#include "base/logging.h"
+
+namespace crashpad {
+
+namespace {
+
+// These are the core-generating signals.
+//
+// On macOS, these come from 10.12.3 xnu-3789.41.3/bsd/sys/signalvar.h sigprop:
+// entries with SA_CORE are in the set.
+//
+// For Linux, see linux-4.4.52/kernel/signal.c get_signal() and
+// linux-4.4.52/include/linux/signal.h sig_kernel_coredump(): signals in
+// SIG_KERNEL_COREDUMP_MASK are in the set.
+constexpr int kCrashSignals[] = {
+    SIGABRT,
+    SIGBUS,
+    SIGFPE,
+    SIGILL,
+    SIGQUIT,
+    SIGSEGV,
+    SIGSYS,
+    SIGTRAP,
+#if defined(SIGEMT)
+    SIGEMT,
+#endif  // defined(SIGEMT)
+#if defined(OS_LINUX)
+    SIGXCPU,
+    SIGXFSZ,
+#endif  // defined(OS_LINUX)
+};
+
+// These are the non-core-generating but terminating signals.
+//
+// On macOS, these come from 10.12.3 xnu-3789.41.3/bsd/sys/signalvar.h sigprop:
+// entries with SA_KILL but not SA_CORE are in the set. SIGKILL is excluded
+// because it is uncatchable.
+//
+// For Linux, see linux-4.4.52/kernel/signal.c get_signal() and
+// linux-4.4.52/include/linux/signal.h sig_kernel_coredump(),
+// sig_kernel_ignore(), and sig_kernel_stop(): signals not in
+// SIG_KERNEL_COREDUMP_MASK, SIG_KERNEL_IGNORE_MASK, or SIG_KERNEL_STOP_MASK are
+// in the set. SIGKILL is excluded because it is uncatchable (it’s in
+// SIG_KERNEL_ONLY_MASK and qualifies for sig_kernel_only()). Real-time signals
+// in the range [SIGRTMIN, SIGRTMAX) also have termination as the default
+// action, although they are not listed here.
+constexpr int kTerminateSignals[] = {
+    SIGALRM,
+    SIGHUP,
+    SIGINT,
+    SIGPIPE,
+    SIGPROF,
+    SIGTERM,
+    SIGUSR1,
+    SIGUSR2,
+    SIGVTALRM,
+#if defined(SIGPWR)
+    SIGPWR,
+#endif  // defined(SIGPWR)
+#if defined(SIGSTKFLT)
+    SIGSTKFLT,
+#endif  // defined(SIGSTKFLT)
+#if defined(OS_MACOSX)
+    SIGXCPU,
+    SIGXFSZ,
+#endif  // defined(OS_MACOSX)
+#if defined(OS_LINUX)
+    SIGIO,
+#endif  // defined(OS_LINUX)
+};
+
+bool InstallHandlers(const std::vector<int>& signals,
+                     Signals::Handler handler,
+                     int flags,
+                     Signals::OldActions* old_actions) {
+  bool success = true;
+  for (int sig : signals) {
+    success &= Signals::InstallHandler(
+        sig,
+        handler,
+        flags,
+        old_actions ? old_actions->ActionForSignal(sig) : nullptr);
+  }
+  return success;
+}
+
+bool IsSignalInSet(int sig, const int* set, size_t set_size) {
+  for (size_t index = 0; index < set_size; ++index) {
+    if (sig == set[index]) {
+      return true;
+    }
+  }
+  return false;
+}
+
+}  // namespace
+
+struct sigaction* Signals::OldActions::ActionForSignal(int sig) {
+  DCHECK_GT(sig, 0);
+  const size_t slot = sig - 1;
+  DCHECK_LT(slot, arraysize(actions_));
+  return &actions_[slot];
+}
+
+// static
+bool Signals::InstallHandler(int sig,
+                             Handler handler,
+                             int flags,
+                             struct sigaction* old_action) {
+  struct sigaction action;
+  sigemptyset(&action.sa_mask);
+  action.sa_flags = flags | SA_SIGINFO;
+  action.sa_sigaction = handler;
+  if (sigaction(sig, &action, old_action) != 0) {
+    PLOG(ERROR) << "sigaction " << sig;
+    return false;
+  }
+  return true;
+}
+
+// static
+bool Signals::InstallCrashHandlers(Handler handler,
+                                   int flags,
+                                   OldActions* old_actions) {
+  return InstallHandlers(
+      std::vector<int>(kCrashSignals, kCrashSignals + arraysize(kCrashSignals)),
+      handler,
+      flags,
+      old_actions);
+}
+
+// static
+bool Signals::InstallTerminateHandlers(Handler handler,
+                                       int flags,
+                                       OldActions* old_actions) {
+  return InstallHandlers(
+      std::vector<int>(kTerminateSignals,
+                       kTerminateSignals + arraysize(kTerminateSignals)),
+      handler,
+      flags,
+      old_actions);
+}
+
+// static
+bool Signals::WillSignalReraiseAutonomously(const siginfo_t* siginfo) {
+  // Signals received other than via hardware faults, such as those raised
+  // asynchronously via kill() and raise(), and those arising via hardware traps
+  // such as int3 on x86 (resulting in SIGTRAP but advancing the instruction
+  // pointer), will not reoccur on their own when returning from the signal
+  // handler.
+  //
+  // Unfortunately, on macOS, when SIGBUS is received asynchronously via kill(),
+  // siginfo->si_code makes it appear as though it was actually received via a
+  // hardware fault. See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c
+  // sendsig(). Asynchronous SIGBUS will not re-raise itself autonomously, but
+  // this function (acting on information from the kernel) behaves as though it
+  // will. This isn’t ideal, but asynchronous SIGBUS is an unexpected condition.
+  // The alternative, to never treat SIGBUS as autonomously re-raising, is a bad
+  // idea because the explicit re-raise would lose properties associated with
+  // the the original signal, which are valuable for debugging and are visible
+  // to a Mach exception handler. Since SIGBUS is normally received
+  // synchronously in response to a hardware fault, don’t sweat the unexpected
+  // asynchronous case.
+  //
+  // SIGSEGV on macOS originating from a general protection fault is a more
+  // difficult case: si_code is cleared, making the signal appear asynchronous.
+  // See 10.12.3 xnu-3789.41.3/bsd/dev/i386/unix_signal.c sendsig().
+  const int sig = siginfo->si_signo;
+  const int code = siginfo->si_code;
+
+  // Only these signals can be generated from hardware faults and can re-raise
+  // autonomously.
+  return (sig == SIGBUS ||
+          sig == SIGFPE ||
+          sig == SIGILL ||
+          sig == SIGSEGV) &&
+
+         // The signal was only generated from a hardware fault if the code is a
+         // positive number not matching one of these SI_* constants. See
+         // “Signal Actions” under XRAT “Rationale”/B.2.4 “Signal Concepts” in
+         // POSIX.1-2008, 2016 Edition, regarding si_code. The historical
+         // behavior does not use these SI_* constants and signals generated
+         // asynchronously show up with a code of 0. On macOS, the SI_*
+         // constants are defined but never used, and the historical value of 0
+         // remains. See 10.12.3 xnu-3789.41.3/bsd/kern/kern_sig.c
+         // psignal_internal().
+         (code > 0 &&
+          code != SI_ASYNCIO &&
+          code != SI_MESGQ &&
+          code != SI_QUEUE &&
+          code != SI_TIMER &&
+          code != SI_USER &&
+#if defined(SI_DETHREAD)
+          code != SI_DETHREAD &&
+#endif  // defiend(SI_DETHREAD)
+#if defined(SI_KERNEL)
+          // In Linux, SI_KERNEL is used for signals that are raised by the
+          // kernel in software, opposing SI_USER. See
+          // linux-4.4.52/kernel/signal.c __send_signal(). Signals originating
+          // from hardware faults do not use this SI_KERNEL, but a proper signal
+          // code translated in architecture-specific code from the
+          // characteristics of the hardware fault.
+          code != SI_KERNEL &&
+#endif  // defined(SI_KERNEL)
+#if defined(SI_SIGIO)
+          code != SI_SIGIO &&
+#endif  // defined(SI_SIGIO)
+#if defined(SI_TKILL)
+          code != SI_TKILL &&
+#endif  // defined(SI_TKILL)
+          true);
+}
+
+// static
+void Signals::RestoreHandlerAndReraiseSignalOnReturn(
+    const siginfo_t* siginfo,
+    const struct sigaction* old_action) {
+  // Failures in this function should _exit(kFailureExitCode). This is a quick
+  // and quiet failure. This function runs in signal handler context, and it’s
+  // difficult to safely be loud from a signal handler.
+  const int kFailureExitCode = 191;
+
+  struct sigaction default_action;
+  sigemptyset(&default_action.sa_mask);
+  default_action.sa_flags = 0;
+  default_action.sa_handler = SIG_DFL;
+
+  const struct sigaction* restore_action =
+      old_action ? old_action : &default_action;
+
+  // Try to restore restore_action. If that fails and restore_action was
+  // old_action, the problem may have been that old_action was bogus, so try to
+  // set the default action.
+  const int sig = siginfo->si_signo;
+  if (sigaction(sig, restore_action, nullptr) != 0 && old_action &&
+      sigaction(sig, &default_action, nullptr) != 0) {
+    _exit(kFailureExitCode);
+  }
+
+  // Explicitly re-raise the signal if it will not re-raise itself. Because
+  // signal handlers normally execute with their signal blocked, this raise()
+  // cannot immediately deliver the signal. Delivery is deferred until the
+  // signal handler returns and the signal becomes unblocked. The re-raised
+  // signal will appear with the same context as where it was initially
+  // triggered.
+  if (!WillSignalReraiseAutonomously(siginfo) && raise(sig) != 0) {
+    _exit(kFailureExitCode);
+  }
+}
+
+// static
+bool Signals::IsCrashSignal(int sig) {
+  return IsSignalInSet(sig, kCrashSignals, arraysize(kCrashSignals));
+}
+
+// static
+bool Signals::IsTerminateSignal(int sig) {
+  return IsSignalInSet(sig, kTerminateSignals, arraysize(kTerminateSignals));
+}
+
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/posix/signals.h b/third_party/crashpad/crashpad/util/posix/signals.h
new file mode 100644
index 0000000..36d33cd
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/posix/signals.h
@@ -0,0 +1,228 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef CRASHPAD_UTIL_POSIX_SIGNALS_H_
+#define CRASHPAD_UTIL_POSIX_SIGNALS_H_
+
+#include <signal.h>
+
+#include "base/macros.h"
+
+namespace crashpad {
+
+//! \brief Utilities for handling POSIX signals.
+class Signals {
+ public:
+  //! \brief The type used for `struct sigaction::sa_sigaction`.
+  using Handler = void (*)(int, siginfo_t*, void*);
+
+  //! \brief A group of `struct sigaction` structures corresponding to a set
+  //!     of signals’ previous actions, addressable by signal number.
+  //!
+  //! This type is used to store previous signal actions when new actions are
+  //! installed in batch by InstallCrashHandlers() or
+  //! InstallTerminateHandlers().
+  //!
+  //! This object is not initialized by any constructor. Its expected initial
+  //! state is to have its contents filled with zeroes. Because signal handlers
+  //! are stateless (there is no “context” parameter), any state must be
+  //! accessed via objects of static storage duration, and it is expected that
+  //! objects of this class will only ever exist with static storage duration,
+  //! which in the absence of a constructor will be zero-initialized as
+  //! expected. In the event that an object of this class must exist with a
+  //! different storage duration, such as automatic or dynamic storage duration,
+  //! it must be explicitly initialized. For example: `OldActions old_actions =
+  //! {};`.
+  class OldActions {
+   public:
+    // DISALLOW_COPY_AND_ASSIGN removes the default constructor, so explicitly
+    // opt for it. This should not result in any static initialization code even
+    // when an object of this class is given static storage duration.
+    OldActions() = default;
+
+    //! \brief Returns a `struct sigaction` structure corresponding to the
+    //!     given signal.
+    //!
+    //! \note This method is safe to call from a signal handler.
+    struct sigaction* ActionForSignal(int sig);
+
+   private:
+    // As a small storage optimization, don’t waste any space on a slot for
+    // signal 0, because there is no signal 0.
+    struct sigaction actions_[NSIG - 1];
+
+    DISALLOW_COPY_AND_ASSIGN(OldActions);
+  };
+
+  //! \brief Installs a new signal handler.
+  //!
+  //! \param[in] sig The signal number to handle.
+  //! \param[in] handler A signal-handling function to execute, used as the
+  //!     `struct sigaction::sa_sigaction` field when calling `sigaction()`.
+  //! \param[in] flags Flags to pass to `sigaction()` in the `struct
+  //!     sigaction::sa_flags` field. `SA_SIGINFO` will be specified implicitly.
+  //! \param[out] old_action The previous action for the signal, replaced by the
+  //!     new action. May be `nullptr` if not needed.
+  //!
+  //! \return `true` on success. `false` on failure with a message logged.
+  //!
+  //! \warning This function may not be called from a signal handler because of
+  //!     its use of logging. See RestoreHandlerAndReraiseSignalOnReturn()
+  //!     instead.
+  static bool InstallHandler(int sig,
+                             Handler handler,
+                             int flags,
+                             struct sigaction* old_action);
+
+  //! \brief Installs a new signal handler for all signals associated with
+  //!     crashes.
+  //!
+  //! Signals associated with crashes are those whose default dispositions
+  //! involve creating a core dump. The precise set of signals involved varies
+  //! between operating systems.
+  //!
+  //! A single signal may either be associated with a crash or with termination
+  //! (see InstallTerminateHandlers()), and perhaps neither, but never both.
+  //!
+  //! \param[in] handler A signal-handling function to execute, used as the
+  //!     `struct sigaction::sa_sigaction` field when calling `sigaction()`.
+  //! \param[in] flags Flags to pass to `sigaction()` in the `struct
+  //!     sigaction::sa_flags` field. `SA_SIGINFO` will be specified implicitly.
+  //! \param[out] old_actions The previous actions for the signals, replaced by
+  //!     the new action. May be `nullptr` if not needed. The same \a
+  //!     old_actions object may be used for calls to both this function and
+  //!     InstallTerminateHandlers().
+  //!
+  //! \return `true` on success. `false` on failure with a message logged.
+  //!
+  //! \warning This function may not be called from a signal handler because of
+  //!     its use of logging. See RestoreHandlerAndReraiseSignalOnReturn()
+  //!     instead.
+  static bool InstallCrashHandlers(Handler handler,
+                                   int flags,
+                                   OldActions* old_actions);
+
+  //! \brief Installs a new signal handler for all signals associated with
+  //!     termination.
+  //!
+  //! Signals associated with termination are those whose default dispositions
+  //! involve terminating the process without creating a core dump. The precise
+  //! set of signals involved varies between operating systems.
+  //!
+  //! A single signal may either be associated with termination or with a
+  //! crash (see InstalCrashHandlers()), and perhaps neither, but never both.
+  //!
+  //! \param[in] handler A signal-handling function to execute, used as the
+  //!     `struct sigaction::sa_sigaction` field when calling `sigaction()`.
+  //! \param[in] flags Flags to pass to `sigaction()` in the `struct
+  //!     sigaction::sa_flags` field. `SA_SIGINFO` will be specified implicitly.
+  //! \param[out] old_actions The previous actions for the signals, replaced by
+  //!     the new action. May be `nullptr` if not needed. The same \a
+  //!     old_actions object may be used for calls to both this function and
+  //!     InstallCrashHandlers().
+  //!
+  //! \return `true` on success. `false` on failure with a message logged.
+  //!
+  //! \warning This function may not be called from a signal handler because of
+  //!     its use of logging. See RestoreHandlerAndReraiseSignalOnReturn()
+  //!     instead.
+  static bool InstallTerminateHandlers(Handler handler,
+                                       int flags,
+                                       OldActions* old_actions);
+
+  //! \brief Determines whether a signal will be re-raised autonomously upon
+  //!     return from a signal handler.
+  //!
+  //! Certain signals, when generated synchronously in response to a hardware
+  //! fault, are unrecoverable. Upon return from the signal handler, the same
+  //! action that triggered the signal to be raised initially will be retried,
+  //! and unless the signal handler took action to mitigate this error, the same
+  //! signal will be re-raised. As an example, a CPU will not be able to read
+  //! unmapped memory (causing `SIGSEGV`), thus the signal will be re-raised
+  //! upon return from the signal handler unless the signal handler established
+  //! a memory mapping where required.
+  //!
+  //! It is important to distinguish between these synchronous signals generated
+  //! in response to a hardware fault and signals generated asynchronously or in
+  //! software. As an example, `SIGSEGV` will not re-raise autonomously if sent
+  //! by `kill()`.
+  //!
+  //! This function distinguishes between signals that can re-raise
+  //! autonomously, and for those that can, between instances of the signal that
+  //! were generated synchronously in response to a hardware fault and instances
+  //! that were generated by other means.
+  //!
+  //! \param[in] siginfo A pointer to a `siginfo_t` object received by a signal
+  //!     handler.
+  //!
+  //! \return `true` if the signal being handled will re-raise itself
+  //!     autonomously upon return from a signal handler. `false` if it will
+  //!     not. When this function returns `false`, a signal can still be
+  //!     re-raised upon return from a signal handler by calling `raise()` from
+  //!     within the signal handler.
+  //!
+  //! \note This function is safe to call from a signal handler.
+  static bool WillSignalReraiseAutonomously(const siginfo_t* siginfo);
+
+  //! \brief Restores a previous signal action and arranges to re-raise a signal
+  //!     on return from a signal handler.
+  //!
+  //! \param[in] siginfo A pointer to a `siginfo_t` object received by a signal
+  //!     handler.
+  //! \param[in] old_action The previous action for the signal, which will be
+  //!     re-established as the signal’s action. May be `nullptr`, which directs
+  //!     the default action for the signal to be used.
+  //!
+  //! If this function fails, it will immediately call `_exit()` and set an exit
+  //! status of `191`.
+  //!
+  //! \note This function may only be called from a signal handler.
+  static void RestoreHandlerAndReraiseSignalOnReturn(
+      const siginfo_t* siginfo,
+      const struct sigaction* old_action);
+
+  //! \brief Determines whether a signal is associated with a crash.
+  //!
+  //! Signals associated with crashes are those whose default dispositions
+  //! involve creating a core dump. The precise set of signals involved varies
+  //! between operating systems.
+  //!
+  //! \param[in] sig The signal to test.
+  //!
+  //! \return `true` if \a sig is associated with a crash. `false` otherwise.
+  //!
+  //! \note This function is safe to call from a signal handler.
+  static bool IsCrashSignal(int sig);
+
+  //! \brief Determines whether a signal is associated with termination.
+  //!
+  //! Signals associated with termination are those whose default dispositions
+  //! involve terminating the process without creating a core dump. The precise
+  //! set of signals involved varies between operating systems.
+  //!
+  //! \param[in] sig The signal to test.
+  //!
+  //! \return `true` if \a sig is associated with termination. `false`
+  //!     otherwise.
+  //!
+  //! \note This function is safe to call from a signal handler.
+  static bool IsTerminateSignal(int sig);
+
+ private:
+  DISALLOW_IMPLICIT_CONSTRUCTORS(Signals);
+};
+
+}  // namespace crashpad
+
+#endif  // CRASHPAD_UTIL_POSIX_SIGNALS_H_
diff --git a/third_party/crashpad/crashpad/util/posix/signals_test.cc b/third_party/crashpad/crashpad/util/posix/signals_test.cc
new file mode 100644
index 0000000..7d4fb75
--- /dev/null
+++ b/third_party/crashpad/crashpad/util/posix/signals_test.cc
@@ -0,0 +1,579 @@
+// Copyright 2017 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "util/posix/signals.h"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <limits>
+
+#include "base/compiler_specific.h"
+#include "base/files/scoped_file.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
+#include "gtest/gtest.h"
+#include "test/errors.h"
+#include "test/multiprocess.h"
+#include "test/scoped_temp_dir.h"
+
+namespace crashpad {
+namespace test {
+namespace {
+
+constexpr int kUnexpectedExitStatus = 3;
+
+// Keep synchronized with CauseSignal().
+bool CanCauseSignal(int sig) {
+  return sig == SIGABRT ||
+         sig == SIGALRM ||
+         sig == SIGBUS ||
+#if !defined(ARCH_CPU_ARM64)
+         sig == SIGFPE ||
+#endif  // !defined(ARCH_CPU_ARM64)
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARMEL)
+         sig == SIGILL ||
+#endif  // defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARMEL
+         sig == SIGPIPE ||
+         sig == SIGSEGV ||
+#if defined(OS_MACOSX)
+         sig == SIGSYS ||
+#endif  // OS_MACOSX
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM64)
+         sig == SIGTRAP ||
+#endif  // defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM64)
+         false;
+}
+
+// Keep synchronized with CanCauseSignal().
+void CauseSignal(int sig) {
+  switch (sig) {
+    case SIGABRT: {
+      abort();
+      break;
+    }
+
+    case SIGALRM: {
+      struct itimerval itimer = {};
+      itimer.it_value.tv_usec = 1E3;  // 1 millisecond
+      if (setitimer(ITIMER_REAL, &itimer, nullptr) != 0) {
+        PLOG(ERROR) << "setitimer";
+        _exit(kUnexpectedExitStatus);
+      }
+
+      while (true) {
+        sleep(std::numeric_limits<unsigned int>::max());
+      }
+    }
+
+    case SIGBUS: {
+      char* mapped;
+      {
+        base::ScopedFD fd;
+        {
+          ScopedTempDir temp_dir;
+          fd.reset(open(temp_dir.path().Append("empty").value().c_str(),
+                        O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_CLOEXEC,
+                        0644));
+          if (fd.get() < 0) {
+            PLOG(ERROR) << "open";
+          }
+        }
+        if (fd.get() < 0) {
+          _exit(kUnexpectedExitStatus);
+        }
+
+        mapped = reinterpret_cast<char*>(mmap(nullptr,
+                                              getpagesize(),
+                                              PROT_READ | PROT_WRITE,
+                                              MAP_PRIVATE,
+                                              fd.get(),
+                                              0));
+        if (mapped == MAP_FAILED) {
+          PLOG(ERROR) << "mmap";
+        }
+      }
+      if (mapped == MAP_FAILED) {
+        _exit(kUnexpectedExitStatus);
+      }
+
+      *mapped = 0;
+
+      _exit(kUnexpectedExitStatus);
+      break;
+    }
+
+#if !defined(ARCH_CPU_ARM64)
+    // ARM64 has hardware integer division instructions that don’t generate a
+    // trap for divide-by-zero, so this doesn’t produce SIGFPE.
+    case SIGFPE: {
+      // Optimization makes this tricky, so get zero from a system call likely
+      // to succeed, and try to do something with the result.
+      struct stat stat_buf;
+      int zero = stat("/", &stat_buf);
+      if (zero == -1) {
+        // It’s important to check |== -1| and not |!= 0|. An optimizer is free
+        // to discard an |== 0| branch entirely, because division by zero is
+        // undefined behavior.
+        PLOG(ERROR) << "stat";
+        _exit(kUnexpectedExitStatus);
+      }
+
+      int quotient = 2 / zero;
+      fstat(quotient, &stat_buf);
+      break;
+    }
+#endif  // ARCH_CPU_ARM64
+
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARMEL)
+    case SIGILL: {
+      // __builtin_trap() causes SIGTRAP on arm64 on Android.
+      __builtin_trap();
+      break;
+    }
+#endif  // defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARMEL)
+
+    case SIGPIPE: {
+      int pipe_fds[2];
+      if (pipe(pipe_fds) != 0) {
+        PLOG(ERROR) << "pipe";
+        _exit(kUnexpectedExitStatus);
+      }
+
+      if (close(pipe_fds[0]) != 0) {
+        PLOG(ERROR) << "close";
+        _exit(kUnexpectedExitStatus);
+      }
+
+      char c = 0;
+      ssize_t rv = write(pipe_fds[1], &c, sizeof(c));
+      if (rv < 0) {
+        PLOG(ERROR) << "write";
+        _exit(kUnexpectedExitStatus);
+      } else if (rv != sizeof(c)) {
+        LOG(ERROR) << "write";
+        _exit(kUnexpectedExitStatus);
+      }
+      break;
+    }
+
+    case SIGSEGV: {
+      volatile int* i = nullptr;
+      *i = 0;
+      break;
+    }
+
+#if defined(OS_MACOSX)
+    case SIGSYS: {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+      int rv = syscall(0);
+#pragma clang diagnostic pop
+      if (rv != 0) {
+        PLOG(ERROR) << "syscall";
+        _exit(kUnexpectedExitStatus);
+      }
+      break;
+    }
+#endif  // OS_MACOSX
+
+#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM64)
+    case SIGTRAP: {
+#if defined(ARCH_CPU_X86_FAMILY)
+      asm("int3");
+#elif defined(ARCH_CPU_ARM64)
+      // bkpt #0 should work for 32-bit ARCH_CPU_ARMEL, but according to
+      // https://crrev.com/f53167270c44, it only causes SIGTRAP on Linux under a
+      // 64-bit kernel. For a pure 32-bit armv7 system, it generates SIGBUS.
+      asm("brk #0");
+#endif
+      break;
+    }
+#endif  // defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM64)
+
+    default: {
+      LOG(ERROR) << "unexpected signal " << sig;
+      _exit(kUnexpectedExitStatus);
+      break;
+    }
+  }
+}
+
+class SignalsTest : public Multiprocess {
+ public:
+  enum class SignalSource {
+    kCause,
+    kRaise,
+  };
+  enum class TestType {
+    kDefaultHandler,
+    kHandlerExits,
+    kHandlerReraisesToDefault,
+    kHandlerReraisesToPrevious,
+  };
+  static constexpr int kExitingHandlerExitStatus = 2;
+
+  SignalsTest(TestType test_type, SignalSource signal_source, int sig)
+      : Multiprocess(),
+        sig_(sig),
+        test_type_(test_type),
+        signal_source_(signal_source) {}
+  ~SignalsTest() {}
+
+ private:
+  static void SignalHandler_Exit(int sig, siginfo_t* siginfo, void* context) {
+    _exit(kExitingHandlerExitStatus);
+  }
+
+  static void SignalHandler_ReraiseToDefault(int sig,
+                                             siginfo_t* siginfo,
+                                             void* context) {
+    Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr);
+  }
+
+  static void SignalHandler_ReraiseToPrevious(int sig,
+                                              siginfo_t* siginfo,
+                                              void* context) {
+    Signals::RestoreHandlerAndReraiseSignalOnReturn(
+        siginfo, old_actions_.ActionForSignal(sig));
+  }
+
+  // Multiprocess:
+  void MultiprocessParent() override {}
+
+  void MultiprocessChild() override {
+    bool (*install_handlers)(Signals::Handler, int, Signals::OldActions*);
+    if (Signals::IsCrashSignal(sig_)) {
+      install_handlers = Signals::InstallCrashHandlers;
+    } else if (Signals::IsTerminateSignal(sig_)) {
+      install_handlers = Signals::InstallTerminateHandlers;
+    } else {
+      _exit(kUnexpectedExitStatus);
+    }
+
+    switch (test_type_) {
+      case TestType::kDefaultHandler: {
+        // Don’t rely on the default handler being active. Something may have
+        // changed it (particularly on Android).
+        struct sigaction action;
+        sigemptyset(&action.sa_mask);
+        action.sa_flags = 0;
+        action.sa_handler = SIG_DFL;
+        ASSERT_EQ(0, sigaction(sig_, &action, nullptr))
+            << ErrnoMessage("sigaction");
+        break;
+      }
+
+      case TestType::kHandlerExits: {
+        ASSERT_TRUE(install_handlers(SignalHandler_Exit, 0, nullptr));
+        break;
+      }
+
+      case TestType::kHandlerReraisesToDefault: {
+        ASSERT_TRUE(
+            install_handlers(SignalHandler_ReraiseToDefault, 0, nullptr));
+        break;
+      }
+
+      case TestType::kHandlerReraisesToPrevious: {
+        ASSERT_TRUE(install_handlers(SignalHandler_Exit, 0, nullptr));
+        ASSERT_TRUE(install_handlers(
+            SignalHandler_ReraiseToPrevious, 0, &old_actions_));
+        break;
+      }
+    }
+
+    switch (signal_source_) {
+      case SignalSource::kCause:
+        CauseSignal(sig_);
+        break;
+      case SignalSource::kRaise:
+        raise(sig_);
+        break;
+    }
+
+    _exit(kUnexpectedExitStatus);
+  }
+
+  int sig_;
+  TestType test_type_;
+  SignalSource signal_source_;
+  static Signals::OldActions old_actions_;
+
+  DISALLOW_COPY_AND_ASSIGN(SignalsTest);
+};
+
+Signals::OldActions SignalsTest::old_actions_;
+
+bool ShouldTestSignal(int sig) {
+  return Signals::IsCrashSignal(sig) || Signals::IsTerminateSignal(sig);
+}
+
+TEST(Signals, WillSignalReraiseAutonomously) {
+  const struct {
+    int sig;
+    int code;
+    bool result;
+  } kTestData[] = {
+      {SIGBUS, BUS_ADRALN, true},
+      {SIGFPE, FPE_FLTDIV, true},
+      {SIGILL, ILL_ILLOPC, true},
+      {SIGSEGV, SEGV_MAPERR, true},
+      {SIGBUS, 0, false},
+      {SIGFPE, -1, false},
+      {SIGILL, SI_USER, false},
+      {SIGSEGV, SI_QUEUE, false},
+      {SIGTRAP, TRAP_BRKPT, false},
+      {SIGHUP, SEGV_MAPERR, false},
+      {SIGINT, SI_USER, false},
+  };
+  for (size_t index = 0; index < arraysize(kTestData); ++index) {
+    const auto test_data = kTestData[index];
+    SCOPED_TRACE(base::StringPrintf(
+        "index %zu, sig %d, code %d", index, test_data.sig, test_data.code));
+    siginfo_t siginfo = {};
+    siginfo.si_signo = test_data.sig;
+    siginfo.si_code = test_data.code;
+    EXPECT_EQ(test_data.result,
+              Signals::WillSignalReraiseAutonomously(&siginfo));
+  }
+}
+
+TEST(Signals, Cause_DefaultHandler) {
+  for (int sig = 1; sig < NSIG; ++sig) {
+    SCOPED_TRACE(base::StringPrintf("sig %d (%s)", sig, strsignal(sig)));
+
+    if (!CanCauseSignal(sig)) {
+      continue;
+    }
+
+    SignalsTest test(SignalsTest::TestType::kDefaultHandler,
+                     SignalsTest::SignalSource::kCause,
+                     sig);
+    test.SetExpectedChildTermination(Multiprocess::kTerminationSignal, sig);
+    test.Run();
+  }
+}
+
+TEST(Signals, Cause_HandlerExits) {
+  for (int sig = 1; sig < NSIG; ++sig) {
+    SCOPED_TRACE(base::StringPrintf("sig %d (%s)", sig, strsignal(sig)));
+
+    if (!CanCauseSignal(sig)) {
+      continue;
+    }
+
+    SignalsTest test(SignalsTest::TestType::kHandlerExits,
+                     SignalsTest::SignalSource::kCause,
+                     sig);
+    test.SetExpectedChildTermination(Multiprocess::kTerminationNormal,
+                                     SignalsTest::kExitingHandlerExitStatus);
+    test.Run();
+  }
+}
+
+TEST(Signals, Cause_HandlerReraisesToDefault) {
+  for (int sig = 1; sig < NSIG; ++sig) {
+    SCOPED_TRACE(base::StringPrintf("sig %d (%s)", sig, strsignal(sig)));
+
+    if (!CanCauseSignal(sig)) {
+      continue;
+    }
+
+    SignalsTest test(SignalsTest::TestType::kHandlerReraisesToDefault,
+                     SignalsTest::SignalSource::kCause,
+                     sig);
+    test.SetExpectedChildTermination(Multiprocess::kTerminationSignal, sig);
+    test.Run();
+  }
+}
+
+TEST(Signals, Cause_HandlerReraisesToPrevious) {
+  for (int sig = 1; sig < NSIG; ++sig) {
+    SCOPED_TRACE(base::StringPrintf("sig %d (%s)", sig, strsignal(sig)));
+
+    if (!CanCauseSignal(sig)) {
+      continue;
+    }
+
+    SignalsTest test(SignalsTest::TestType::kHandlerReraisesToPrevious,
+                     SignalsTest::SignalSource::kCause,
+                     sig);
+    test.SetExpectedChildTermination(Multiprocess::kTerminationNormal,
+                                     SignalsTest::kExitingHandlerExitStatus);
+    test.Run();
+  }
+}
+
+TEST(Signals, Raise_DefaultHandler) {
+  for (int sig = 1; sig < NSIG; ++sig) {
+    SCOPED_TRACE(base::StringPrintf("sig %d (%s)", sig, strsignal(sig)));
+
+    if (!ShouldTestSignal(sig)) {
+      continue;
+    }
+
+    SignalsTest test(SignalsTest::TestType::kDefaultHandler,
+                     SignalsTest::SignalSource::kRaise,
+                     sig);
+    test.SetExpectedChildTermination(Multiprocess::kTerminationSignal, sig);
+    test.Run();
+  }
+}
+
+TEST(Signals, Raise_HandlerExits) {
+  for (int sig = 1; sig < NSIG; ++sig) {
+    SCOPED_TRACE(base::StringPrintf("sig %d (%s)", sig, strsignal(sig)));
+
+    if (!ShouldTestSignal(sig)) {
+      continue;
+    }
+
+    SignalsTest test(SignalsTest::TestType::kHandlerExits,
+                     SignalsTest::SignalSource::kRaise,
+                     sig);
+    test.SetExpectedChildTermination(Multiprocess::kTerminationNormal,
+                                     SignalsTest::kExitingHandlerExitStatus);
+    test.Run();
+  }
+}
+
+TEST(Signals, Raise_HandlerReraisesToDefault) {
+  for (int sig = 1; sig < NSIG; ++sig) {
+    SCOPED_TRACE(base::StringPrintf("sig %d (%s)", sig, strsignal(sig)));
+
+    if (!ShouldTestSignal(sig)) {
+      continue;
+    }
+
+#if defined(OS_MACOSX)
+    if (sig == SIGBUS) {
+      // Signal handlers can’t distinguish between SIGBUS arising out of a
+      // hardware fault and SIGBUS raised asynchronously.
+      // Signals::RestoreHandlerAndReraiseSignalOnReturn() assumes that SIGBUS
+      // comes from a hardware fault, but this test uses raise(), so the
+      // re-raise test must be skipped.
+      continue;
+    }
+#endif  // defined(OS_MACOSX)
+
+    SignalsTest test(SignalsTest::TestType::kHandlerReraisesToDefault,
+                     SignalsTest::SignalSource::kRaise,
+                     sig);
+    test.SetExpectedChildTermination(Multiprocess::kTerminationSignal, sig);
+    test.Run();
+  }
+}
+
+TEST(Signals, Raise_HandlerReraisesToPrevious) {
+  for (int sig = 1; sig < NSIG; ++sig) {
+    SCOPED_TRACE(base::StringPrintf("sig %d (%s)", sig, strsignal(sig)));
+
+    if (!ShouldTestSignal(sig)) {
+      continue;
+    }
+
+#if defined(OS_MACOSX)
+    if (sig == SIGBUS) {
+      // Signal handlers can’t distinguish between SIGBUS arising out of a
+      // hardware fault and SIGBUS raised asynchronously.
+      // Signals::RestoreHandlerAndReraiseSignalOnReturn() assumes that SIGBUS
+      // comes from a hardware fault, but this test uses raise(), so the
+      // re-raise test must be skipped.
+      continue;
+    }
+#endif  // defined(OS_MACOSX)
+
+    SignalsTest test(SignalsTest::TestType::kHandlerReraisesToPrevious,
+                     SignalsTest::SignalSource::kRaise,
+                     sig);
+    test.SetExpectedChildTermination(Multiprocess::kTerminationNormal,
+                                     SignalsTest::kExitingHandlerExitStatus);
+    test.Run();
+  }
+}
+
+TEST(Signals, IsCrashSignal) {
+  // Always crash signals.
+  EXPECT_TRUE(Signals::IsCrashSignal(SIGABRT));
+  EXPECT_TRUE(Signals::IsCrashSignal(SIGBUS));
+  EXPECT_TRUE(Signals::IsCrashSignal(SIGFPE));
+  EXPECT_TRUE(Signals::IsCrashSignal(SIGILL));
+  EXPECT_TRUE(Signals::IsCrashSignal(SIGQUIT));
+  EXPECT_TRUE(Signals::IsCrashSignal(SIGSEGV));
+  EXPECT_TRUE(Signals::IsCrashSignal(SIGSYS));
+  EXPECT_TRUE(Signals::IsCrashSignal(SIGTRAP));
+
+  // Always terminate signals.
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGALRM));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGHUP));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGINT));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGPIPE));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGPROF));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGTERM));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGUSR1));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGUSR2));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGVTALRM));
+
+  // Never crash or terminate signals.
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGCHLD));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGCONT));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGTSTP));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGTTIN));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGTTOU));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGURG));
+  EXPECT_FALSE(Signals::IsCrashSignal(SIGWINCH));
+}
+
+TEST(Signals, IsTerminateSignal) {
+  // Always terminate signals.
+  EXPECT_TRUE(Signals::IsTerminateSignal(SIGALRM));
+  EXPECT_TRUE(Signals::IsTerminateSignal(SIGHUP));
+  EXPECT_TRUE(Signals::IsTerminateSignal(SIGINT));
+  EXPECT_TRUE(Signals::IsTerminateSignal(SIGPIPE));
+  EXPECT_TRUE(Signals::IsTerminateSignal(SIGPROF));
+  EXPECT_TRUE(Signals::IsTerminateSignal(SIGTERM));
+  EXPECT_TRUE(Signals::IsTerminateSignal(SIGUSR1));
+  EXPECT_TRUE(Signals::IsTerminateSignal(SIGUSR2));
+  EXPECT_TRUE(Signals::IsTerminateSignal(SIGVTALRM));
+
+  // Always crash signals.
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGABRT));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGBUS));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGFPE));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGILL));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGQUIT));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGSEGV));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGSYS));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGTRAP));
+
+  // Never crash or terminate signals.
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGCHLD));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGCONT));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGTSTP));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGTTIN));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGTTOU));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGURG));
+  EXPECT_FALSE(Signals::IsTerminateSignal(SIGWINCH));
+}
+
+}  // namespace
+}  // namespace test
+}  // namespace crashpad
diff --git a/third_party/crashpad/crashpad/util/util.gyp b/third_party/crashpad/crashpad/util/util.gyp
index b27337c..9e57b44 100644
--- a/third_party/crashpad/crashpad/util/util.gyp
+++ b/third_party/crashpad/crashpad/util/util.gyp
@@ -135,6 +135,8 @@
         'posix/drop_privileges.h',
         'posix/process_info.h',
         'posix/process_info_mac.cc',
+        'posix/signals.cc',
+        'posix/signals.h',
         'posix/symbolic_constants_posix.cc',
         'posix/symbolic_constants_posix.h',
         'stdlib/aligned_allocator.cc',
@@ -271,6 +273,7 @@
           'link_settings': {
             'libraries': [
               '-luser32.lib',
+              '-lversion.lib',
               '-lwinhttp.lib',
             ],
           },
diff --git a/third_party/crashpad/crashpad/util/util_test.gyp b/third_party/crashpad/crashpad/util/util_test.gyp
index e16a292..a33e474 100644
--- a/third_party/crashpad/crashpad/util/util_test.gyp
+++ b/third_party/crashpad/crashpad/util/util_test.gyp
@@ -74,6 +74,7 @@
         'numeric/in_range_cast_test.cc',
         'numeric/int128_test.cc',
         'posix/process_info_test.cc',
+        'posix/signals_test.cc',
         'posix/symbolic_constants_posix_test.cc',
         'stdlib/aligned_allocator_test.cc',
         'stdlib/map_insert_test.cc',
diff --git a/third_party/libprotobuf-mutator/OWNERS b/third_party/libprotobuf-mutator/OWNERS
new file mode 100644
index 0000000..5f74ed3
--- /dev/null
+++ b/third_party/libprotobuf-mutator/OWNERS
@@ -0,0 +1,3 @@
+aizatsky@chromium.org
+vitalybuka@chromium.org
+
diff --git a/third_party/libprotobuf-mutator/README.chromium b/third_party/libprotobuf-mutator/README.chromium
new file mode 100644
index 0000000..768ee8f
--- /dev/null
+++ b/third_party/libprotobuf-mutator/README.chromium
@@ -0,0 +1,13 @@
+Name: libprotobuf-mutator
+URL: https://github.com/google/libprotobuf-mutator
+Version: 0
+License: Apache 2.0
+License File: src/LICENSE
+Security Critical: no
+
+Description:
+Library for protocol buffer mutation. Assistance library to in-process
+coverage-guided fuzz testing (fuzzing).
+
+Local Modifications:
+None.
diff --git a/tools/chrome_extensions/open_my_editor/OWNERS b/tools/chrome_extensions/open_my_editor/OWNERS
new file mode 100644
index 0000000..b776147
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/OWNERS
@@ -0,0 +1,2 @@
+chaopeng@chromium.org
+watk@chromium.org
\ No newline at end of file
diff --git a/tools/chrome_extensions/open_my_editor/README.md b/tools/chrome_extensions/open_my_editor/README.md
new file mode 100644
index 0000000..584c3f3
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/README.md
@@ -0,0 +1,54 @@
+# Open My Editor (OME)
+
+OME gives you a context menu for opening files in your editor on
+[Chromium Code Search](https://cs.chromium.org/), 
+[Chromium Code Review](https://codereview.chromium.org/) and 
+[Chromium Build](https://build.chromium.org).
+
+For Chromium Code Search, right click on code block and select `Open My Editor`, 
+it will open the file in your editor at the selected line.
+
+![Chromium Code Search](./images/cs.png)
+
+For Chromium Code Search, right click on symbol or filename and select 
+`Open My Editor by link` can also open file (maybe with linenumber).
+
+![Chromium Code Search by link](./images/open-by-link-cs.png)
+
+For Chromium Code Review, right click on the patchset table and select 
+`Open My Editor`, it will open all the files in the patchset.
+
+![Chromium Code Review](./images/cr.png)
+
+For Chromium Code Review, you can also right click on a filename and select 
+`Open My Editor by link`.
+
+![Chromium Code Review by link](./images/open-by-link-cr.png)
+
+For any build.chromium.org site, select the file path then right click and 
+select `Open My Editor $file`.
+
+## Installation
+
+1. Install the [Chrome Extension](https://chrome.google.com/webstore/detail/ome/ddmghiaepldohkneojcfejekplkakgjg?hl=en-US)
+2. Install dependencies `pip install bottle sh`, you may need to install 
+   `python` and `python-pip` if you don't have `pip`.
+
+3. Start `omed.py`
+  
+    ```
+    python ${CHROMIUM_SRC}/tools/chrome_extensions/open_my_editor/omed.py
+    ```
+
+    It's convenient to configure your system to automatically run omed.py at
+    startup so that you don't have to remember to manually start it.
+
+4. Create a `myeditor` executable to be used for launching your editor, and add 
+   it to your path. See [`myeditor-example/`](https://chromium.googlesource.com/chromium/src.git/+/master/tools/chrome_extensions/open_my_editor/myeditor-example/).
+5. Enjoy.
+
+## How it works
+
+In the Chrome Extension, I read the filepath and line number from right click,  
+then make a http call to `omed.py`. `omed.py` calls `myeditor` to open your 
+editor.
diff --git a/tools/chrome_extensions/open_my_editor/ext/background.js b/tools/chrome_extensions/open_my_editor/ext/background.js
new file mode 100644
index 0000000..7065510
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/ext/background.js
@@ -0,0 +1,108 @@
+// 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.
+
+function get_query(uri, key) {
+  if (uri.includes('?')) {
+    let query_str = uri.split('?')[1];
+    let queries = query_str.split('&');
+    for (let query of queries) {
+      let ss = query.split('=');
+      if (ss.length == 2 && ss[0] == key)
+        return ss[1];
+    }
+  }
+  return undefined;
+}
+
+function open_by_selection(selectionText) {
+  if (selectionText)
+    fetch('http://127.0.0.1:8989/file?f=' + selectionText + '&l=1');
+}
+
+function open_by_link(pageUrl, info, tabId) {
+  if (pageUrl.startsWith('https://cs.chromium.org/')) {
+    if (info.linkUrl.startsWith('https://cs.chromium.org/chromium/src/')) {
+      let filepath =
+          info.linkUrl.replace('https://cs.chromium.org/chromium/src/', '')
+              .replace(/\?.*/, '');
+      let line = get_query(info.linkUrl, 'l');
+      line = line != undefined ? line : '1';
+      fetch('http://127.0.0.1:8989/file?f=' + filepath + '&l=' + line);
+    }
+  } else if (pageUrl.startsWith('https://codereview.chromium.org/')) {
+    if (info.linkUrl.match('https://codereview.chromium.org/.*/patch/') !=
+        null) {
+      chrome.tabs.sendMessage(tabId, 'getFile', (res) => {
+        if (res.file)
+          fetch('http://127.0.0.1:8989/file?f=' + res.file + '&l=1');
+      });
+    } else if (
+        info.linkUrl.match(
+            /https:\/\/codereview.chromium.org\/\d*\/diff\/\d*\//) != null) {
+      let filepath = info.linkUrl.replace(
+          /https:\/\/codereview.chromium.org\/\d*\/diff\/\d*\//, '');
+      fetch('http://127.0.0.1:8989/file?f=' + filepath + '&l=1');
+    }
+  }
+}
+
+function cs_open_by_current_line(tabId, url) {
+  chrome.tabs.sendMessage(tabId, 'getLine', (res) => {
+    let line = res.line;
+
+    let filepath = url.replace('https://cs.chromium.org/chromium/src/', '')
+                       .replace(/\?.*/, '');
+
+    fetch('http://127.0.0.1:8989/file?f=' + filepath + '&l=' + line);
+  });
+}
+
+function cr_open_all_in_patchset(tabId) {
+  chrome.tabs.sendMessage(tabId, 'getFiles', (res) => {
+    fetch('http://127.0.0.1:8989/files?f=' + res.files.join(',,'));
+  });
+}
+
+chrome.contextMenus.onClicked.addListener((info, tab) => {
+  if (info.menuItemId == 'ome-selection') {
+    open_by_selection(info.selectionText);
+  } else if (info.menuItemId == 'ome-link') {
+    open_by_link(tab.url, info, tab.id);
+  } else if (info.menuItemId == 'ome') {
+    if (tab.url.startsWith('https://cs.chromium.org/chromium/src/')) {
+      cs_open_by_current_line(tab.id, tab.url);
+    } else if (tab.url.startsWith('https://codereview.chromium.org/')) {
+      cr_open_all_in_patchset(tab.id);
+    }
+  }
+});
+
+chrome.runtime.onInstalled.addListener(() => {
+  chrome.contextMenus.create({
+    'title': 'Open My Editor',
+    'id': 'ome',
+    'contexts': ['page'],
+    'documentUrlPatterns': [
+      'https://cs.chromium.org/chromium/src/*',
+      'https://codereview.chromium.org/*'
+    ]
+  });
+  chrome.contextMenus.create({
+    'title': 'Open My Editor by Link',
+    'id': 'ome-link',
+    'contexts': ['link'],
+    'documentUrlPatterns':
+        ['https://cs.chromium.org/*', 'https://codereview.chromium.org/*']
+  });
+  chrome.contextMenus.create({
+    'title': 'Open My Editor for "%s"',
+    'id': 'ome-selection',
+    'contexts': ['selection'],
+    'documentUrlPatterns': [
+      // TODO(chaopeng) Should be only except CS and CR, But I dont know how to.
+      // So only list the sites here.
+      'https://build.chromium.org/*', 'https://chromium.org/*'
+    ]
+  });
+});
diff --git a/tools/chrome_extensions/open_my_editor/ext/cr-content.js b/tools/chrome_extensions/open_my_editor/ext/cr-content.js
new file mode 100644
index 0000000..10860ed
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/ext/cr-content.js
@@ -0,0 +1,41 @@
+// 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.
+
+// For codereview.chromium.org
+
+let clicked_element = null;
+
+document.addEventListener('mousedown', (event) => {
+  // right click
+  if (event.button == 2)
+    clicked_element = event.target;
+});
+
+chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
+  if (request == 'getFiles') {
+    let element = clicked_element;
+    while (element != null && element.tagName != 'TABLE')
+      element = element.parentElement;
+
+    let trs = element.getElementsByTagName('TR');
+    if (trs.length == 0)
+      alert('Please toggle one patchset.');
+
+    let files = [];
+    for (let i = 1; i < trs.length; ++i) {
+      let tr = trs[i];
+      if (tr.getAttribute('name') != 'patch')
+        continue;
+      // Skip deleted file.
+      if (tr.children[1].firstChild.data == 'D')
+        continue;
+
+      files.push(tr.children[2].children[0].text.replace(/\s*/g, ''));
+    }
+
+    sendResponse({files: files});
+  } else if (request == 'getFile' && clicked_element.tagName == 'A') {
+    sendResponse({file: clicked_element.text});
+  }
+});
\ No newline at end of file
diff --git a/tools/chrome_extensions/open_my_editor/ext/cs-content.js b/tools/chrome_extensions/open_my_editor/ext/cs-content.js
new file mode 100644
index 0000000..7df1b85
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/ext/cs-content.js
@@ -0,0 +1,28 @@
+// 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.
+
+// For cs.chromium.org
+
+let line = 0;
+
+document.addEventListener('mousedown', (event) => {
+  // right click
+  if (event.button == 2) {
+    let element = event.target;
+    while (element != null && element.tagName == 'SPAN') {
+      if (element.className == 'stx-line') {
+        line = parseInt(element.id.split('_')[1]);
+        break;
+      } else {
+        element = element.parentElement;
+      }
+    }
+  }
+}, true);
+
+chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
+  if (request == 'getLine') {
+    sendResponse({line: line});
+  }
+});
\ No newline at end of file
diff --git a/tools/chrome_extensions/open_my_editor/ext/icon-16.png b/tools/chrome_extensions/open_my_editor/ext/icon-16.png
new file mode 100644
index 0000000..3692967
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/ext/icon-16.png
Binary files differ
diff --git a/tools/chrome_extensions/open_my_editor/ext/manifest.json b/tools/chrome_extensions/open_my_editor/ext/manifest.json
new file mode 100644
index 0000000..a5e6518
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/ext/manifest.json
@@ -0,0 +1,39 @@
+{
+  "name": "OME",
+  "description": "OME gives you a context menu for opening files in your editor on Chromium Code Search and Code Review.",
+  "version": "0.4.0",
+  "permissions": [
+    "contextMenus",
+    "tabs",
+    "activeTab",
+    "http://127.0.0.1:8989/*"
+  ],
+  "icons": {
+    "16": "icon-16.png"
+  },
+  "background": {
+    "persistent": false,
+    "scripts": [
+      "background.js"
+    ]
+  },
+  "content_scripts": [
+    {
+      "matches": [
+        "https://cs.chromium.org/chromium/src/*"
+      ],
+      "js": [
+        "cs-content.js"
+      ]
+    },
+    {
+      "matches": [
+        "https://codereview.chromium.org/*"
+      ],
+      "js": [
+        "cr-content.js"
+      ]
+    }
+  ],
+  "manifest_version": 2
+}
\ No newline at end of file
diff --git a/tools/chrome_extensions/open_my_editor/images/cr.png b/tools/chrome_extensions/open_my_editor/images/cr.png
new file mode 100644
index 0000000..3aafe4c
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/images/cr.png
Binary files differ
diff --git a/tools/chrome_extensions/open_my_editor/images/cs.png b/tools/chrome_extensions/open_my_editor/images/cs.png
new file mode 100644
index 0000000..489e2fac
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/images/cs.png
Binary files differ
diff --git a/tools/chrome_extensions/open_my_editor/images/open-by-link-cr.png b/tools/chrome_extensions/open_my_editor/images/open-by-link-cr.png
new file mode 100644
index 0000000..b38a566
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/images/open-by-link-cr.png
Binary files differ
diff --git a/tools/chrome_extensions/open_my_editor/images/open-by-link-cs.png b/tools/chrome_extensions/open_my_editor/images/open-by-link-cs.png
new file mode 100644
index 0000000..b4f7305
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/images/open-by-link-cs.png
Binary files differ
diff --git a/tools/chrome_extensions/open_my_editor/myeditor-example/qtcreator-example.py b/tools/chrome_extensions/open_my_editor/myeditor-example/qtcreator-example.py
new file mode 100755
index 0000000..d9a5aa1c
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/myeditor-example/qtcreator-example.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""
+This is a wrapper script to start your editor. You also need to add this script
+to your path.
+"""
+
+import argparse
+import os
+import sh
+
+def qtcreator_open_file(filepath, line=1):
+  sh.qtcreator("-client", filepath + ":" + str(line))
+
+CHROMIUM_ROOT = os.environ['HOME'] + "/workspace/chromium/src"
+
+os.chdir(CHROMIUM_ROOT)
+
+###### Dont change this part. BEGIN #####
+parser = argparse.ArgumentParser()
+parser.add_argument("-f", "--filepath", help="Filepath.")
+parser.add_argument("-l", "--line", type=int, help="Line number.")
+parser.add_argument("-m", "--multifilepath", help="Multi Filepath.")
+args = parser.parse_args()
+###### Dont change this part. END   #####
+
+# I dont have a good idea to start a QtCreator instance, so please open it
+# manually.
+
+# Open one file with line number.
+if args.filepath != None:
+  qtcreator_open_file(args.filepath, args.line)
+# Open multiple files.
+else:
+  for filepath in args.multifilepath.split(",,"):
+    qtcreator_open_file(filepath)
diff --git a/tools/chrome_extensions/open_my_editor/myeditor-example/vscode-example.py b/tools/chrome_extensions/open_my_editor/myeditor-example/vscode-example.py
new file mode 100755
index 0000000..ecd8250
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/myeditor-example/vscode-example.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""
+This is a wrapper script to start your editor. You also need to add this script
+to your path.
+"""
+
+import argparse
+import os
+import sh
+
+CHROMIUM_ROOT = os.environ['HOME'] + "/workspace/chromium/src"
+
+os.chdir(CHROMIUM_ROOT)
+
+###### Dont change this part. BEGIN #####
+parser = argparse.ArgumentParser()
+parser.add_argument("-f", "--filepath", help="Filepath.")
+parser.add_argument("-l", "--line", type=int, help="Line number.")
+parser.add_argument("-m", "--multifilepath", help="Multi Filepath.")
+args = parser.parse_args()
+###### Dont change this part. END   #####
+
+# Start a vscode instance.
+sh.code(".")
+
+# Open one file with line number.
+if args.filepath != None:
+  sh.code("-g", args.filepath + ":" + str(args.line))
+# Open multiple files.
+else:
+  sh.code(args.multifilepath.split(",,"))
diff --git a/tools/chrome_extensions/open_my_editor/omed.py b/tools/chrome_extensions/open_my_editor/omed.py
new file mode 100755
index 0000000..2998c68
--- /dev/null
+++ b/tools/chrome_extensions/open_my_editor/omed.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""
+HTTP server for handling requests to open files.
+"""
+
+from bottle import Bottle, install, get, response, request, run
+import logging
+import sys
+import sh
+
+logfile = "/tmp/omed.log"
+# Get it a path for log.
+if len(sys.argv) == 2:
+  logfile = sys.argv[1]
+
+logging.basicConfig(filename=logfile, level=logging.INFO)
+logger = logging.getLogger('omed')
+
+def log(func):
+  def wrapper(*args, **kwargs):
+    logger.info(
+        '%s %s %s %s' %
+        (request.remote_addr, request.method, request.url, response.status))
+
+    req = func(*args, **kwargs)
+    return req
+  return wrapper
+
+install(log)
+
+@get('/file')
+def open_file():
+  filepath = request.query.f
+  line = request.query.l
+
+  logger.info("open file: " + filepath + ":" + line)
+
+  sh.myeditor("-f", filepath, "-l", line)
+  return
+
+@get('/files')
+def open_files():
+  filepaths = request.query.f
+
+  logger.info("open files: " + filepaths)
+
+  sh.myeditor("-m", filepaths)
+  return
+
+run(port=8989, host='127.0.0.1')
diff --git a/tools/gn/ninja_binary_target_writer_unittest.cc b/tools/gn/ninja_binary_target_writer_unittest.cc
index 381eb39..6ac8146 100644
--- a/tools/gn/ninja_binary_target_writer_unittest.cc
+++ b/tools/gn/ninja_binary_target_writer_unittest.cc
@@ -772,7 +772,6 @@
   {
     Target pch_target(&pch_settings,
                       Label(SourceDir("//foo/"), "pch_target"));
-    pch_target.config_values().set_precompiled_header("build/precompile.h");
     pch_target.config_values().set_precompiled_source(
         SourceFile("//build/precompile.h"));
     pch_target.config_values().cflags_c().push_back("-std=c99");
diff --git a/tools/gn/variables.cc b/tools/gn/variables.cc
index 3b60c90..66460e98 100644
--- a/tools/gn/variables.cc
+++ b/tools/gn/variables.cc
@@ -1451,18 +1451,31 @@
   config applying to this target specifies this value. In addition, the tool
   corresponding to the source files must also specify precompiled headers (see
   "gn help tool"). The tool will also specify what type of precompiled headers
-  to use.
+  to use, by setting precompiled_header_type to either "gcc" or "msvc".
 
   The precompiled header/source variables can be specified on a target or a
   config, but must be the same for all configs applying to a given target since
   a target can only have one precompiled header.
 
+  If you use both C and C++ sources, the precompiled header and source file
+  will be compiled once per language. You will want to make sure to wrap C++
+  includes in __cplusplus #ifdefs so the file will compile in C mode.
+
+GCC precompiled headers
+
+  When using GCC-style precompiled headers, "precompiled_source" contains the
+  path of a .h file that is precompiled and then included by all source files
+  in targets that set "precompiled_source".
+
+  The value of "precompiled_header" is not used with GCC-style precompiled
+  headers.
+
 MSVC precompiled headers
 
   When using MSVC-style precompiled headers, the "precompiled_header" value is
   a string corresponding to the header. This is NOT a path to a file that GN
-  recognises, but rather the exact string that appears in quotes after an
-  #include line in source code. The compiler will match this string against
+  recognises, but rather the exact string that appears in quotes after
+  an #include line in source code. The compiler will match this string against
   includes or forced includes (/FI).
 
   MSVC also requires a source file to compile the header with. This must be
@@ -1470,10 +1483,6 @@
   this IS a GN-style file name, and tells GN which source file to compile to
   make the .pch file used for subsequent compiles.
 
-  If you use both C and C++ sources, the precompiled header and source file
-  will be compiled using both tools. You will want to make sure to wrap C++
-  includes in __cplusplus #ifdefs so the file will compile in C mode.
-
   For example, if the toolchain specifies MSVC headers:
 
     toolchain("vc_x64") {
@@ -1500,6 +1509,15 @@
       ...
 )";
 
+const char kPrecompiledHeaderType[] = "precompiled_header_type";
+const char kPrecompiledHeaderType_HelpShort[] =
+    "precompiled_header_type: [string] \"gcc\" or \"msvc\".";
+const char kPrecompiledHeaderType_Help[] =
+    R"(precompiled_header_type: [string] "gcc" or "msvc".
+
+  See "gn help precompiled_header".
+)";
+
 const char kPrecompiledSource[] = "precompiled_source";
 const char kPrecompiledSource_HelpShort[] =
     "precompiled_source: [file name] Source file to precompile.";
@@ -1904,6 +1922,7 @@
     INSERT_VARIABLE(OutputPrefixOverride)
     INSERT_VARIABLE(Outputs)
     INSERT_VARIABLE(PrecompiledHeader)
+    INSERT_VARIABLE(PrecompiledHeaderType)
     INSERT_VARIABLE(PrecompiledSource)
     INSERT_VARIABLE(ProductType)
     INSERT_VARIABLE(Public)
diff --git a/tools/gn/variables.h b/tools/gn/variables.h
index df94b65..2af40c5e 100644
--- a/tools/gn/variables.h
+++ b/tools/gn/variables.h
@@ -239,6 +239,10 @@
 extern const char kPrecompiledHeader_HelpShort[];
 extern const char kPrecompiledHeader_Help[];
 
+extern const char kPrecompiledHeaderType[];
+extern const char kPrecompiledHeaderType_HelpShort[];
+extern const char kPrecompiledHeaderType_Help[];
+
 extern const char kPrecompiledSource[];
 extern const char kPrecompiledSource_HelpShort[];
 extern const char kPrecompiledSource_Help[];
diff --git a/tools/grit/grit/format/resource_map.py b/tools/grit/grit/format/resource_map.py
index aca302b7..f1e3132 100755
--- a/tools/grit/grit/format/resource_map.py
+++ b/tools/grit/grit/format/resource_map.py
@@ -66,15 +66,17 @@
 ''' % { 'map_name': GetMapName(root) }
 
 
-def _FormatSourceHeader(root):
+def _FormatSourceHeader(root, output_dir):
   '''Create the header of the C++ source file for the resource mapping.'''
   rc_header_file = None
   map_header_file = None
   for output in root.GetOutputFiles():
     if 'rc_header' == output.GetType():
-      rc_header_file = output.GetFilename()
+      rc_header_file = util.MakeRelativePath(output_dir,
+                                             output.GetOutputFilename())
     elif 'resource_map_header' == output.GetType():
-      map_header_file = output.GetFilename()
+      map_header_file = util.MakeRelativePath(output_dir,
+                                              output.GetOutputFilename())
   if not rc_header_file or not map_header_file:
     raise Exception('resource_map_source output type requires '
         'resource_map_header and rc_header outputs')
@@ -108,7 +110,7 @@
 def _FormatSource(get_key, root, lang, output_dir):
   from grit.format import rc_header
   from grit.node import include, structure, message
-  yield _FormatSourceHeader(root)
+  yield _FormatSourceHeader(root, output_dir)
   tids = rc_header.GetIds(root)
   seen = set()
   active_descendants = [item for item in root.ActiveDescendants()]
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index c2084d5..79fb7dc 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -20275,7 +20275,8 @@
   </summary>
 </histogram>
 
-<histogram name="FirstUserAction.BackgroundTime.MainIntent" units="minutes">
+<histogram base="true" name="FirstUserAction.BackgroundTime.MainIntent"
+    units="minutes">
   <owner>tedchoc@chromium.org</owner>
   <summary>
     The amount of time (in minutes) that the app was in the background before
@@ -44033,6 +44034,59 @@
   </summary>
 </histogram>
 
+<histogram name="Omnibox.ZeroSuggest.Eligible.OnFocus"
+    enum="ZeroSuggestEligibleOnFocus">
+  <owner>mpearson@chromium.org</owner>
+  <summary>
+    Whether the user has settings configured so that the current page URL can be
+    sent to the suggest server to request contextual suggestions.  For example,
+    this is only supported for users who have Google as their default search
+    engine (unmodified version of Google), have search suggest enabled, are
+    signed-in and syncing without a custom passphrase, and don't have an
+    incognito window open.  There are other criteria too.  Recorded on focus in
+    the omnibox if there is default search provider and we've constructed a
+    suggest URL.
+
+    Some additional guidelines: if an incognito window is open, all focus events
+    will go into the &quot;generally ineligible&quot; bucket. Likewise, if the
+    current page is a search results page, we don't allow contextual suggestions
+    either so focus events on those pages go in the &quot;generally
+    ineligible&quot; bucket.  The difference between &quot;eligible&quot; and
+    &quot;generally eligible but not this time&quot; depends only the properties
+    of the current URL.
+
+    Recorded regardless of whether contextual or non-contextual zero suggest is
+    currently enabled on the user's platform.  However, if zero suggest (in all
+    forms) is entirely disabled, the user will be perpetually ineligible.
+  </summary>
+</histogram>
+
+<histogram name="Omnibox.ZeroSuggest.Eligible.OnProfileOpen"
+    enum="BooleanSupported">
+  <owner>mpearson@chromium.org</owner>
+  <summary>
+    Whether the user has settings configured so that the current page URL could
+    be sent to the suggest server to request contextual suggestions.  For
+    example, this is only supported for users who have Google as their default
+    search engine (unmodified version of Google), have search suggest enabled,
+    and are signed-in and syncing without a custom passphrase.  There are other
+    criteria too.  Recorded on profile open.  Note that opening an incognito
+    window (if none are currently open under the given profile) counts as
+    opening a new profile.
+
+    Some additional guidelines: unlike Omnibox.ZeroSuggest.Eligible.OnFocus,
+    because this is recorded on profile open, users cannot be declared
+    ineligible because they have an incognito window open (it's impossible to
+    have an incognito window open for a given profile at the time of profile
+    open) and also cannot be declared ineligible because the user is viewing a
+    search results page.  (We test this on-profile-open using an arbitrary URL.)
+
+    Recorded regardless of whether contextual or non-contextual zero suggest is
+    currently enabled on the user's platform.  However, if zero suggest (in all
+    forms) is entirely disabled, the user will be perpetually ineligible.
+  </summary>
+</histogram>
+
 <histogram name="Omnibox.ZeroSuggest.MostVisitedResultsCounterfactual">
   <owner>hfung@chromium.org</owner>
   <summary>
@@ -44219,6 +44273,42 @@
   </summary>
 </histogram>
 
+<histogram name="OSX.KeychainReauthorizeIfNeeded" units="count">
+  <owner>kerrnel@chromium.org</owner>
+  <owner>mark@chromium.org</owner>
+  <summary>
+    The number of previous times that the keychain reauthorization did not
+    complete, when run during the main browser launch.
+  </summary>
+</histogram>
+
+<histogram name="OSX.KeychainReauthorizeIfNeededAtUpdate" units="count">
+  <owner>kerrnel@chromium.org</owner>
+  <owner>mark@chromium.org</owner>
+  <summary>
+    The number of previous times that the keychain reauthorization did not
+    complete, when run at update time.
+  </summary>
+</histogram>
+
+<histogram name="OSX.KeychainReauthorizeIfNeededAtUpdateSuccess" units="count">
+  <owner>kerrnel@chromium.org</owner>
+  <owner>mark@chromium.org</owner>
+  <summary>
+    How many times the keychain reauthorization ran before finally succeeding,
+    when run at update time.
+  </summary>
+</histogram>
+
+<histogram name="OSX.KeychainReauthorizeIfNeededSuccess" units="count">
+  <owner>kerrnel@chromium.org</owner>
+  <owner>mark@chromium.org</owner>
+  <summary>
+    How many times the keychain reauthorization ran before finally succeeding,
+    when run during the main browser launch.
+  </summary>
+</histogram>
+
 <histogram name="OSX.RendererHost.SurfaceWaitTime" units="ms">
   <obsolete>
     Deprecated as of 11/2015.
@@ -113763,6 +113853,21 @@
   </int>
 </enum>
 
+<enum name="ZeroSuggestEligibleOnFocus" type="int">
+  <int value="0" label="Eligible">
+    URL can be currently sent to the suggest server.
+  </int>
+  <int value="1"
+      label="Generally eligible in current context but particular URL
+             ineligible">
+    URL cannot be sent to the suggest server but another URL would be eligible
+    at this time.
+  </int>
+  <int value="2" label="Generally ineligible in current context">
+    No URL can be sent to the suggest server at this time.
+  </int>
+</enum>
+
 </enums>
 
 <!-- Histogram suffixes list -->
@@ -115286,7 +115391,13 @@
   <suffix name="Autofill"/>
   <suffix name="Policy"/>
   <suffix name="SpellChecker"/>
-  <suffix name="NTPSnippets"/>
+  <suffix name="NTPSnippets">
+    <obsolete>
+      Deprecated March 2017
+    </obsolete>
+  </suffix>
+  <suffix name="NTPSnippetsSuggestions"/>
+  <suffix name="NTPSnippetsThumbnails"/>
   <affected-histogram name="DataUse.MessageSize"/>
 </histogram_suffixes>
 
@@ -115975,7 +116086,7 @@
   <affected-histogram name="Renderer4.LoadType"/>
 </histogram_suffixes>
 
-<histogram_suffixes name="FirstUserActionTypes">
+<histogram_suffixes name="FirstUserActionTypes" separator=".">
   <suffix name="Backgrounded" label="The user sent Chrome to the background"/>
   <suffix name="Continuation"
       label="The user continued the task from the last time they used the app"/>
diff --git a/ui/base/webui/OWNERS b/ui/base/webui/OWNERS
index 262db99..8624e36 100644
--- a/ui/base/webui/OWNERS
+++ b/ui/base/webui/OWNERS
@@ -1,2 +1,4 @@
 dbeam@chromium.org
 estade@chromium.org
+
+# COMPONENT: UI>Browser>WebUI
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index ba2ed35..38765fc 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -677,7 +677,10 @@
   }
 
   if (!is_android && !is_ios) {
-    sources += [ "render_text_unittest.cc" ]
+    sources += [
+      "paint_vector_icon_unittest.cc",
+      "render_text_unittest.cc",
+    ]
   }
 
   # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
diff --git a/ui/gfx/color_transform.cc b/ui/gfx/color_transform.cc
index 994c4af..4401ce5 100644
--- a/ui/gfx/color_transform.cc
+++ b/ui/gfx/color_transform.cc
@@ -8,6 +8,7 @@
 #include <cmath>
 #include <list>
 #include <memory>
+#include <sstream>
 
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
@@ -35,8 +36,17 @@
 
 namespace {
 
+void InitStringStream(std::stringstream* ss) {
+  ss->imbue(std::locale::classic());
+  ss->precision(8);
+  *ss << std::scientific;
+}
+
 std::string Str(float f) {
-  return base::StringPrintf("%+1.8e", f);
+  std::stringstream ss;
+  InitStringStream(&ss);
+  ss << f;
+  return ss.str();
 }
 
 // Helper for scoped QCMS profiles.
@@ -52,7 +62,7 @@
 Transform Invert(const Transform& t) {
   Transform ret = t;
   if (!t.GetInverse(&ret)) {
-    LOG(ERROR) << "Inverse should alsways be possible.";
+    LOG(ERROR) << "Inverse should always be possible.";
   }
   return ret;
 }
@@ -259,7 +269,7 @@
   virtual bool IsNull() { return false; }
   virtual void Transform(ColorTransform::TriStim* color, size_t num) const = 0;
   virtual bool CanAppendShaderSource() { return false; }
-  virtual void AppendShaderSource(std::string* result) { NOTREACHED(); }
+  virtual void AppendShaderSource(std::stringstream* result) { NOTREACHED(); }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ColorTransformStep);
@@ -300,19 +310,13 @@
   gfx::ColorSpace dst_;
 };
 
-#define SRC(...)                                                     \
-  do {                                                               \
-    *result += std::string("  ") + base::StringPrintf(__VA_ARGS__) + \
-               std::string("\n");                                    \
-  } while (0)
-
 class ColorTransformNull : public ColorTransformStep {
  public:
   ColorTransformNull* GetNull() override { return this; }
   bool IsNull() override { return true; }
   void Transform(ColorTransform::TriStim* color, size_t num) const override {}
   bool CanAppendShaderSource() override { return true; }
-  void AppendShaderSource(std::string* result) override {}
+  void AppendShaderSource(std::stringstream* result) override {}
 };
 
 class ColorTransformMatrix : public ColorTransformStep {
@@ -341,16 +345,24 @@
 
   bool CanAppendShaderSource() override { return true; }
 
-  void AppendShaderSource(std::string* result) override {
+  void AppendShaderSource(std::stringstream* result) override {
     const SkMatrix44& m = matrix_.matrix();
-    SRC("color = mat3(%+1.8e, %+1.8e, %+1.8e,",  // column 1
-        m.get(0, 0), m.get(1, 0), m.get(2, 0));
-    SRC("             %+1.8e, %+1.8e, %+1.8e,",  // column 2
-        m.get(0, 1), m.get(1, 1), m.get(2, 1));
-    SRC("             %+1.8e, %+1.8e, %+1.8e) * color;",  // column 3
-        m.get(0, 2), m.get(1, 2), m.get(2, 2));
-    SRC("color = vec3(%+1.8e, %+1.8e, %+1.8e) + color;",  // column 4
-        m.get(0, 3), m.get(1, 3), m.get(2, 3));
+    *result << "  color = mat3(";
+    *result << m.get(0, 0) << ", " << m.get(1, 0) << ", " << m.get(2, 0) << ",";
+    *result << std::endl;
+    *result << "               ";
+    *result << m.get(0, 1) << ", " << m.get(1, 1) << ", " << m.get(2, 1) << ",";
+    *result << std::endl;
+    *result << "               ";
+    *result << m.get(0, 2) << ", " << m.get(1, 2) << ", " << m.get(2, 2) << ")";
+    *result << " * color;" << std::endl;
+
+    // Only print the translational component if it isn't the identity.
+    if (m.get(0, 3) != 0.f || m.get(1, 3) != 0.f || m.get(2, 3) != 0.f) {
+      *result << "  color += vec3(";
+      *result << m.get(0, 3) << ", " << m.get(1, 3) << ", " << m.get(2, 3);
+      *result << ");" << std::endl;
+    }
   }
 
  private:
@@ -393,7 +405,7 @@
 
   bool CanAppendShaderSource() override { return true; }
 
-  void AppendShaderSourceChannel(std::string* result, const char* value) {
+  void AppendShaderSourceChannel(std::stringstream* result, const char* value) {
     const float kEpsilon = 1.f / 1024.f;
 
     // Construct the linear segment
@@ -421,16 +433,16 @@
 
     // Add both parts, skpping the if clause if possible.
     if (fn_.fD > kEpsilon) {
-      SRC("if (%s < %f)", value, fn_.fD);
-      SRC("  %s = %s;", value, linear.c_str());
-      SRC("else");
-      SRC("  %s = %s;", value, nonlinear.c_str());
+      *result << "  if (" << value << " < " << Str(fn_.fD) << ")" << std::endl;
+      *result << "    " << value << " = " << linear << ";" << std::endl;
+      *result << "  else" << std::endl;
+      *result << "    " << value << " = " << nonlinear << ";" << std::endl;
     } else {
-      SRC("%s = %s;", value, nonlinear.c_str());
+      *result << "  " << value << " = " << nonlinear << ";" << std::endl;
     }
   }
 
-  void AppendShaderSource(std::string* result) override {
+  void AppendShaderSource(std::stringstream* result) override {
     // Append the transfer function for each channel.
     AppendShaderSourceChannel(result, "color.r");
     AppendShaderSourceChannel(result, "color.g");
@@ -816,13 +828,14 @@
 }
 
 std::string ColorTransformInternal::GetShaderSource() const {
-  std::string result;
-  result += "vec3 DoColorConversion(vec3 color) {\n";
+  std::stringstream result;
+  InitStringStream(&result);
+  result << "vec3 DoColorConversion(vec3 color) {" << std::endl;
   for (const auto& step : steps_)
     step->AppendShaderSource(&result);
-  result += "  return color;\n";
-  result += "}\n";
-  return result;
+  result << "  return color;" << std::endl;
+  result << "}" << std::endl;
+  return result.str();
 }
 
 bool ColorTransformInternal::CanGetShaderSource() const {
diff --git a/ui/gfx/color_transform_unittest.cc b/ui/gfx/color_transform_unittest.cc
index 09d5dce0..6c223bca 100644
--- a/ui/gfx/color_transform_unittest.cc
+++ b/ui/gfx/color_transform_unittest.cc
@@ -388,36 +388,33 @@
           ->GetShaderSource();
   std::string expected =
       "vec3 DoColorConversion(vec3 color) {\n"
-      "  color = mat3(+1.16438353e+00, +1.16438353e+00, +1.16438353e+00,\n"
-      "               -2.28029018e-09, -2.13248596e-01, +2.11240172e+00,\n"
-      "               +1.79274118e+00, -5.32909274e-01, -5.96049432e-10)"
-      " * color;\n"
-      "  color = vec3(-9.69429970e-01, +3.00019622e-01, -1.12926030e+00)"
-      " + color;\n"
-      "  if (color.r < 0.040450)\n"
-      "    color.r = +7.73993805e-02 * color.r;\n"
-      "  else\n"
-      "    color.r = pow(+9.47867334e-01 * color.r + +5.21326549e-02, "
-      "+2.40000010e+00);\n"
-      "  if (color.g < 0.040450)\n"
-      "    color.g = +7.73993805e-02 * color.g;\n"
-      "  else\n"
-      "    color.g = pow(+9.47867334e-01 * color.g + +5.21326549e-02, "
-      "+2.40000010e+00);\n"
-      "  if (color.b < 0.040450)\n"
-      "    color.b = +7.73993805e-02 * color.b;\n"
-      "  else\n"
-      "    color.b = pow(+9.47867334e-01 * color.b + +5.21326549e-02, "
-      "+2.40000010e+00);\n"
-      "  color = mat3(+6.27403915e-01, +6.90973178e-02, +1.63914412e-02,\n"
-      "               +3.29283148e-01, +9.19540286e-01, +8.80132914e-02,\n"
-      "               +4.33131084e-02, +1.13623003e-02, +8.95595253e-01) "
+      "  color = mat3(1.16438353e+00, 1.16438353e+00, 1.16438353e+00,\n"
+      "               -2.28029018e-09, -2.13248596e-01, 2.11240172e+00,\n"
+      "               1.79274118e+00, -5.32909274e-01, -5.96049432e-10) "
       "* color;\n"
-      "  color = vec3(+0.00000000e+00, +0.00000000e+00, +0.00000000e+00) "
-      "+ color;\n"
-      "  color.r = pow(color.r, +3.57142866e-01);\n"
-      "  color.g = pow(color.g, +3.57142866e-01);\n"
-      "  color.b = pow(color.b, +3.57142866e-01);\n"
+      "  color += vec3(-9.69429970e-01, 3.00019622e-01, -1.12926030e+00);\n"
+      "  if (color.r < 4.04499359e-02)\n"
+      "    color.r = 7.73993805e-02 * color.r;\n"
+      "  else\n"
+      "    color.r = pow(9.47867334e-01 * color.r + 5.21326549e-02, "
+      "2.40000010e+00);\n"
+      "  if (color.g < 4.04499359e-02)\n"
+      "    color.g = 7.73993805e-02 * color.g;\n"
+      "  else\n"
+      "    color.g = pow(9.47867334e-01 * color.g + 5.21326549e-02, "
+      "2.40000010e+00);\n"
+      "  if (color.b < 4.04499359e-02)\n"
+      "    color.b = 7.73993805e-02 * color.b;\n"
+      "  else\n"
+      "    color.b = pow(9.47867334e-01 * color.b + 5.21326549e-02, "
+      "2.40000010e+00);\n"
+      "  color = mat3(6.27403915e-01, 6.90973178e-02, 1.63914412e-02,\n"
+      "               3.29283148e-01, 9.19540286e-01, 8.80132914e-02,\n"
+      "               4.33131084e-02, 1.13623003e-02, 8.95595253e-01) "
+      "* color;\n"
+      "  color.r = pow(color.r, 3.57142866e-01);\n"
+      "  color.g = pow(color.g, 3.57142866e-01);\n"
+      "  color.b = pow(color.b, 3.57142866e-01);\n"
       "  return color;\n"
       "}\n";
   EXPECT_EQ(source, expected);
diff --git a/ui/gfx/paint_vector_icon.cc b/ui/gfx/paint_vector_icon.cc
index 7d1601dc..2f5c762 100644
--- a/ui/gfx/paint_vector_icon.cc
+++ b/ui/gfx/paint_vector_icon.cc
@@ -148,6 +148,13 @@
       }
 
       case R_MOVE_TO: {
+        if (previous_command_type == CLOSE) {
+          // This triggers injectMoveToIfNeeded() so that the next subpath will
+          // start at the correct place. See
+          // [ https://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand ].
+          path.rLineTo(0, 0);
+        }
+
         SkScalar x = path_elements[++i].arg;
         SkScalar y = path_elements[++i].arg;
         path.rMoveTo(x, y);
diff --git a/ui/gfx/paint_vector_icon_unittest.cc b/ui/gfx/paint_vector_icon_unittest.cc
new file mode 100644
index 0000000..6786bf12
--- /dev/null
+++ b/ui/gfx/paint_vector_icon_unittest.cc
@@ -0,0 +1,63 @@
+// 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 "ui/gfx/paint_vector_icon.h"
+
+#include <gtest/gtest.h>
+#include <vector>
+
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkPath.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/vector_icon_types.h"
+
+namespace gfx {
+
+namespace {
+
+class MockCanvas : public SkCanvas {
+ public:
+  MockCanvas(int width, int height) : SkCanvas(width, height) {}
+
+  // SkCanvas overrides:
+  void onDrawPath(const SkPath& path, const SkPaint& paint) override {
+    paths_.push_back(path);
+  }
+
+  const std::vector<SkPath>& paths() const { return paths_; }
+
+ private:
+  std::vector<SkPath> paths_;
+
+  DISALLOW_COPY_AND_ASSIGN(MockCanvas);
+};
+
+// Tests that a relative move to command (R_MOVE_TO) after a close command
+// (CLOSE) uses the correct starting point. See crbug.com/697497
+TEST(VectorIconTest, RelativeMoveToAfterClose) {
+  MockCanvas mock(100, 100);
+  Canvas canvas(&mock, 1.0f);
+
+  const PathElement elements[] = {
+      MOVE_TO, 4, 5,
+      LINE_TO, 10, 11,
+      CLOSE,
+      // This move should use (4, 5) as the start point rather than (10, 11).
+      R_MOVE_TO, 20, 21,
+      R_LINE_TO, 50, 51,
+      END,
+  };
+  const VectorIcon icon = {elements, nullptr};
+
+  PaintVectorIcon(&canvas, icon, 100, SK_ColorMAGENTA);
+  ASSERT_EQ(1U, mock.paths().size());
+  SkPoint last_point;
+  EXPECT_TRUE(mock.paths()[0].getLastPt(&last_point));
+  EXPECT_EQ(SkIntToScalar(74), last_point.x());
+  EXPECT_EQ(SkIntToScalar(77), last_point.y());
+}
+
+}  // namespace
+
+}  // namespace gfx
diff --git a/ui/gl/init/gl_factory_ozone.cc b/ui/gl/init/gl_factory_ozone.cc
index e47eaae..5d740f2 100644
--- a/ui/gl/init/gl_factory_ozone.cc
+++ b/ui/gl/init/gl_factory_ozone.cc
@@ -7,57 +7,16 @@
 #include "base/logging.h"
 #include "base/trace_event/trace_event.h"
 #include "ui/gl/gl_context.h"
-#include "ui/gl/gl_context_osmesa.h"
 #include "ui/gl/gl_context_stub.h"
 #include "ui/gl/gl_implementation.h"
 #include "ui/gl/gl_share_group.h"
 #include "ui/gl/gl_surface.h"
-#include "ui/gl/gl_surface_osmesa.h"
 #include "ui/gl/gl_surface_stub.h"
 #include "ui/gl/init/ozone_util.h"
 
 namespace gl {
 namespace init {
 
-namespace {
-
-bool HasDefaultImplementation(GLImplementation impl) {
-  return impl == kGLImplementationOSMesaGL || impl == kGLImplementationMockGL ||
-         impl == kGLImplementationStubGL;
-}
-
-scoped_refptr<GLSurface> CreateDefaultViewGLSurface(
-    gfx::AcceleratedWidget window) {
-  switch (GetGLImplementation()) {
-    case kGLImplementationOSMesaGL:
-      return InitializeGLSurface(new GLSurfaceOSMesaHeadless());
-    case kGLImplementationMockGL:
-    case kGLImplementationStubGL:
-      return InitializeGLSurface(new GLSurfaceStub());
-    default:
-      NOTREACHED();
-  }
-  return nullptr;
-}
-
-scoped_refptr<GLSurface> CreateDefaultOffscreenGLSurface(
-    const gfx::Size& size) {
-  switch (GetGLImplementation()) {
-    case kGLImplementationOSMesaGL:
-      return InitializeGLSurface(
-          new GLSurfaceOSMesa(
-              GLSurfaceFormat(GLSurfaceFormat::PIXEL_LAYOUT_BGRA), size));
-    case kGLImplementationMockGL:
-    case kGLImplementationStubGL:
-      return InitializeGLSurface(new GLSurfaceStub);
-    default:
-      NOTREACHED();
-  }
-  return nullptr;
-}
-
-}  // namespace
-
 std::vector<GLImplementation> GetAllowedGLImplementations() {
   ui::OzonePlatform::InitializeForGPU();
   return GetSurfaceFactoryOzone()->GetAllowedGLImplementations();
@@ -89,9 +48,6 @@
       stub_context->SetUseStubApi(true);
       return stub_context;
     }
-    case kGLImplementationOSMesaGL:
-      return InitializeGLContext(new GLContextOSMesa(share_group),
-                                 compatible_surface, attribs);
     default:
       NOTREACHED();
   }
@@ -104,8 +60,13 @@
   if (HasGLOzone())
     return GetGLOzone()->CreateViewGLSurface(window);
 
-  if (HasDefaultImplementation(GetGLImplementation()))
-    return CreateDefaultViewGLSurface(window);
+  switch (GetGLImplementation()) {
+    case kGLImplementationMockGL:
+    case kGLImplementationStubGL:
+      return InitializeGLSurface(new GLSurfaceStub());
+    default:
+      NOTREACHED();
+  }
 
   return nullptr;
 }
@@ -132,8 +93,13 @@
   if (HasGLOzone())
     return GetGLOzone()->CreateOffscreenGLSurface(size);
 
-  if (HasDefaultImplementation(GetGLImplementation()))
-    return CreateDefaultOffscreenGLSurface(size);
+  switch (GetGLImplementation()) {
+    case kGLImplementationMockGL:
+    case kGLImplementationStubGL:
+      return InitializeGLSurface(new GLSurfaceStub);
+    default:
+      NOTREACHED();
+  }
 
   return nullptr;
 }
diff --git a/ui/gl/init/gl_initializer_ozone.cc b/ui/gl/init/gl_initializer_ozone.cc
index 6e5fc67..a42e220e2 100644
--- a/ui/gl/init/gl_initializer_ozone.cc
+++ b/ui/gl/init/gl_initializer_ozone.cc
@@ -7,8 +7,6 @@
 #include "base/logging.h"
 #include "ui/gl/gl_bindings.h"
 #include "ui/gl/gl_gl_api_implementation.h"
-#include "ui/gl/gl_implementation_osmesa.h"
-#include "ui/gl/gl_osmesa_api_implementation.h"
 #include "ui/gl/gl_surface.h"
 #include "ui/gl/init/ozone_util.h"
 
@@ -20,13 +18,13 @@
     return GetGLOzone()->InitializeGLOneOffPlatform();
 
   switch (GetGLImplementation()) {
-    case kGLImplementationOSMesaGL:
     case kGLImplementationMockGL:
     case kGLImplementationStubGL:
       return true;
     default:
-      return false;
+      NOTREACHED();
   }
+  return false;
 }
 
 bool InitializeStaticGLBindings(GLImplementation implementation) {
@@ -41,8 +39,6 @@
   }
 
   switch (implementation) {
-    case kGLImplementationOSMesaGL:
-      return InitializeStaticGLBindingsOSMesaGL();
     case kGLImplementationMockGL:
     case kGLImplementationStubGL:
       SetGLImplementation(implementation);
@@ -62,7 +58,6 @@
   }
 
   InitializeDebugGLBindingsGL();
-  InitializeDebugGLBindingsOSMESA();
 }
 
 void ShutdownGLPlatform() {
@@ -72,7 +67,6 @@
   }
 
   ClearBindingsGL();
-  ClearBindingsOSMESA();
 }
 
 }  // namespace init
diff --git a/ui/ozone/common/BUILD.gn b/ui/ozone/common/BUILD.gn
index c98ff2a..67e65754 100644
--- a/ui/ozone/common/BUILD.gn
+++ b/ui/ozone/common/BUILD.gn
@@ -16,6 +16,8 @@
     "egl_util.h",
     "gl_ozone_egl.cc",
     "gl_ozone_egl.h",
+    "gl_ozone_osmesa.cc",
+    "gl_ozone_osmesa.h",
     "gpu/ozone_gpu_message_generator.cc",
     "gpu/ozone_gpu_message_generator.h",
     "gpu/ozone_gpu_message_params.cc",
diff --git a/ui/ozone/common/gl_ozone_osmesa.cc b/ui/ozone/common/gl_ozone_osmesa.cc
new file mode 100644
index 0000000..2ee4dbb
--- /dev/null
+++ b/ui/ozone/common/gl_ozone_osmesa.cc
@@ -0,0 +1,72 @@
+// 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 "ui/ozone/common/gl_ozone_osmesa.h"
+
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_context_osmesa.h"
+#include "ui/gl/gl_gl_api_implementation.h"
+#include "ui/gl/gl_implementation_osmesa.h"
+#include "ui/gl/gl_osmesa_api_implementation.h"
+#include "ui/gl/gl_share_group.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_surface_format.h"
+#include "ui/gl/gl_surface_osmesa.h"
+
+namespace ui {
+
+GLOzoneOSMesa::GLOzoneOSMesa() {}
+
+GLOzoneOSMesa::~GLOzoneOSMesa() {}
+
+bool GLOzoneOSMesa::InitializeGLOneOffPlatform() {
+  return true;
+}
+
+bool GLOzoneOSMesa::InitializeStaticGLBindings(
+    gl::GLImplementation implementation) {
+  return gl::InitializeStaticGLBindingsOSMesaGL();
+}
+
+void GLOzoneOSMesa::InitializeDebugGLBindings() {
+  gl::InitializeDebugGLBindingsGL();
+  gl::InitializeDebugGLBindingsOSMESA();
+}
+
+void GLOzoneOSMesa::ShutdownGL() {
+  gl::ClearBindingsGL();
+  gl::ClearBindingsOSMESA();
+}
+
+bool GLOzoneOSMesa::GetGLWindowSystemBindingInfo(
+    gl::GLWindowSystemBindingInfo* info) {
+  return false;
+}
+
+scoped_refptr<gl::GLContext> GLOzoneOSMesa::CreateGLContext(
+    gl::GLShareGroup* share_group,
+    gl::GLSurface* compatible_surface,
+    const gl::GLContextAttribs& attribs) {
+  return gl::InitializeGLContext(new gl::GLContextOSMesa(share_group),
+                                 compatible_surface, attribs);
+}
+
+scoped_refptr<gl::GLSurface> GLOzoneOSMesa::CreateViewGLSurface(
+    gfx::AcceleratedWidget window) {
+  return gl::InitializeGLSurface(new gl::GLSurfaceOSMesaHeadless());
+}
+
+scoped_refptr<gl::GLSurface> GLOzoneOSMesa::CreateSurfacelessViewGLSurface(
+    gfx::AcceleratedWidget window) {
+  return nullptr;
+}
+
+scoped_refptr<gl::GLSurface> GLOzoneOSMesa::CreateOffscreenGLSurface(
+    const gfx::Size& size) {
+  return gl::InitializeGLSurface(
+      new gl::GLSurfaceOSMesa(gl::GLSurfaceFormat::PIXEL_LAYOUT_BGRA, size));
+}
+
+}  // namespace ui
diff --git a/ui/ozone/common/gl_ozone_osmesa.h b/ui/ozone/common/gl_ozone_osmesa.h
new file mode 100644
index 0000000..9ec57ca
--- /dev/null
+++ b/ui/ozone/common/gl_ozone_osmesa.h
@@ -0,0 +1,44 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_OZONE_COMMON_GL_OZONE_OSMESA_H_
+#define UI_OZONE_COMMON_GL_OZONE_OSMESA_H_
+
+#include "base/macros.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/ozone/public/gl_ozone.h"
+
+namespace ui {
+
+// GLOzone implementation that uses OSMesa.
+class GLOzoneOSMesa : public GLOzone {
+ public:
+  GLOzoneOSMesa();
+  ~GLOzoneOSMesa() override;
+
+  // GLOzone:
+  bool InitializeGLOneOffPlatform() override;
+  bool InitializeStaticGLBindings(gl::GLImplementation implementation) override;
+  void InitializeDebugGLBindings() override;
+  void ShutdownGL() override;
+  bool GetGLWindowSystemBindingInfo(
+      gl::GLWindowSystemBindingInfo* info) override;
+  scoped_refptr<gl::GLContext> CreateGLContext(
+      gl::GLShareGroup* share_group,
+      gl::GLSurface* compatible_surface,
+      const gl::GLContextAttribs& attribs) override;
+  scoped_refptr<gl::GLSurface> CreateViewGLSurface(
+      gfx::AcceleratedWidget window) override;
+  scoped_refptr<gl::GLSurface> CreateSurfacelessViewGLSurface(
+      gfx::AcceleratedWidget window) override;
+  scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface(
+      const gfx::Size& size) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(GLOzoneOSMesa);
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_COMMON_GL_OZONE_OSMESA_H_
diff --git a/ui/ozone/platform/cast/surface_factory_cast.cc b/ui/ozone/platform/cast/surface_factory_cast.cc
index 8fca083..5dff4467 100644
--- a/ui/ozone/platform/cast/surface_factory_cast.cc
+++ b/ui/ozone/platform/cast/surface_factory_cast.cc
@@ -13,6 +13,7 @@
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/native_pixmap.h"
 #include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/common/gl_ozone_osmesa.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
 
 namespace ui {
@@ -87,12 +88,16 @@
 
 }  // namespace
 
-SurfaceFactoryCast::SurfaceFactoryCast() {}
+SurfaceFactoryCast::SurfaceFactoryCast() : SurfaceFactoryCast(nullptr) {}
 
 SurfaceFactoryCast::SurfaceFactoryCast(
     std::unique_ptr<chromecast::CastEglPlatform> egl_platform)
-    : egl_implementation_(
-          base::MakeUnique<GLOzoneEglCast>(std::move(egl_platform))) {}
+    : osmesa_implementation_(base::MakeUnique<GLOzoneOSMesa>()) {
+  if (egl_platform) {
+    egl_implementation_ =
+        base::MakeUnique<GLOzoneEglCast>(std::move(egl_platform));
+  }
+}
 
 SurfaceFactoryCast::~SurfaceFactoryCast() {}
 
@@ -109,6 +114,8 @@
   switch (implementation) {
     case gl::kGLImplementationEGLGLES2:
       return egl_implementation_.get();
+    case gl::kGLImplementationOSMesaGL:
+      return osmesa_implementation_.get();
     default:
       return nullptr;
   }
diff --git a/ui/ozone/platform/cast/surface_factory_cast.h b/ui/ozone/platform/cast/surface_factory_cast.h
index 23d1e221..d25688a0 100644
--- a/ui/ozone/platform/cast/surface_factory_cast.h
+++ b/ui/ozone/platform/cast/surface_factory_cast.h
@@ -41,6 +41,7 @@
 
  private:
   std::unique_ptr<GLOzoneEglCast> egl_implementation_;
+  std::unique_ptr<GLOzone> osmesa_implementation_;
 
   DISALLOW_COPY_AND_ASSIGN(SurfaceFactoryCast);
 };
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
index 6abf013..59b1bb5 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.cc
@@ -17,6 +17,7 @@
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/ozone/common/egl_util.h"
 #include "ui/ozone/common/gl_ozone_egl.h"
+#include "ui/ozone/common/gl_ozone_osmesa.h"
 #include "ui/ozone/platform/drm/common/drm_util.h"
 #include "ui/ozone/platform/drm/gpu/drm_thread_proxy.h"
 #include "ui/ozone/platform/drm/gpu/drm_window_proxy.h"
@@ -75,7 +76,9 @@
 }  // namespace
 
 GbmSurfaceFactory::GbmSurfaceFactory(DrmThreadProxy* drm_thread_proxy)
-    : egl_implementation_(new GLOzoneEGLGbm(this, drm_thread_proxy)),
+    : egl_implementation_(
+          base::MakeUnique<GLOzoneEGLGbm>(this, drm_thread_proxy)),
+      osmesa_implementation_(base::MakeUnique<GLOzoneOSMesa>()),
       drm_thread_proxy_(drm_thread_proxy) {}
 
 GbmSurfaceFactory::~GbmSurfaceFactory() {
@@ -104,10 +107,8 @@
 std::vector<gl::GLImplementation>
 GbmSurfaceFactory::GetAllowedGLImplementations() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  std::vector<gl::GLImplementation> impls;
-  impls.push_back(gl::kGLImplementationEGLGLES2);
-  impls.push_back(gl::kGLImplementationOSMesaGL);
-  return impls;
+  return std::vector<gl::GLImplementation>{gl::kGLImplementationEGLGLES2,
+                                           gl::kGLImplementationOSMesaGL};
 }
 
 GLOzone* GbmSurfaceFactory::GetGLOzone(gl::GLImplementation implementation) {
@@ -115,6 +116,8 @@
   switch (implementation) {
     case gl::kGLImplementationEGLGLES2:
       return egl_implementation_.get();
+    case gl::kGLImplementationOSMesaGL:
+      return osmesa_implementation_.get();
     default:
       return nullptr;
   }
diff --git a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
index aaf5054..48f429c 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
+++ b/ui/ozone/platform/drm/gpu/gbm_surface_factory.h
@@ -53,6 +53,7 @@
 
  private:
   std::unique_ptr<GLOzone> egl_implementation_;
+  std::unique_ptr<GLOzone> osmesa_implementation_;
 
   base::ThreadChecker thread_checker_;
 
diff --git a/ui/ozone/platform/headless/headless_surface_factory.cc b/ui/ozone/platform/headless/headless_surface_factory.cc
index 73f4cfb..11222a88f 100644
--- a/ui/ozone/platform/headless/headless_surface_factory.cc
+++ b/ui/ozone/platform/headless/headless_surface_factory.cc
@@ -16,6 +16,7 @@
 #include "ui/gfx/native_pixmap.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/gfx/vsync_provider.h"
+#include "ui/ozone/common/gl_ozone_osmesa.h"
 #include "ui/ozone/platform/headless/headless_window.h"
 #include "ui/ozone/platform/headless/headless_window_manager.h"
 #include "ui/ozone/public/surface_ozone_canvas.h"
@@ -111,10 +112,26 @@
 
 HeadlessSurfaceFactory::HeadlessSurfaceFactory(
     HeadlessWindowManager* window_manager)
-    : window_manager_(window_manager) {}
+    : window_manager_(window_manager),
+      osmesa_implementation_(base::MakeUnique<GLOzoneOSMesa>()) {}
 
 HeadlessSurfaceFactory::~HeadlessSurfaceFactory() {}
 
+std::vector<gl::GLImplementation>
+HeadlessSurfaceFactory::GetAllowedGLImplementations() {
+  return std::vector<gl::GLImplementation>{gl::kGLImplementationOSMesaGL};
+}
+
+GLOzone* HeadlessSurfaceFactory::GetGLOzone(
+    gl::GLImplementation implementation) {
+  switch (implementation) {
+    case gl::kGLImplementationOSMesaGL:
+      return osmesa_implementation_.get();
+    default:
+      return nullptr;
+  }
+}
+
 std::unique_ptr<SurfaceOzoneCanvas>
 HeadlessSurfaceFactory::CreateCanvasForWidget(gfx::AcceleratedWidget widget) {
   HeadlessWindow* window = window_manager_->GetWindow(widget);
diff --git a/ui/ozone/platform/headless/headless_surface_factory.h b/ui/ozone/platform/headless/headless_surface_factory.h
index dfe3d3ec..f274882 100644
--- a/ui/ozone/platform/headless/headless_surface_factory.h
+++ b/ui/ozone/platform/headless/headless_surface_factory.h
@@ -5,7 +5,11 @@
 #ifndef UI_OZONE_PLATFORM_HEADLESS_HEADLESS_SURFACE_FACTORY_H_
 #define UI_OZONE_PLATFORM_HEADLESS_HEADLESS_SURFACE_FACTORY_H_
 
+#include <memory>
+#include <vector>
+
 #include "base/macros.h"
+#include "ui/ozone/public/gl_ozone.h"
 #include "ui/ozone/public/surface_factory_ozone.h"
 
 namespace ui {
@@ -19,6 +23,8 @@
   ~HeadlessSurfaceFactory() override;
 
   // SurfaceFactoryOzone:
+  std::vector<gl::GLImplementation> GetAllowedGLImplementations() override;
+  GLOzone* GetGLOzone(gl::GLImplementation implementation) override;
   std::unique_ptr<SurfaceOzoneCanvas> CreateCanvasForWidget(
       gfx::AcceleratedWidget w) override;
   scoped_refptr<NativePixmap> CreateNativePixmap(
@@ -30,6 +36,8 @@
  private:
   HeadlessWindowManager* window_manager_;
 
+  std::unique_ptr<GLOzone> osmesa_implementation_;
+
   DISALLOW_COPY_AND_ASSIGN(HeadlessSurfaceFactory);
 };
 
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory.cc b/ui/ozone/platform/wayland/wayland_surface_factory.cc
index 46752c9..b5f365b4 100644
--- a/ui/ozone/platform/wayland/wayland_surface_factory.cc
+++ b/ui/ozone/platform/wayland/wayland_surface_factory.cc
@@ -14,6 +14,7 @@
 #include "ui/gfx/vsync_provider.h"
 #include "ui/ozone/common/egl_util.h"
 #include "ui/ozone/common/gl_ozone_egl.h"
+#include "ui/ozone/common/gl_ozone_osmesa.h"
 #include "ui/ozone/platform/wayland/gl_surface_wayland.h"
 #include "ui/ozone/platform/wayland/wayland_connection.h"
 #include "ui/ozone/platform/wayland/wayland_object.h"
@@ -128,7 +129,8 @@
 
 class GLOzoneEGLWayland : public GLOzoneEGL {
  public:
-  GLOzoneEGLWayland(WaylandConnection* connection) : connection_(connection) {}
+  explicit GLOzoneEGLWayland(WaylandConnection* connection)
+      : connection_(connection) {}
   ~GLOzoneEGLWayland() override {}
 
   scoped_refptr<gl::GLSurface> CreateViewGLSurface(
@@ -182,9 +184,10 @@
 }  // namespace
 
 WaylandSurfaceFactory::WaylandSurfaceFactory(WaylandConnection* connection)
-    : connection_(connection) {
+    : connection_(connection),
+      osmesa_implementation_(base::MakeUnique<GLOzoneOSMesa>()) {
   if (connection_)
-    egl_implementation_.reset(new GLOzoneEGLWayland(connection_));
+    egl_implementation_ = base::MakeUnique<GLOzoneEGLWayland>(connection_);
 }
 
 WaylandSurfaceFactory::~WaylandSurfaceFactory() {}
@@ -201,7 +204,9 @@
 std::vector<gl::GLImplementation>
 WaylandSurfaceFactory::GetAllowedGLImplementations() {
   std::vector<gl::GLImplementation> impls;
-  impls.push_back(gl::kGLImplementationEGLGLES2);
+  if (egl_implementation_)
+    impls.push_back(gl::kGLImplementationEGLGLES2);
+  impls.push_back(gl::kGLImplementationOSMesaGL);
   return impls;
 }
 
@@ -210,6 +215,8 @@
   switch (implementation) {
     case gl::kGLImplementationEGLGLES2:
       return egl_implementation_.get();
+    case gl::kGLImplementationOSMesaGL:
+      return osmesa_implementation_.get();
     default:
       return nullptr;
   }
diff --git a/ui/ozone/platform/wayland/wayland_surface_factory.h b/ui/ozone/platform/wayland/wayland_surface_factory.h
index c2a439c..1ae4d8c 100644
--- a/ui/ozone/platform/wayland/wayland_surface_factory.h
+++ b/ui/ozone/platform/wayland/wayland_surface_factory.h
@@ -38,6 +38,7 @@
  private:
   WaylandConnection* connection_;
   std::unique_ptr<GLOzone> egl_implementation_;
+  std::unique_ptr<GLOzone> osmesa_implementation_;
 
   DISALLOW_COPY_AND_ASSIGN(WaylandSurfaceFactory);
 };
diff --git a/ui/ozone/platform/x11/x11_surface_factory.cc b/ui/ozone/platform/x11/x11_surface_factory.cc
index bb92d7e..27570cc 100644
--- a/ui/ozone/platform/x11/x11_surface_factory.cc
+++ b/ui/ozone/platform/x11/x11_surface_factory.cc
@@ -6,12 +6,14 @@
 
 #include <X11/Xlib.h>
 
+#include "base/memory/ptr_util.h"
 #include "third_party/khronos/EGL/egl.h"
 #include "ui/gfx/x/x11_types.h"
 #include "ui/gl/egl_util.h"
 #include "ui/gl/gl_surface_egl.h"
 #include "ui/ozone/common/egl_util.h"
 #include "ui/ozone/common/gl_ozone_egl.h"
+#include "ui/ozone/common/gl_ozone_osmesa.h"
 #include "ui/ozone/platform/x11/gl_ozone_glx.h"
 
 namespace ui {
@@ -149,21 +151,19 @@
 
 }  // namespace
 
-X11SurfaceFactory::X11SurfaceFactory() {
-  glx_implementation_.reset(new GLOzoneGLX());
-  egl_implementation_.reset(new GLOzoneEGLX11());
-}
+X11SurfaceFactory::X11SurfaceFactory()
+    : glx_implementation_(base::MakeUnique<GLOzoneGLX>()),
+      egl_implementation_(base::MakeUnique<GLOzoneEGLX11>()),
+      osmesa_implementation_(base::MakeUnique<GLOzoneOSMesa>()) {}
 
 X11SurfaceFactory::~X11SurfaceFactory() {}
 
 std::vector<gl::GLImplementation>
 X11SurfaceFactory::GetAllowedGLImplementations() {
-  std::vector<gl::GLImplementation> impls;
-  impls.push_back(gl::kGLImplementationEGLGLES2);
   // DesktopGL (GLX) should be the first option when crbug.com/646982 is fixed.
-  impls.push_back(gl::kGLImplementationDesktopGL);
-  impls.push_back(gl::kGLImplementationOSMesaGL);
-  return impls;
+  return std::vector<gl::GLImplementation>{gl::kGLImplementationEGLGLES2,
+                                           gl::kGLImplementationDesktopGL,
+                                           gl::kGLImplementationOSMesaGL};
 }
 
 GLOzone* X11SurfaceFactory::GetGLOzone(gl::GLImplementation implementation) {
@@ -172,6 +172,8 @@
       return glx_implementation_.get();
     case gl::kGLImplementationEGLGLES2:
       return egl_implementation_.get();
+    case gl::kGLImplementationOSMesaGL:
+      return osmesa_implementation_.get();
     default:
       return nullptr;
   }
diff --git a/ui/ozone/platform/x11/x11_surface_factory.h b/ui/ozone/platform/x11/x11_surface_factory.h
index 77bee714..4dc6dc0 100644
--- a/ui/ozone/platform/x11/x11_surface_factory.h
+++ b/ui/ozone/platform/x11/x11_surface_factory.h
@@ -28,6 +28,7 @@
  private:
   std::unique_ptr<GLOzone> glx_implementation_;
   std::unique_ptr<GLOzone> egl_implementation_;
+  std::unique_ptr<GLOzone> osmesa_implementation_;
 
   DISALLOW_COPY_AND_ASSIGN(X11SurfaceFactory);
 };
diff --git a/ui/ozone/public/surface_factory_ozone.cc b/ui/ozone/public/surface_factory_ozone.cc
index 4376eea..94d2dda 100644
--- a/ui/ozone/public/surface_factory_ozone.cc
+++ b/ui/ozone/public/surface_factory_ozone.cc
@@ -18,7 +18,7 @@
 
 std::vector<gl::GLImplementation>
 SurfaceFactoryOzone::GetAllowedGLImplementations() {
-  return std::vector<gl::GLImplementation>{gl::kGLImplementationOSMesaGL};
+  return std::vector<gl::GLImplementation>();
 }
 
 GLOzone* SurfaceFactoryOzone::GetGLOzone(gl::GLImplementation implementation) {
diff --git a/ui/webui/OWNERS b/ui/webui/OWNERS
index aa8c525..9fcad090 100644
--- a/ui/webui/OWNERS
+++ b/ui/webui/OWNERS
@@ -9,3 +9,5 @@
 
 # Emeritus
 estade@chromium.org
+
+# COMPONENT: UI>Browser>WebUI