diff --git a/DEPS b/DEPS
index e3c095c..136e8ba 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'e2d4141679805b4c2a711d113f2b7360cb50924c',
+  'skia_revision': '7cf774573cc5bc7e588ed4489d0a4127e9edf0cc',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'd689ef2e187e8755649680d75bb97be04b507daf',
+  'v8_revision': 'f47962efbb797d21e50e9d8e2b74a7e03817c327',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -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': '04a407093c135cdf08644a03c210ae2182869254',
+  'pdfium_revision': 'd0bbccdd32113baf95ae16565c0314166d989638',
   # 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.
diff --git a/chrome/app/theme/default_100_percent/cros/notification_play_store.png b/chrome/app/theme/default_100_percent/cros/notification_play_store.png
index 6c7b7f7c..f7bc2b3 100644
--- a/chrome/app/theme/default_100_percent/cros/notification_play_store.png
+++ b/chrome/app/theme/default_100_percent/cros/notification_play_store.png
Binary files differ
diff --git a/chrome/app/theme/default_200_percent/cros/notification_play_store.png b/chrome/app/theme/default_200_percent/cros/notification_play_store.png
index 03b4891..d8e844d 100644
--- a/chrome/app/theme/default_200_percent/cros/notification_play_store.png
+++ b/chrome/app/theme/default_200_percent/cros/notification_play_store.png
Binary files differ
diff --git a/chrome/browser/resources/.clang-format b/chrome/browser/resources/.clang-format
index 8fd4c4a..d455a85 100644
--- a/chrome/browser/resources/.clang-format
+++ b/chrome/browser/resources/.clang-format
@@ -1,13 +1,8 @@
+# Please keep this file the same as ui/webui/resources/.clang-format.
 BasedOnStyle: Chromium
 
 # Renaming quotes in <include> and <if> break things.
 # For normal JS code, please prefer ' to ".
 JavaScriptQuotes: Leave
 
-AllowShortBlocksOnASingleLine: false
-AllowShortCaseLabelsOnASingleLine: false
 AllowShortFunctionsOnASingleLine: Empty
-AllowShortIfStatementsOnASingleLine: false
-AllowShortLoopsOnASingleLine: false
-SpacesInContainerLiterals: false
-SpacesInSquareBrackets: false
diff --git a/chrome/browser/resources/chromeos/arc_support/icon/48.png b/chrome/browser/resources/chromeos/arc_support/icon/48.png
index 8f6bf825..a36e36a6 100644
--- a/chrome/browser/resources/chromeos/arc_support/icon/48.png
+++ b/chrome/browser/resources/chromeos/arc_support/icon/48.png
Binary files differ
diff --git a/chrome/browser/resources/chromeos/arc_support/icon/96.png b/chrome/browser/resources/chromeos/arc_support/icon/96.png
index 1014993..81aebf0f 100644
--- a/chrome/browser/resources/chromeos/arc_support/icon/96.png
+++ b/chrome/browser/resources/chromeos/arc_support/icon/96.png
Binary files differ
diff --git a/chrome/browser/ui/app_list/arc/arc_app_icon.cc b/chrome/browser/ui/app_list/arc/arc_app_icon.cc
index c5df2c4..6f1bbc7 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_icon.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_icon.cc
@@ -127,15 +127,17 @@
 
 gfx::ImageSkiaRep ArcAppIcon::Source::GetImageForScale(float scale) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (host_)
-    host_->LoadForScaleFactor(ui::GetSupportedScaleFactor(scale));
 
   // Host loads icon asynchronously, so use default icon so far.
   int resource_id;
   if (host_ && host_->app_id() == arc::kPlayStoreAppId) {
+    // Don't request icon from Android side. Use overloaded Chrome icon for Play
+    // Store that is adopted according Chrome style.
     resource_id = scale >= 1.5f ?
         IDR_ARC_SUPPORT_ICON_96 : IDR_ARC_SUPPORT_ICON_48;
   } else {
+    if (host_)
+      host_->LoadForScaleFactor(ui::GetSupportedScaleFactor(scale));
     resource_id = IDR_APP_DEFAULT_ICON;
   }
 
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h
index 71c8865..1e3ca73d 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.h
@@ -19,10 +19,10 @@
 // a button-like token on the left-hand side).
 @interface AutocompleteTextFieldCell : StyledTextFieldCell {
  @private
-  // Decorations which live to the left and right of the text, ordered
+  // Decorations which live before and after the text, ordered
   // from outside in.  Decorations are owned by |LocationBarViewMac|.
-  std::vector<LocationBarDecoration*> leftDecorations_;
-  std::vector<LocationBarDecoration*> rightDecorations_;
+  std::vector<LocationBarDecoration*> leadingDecorations_;
+  std::vector<LocationBarDecoration*> trailingDecorations_;
 
   // The decoration associated to the current dragging session.
   LocationBarDecoration* draggedDecoration_;
@@ -56,13 +56,13 @@
 // Clear |leftDecorations_| and |rightDecorations_|.
 - (void)clearDecorations;
 
-// Add a new left-side decoration to the right of the existing
-// left-side decorations.
-- (void)addLeftDecoration:(LocationBarDecoration*)decoration;
+// Add a new leading decoration after the existing
+// leading decorations.
+- (void)addLeadingDecoration:(LocationBarDecoration*)decoration;
 
-// Add a new right-side decoration to the left of the existing
-// right-side decorations.
-- (void)addRightDecoration:(LocationBarDecoration*)decoration;
+// Add a new trailing decoration before the existing
+// trailing decorations.
+- (void)addTrailingDecoration:(LocationBarDecoration*)decoration;
 
 // The width available after accounting for decorations.
 - (CGFloat)availableWidthInFrame:(const NSRect)frame;
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
index 4a34a26d..f7b55825 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell.mm
@@ -11,6 +11,7 @@
 #include "base/mac/mac_logging.h"
 #include "chrome/browser/search/search.h"
 #include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/ui/cocoa/l10n_util.h"
 #import "chrome/browser/ui/cocoa/location_bar/autocomplete_text_field.h"
 #import "chrome/browser/ui/cocoa/location_bar/location_bar_decoration.h"
 #import "chrome/browser/ui/cocoa/themed_window.h"
@@ -32,10 +33,11 @@
 
 // How far to inset the left- and right-hand decorations from the field's
 // bounds.
-const CGFloat kRightDecorationXOffset = 2.0;
-const CGFloat kLeftDecorationXOffset = 1.0;
+const CGFloat kTrailingDecorationXPadding = 2.0;
+const CGFloat kLeadingDecorationXPadding = 1.0;
 
-// How much the text frame needs to overlap the rightmost left decoration.
+// How much the text frame needs to overlap the outermost leading
+// decoration.
 const CGFloat kTextFrameDecorationOverlap = 5.0;
 
 // How long to wait for mouse-up on the location icon before assuming
@@ -106,54 +108,64 @@
 }
 
 // Helper function for calculating placement of decorations w/in the cell.
-// |frame| is the cell's boundary rectangle, |remaining_frame| will get any
-// space left after decorations are laid out (for text).  |left_decorations| is
-// a set of decorations for the left-hand side of the cell, |right_decorations|
-// for the right-hand side.
+// |frame| is the cell's boundary rectangle, |text_frame| will get any
+// space left after decorations are laid out (for text).
+// |leading_decorations| is a set of decorations for the leading side of
+// the cell, |trailing_decorations| for the right-hand side.
 // |decorations| will contain the resulting visible decorations, and
 // |decoration_frames| will contain their frames in the same coordinates as
-// |frame|.  Decorations will be ordered left to right. As a convenience returns
-// the index of the first right-hand decoration.
+// |frame|.  Decorations will be ordered left to right in LTR, and right to
+// left.
+// As a convenience, returns the index of the first right-hand decoration.
 size_t CalculatePositionsInFrame(
-    NSRect frame,
-    const std::vector<LocationBarDecoration*>& left_decorations,
-    const std::vector<LocationBarDecoration*>& right_decorations,
+    const NSRect frame,
+    const std::vector<LocationBarDecoration*>& leading_decorations,
+    const std::vector<LocationBarDecoration*>& trailing_decorations,
     std::vector<LocationBarDecoration*>* decorations,
     std::vector<NSRect>* decoration_frames,
-    NSRect* remaining_frame) {
+    NSRect* text_frame) {
   decorations->clear();
   decoration_frames->clear();
+  *text_frame = frame;
 
-  // Layout |left_decorations| against the LHS.
-  CalculatePositionsHelper(frame, left_decorations, NSMinXEdge,
-                           kLeftDecorationXOffset, decorations,
-                           decoration_frames, &frame);
+  // Layout |leading_decorations| against the leading side.
+  CalculatePositionsHelper(*text_frame, leading_decorations, NSMinXEdge,
+                           kLeadingDecorationXPadding, decorations,
+                           decoration_frames, text_frame);
   DCHECK_EQ(decorations->size(), decoration_frames->size());
 
-  // Capture the number of visible left-hand decorations.
-  const size_t left_count = decorations->size();
+  // Capture the number of visible leading decorations.
+  size_t leading_count = decorations->size();
 
   // Extend the text frame so that it slightly overlaps the rightmost left
   // decoration.
-  if (left_count) {
-    frame.origin.x -= kTextFrameDecorationOverlap;
-    frame.size.width += kTextFrameDecorationOverlap;
+  if (leading_count) {
+    text_frame->origin.x -= kTextFrameDecorationOverlap;
+    text_frame->size.width += kTextFrameDecorationOverlap;
   }
 
-  // Layout |right_decorations| against the RHS.
-  CalculatePositionsHelper(frame, right_decorations, NSMaxXEdge,
-                           kRightDecorationXOffset, decorations,
-                           decoration_frames, &frame);
+  // Layout |trailing_decorations| against the trailing side.
+  CalculatePositionsHelper(*text_frame, trailing_decorations, NSMaxXEdge,
+                           kTrailingDecorationXPadding, decorations,
+                           decoration_frames, text_frame);
   DCHECK_EQ(decorations->size(), decoration_frames->size());
 
   // Reverse the right-hand decorations so that overall everything is
   // sorted left to right.
-  std::reverse(decorations->begin() + left_count, decorations->end());
-  std::reverse(decoration_frames->begin() + left_count,
+  std::reverse(decorations->begin() + leading_count, decorations->end());
+  std::reverse(decoration_frames->begin() + leading_count,
                decoration_frames->end());
 
-  *remaining_frame = frame;
-  return left_count;
+  // Flip all frames in RTL.
+  if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) {
+    for (NSRect& rect : *decoration_frames)
+      rect.origin.x = NSWidth(frame) - NSWidth(rect) - NSMinX(rect);
+    text_frame->origin.x =
+        NSWidth(frame) - NSWidth(*text_frame) - NSMinX(*text_frame);
+    leading_count = decorations->size() - leading_count;
+  }
+
+  return leading_count;
 }
 
 }  // namespace
@@ -191,24 +203,24 @@
 }
 
 - (void)clearDecorations {
-  leftDecorations_.clear();
-  rightDecorations_.clear();
+  leadingDecorations_.clear();
+  trailingDecorations_.clear();
   [self clearTrackingArea];
 }
 
-- (void)addLeftDecoration:(LocationBarDecoration*)decoration {
-  leftDecorations_.push_back(decoration);
+- (void)addLeadingDecoration:(LocationBarDecoration*)decoration {
+  leadingDecorations_.push_back(decoration);
 }
 
-- (void)addRightDecoration:(LocationBarDecoration*)decoration {
-  rightDecorations_.push_back(decoration);
+- (void)addTrailingDecoration:(LocationBarDecoration*)decoration {
+  trailingDecorations_.push_back(decoration);
 }
 
 - (CGFloat)availableWidthInFrame:(const NSRect)frame {
   std::vector<LocationBarDecoration*> decorations;
   std::vector<NSRect> decorationFrames;
   NSRect textFrame;
-  CalculatePositionsInFrame(frame, leftDecorations_, rightDecorations_,
+  CalculatePositionsInFrame(frame, leadingDecorations_, trailingDecorations_,
                             &decorations, &decorationFrames, &textFrame);
 
   return NSWidth(textFrame);
@@ -224,8 +236,9 @@
   std::vector<LocationBarDecoration*> decorations;
   std::vector<NSRect> decorationFrames;
   NSRect textFrame;
-  CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
-                            &decorations, &decorationFrames, &textFrame);
+  CalculatePositionsInFrame(cellFrame, leadingDecorations_,
+                            trailingDecorations_, &decorations,
+                            &decorationFrames, &textFrame);
 
   // Find our decoration and return the corresponding frame.
   std::vector<LocationBarDecoration*>::const_iterator iter =
@@ -247,9 +260,12 @@
                       isLeftDecoration:(BOOL*)isLeftDecoration {
   NSRect decorationFrame =
       [self frameForDecoration:decoration inFrame:cellFrame];
+  std::vector<LocationBarDecoration*>& left_decorations =
+      cocoa_l10n_util::ShouldDoExperimentalRTLLayout() ? trailingDecorations_
+                                                       : leadingDecorations_;
   *isLeftDecoration =
-      std::find(leftDecorations_.begin(), leftDecorations_.end(), decoration) !=
-      leftDecorations_.end();
+      std::find(left_decorations.begin(), left_decorations.end(), decoration) !=
+      left_decorations.end();
   return decoration->GetBackgroundFrame(decorationFrame);
 }
 
@@ -259,8 +275,9 @@
   std::vector<LocationBarDecoration*> decorations;
   std::vector<NSRect> decorationFrames;
   NSRect textFrame = [super textFrameForFrame:cellFrame];
-  CalculatePositionsInFrame(textFrame, leftDecorations_, rightDecorations_,
-                            &decorations, &decorationFrames, &textFrame);
+  CalculatePositionsInFrame(textFrame, leadingDecorations_,
+                            trailingDecorations_, &decorations,
+                            &decorationFrames, &textFrame);
 
   // The text needs to be slightly higher than its default position to match the
   // Material Design spec. It turns out this adjustment is equal to the single
@@ -282,9 +299,9 @@
   std::vector<LocationBarDecoration*> decorations;
   std::vector<NSRect> decorationFrames;
   NSRect textFrame;
-  size_t left_count =
-      CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
-                                &decorations, &decorationFrames, &textFrame);
+  size_t left_count = CalculatePositionsInFrame(
+      cellFrame, leadingDecorations_, trailingDecorations_, &decorations,
+      &decorationFrames, &textFrame);
 
   // Determine the left-most extent for the i-beam cursor.
   CGFloat minX = NSMinX(textFrame);
@@ -383,8 +400,9 @@
   std::vector<NSRect> decorationFrames;
   NSRect workingFrame;
 
-  CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
-                            &decorations, &decorationFrames, &workingFrame);
+  CalculatePositionsInFrame(cellFrame, leadingDecorations_,
+                            trailingDecorations_, &decorations,
+                            &decorationFrames, &workingFrame);
 
   // Draw the decorations. Do this after drawing the interior because the
   // field editor's background rect overlaps the right edge of the security
@@ -403,20 +421,13 @@
   const NSPoint locationInView =
       [controlView convertPoint:location fromView:nil];
 
-  // If we have decorations, the drop can't occur at their horizontal padding.
-  if (!leftDecorations_.empty() && locationInView.x < kLeftDecorationXOffset)
-    return false;
-
-  if (!rightDecorations_.empty() &&
-      locationInView.x > NSWidth(cellFrame) - kRightDecorationXOffset) {
-    return false;
-  }
-
-  LocationBarDecoration* decoration =
-      [self decorationForLocationInWindow:location
-                                   inRect:cellFrame
-                                   ofView:controlView];
-  return !decoration;
+  NSRect textFrame;
+  std::vector<LocationBarDecoration*> decorations;
+  std::vector<NSRect> decorationFrames;
+  CalculatePositionsInFrame(cellFrame, leadingDecorations_,
+                            trailingDecorations_, &decorations,
+                            &decorationFrames, &textFrame);
+  return NSPointInRect(locationInView, textFrame);
 }
 
 - (LocationBarDecoration*)decorationForEvent:(NSEvent*)theEvent
@@ -439,8 +450,9 @@
   std::vector<LocationBarDecoration*> decorations;
   std::vector<NSRect> decorationFrames;
   NSRect textFrame;
-  CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
-                            &decorations, &decorationFrames, &textFrame);
+  CalculatePositionsInFrame(cellFrame, leadingDecorations_,
+                            trailingDecorations_, &decorations,
+                            &decorationFrames, &textFrame);
 
   for (size_t i = 0; i < decorations.size(); ++i) {
     if (NSMouseInRect(locationInView, decorationFrames[i], flipped))
@@ -670,8 +682,9 @@
   std::vector<LocationBarDecoration*> decorations;
   std::vector<NSRect> decorationFrames;
   NSRect textFrame;
-  CalculatePositionsInFrame(cellFrame, leftDecorations_, rightDecorations_,
-                            &decorations, &decorationFrames, &textFrame);
+  CalculatePositionsInFrame(cellFrame, leadingDecorations_,
+                            trailingDecorations_, &decorations,
+                            &decorationFrames, &textFrame);
   [self clearTrackingArea];
 
   for (size_t i = 0; i < decorations.size(); ++i) {
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
index e59794e..b913e67 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_cell_unittest.mm
@@ -15,6 +15,7 @@
 #import "chrome/browser/ui/cocoa/location_bar/selected_keyword_decoration.h"
 #import "chrome/browser/ui/cocoa/location_bar/star_decoration.h"
 #import "chrome/browser/ui/cocoa/test/cocoa_test_helper.h"
+#import "chrome/browser/ui/cocoa/test/scoped_force_rtl_mac.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #import "testing/gtest_mac.h"
@@ -58,12 +59,12 @@
     [cell setBordered:YES];
 
     [cell clearDecorations];
-    mock_left_decoration_.SetVisible(false);
-    [cell addLeftDecoration:&mock_left_decoration_];
-    mock_right_decoration0_.SetVisible(false);
-    mock_right_decoration1_.SetVisible(false);
-    [cell addRightDecoration:&mock_right_decoration0_];
-    [cell addRightDecoration:&mock_right_decoration1_];
+    mock_leading_decoration_.SetVisible(false);
+    [cell addLeadingDecoration:&mock_leading_decoration_];
+    mock_trailing_decoration0_.SetVisible(false);
+    mock_trailing_decoration1_.SetVisible(false);
+    [cell addTrailingDecoration:&mock_trailing_decoration0_];
+    [cell addTrailingDecoration:&mock_trailing_decoration1_];
 
     [view_ setCell:cell.get()];
 
@@ -71,9 +72,9 @@
   }
 
   NSTextField* view_;
-  MockDecoration mock_left_decoration_;
-  MockDecoration mock_right_decoration0_;
-  MockDecoration mock_right_decoration1_;
+  MockDecoration mock_leading_decoration_;
+  MockDecoration mock_trailing_decoration0_;
+  MockDecoration mock_trailing_decoration1_;
 };
 
 // Basic view tests (AddRemove, Display).
@@ -101,7 +102,7 @@
   SelectedKeywordDecoration selected_keyword_decoration;
   selected_keyword_decoration.SetVisible(true);
   selected_keyword_decoration.SetKeyword(base::ASCIIToUTF16("Google"), false);
-  [cell addLeftDecoration:&selected_keyword_decoration];
+  [cell addLeadingDecoration:&selected_keyword_decoration];
   EXPECT_NE(selected_keyword_decoration.GetWidthForSpace(kVeryWide),
             LocationBarDecoration::kOmittedWidth);
 
@@ -111,7 +112,7 @@
   LocationIconDecoration location_icon_decoration(NULL);
   location_icon_decoration.SetVisible(true);
   location_icon_decoration.SetImage([NSImage imageNamed:@"NSApplicationIcon"]);
-  [cell addLeftDecoration:&location_icon_decoration];
+  [cell addLeadingDecoration:&location_icon_decoration];
   EXPECT_NE(location_icon_decoration.GetWidthForSpace(kVeryWide),
             LocationBarDecoration::kOmittedWidth);
 
@@ -121,27 +122,27 @@
   security_state_bubble_decoration.SetImage(
       [NSImage imageNamed:@"NSApplicationIcon"]);
   security_state_bubble_decoration.SetLabel(@"Application");
-  [cell addLeftDecoration:&security_state_bubble_decoration];
+  [cell addLeadingDecoration:&security_state_bubble_decoration];
   EXPECT_NE(security_state_bubble_decoration.GetWidthForSpace(kVeryWide),
             LocationBarDecoration::kOmittedWidth);
 
   StarDecoration star_decoration(NULL);
   star_decoration.SetVisible(true);
-  [cell addRightDecoration:&star_decoration];
+  [cell addTrailingDecoration:&star_decoration];
   EXPECT_NE(star_decoration.GetWidthForSpace(kVeryWide),
             LocationBarDecoration::kOmittedWidth);
 
   KeywordHintDecoration keyword_hint_decoration;
   keyword_hint_decoration.SetVisible(true);
   keyword_hint_decoration.SetKeyword(base::ASCIIToUTF16("google"), false);
-  [cell addRightDecoration:&keyword_hint_decoration];
+  [cell addTrailingDecoration:&keyword_hint_decoration];
   EXPECT_NE(keyword_hint_decoration.GetWidthForSpace(kVeryWide),
             LocationBarDecoration::kOmittedWidth);
 
   // Make sure we're actually calling |DrawInFrame()|.
   StrictMock<MockDecoration> mock_decoration;
   mock_decoration.SetVisible(true);
-  [cell addLeftDecoration:&mock_decoration];
+  [cell addLeadingDecoration:&mock_decoration];
   EXPECT_CALL(mock_decoration, DrawInFrame(_, _));
   EXPECT_NE(mock_decoration.GetWidthForSpace(kVeryWide),
             LocationBarDecoration::kOmittedWidth);
@@ -169,8 +170,8 @@
   EXPECT_EQ(NSMaxX(bounds), NSMaxX(textFrame));
   EXPECT_TRUE(NSContainsRect(cursorFrame, textFrame));
 
-  // Decoration on the left takes up space.
-  mock_left_decoration_.SetVisible(true);
+  // Leading decoration takes up space.
+  mock_leading_decoration_.SetVisible(true);
   textFrame = [cell textFrameForFrame:bounds];
   EXPECT_FALSE(NSIsEmptyRect(textFrame));
   EXPECT_TRUE(NSContainsRect(bounds, textFrame));
@@ -193,34 +194,34 @@
   // Save the starting frame for after clear.
   const NSRect originalDrawingRect = drawingRect;
 
-  mock_left_decoration_.SetVisible(true);
+  mock_leading_decoration_.SetVisible(true);
   textFrame = [cell textFrameForFrame:bounds];
   drawingRect = [cell drawingRectForBounds:bounds];
   EXPECT_FALSE(NSIsEmptyRect(drawingRect));
   EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
 
-  mock_right_decoration0_.SetVisible(true);
+  mock_trailing_decoration0_.SetVisible(true);
   textFrame = [cell textFrameForFrame:bounds];
   drawingRect = [cell drawingRectForBounds:bounds];
   EXPECT_FALSE(NSIsEmptyRect(drawingRect));
   EXPECT_TRUE(NSContainsRect(NSInsetRect(textFrame, 1, 1), drawingRect));
 
-  mock_left_decoration_.SetVisible(false);
-  mock_right_decoration0_.SetVisible(false);
+  mock_leading_decoration_.SetVisible(false);
+  mock_trailing_decoration0_.SetVisible(false);
   drawingRect = [cell drawingRectForBounds:bounds];
   EXPECT_FALSE(NSIsEmptyRect(drawingRect));
   EXPECT_NSEQ(drawingRect, originalDrawingRect);
 }
 
-// Test that left decorations are at the correct edge of the cell.
-TEST_F(AutocompleteTextFieldCellTest, LeftDecorationFrame) {
+// Test that leading decorations are at the correct edge of the cell.
+TEST_F(AutocompleteTextFieldCellTest, LeadingDecorationFrame) {
   AutocompleteTextFieldCell* cell =
       static_cast<AutocompleteTextFieldCell*>([view_ cell]);
   const NSRect bounds = [view_ bounds];
 
-  mock_left_decoration_.SetVisible(true);
+  mock_leading_decoration_.SetVisible(true);
   const NSRect decorationRect =
-      [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
+      [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds];
   EXPECT_FALSE(NSIsEmptyRect(decorationRect));
   EXPECT_TRUE(NSContainsRect(bounds, decorationRect));
 
@@ -233,24 +234,24 @@
   EXPECT_GT(NSMinX(textFrame), NSMinX(decorationRect));
 }
 
-// Test that right decorations are at the correct edge of the cell.
-TEST_F(AutocompleteTextFieldCellTest, RightDecorationFrame) {
+// Test that trailing decorations are at the correct edge of the cell.
+TEST_F(AutocompleteTextFieldCellTest, TrailingDecorationFrame) {
   AutocompleteTextFieldCell* cell =
       static_cast<AutocompleteTextFieldCell*>([view_ cell]);
   const NSRect bounds = [view_ bounds];
 
-  mock_right_decoration0_.SetVisible(true);
-  mock_right_decoration1_.SetVisible(true);
+  mock_trailing_decoration0_.SetVisible(true);
+  mock_trailing_decoration1_.SetVisible(true);
 
   const NSRect decoration0Rect =
-      [cell frameForDecoration:&mock_right_decoration0_ inFrame:bounds];
+      [cell frameForDecoration:&mock_trailing_decoration0_ inFrame:bounds];
   EXPECT_FALSE(NSIsEmptyRect(decoration0Rect));
   EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect));
 
-  // Right-side decorations are ordered from rightmost to leftmost.
+  // Trailing decorations are ordered from innermost to outermost.
   // Outer decoration (0) to right of inner decoration (1).
   const NSRect decoration1Rect =
-      [cell frameForDecoration:&mock_right_decoration1_ inFrame:bounds];
+      [cell frameForDecoration:&mock_trailing_decoration1_ inFrame:bounds];
   EXPECT_FALSE(NSIsEmptyRect(decoration1Rect));
   EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect));
   EXPECT_LT(NSMinX(decoration1Rect), NSMinX(decoration0Rect));
@@ -269,33 +270,89 @@
 TEST_F(AutocompleteTextFieldCellTest, UpdateToolTips) {
   NSString* tooltip = @"tooltip";
 
-  // Left decoration returns a tooltip, make sure it is called at
+  // Leading decoration returns a tooltip, make sure it is called at
   // least once.
-  mock_left_decoration_.SetVisible(true);
-  EXPECT_CALL(mock_left_decoration_, GetToolTip())
+  mock_leading_decoration_.SetVisible(true);
+  EXPECT_CALL(mock_leading_decoration_, GetToolTip())
       .WillOnce(Return(tooltip))
       .WillRepeatedly(Return(tooltip));
 
   // Right decoration returns no tooltip, make sure it is called at
   // least once.
-  mock_right_decoration0_.SetVisible(true);
-  EXPECT_CALL(mock_right_decoration0_, GetToolTip())
+  mock_trailing_decoration0_.SetVisible(true);
+  EXPECT_CALL(mock_trailing_decoration0_, GetToolTip())
       .WillOnce(Return((NSString*)nil))
       .WillRepeatedly(Return((NSString*)nil));
 
   AutocompleteTextFieldCell* cell =
       static_cast<AutocompleteTextFieldCell*>([view_ cell]);
   const NSRect bounds = [view_ bounds];
-  const NSRect leftDecorationRect =
-      [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
+  const NSRect leadingDecorationRect =
+      [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds];
 
-  // |controlView| gets the tooltip for the left decoration.
+  // |controlView| gets the tooltip for the leading decoration.
   id controlView = [OCMockObject mockForClass:[AutocompleteTextField class]];
-  [[controlView expect] addToolTip:tooltip forRect:leftDecorationRect];
+  [[controlView expect] addToolTip:tooltip forRect:leadingDecorationRect];
 
   [cell updateMouseTrackingAndToolTipsInRect:bounds ofView:controlView];
 
   EXPECT_OCMOCK_VERIFY(controlView);
 }
 
+class AutocompleteTextFieldCellTestRTL : public AutocompleteTextFieldCellTest {
+ private:
+  cocoa_l10n_util::ScopedForceRTLMac rtl_;
+};
+
+// Test that leading decorations are at the correct edge of the cell.
+TEST_F(AutocompleteTextFieldCellTestRTL, LeadingDecorationFrame) {
+  AutocompleteTextFieldCell* cell =
+      static_cast<AutocompleteTextFieldCell*>([view_ cell]);
+  const NSRect bounds = [view_ bounds];
+
+  mock_leading_decoration_.SetVisible(true);
+  const NSRect decorationRect =
+      [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds];
+  EXPECT_FALSE(NSIsEmptyRect(decorationRect));
+  EXPECT_TRUE(NSContainsRect(bounds, decorationRect));
+  // Decoration should be right of |drawingRect|.
+  const NSRect drawingRect = [cell drawingRectForBounds:bounds];
+  EXPECT_LT(NSMinX(drawingRect), NSMinX(decorationRect));
+
+  // Decoration should be right of |textFrame|.
+  const NSRect textFrame = [cell textFrameForFrame:bounds];
+  EXPECT_LT(NSMinX(textFrame), NSMinX(decorationRect));
+}
+
+// Test that trailing decorations are at the correct edge of the cell.
+TEST_F(AutocompleteTextFieldCellTestRTL, TrailingDecorationFrame) {
+  AutocompleteTextFieldCell* cell =
+      static_cast<AutocompleteTextFieldCell*>([view_ cell]);
+  const NSRect bounds = [view_ bounds];
+
+  mock_trailing_decoration0_.SetVisible(true);
+  mock_trailing_decoration1_.SetVisible(true);
+
+  const NSRect decoration0Rect =
+      [cell frameForDecoration:&mock_trailing_decoration0_ inFrame:bounds];
+  EXPECT_FALSE(NSIsEmptyRect(decoration0Rect));
+  EXPECT_TRUE(NSContainsRect(bounds, decoration0Rect));
+
+  // Trailing decorations are ordered from front to back..
+  // Outer decoration (0) to the left of inner decoration (1).
+  const NSRect decoration1Rect =
+      [cell frameForDecoration:&mock_trailing_decoration1_ inFrame:bounds];
+  EXPECT_FALSE(NSIsEmptyRect(decoration1Rect));
+  EXPECT_TRUE(NSContainsRect(bounds, decoration1Rect));
+  EXPECT_GT(NSMinX(decoration1Rect), NSMinX(decoration0Rect));
+
+  // Decoration should be left of |drawingRect|.
+  const NSRect drawingRect = [cell drawingRectForBounds:bounds];
+  EXPECT_GT(NSMinX(drawingRect), NSMinX(decoration1Rect));
+
+  // Decoration should be left of |textFrame|.
+  const NSRect textFrame = [cell textFrameForFrame:bounds];
+  EXPECT_GT(NSMinX(textFrame), NSMinX(decoration1Rect));
+}
+
 }  // namespace
diff --git a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
index e231f51..367f9d2f 100644
--- a/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
+++ b/chrome/browser/ui/cocoa/location_bar/autocomplete_text_field_unittest.mm
@@ -85,11 +85,11 @@
     AutocompleteTextFieldCell* cell = [field_ cell];
     [cell clearDecorations];
 
-    mock_left_decoration_.SetVisible(false);
-    [cell addLeftDecoration:&mock_left_decoration_];
+    mock_leading_decoration_.SetVisible(false);
+    [cell addLeadingDecoration:&mock_leading_decoration_];
 
-    mock_right_decoration_.SetVisible(false);
-    [cell addRightDecoration:&mock_right_decoration_];
+    mock_trailing_decoration_.SetVisible(false);
+    [cell addTrailingDecoration:&mock_trailing_decoration_];
 
     window_delegate_.reset(
         [[AutocompleteTextFieldWindowTestDelegate alloc] init]);
@@ -128,8 +128,8 @@
   }
 
   AutocompleteTextField* field_;
-  MockDecoration mock_left_decoration_;
-  MockDecoration mock_right_decoration_;
+  MockDecoration mock_leading_decoration_;
+  MockDecoration mock_trailing_decoration_;
   base::scoped_nsobject<AutocompleteTextFieldWindowTestDelegate>
       window_delegate_;
 };
@@ -296,14 +296,14 @@
   const NSRect baseEditorFrame = EditorFrame();
 
   // A decoration should result in a strictly smaller editor frame.
-  mock_left_decoration_.SetVisible(true);
+  mock_leading_decoration_.SetVisible(true);
   [field_ resetFieldEditorFrameIfNeeded];
   EXPECT_NSNE(baseEditorFrame, EditorFrame());
   EXPECT_TRUE(NSContainsRect(baseEditorFrame, EditorFrame()));
 
   // Removing the decoration and using -resetFieldEditorFrameIfNeeded
   // should result in the same frame as the standard focus machinery.
-  mock_left_decoration_.SetVisible(false);
+  mock_leading_decoration_.SetVisible(false);
   [field_ resetFieldEditorFrameIfNeeded];
   EXPECT_NSEQ(baseEditorFrame, EditorFrame());
 }
@@ -316,10 +316,10 @@
   AutocompleteTextFieldCell* cell = [field_ cell];
 
   // Make sure decoration isn't already visible, then make it visible.
-  EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
+  EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_
                                              inFrame:[field_ bounds]]));
-  mock_left_decoration_.SetVisible(true);
-  EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
+  mock_leading_decoration_.SetVisible(true);
+  EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_
                                               inFrame:[field_ bounds]]));
 
   // Capture the editor frame resulting from the standard focus
@@ -329,8 +329,8 @@
   const NSRect baseEditorFrame = EditorFrame();
 
   // When the decoration is not visible the frame should be strictly larger.
-  mock_left_decoration_.SetVisible(false);
-  EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
+  mock_leading_decoration_.SetVisible(false);
+  EXPECT_TRUE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_
                                              inFrame:[field_ bounds]]));
   [field_ resetFieldEditorFrameIfNeeded];
   EXPECT_NSNE(baseEditorFrame, EditorFrame());
@@ -338,8 +338,8 @@
 
   // When the decoration is visible, -resetFieldEditorFrameIfNeeded
   // should result in the same frame as the standard focus machinery.
-  mock_left_decoration_.SetVisible(true);
-  EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_left_decoration_
+  mock_leading_decoration_.SetVisible(true);
+  EXPECT_FALSE(NSIsEmptyRect([cell frameForDecoration:&mock_leading_decoration_
                                               inFrame:[field_ bounds]]));
 
   [field_ resetFieldEditorFrameIfNeeded];
@@ -368,7 +368,7 @@
   [editor didChangeText];
 
   // No messages to |field_observer_| when the frame actually changes.
-  mock_left_decoration_.SetVisible(true);
+  mock_leading_decoration_.SetVisible(true);
   [field_ resetFieldEditorFrameIfNeeded];
   EXPECT_NSNE(baseEditorFrame, EditorFrame());
 }
@@ -378,13 +378,13 @@
 TEST_F(AutocompleteTextFieldTest, ClickRightDecorationPutsCaretRightmost) {
   // Decoration does not handle the mouse event, so the cell should
   // process it.  Called at least once.
-  EXPECT_CALL(mock_right_decoration_, AcceptsMousePress())
+  EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress())
       .WillOnce(Return(false))
       .WillRepeatedly(Return(false));
 
   // Set the decoration before becoming responder.
   EXPECT_FALSE([field_ currentEditor]);
-  mock_right_decoration_.SetVisible(true);
+  mock_trailing_decoration_.SetVisible(true);
 
   // Make first responder should select all.
   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
@@ -396,7 +396,7 @@
   AutocompleteTextFieldCell* cell = [field_ cell];
   const NSRect bounds = [field_ bounds];
   const NSRect iconFrame =
-      [cell frameForDecoration:&mock_right_decoration_ inFrame:bounds];
+      [cell frameForDecoration:&mock_trailing_decoration_ inFrame:bounds];
   const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
   NSEvent* downEvent = Event(field_, point, NSLeftMouseDown);
   NSEvent* upEvent = Event(field_, point, NSLeftMouseUp);
@@ -413,13 +413,13 @@
 TEST_F(AutocompleteTextFieldTest, ClickLeftDecorationPutsCaretLeftmost) {
   // Decoration does not handle the mouse event, so the cell should
   // process it.  Called at least once.
-  EXPECT_CALL(mock_left_decoration_, AcceptsMousePress())
+  EXPECT_CALL(mock_leading_decoration_, AcceptsMousePress())
       .WillOnce(Return(false))
       .WillRepeatedly(Return(false));
 
   // Set the decoration before becoming responder.
   EXPECT_FALSE([field_ currentEditor]);
-  mock_left_decoration_.SetVisible(true);
+  mock_leading_decoration_.SetVisible(true);
 
   // Make first responder should select all.
   [test_window() makePretendKeyWindowAndSetFirstResponder:field_];
@@ -431,7 +431,7 @@
   AutocompleteTextFieldCell* cell = [field_ cell];
   const NSRect bounds = [field_ bounds];
   const NSRect iconFrame =
-      [cell frameForDecoration:&mock_left_decoration_ inFrame:bounds];
+      [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds];
   const NSPoint point = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
   NSEvent* downEvent = Event(field_, point, NSLeftMouseDown);
   NSEvent* upEvent = Event(field_, point, NSLeftMouseUp);
@@ -560,15 +560,15 @@
   // At this point, not focussed.
   EXPECT_FALSE([field_ currentEditor]);
 
-  mock_left_decoration_.SetVisible(true);
-  EXPECT_CALL(mock_left_decoration_, AcceptsMousePress())
+  mock_leading_decoration_.SetVisible(true);
+  EXPECT_CALL(mock_leading_decoration_, AcceptsMousePress())
       .WillRepeatedly(Return(true));
 
   AutocompleteTextFieldCell* cell = [field_ cell];
   [cell updateMouseTrackingAndToolTipsInRect:[field_ frame] ofView:field_];
 
-  const NSRect iconFrame =
-      [cell frameForDecoration:&mock_left_decoration_ inFrame:[field_ bounds]];
+  const NSRect iconFrame = [cell frameForDecoration:&mock_leading_decoration_
+                                            inFrame:[field_ bounds]];
   const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
   NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1);
   NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1);
@@ -577,7 +577,7 @@
   // mouse-up.
   [NSApp postEvent:upEvent atStart:YES];
 
-  EXPECT_CALL(mock_left_decoration_, OnMousePressed(_, _))
+  EXPECT_CALL(mock_leading_decoration_, OnMousePressed(_, _))
       .WillOnce(Return(true));
   [field_ mouseDown:downEvent];
 
@@ -591,7 +591,7 @@
   downEvent = Event(field_, location, NSLeftMouseDown, 1);
   upEvent = Event(field_, location, NSLeftMouseUp, 1);
   [NSApp postEvent:upEvent atStart:YES];
-  EXPECT_CALL(mock_left_decoration_, OnMousePressed(_, _))
+  EXPECT_CALL(mock_leading_decoration_, OnMousePressed(_, _))
       .WillOnce(Return(true));
   [field_ mouseDown:downEvent];
 
@@ -609,8 +609,8 @@
   // At this point, not focussed.
   EXPECT_FALSE([field_ currentEditor]);
 
-  mock_right_decoration_.SetVisible(true);
-  EXPECT_CALL(mock_right_decoration_, AcceptsMousePress())
+  mock_trailing_decoration_.SetVisible(true);
+  EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress())
       .WillRepeatedly(Return(true));
 
   AutocompleteTextFieldCell* cell = [field_ cell];
@@ -618,7 +618,7 @@
 
   const NSRect bounds = [field_ bounds];
   const NSRect iconFrame =
-      [cell frameForDecoration:&mock_right_decoration_ inFrame:bounds];
+      [cell frameForDecoration:&mock_trailing_decoration_ inFrame:bounds];
   const NSPoint location = NSMakePoint(NSMidX(iconFrame), NSMidY(iconFrame));
   NSEvent* downEvent = Event(field_, location, NSLeftMouseDown, 1);
   NSEvent* upEvent = Event(field_, location, NSLeftMouseUp, 1);
@@ -627,7 +627,7 @@
   // mouse-up.
   [NSApp postEvent:upEvent atStart:YES];
 
-  EXPECT_CALL(mock_right_decoration_, OnMousePressed(_, _))
+  EXPECT_CALL(mock_trailing_decoration_, OnMousePressed(_, _))
       .WillOnce(Return(true));
   [field_ mouseDown:downEvent];
 }
@@ -648,27 +648,27 @@
 
   base::scoped_nsobject<NSMenu> menu([[NSMenu alloc] initWithTitle:@"Menu"]);
 
-  mock_left_decoration_.SetVisible(true);
-  mock_right_decoration_.SetVisible(true);
+  mock_leading_decoration_.SetVisible(true);
+  mock_trailing_decoration_.SetVisible(true);
 
   // The item with a menu returns it.
-  NSRect actionFrame = [cell frameForDecoration:&mock_right_decoration_
-                                        inFrame:bounds];
+  NSRect actionFrame =
+      [cell frameForDecoration:&mock_trailing_decoration_ inFrame:bounds];
   NSPoint location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame));
   NSEvent* event = Event(field_, location, NSRightMouseDown, 1);
 
   // Check that the decoration is called, and the field returns the
   // menu.
-  EXPECT_CALL(mock_right_decoration_, GetMenu())
+  EXPECT_CALL(mock_trailing_decoration_, GetMenu())
       .WillOnce(Return(menu.get()));
   NSMenu *decorationMenu = [field_ decorationMenuForEvent:event];
   EXPECT_EQ(decorationMenu, menu);
 
   // The item without a menu returns nil.
-  EXPECT_CALL(mock_left_decoration_, GetMenu())
+  EXPECT_CALL(mock_leading_decoration_, GetMenu())
       .WillOnce(Return(static_cast<NSMenu*>(nil)));
-  actionFrame = [cell frameForDecoration:&mock_left_decoration_
-                                 inFrame:bounds];
+  actionFrame =
+      [cell frameForDecoration:&mock_leading_decoration_ inFrame:bounds];
   location = NSMakePoint(NSMidX(actionFrame), NSMidY(actionFrame));
   event = Event(field_, location, NSRightMouseDown, 1);
   EXPECT_FALSE([field_ decorationMenuForEvent:event]);
@@ -796,13 +796,13 @@
 TEST_F(AutocompleteTextFieldTest, UpdateTrackingAreas) {
   AutocompleteTextFieldCell* cell = [field_ cell];
 
-  mock_left_decoration_.SetVisible(true);
-  mock_right_decoration_.SetVisible(true);
+  mock_leading_decoration_.SetVisible(true);
+  mock_trailing_decoration_.SetVisible(true);
 
-  EXPECT_CALL(mock_left_decoration_, AcceptsMousePress())
+  EXPECT_CALL(mock_leading_decoration_, AcceptsMousePress())
       .WillOnce(Return(true))
       .WillRepeatedly(Return(true));
-  EXPECT_CALL(mock_right_decoration_, AcceptsMousePress())
+  EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress())
       .WillOnce(Return(false))
       .WillRepeatedly(Return(false));
   [cell updateMouseTrackingAndToolTipsInRect:[field_ bounds] ofView:field_];
@@ -812,7 +812,7 @@
   [cell clearTrackingArea];
   EXPECT_TRUE([cell mouseTrackingDecorations].empty());
 
-  EXPECT_CALL(mock_right_decoration_, AcceptsMousePress())
+  EXPECT_CALL(mock_trailing_decoration_, AcceptsMousePress())
       .WillOnce(Return(true))
       .WillRepeatedly(Return(true));
 
@@ -831,14 +831,14 @@
   noninteractive_decoration.SetVisible(true);
   EXPECT_CALL(noninteractive_decoration, AcceptsMousePress())
       .WillRepeatedly(testing::Return(false));
-  [cell addLeftDecoration:&noninteractive_decoration];
+  [cell addLeadingDecoration:&noninteractive_decoration];
 
   // Set up an interactive decoration.
   MockDecoration interactive_decoration;
   EXPECT_CALL(interactive_decoration, AcceptsMousePress())
       .WillRepeatedly(testing::Return(true));
   interactive_decoration.SetVisible(true);
-  [cell addLeftDecoration:&interactive_decoration];
+  [cell addLeadingDecoration:&interactive_decoration];
   [cell updateMouseTrackingAndToolTipsInRect:[field_ frame] ofView:field_];
   EXPECT_CALL(interactive_decoration, OnMousePressed(_, _))
       .WillRepeatedly(testing::Return(true));
diff --git a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
index 40e2d93..0591b5d6 100644
--- a/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
+++ b/chrome/browser/ui/cocoa/location_bar/bubble_decoration.mm
@@ -83,7 +83,7 @@
     image_rect.size = image_size;
     if (cocoa_l10n_util::ShouldDoExperimentalRTLLayout()) {
       image_rect.origin.x =
-          NSMaxX(frame) - NSWidth(image_rect) - NSMinX(image_rect);
+          NSMaxX(frame) - NSWidth(image_rect) - kLeftSidePadding;
     }
   }
   return image_rect;
diff --git a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
index 08f552b..378a7eb 100644
--- a/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
+++ b/chrome/browser/ui/cocoa/location_bar/location_bar_view_mac.mm
@@ -410,32 +410,32 @@
 void LocationBarViewMac::Layout() {
   AutocompleteTextFieldCell* cell = [field_ cell];
 
-  // Reset the left-hand decorations.
+  // Reset the leading decorations.
   // TODO(shess): Shortly, this code will live somewhere else, like in
   // the constructor.  I am still wrestling with how best to deal with
   // right-hand decorations, which are not a static set.
   [cell clearDecorations];
-  [cell addLeftDecoration:location_icon_decoration_.get()];
-  [cell addLeftDecoration:selected_keyword_decoration_.get()];
-  [cell addLeftDecoration:security_state_bubble_decoration_.get()];
-  [cell addRightDecoration:star_decoration_.get()];
-  [cell addRightDecoration:translate_decoration_.get()];
-  [cell addRightDecoration:zoom_decoration_.get()];
-  [cell addRightDecoration:save_credit_card_decoration_.get()];
-  [cell addRightDecoration:manage_passwords_decoration_.get()];
+  [cell addLeadingDecoration:location_icon_decoration_.get()];
+  [cell addLeadingDecoration:selected_keyword_decoration_.get()];
+  [cell addLeadingDecoration:security_state_bubble_decoration_.get()];
+  [cell addTrailingDecoration:star_decoration_.get()];
+  [cell addTrailingDecoration:translate_decoration_.get()];
+  [cell addTrailingDecoration:zoom_decoration_.get()];
+  [cell addTrailingDecoration:save_credit_card_decoration_.get()];
+  [cell addTrailingDecoration:manage_passwords_decoration_.get()];
 
-  // Note that display order is right to left.
+  // Note that display order is front to back.
   for (size_t i = 0; i < page_action_decorations_.size(); ++i) {
-    [cell addRightDecoration:page_action_decorations_[i]];
+    [cell addTrailingDecoration:page_action_decorations_[i]];
   }
 
   for (ScopedVector<ContentSettingDecoration>::iterator i =
        content_setting_decorations_.begin();
        i != content_setting_decorations_.end(); ++i) {
-    [cell addRightDecoration:*i];
+    [cell addTrailingDecoration:*i];
   }
 
-  [cell addRightDecoration:keyword_hint_decoration_.get()];
+  [cell addTrailingDecoration:keyword_hint_decoration_.get()];
 
   // By default only the location icon is visible.
   location_icon_decoration_->SetVisible(true);
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn
index 765994f..a468fe1 100644
--- a/components/metrics/BUILD.gn
+++ b/components/metrics/BUILD.gn
@@ -69,6 +69,9 @@
     "metrics_switches.h",
     "persisted_logs.cc",
     "persisted_logs.h",
+    "persisted_logs_metrics.h",
+    "persisted_logs_metrics_impl.cc",
+    "persisted_logs_metrics_impl.h",
     "stability_metrics_helper.cc",
     "stability_metrics_helper.h",
     "system_memory_stats_recorder.h",
diff --git a/components/metrics/metrics_log_manager.cc b/components/metrics/metrics_log_manager.cc
index 763636b..387b2001 100644
--- a/components/metrics/metrics_log_manager.cc
+++ b/components/metrics/metrics_log_manager.cc
@@ -10,6 +10,7 @@
 #include "base/strings/string_util.h"
 #include "components/metrics/metrics_log.h"
 #include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/persisted_logs_metrics_impl.h"
 
 namespace metrics {
 
@@ -40,13 +41,17 @@
 MetricsLogManager::MetricsLogManager(PrefService* local_state,
                                      size_t max_ongoing_log_size)
     : unsent_logs_loaded_(false),
-      initial_log_queue_(local_state,
+      initial_log_queue_(std::unique_ptr<PersistedLogsMetricsImpl>(
+                             new PersistedLogsMetricsImpl()),
+                         local_state,
                          prefs::kMetricsInitialLogs,
                          prefs::kDeprecatedMetricsInitialLogs,
                          kInitialLogsPersistLimit,
                          kStorageByteLimitPerLogType,
                          0),
-      ongoing_log_queue_(local_state,
+      ongoing_log_queue_(std::unique_ptr<PersistedLogsMetricsImpl>(
+                             new PersistedLogsMetricsImpl()),
+                         local_state,
                          prefs::kMetricsOngoingLogs,
                          prefs::kDeprecatedMetricsOngoingLogs,
                          kOngoingLogsPersistLimit,
diff --git a/components/metrics/metrics_log_manager_unittest.cc b/components/metrics/metrics_log_manager_unittest.cc
index fbd1dd5d..8040ed0 100644
--- a/components/metrics/metrics_log_manager_unittest.cc
+++ b/components/metrics/metrics_log_manager_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/memory/ptr_util.h"
 #include "components/metrics/metrics_log.h"
 #include "components/metrics/metrics_pref_names.h"
+#include "components/metrics/persisted_logs_metrics_impl.h"
 #include "components/metrics/test_metrics_service_client.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/testing_pref_service.h"
@@ -163,7 +164,9 @@
     // Simulate a log having already been unsent from a previous session.
     {
       std::string log("proto");
-      PersistedLogs ongoing_logs(&pref_service, prefs::kMetricsOngoingLogs,
+      PersistedLogs ongoing_logs(std::unique_ptr<PersistedLogsMetricsImpl>(
+                                     new PersistedLogsMetricsImpl()),
+                                 &pref_service, prefs::kMetricsOngoingLogs,
                                  prefs::kDeprecatedMetricsOngoingLogs, 1, 1, 0);
       ongoing_logs.StoreLog(log);
       ongoing_logs.SerializeLogs();
diff --git a/components/metrics/persisted_logs.cc b/components/metrics/persisted_logs.cc
index 12d3a68..a407a0d 100644
--- a/components/metrics/persisted_logs.cc
+++ b/components/metrics/persisted_logs.cc
@@ -14,6 +14,7 @@
 #include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/timer/elapsed_timer.h"
+#include "components/metrics/persisted_logs_metrics.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "third_party/zlib/google/compression_utils.h"
@@ -26,13 +27,6 @@
 const char kLogTimestampKey[] = "timestamp";
 const char kLogDataKey[] = "data";
 
-PersistedLogs::LogReadStatus MakeRecallStatusHistogram(
-    PersistedLogs::LogReadStatus status) {
-  UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogRecallProtobufs",
-                            status, PersistedLogs::END_RECALL_STATUS);
-  return status;
-}
-
 // Reads the value at |index| from |list_value| as a string and Base64-decodes
 // it into |result|. Returns true on success.
 bool ReadBase64String(const base::ListValue& list_value,
@@ -58,7 +52,8 @@
 
 }  // namespace
 
-void PersistedLogs::LogInfo::Init(const std::string& log_data,
+void PersistedLogs::LogInfo::Init(PersistedLogsMetrics* metrics,
+                                  const std::string& log_data,
                                   const std::string& log_timestamp) {
   DCHECK(!log_data.empty());
 
@@ -67,21 +62,21 @@
     return;
   }
 
-  UMA_HISTOGRAM_PERCENTAGE(
-      "UMA.ProtoCompressionRatio",
-      static_cast<int>(100 * compressed_log_data.size() / log_data.size()));
+  metrics->RecordCompressionRatio(compressed_log_data.size(), log_data.size());
 
   hash = base::SHA1HashString(log_data);
   timestamp = log_timestamp;
 }
 
-PersistedLogs::PersistedLogs(PrefService* local_state,
+PersistedLogs::PersistedLogs(std::unique_ptr<PersistedLogsMetrics> metrics,
+                             PrefService* local_state,
                              const char* pref_name,
                              const char* outdated_pref_name,
                              size_t min_log_count,
                              size_t min_log_bytes,
                              size_t max_log_size)
-    : local_state_(local_state),
+    : metrics_(std::move(metrics)),
+      local_state_(local_state),
       pref_name_(pref_name),
       outdated_pref_name_(outdated_pref_name),
       min_log_count_(min_log_count),
@@ -117,7 +112,9 @@
 
 void PersistedLogs::StoreLog(const std::string& log_data) {
   list_.push_back(LogInfo());
-  list_.back().Init(log_data, base::Int64ToString(base::Time::Now().ToTimeT()));
+  list_.back().Init(metrics_.get(),
+                    log_data,
+                    base::Int64ToString(base::Time::Now().ToTimeT()));
 }
 
 void PersistedLogs::StageLog() {
@@ -139,7 +136,7 @@
 PersistedLogs::LogReadStatus PersistedLogs::ReadLogsFromPrefList(
     const base::ListValue& list_value) {
   if (list_value.empty())
-    return MakeRecallStatusHistogram(LIST_EMPTY);
+    return metrics_->RecordLogReadStatus(LIST_EMPTY);
 
   const size_t log_count = list_value.GetSize();
 
@@ -152,7 +149,7 @@
         !dict->GetString(kLogDataKey, &list_[i].compressed_log_data) ||
         !dict->GetString(kLogHashKey, &list_[i].hash)) {
       list_.clear();
-      return MakeRecallStatusHistogram(LOG_STRING_CORRUPTION);
+      return metrics_->RecordLogReadStatus(LOG_STRING_CORRUPTION);
     }
 
     list_[i].compressed_log_data =
@@ -165,7 +162,7 @@
     dict->GetString(kLogTimestampKey, &list_[i].timestamp);
   }
 
-  return MakeRecallStatusHistogram(RECALL_SUCCESS);
+  return metrics_->RecordLogReadStatus(RECALL_SUCCESS);
 }
 
 void PersistedLogs::WriteLogsToPrefList(base::ListValue* list_value) const {
@@ -194,8 +191,7 @@
   for (size_t i = start; i < list_.size(); ++i) {
     size_t log_size = list_[i].compressed_log_data.length();
     if (log_size > max_log_size_) {
-      UMA_HISTOGRAM_COUNTS("UMA.Large Accumulated Log Not Persisted",
-                           static_cast<int>(log_size));
+      metrics_->RecordDroppedLogSize(log_size);
       dropped_logs_num++;
       continue;
     }
@@ -208,13 +204,13 @@
     list_value->Append(std::move(dict_value));
   }
   if (dropped_logs_num > 0)
-    UMA_HISTOGRAM_COUNTS("UMA.UnsentLogs.Dropped", dropped_logs_num);
+    metrics_->RecordDroppedLogsNum(dropped_logs_num);
 }
 
 PersistedLogs::LogReadStatus PersistedLogs::ReadLogsFromOldFormatPrefList(
     const base::ListValue& list_value) {
   if (list_value.empty())
-    return MakeRecallStatusHistogram(LIST_EMPTY);
+    return metrics_->RecordLogReadStatus(LIST_EMPTY);
 
   // For each log, there's two entries in the list (the data and the hash).
   DCHECK_EQ(0U, list_value.GetSize() % 2);
@@ -229,11 +225,11 @@
     if (!ReadBase64String(list_value, i * 2, &list_[i].compressed_log_data) ||
         !ReadBase64String(list_value, i * 2 + 1, &list_[i].hash)) {
       list_.clear();
-      return MakeRecallStatusHistogram(LOG_STRING_CORRUPTION);
+      return metrics_->RecordLogReadStatus(LOG_STRING_CORRUPTION);
     }
   }
 
-  return MakeRecallStatusHistogram(RECALL_SUCCESS);
+  return metrics_->RecordLogReadStatus(RECALL_SUCCESS);
 }
 
 }  // namespace metrics
diff --git a/components/metrics/persisted_logs.h b/components/metrics/persisted_logs.h
index 479924f..2af474b 100644
--- a/components/metrics/persisted_logs.h
+++ b/components/metrics/persisted_logs.h
@@ -7,6 +7,7 @@
 
 #include <stddef.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -18,6 +19,8 @@
 
 namespace metrics {
 
+class PersistedLogsMetrics;
+
 // Maintains a list of unsent logs that are written and restored from disk.
 class PersistedLogs {
  public:
@@ -49,7 +52,8 @@
   //
   // If the optional |max_log_size| parameter is non-zero, all logs larger than
   // that limit will be skipped when writing to disk.
-  PersistedLogs(PrefService* local_state,
+  PersistedLogs(std::unique_ptr<PersistedLogsMetrics> metrics,
+                PrefService* local_state,
                 const char* pref_name,
                 const char* outdated_pref_name,
                 size_t min_log_count,
@@ -110,6 +114,9 @@
   // Reads the list from the ListValue in the old Log-hash pair format.
   LogReadStatus ReadLogsFromOldFormatPrefList(const base::ListValue& list);
 
+  // An object for recording UMA metrics.
+  std::unique_ptr<PersistedLogsMetrics> metrics_;
+
   // A weak pointer to the PrefService object to read and write the preference
   // from.  Calling code should ensure this object continues to exist for the
   // lifetime of the PersistedLogs object.
@@ -134,7 +141,10 @@
   struct LogInfo {
     // Initializes the members based on uncompressed |log_data| and
     // |log_timestamp|.
-    void Init(const std::string& log_data, const std::string& log_timestamp);
+    // |metrics| is the parent's metrics_ object, and should not be held.
+    void Init(PersistedLogsMetrics* metrics,
+              const std::string& log_data,
+              const std::string& log_timestamp);
 
     // Compressed log data - a serialized protobuf that's been gzipped.
     std::string compressed_log_data;
diff --git a/components/metrics/persisted_logs_metrics.h b/components/metrics/persisted_logs_metrics.h
new file mode 100644
index 0000000..5263bd3ed
--- /dev/null
+++ b/components/metrics/persisted_logs_metrics.h
@@ -0,0 +1,35 @@
+// 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 COMPONENTS_METRICS_PERSISTED_LOGS_METRICS_H_
+#define COMPONENTS_METRICS_PERSISTED_LOGS_METRICS_H_
+
+#include "base/macros.h"
+#include "components/metrics/persisted_logs.h"
+
+namespace metrics {
+
+// Interface for recording metrics from PersistedLogs.
+class PersistedLogsMetrics {
+ public:
+  PersistedLogsMetrics() {}
+  ~PersistedLogsMetrics() {}
+
+  virtual PersistedLogs::LogReadStatus RecordLogReadStatus(
+      PersistedLogs::LogReadStatus status) = 0;
+
+  virtual void RecordCompressionRatio(
+    size_t compressed_size, size_t original_size) {}
+
+  virtual void RecordDroppedLogSize(size_t size) {}
+
+  virtual void RecordDroppedLogsNum(int dropped_logs_num) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PersistedLogsMetrics);
+};
+
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_PERSISTED_LOGS_METRICS_H_
diff --git a/components/metrics/persisted_logs_metrics_impl.cc b/components/metrics/persisted_logs_metrics_impl.cc
new file mode 100644
index 0000000..877ad28
--- /dev/null
+++ b/components/metrics/persisted_logs_metrics_impl.cc
@@ -0,0 +1,35 @@
+// 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.
+
+#include "components/metrics/persisted_logs_metrics_impl.h"
+
+#include "base/metrics/histogram_macros.h"
+
+namespace metrics {
+
+PersistedLogs::LogReadStatus
+PersistedLogsMetricsImpl::RecordLogReadStatus(
+    PersistedLogs::LogReadStatus status) {
+  UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogRecallProtobufs",
+                            status, PersistedLogs::END_RECALL_STATUS);
+  return status;
+}
+
+void PersistedLogsMetricsImpl::RecordCompressionRatio(
+    size_t compressed_size, size_t original_size) {
+  UMA_HISTOGRAM_PERCENTAGE(
+      "UMA.ProtoCompressionRatio",
+      static_cast<int>(100 * compressed_size / original_size));
+}
+
+void PersistedLogsMetricsImpl::RecordDroppedLogSize(size_t size) {
+  UMA_HISTOGRAM_COUNTS("UMA.Large Accumulated Log Not Persisted",
+                       static_cast<int>(size));
+}
+
+void PersistedLogsMetricsImpl::RecordDroppedLogsNum(int dropped_logs_num) {
+  UMA_HISTOGRAM_COUNTS("UMA.UnsentLogs.Dropped", dropped_logs_num);
+}
+
+}  // namespace metrics
diff --git a/components/metrics/persisted_logs_metrics_impl.h b/components/metrics/persisted_logs_metrics_impl.h
new file mode 100644
index 0000000..e7f4a2d9
--- /dev/null
+++ b/components/metrics/persisted_logs_metrics_impl.h
@@ -0,0 +1,35 @@
+// 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 COMPONENTS_METRICS_PERSISTED_LOGS_METRICS_IMPL_H_
+#define COMPONENTS_METRICS_PERSISTED_LOGS_METRICS_IMPL_H_
+
+#include "base/macros.h"
+#include "components/metrics/persisted_logs_metrics.h"
+
+namespace metrics {
+
+// Implementation for recording metrics from PersistedLogs.
+class PersistedLogsMetricsImpl : public PersistedLogsMetrics {
+ public:
+  PersistedLogsMetricsImpl() {}
+  ~PersistedLogsMetricsImpl() {}
+
+  PersistedLogs::LogReadStatus RecordLogReadStatus(
+      PersistedLogs::LogReadStatus status) override;
+
+  void RecordCompressionRatio(
+    size_t compressed_size, size_t original_size) override;
+
+  void RecordDroppedLogSize(size_t size) override;
+
+  void RecordDroppedLogsNum(int dropped_logs_num) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(PersistedLogsMetricsImpl);
+};
+
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_PERSISTED_LOGS_METRICS_IMPL_H_
diff --git a/components/metrics/persisted_logs_unittest.cc b/components/metrics/persisted_logs_unittest.cc
index 94b8b7e9..179f4d80 100644
--- a/components/metrics/persisted_logs_unittest.cc
+++ b/components/metrics/persisted_logs_unittest.cc
@@ -11,6 +11,7 @@
 #include "base/rand_util.h"
 #include "base/sha1.h"
 #include "base/values.h"
+#include "components/metrics/persisted_logs_metrics_impl.h"
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/prefs/testing_pref_service.h"
@@ -64,7 +65,9 @@
 class TestPersistedLogs : public PersistedLogs {
  public:
   TestPersistedLogs(PrefService* service, size_t min_log_bytes)
-      : PersistedLogs(service,
+      : PersistedLogs(std::unique_ptr<PersistedLogsMetricsImpl>(
+                             new PersistedLogsMetricsImpl()),
+                      service,
                       kTestPrefName,
                       kTestOutdatedPrefName,
                       kLogCountLimit,
diff --git a/components/network_session_configurator/network_session_configurator.cc b/components/network_session_configurator/network_session_configurator.cc
index 6100395..4e9757f9 100644
--- a/components/network_session_configurator/network_session_configurator.cc
+++ b/components/network_session_configurator/network_session_configurator.cc
@@ -396,6 +396,14 @@
   }
 }
 
+void ConfigureOptimizePreconnectsToProxiesParams(
+    const std::map<std::string, std::string>& proxy_preconnects_trial_params,
+    net::HttpNetworkSession::Params* params) {
+  params->restrict_to_one_preconnect_for_proxies =
+      GetVariationParam(proxy_preconnects_trial_params,
+                        "restrict_to_one_preconnect_for_proxies") == "true";
+}
+
 }  // anonymous namespace
 
 namespace network_session_configurator {
@@ -436,6 +444,12 @@
   const std::string tfo_trial_group =
       base::FieldTrialList::FindFullName(kTCPFastOpenFieldTrialName);
   ConfigureTCPFastOpenParams(tfo_trial_group, params);
+
+  std::map<std::string, std::string> proxy_preconnects_trial_params;
+  variations::GetVariationParams("NetProxyPreconnects",
+                                 &proxy_preconnects_trial_params);
+  ConfigureOptimizePreconnectsToProxiesParams(proxy_preconnects_trial_params,
+                                              params);
 }
 
 }  // namespace network_session_configurator
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index f619693..85b90ce 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -463,6 +463,8 @@
     "devtools/page_navigation_throttle.h",
     "devtools/protocol/color_picker.cc",
     "devtools/protocol/color_picker.h",
+    "devtools/protocol/devtools_domain_handler.cc",
+    "devtools/protocol/devtools_domain_handler.h",
     "devtools/protocol/dom_handler.cc",
     "devtools/protocol/dom_handler.h",
     "devtools/protocol/emulation_handler.cc",
diff --git a/content/browser/devtools/browser_devtools_agent_host.cc b/content/browser/devtools/browser_devtools_agent_host.cc
index a715bb5..86d8eec 100644
--- a/content/browser/devtools/browser_devtools_agent_host.cc
+++ b/content/browser/devtools/browser_devtools_agent_host.cc
@@ -6,7 +6,7 @@
 
 #include "base/bind.h"
 #include "base/guid.h"
-#include "base/json/json_reader.h"
+#include "base/memory/ptr_util.h"
 #include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/protocol/io_handler.h"
 #include "content/browser/devtools/protocol/memory_handler.h"
@@ -36,38 +36,20 @@
 BrowserDevToolsAgentHost::~BrowserDevToolsAgentHost() {
 }
 
-void BrowserDevToolsAgentHost::Attach() {
-  io_handler_.reset(new protocol::IOHandler(GetIOContext()));
-  io_handler_->Wire(session()->dispatcher());
-
-  memory_handler_.reset(new protocol::MemoryHandler());
-  memory_handler_->Wire(session()->dispatcher());
-
-  system_info_handler_.reset(new protocol::SystemInfoHandler());
-  system_info_handler_->Wire(session()->dispatcher());
-
-  tethering_handler_.reset(new protocol::TetheringHandler(
-      socket_callback_, tethering_task_runner_));
-  tethering_handler_->Wire(session()->dispatcher());
-
-  tracing_handler_.reset(new protocol::TracingHandler(
+void BrowserDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+  session->AddHandler(base::WrapUnique(new protocol::IOHandler(
+      GetIOContext())));
+  session->AddHandler(base::WrapUnique(new protocol::MemoryHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::SystemInfoHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::TetheringHandler(
+      socket_callback_, tethering_task_runner_)));
+  session->AddHandler(base::WrapUnique(new protocol::TracingHandler(
       protocol::TracingHandler::Browser,
       FrameTreeNode::kFrameTreeNodeInvalidId,
-      GetIOContext()));
-  tracing_handler_->Wire(session()->dispatcher());
+      GetIOContext())));
 }
 
-void BrowserDevToolsAgentHost::Detach() {
-  io_handler_->Disable();
-  io_handler_.reset();
-  memory_handler_->Disable();
-  memory_handler_.reset();
-  system_info_handler_->Disable();
-  system_info_handler_.reset();
-  tethering_handler_->Disable();
-  tethering_handler_.reset();
-  tracing_handler_->Disable();
-  tracing_handler_.reset();
+void BrowserDevToolsAgentHost::DetachSession(int session_id) {
 }
 
 std::string BrowserDevToolsAgentHost::GetType() {
@@ -94,8 +76,11 @@
 }
 
 bool BrowserDevToolsAgentHost::DispatchProtocolMessage(
+    DevToolsSession* session,
     const std::string& message) {
-  session()->dispatcher()->dispatch(protocol::StringUtil::parseJSON(message));
+  int call_id;
+  std::string method;
+  session->Dispatch(message, false, &call_id, &method);
   return true;
 }
 
diff --git a/content/browser/devtools/browser_devtools_agent_host.h b/content/browser/devtools/browser_devtools_agent_host.h
index d466a29..8be1ef4 100644
--- a/content/browser/devtools/browser_devtools_agent_host.h
+++ b/content/browser/devtools/browser_devtools_agent_host.h
@@ -26,8 +26,11 @@
   ~BrowserDevToolsAgentHost() override;
 
   // DevToolsAgentHostImpl implementation.
-  void Attach() override;
-  void Detach() override;
+  void AttachSession(DevToolsSession* session) override;
+  void DetachSession(int session_id) override;
+  bool DispatchProtocolMessage(
+      DevToolsSession* session,
+      const std::string& message) override;
 
   // DevToolsAgentHost implementation.
   std::string GetType() override;
@@ -36,7 +39,6 @@
   bool Activate() override;
   void Reload() override;
   bool Close() override;
-  bool DispatchProtocolMessage(const std::string& message) override;
 
   scoped_refptr<base::SingleThreadTaskRunner> tethering_task_runner_;
   CreateServerSocketCallback socket_callback_;
diff --git a/content/browser/devtools/devtools_agent_host_impl.cc b/content/browser/devtools/devtools_agent_host_impl.cc
index f0972779..a23f00b5 100644
--- a/content/browser/devtools/devtools_agent_host_impl.cc
+++ b/content/browser/devtools/devtools_agent_host_impl.cc
@@ -106,8 +106,7 @@
 
 DevToolsAgentHostImpl::DevToolsAgentHostImpl(const std::string& id)
     : id_(id),
-      last_session_id_(0),
-      client_(NULL) {
+      last_session_id_(0) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 }
 
@@ -137,68 +136,64 @@
   return new ForwardingAgentHost(id, std::move(delegate));
 }
 
-bool DevToolsAgentHostImpl::InnerAttach(DevToolsAgentHostClient* client,
-                                        bool force) {
-  if (client_ && !force)
+bool DevToolsAgentHostImpl::InnerAttachClient(DevToolsAgentHostClient* client,
+                                              bool force) {
+  if (session_ && !force)
     return false;
 
   scoped_refptr<DevToolsAgentHostImpl> protect(this);
-  if (client_) {
-    client_->AgentHostClosed(this, true);
-    InnerDetach();
-  }
-  client_ = client;
-  session_.reset(new DevToolsSession(this, ++last_session_id_));
-  Attach();
+  if (session_)
+    ForceDetach(true);
+  session_.reset(new DevToolsSession(this, client, ++last_session_id_));
+  AttachSession(session_.get());
   NotifyAttached();
   return true;
 }
 
 bool DevToolsAgentHostImpl::AttachClient(DevToolsAgentHostClient* client) {
-  return InnerAttach(client, false);
+  return InnerAttachClient(client, false);
 }
 
 void DevToolsAgentHostImpl::ForceAttachClient(DevToolsAgentHostClient* client) {
-  InnerAttach(client, true);
+  InnerAttachClient(client, true);
 }
 
 bool DevToolsAgentHostImpl::DetachClient(DevToolsAgentHostClient* client) {
-  if (!client_ || client_ != client)
+  if (!session_ || session_->client() != client)
     return false;
 
   scoped_refptr<DevToolsAgentHostImpl> protect(this);
-  client_ = NULL;
-  InnerDetach();
+  InnerDetachClient();
   return true;
 }
 
 bool DevToolsAgentHostImpl::DispatchProtocolMessage(
     DevToolsAgentHostClient* client,
     const std::string& message) {
-  if (!client_ || client_ != client)
+  if (!session_ || session_->client() != client)
     return false;
-  return DispatchProtocolMessage(message);
+  return DispatchProtocolMessage(session_.get(), message);
 }
 
-void DevToolsAgentHostImpl::InnerDetach() {
-  session_->ResetDispatcher();
-  Detach();
-  io_context_.DiscardAllStreams();
+void DevToolsAgentHostImpl::InnerDetachClient() {
+  int session_id = session_->session_id();
   session_.reset();
+  DetachSession(session_id);
+  io_context_.DiscardAllStreams();
   NotifyDetached();
 }
 
 bool DevToolsAgentHostImpl::IsAttached() {
-  return !!client_;
+  return !!session_;
 }
 
 void DevToolsAgentHostImpl::InspectElement(
     DevToolsAgentHostClient* client,
     int x,
     int y) {
- if (!client_ || client_ != client)
+ if (!session_ || session_->client() != client)
    return;
- InspectElement(x, y);
+ InspectElement(session_.get(), x, y);
 }
 
 std::string DevToolsAgentHostImpl::GetId() {
@@ -248,29 +243,28 @@
   return false;
 }
 
-void DevToolsAgentHostImpl::HostClosed() {
-  if (!client_)
+void DevToolsAgentHostImpl::ForceDetach(bool replaced) {
+  if (!session_)
     return;
-
   scoped_refptr<DevToolsAgentHostImpl> protect(this);
   // Clear |client_| before notifying it.
-  DevToolsAgentHostClient* client = client_;
-  client_ = NULL;
-  client->AgentHostClosed(this, false);
-  InnerDetach();
+  DevToolsAgentHostClient* client = session_->client();
+  InnerDetachClient();
+  client->AgentHostClosed(this, replaced);
 }
 
-void DevToolsAgentHostImpl::InspectElement(int x, int y) {
+void DevToolsAgentHostImpl::InspectElement(
+    DevToolsSession* session,
+    int x,
+    int y) {
 }
 
 void DevToolsAgentHostImpl::SendMessageToClient(int session_id,
                                                 const std::string& message) {
-  if (!client_)
-    return;
   // Filter any messages from previous sessions.
   if (!session_ || session_id != session_->session_id())
     return;
-  client_->DispatchProtocolMessage(this, message);
+  session_->client()->DispatchProtocolMessage(this, message);
 }
 
 // static
@@ -283,14 +277,7 @@
   Instances copy = g_instances.Get();
   for (Instances::iterator it(copy.begin()); it != copy.end(); ++it) {
     DevToolsAgentHostImpl* agent_host = it->second;
-    if (agent_host->client_) {
-      scoped_refptr<DevToolsAgentHostImpl> protect(agent_host);
-      // Clear |client_| before notifying it.
-      DevToolsAgentHostClient* client = agent_host->client_;
-      agent_host->client_ = NULL;
-      client->AgentHostClosed(agent_host, true);
-      agent_host->InnerDetach();
-    }
+    agent_host->ForceDetach(true);
   }
 }
 
diff --git a/content/browser/devtools/devtools_agent_host_impl.h b/content/browser/devtools/devtools_agent_host_impl.h
index 75541d1..8190ce6d 100644
--- a/content/browser/devtools/devtools_agent_host_impl.h
+++ b/content/browser/devtools/devtools_agent_host_impl.h
@@ -23,12 +23,6 @@
 // Describes interface for managing devtools agents from the browser process.
 class CONTENT_EXPORT DevToolsAgentHostImpl : public DevToolsAgentHost {
  public:
-  // Informs the hosted agent that a client host has attached.
-  virtual void Attach() = 0;
-
-  // Informs the hosted agent that a client host has detached.
-  virtual void Detach() = 0;
-
   // DevToolsAgentHost implementation.
   bool AttachClient(DevToolsAgentHostClient* client) override;
   void ForceAttachClient(DevToolsAgentHostClient* client) override;
@@ -57,28 +51,31 @@
 
   static bool ShouldForceCreation();
 
-  virtual bool DispatchProtocolMessage(const std::string& message) = 0;
-  virtual void InspectElement(int x, int y);
+  virtual void AttachSession(DevToolsSession* session) = 0;
+  virtual void DetachSession(int session_id) = 0;
+  virtual bool DispatchProtocolMessage(
+      DevToolsSession* session,
+      const std::string& message) = 0;
+  virtual void InspectElement(DevToolsSession* session, int x, int y);
 
   void NotifyCreated();
-  void HostClosed();
+  void ForceDetach(bool replaced);
   DevToolsIOContext* GetIOContext() { return &io_context_; }
 
+  // TODO(dgozman): remove this accessor.
   DevToolsSession* session() { return session_.get(); }
 
  private:
   friend class DevToolsAgentHost; // for static methods
-  bool InnerAttach(DevToolsAgentHostClient* client, bool force);
-  void InnerDetach();
+  bool InnerAttachClient(DevToolsAgentHostClient* client, bool force);
+  void InnerDetachClient();
   void NotifyAttached();
   void NotifyDetached();
   void NotifyDestroyed();
 
   const std::string id_;
-  int session_id_;
   int last_session_id_;
   std::unique_ptr<DevToolsSession> session_;
-  DevToolsAgentHostClient* client_;
   DevToolsIOContext io_context_;
   static int s_attached_count_;
   static int s_force_creation_count_;
diff --git a/content/browser/devtools/devtools_session.cc b/content/browser/devtools/devtools_session.cc
index 60ccb85..c11aa30 100644
--- a/content/browser/devtools/devtools_session.cc
+++ b/content/browser/devtools/devtools_session.cc
@@ -15,26 +15,48 @@
 
 DevToolsSession::DevToolsSession(
     DevToolsAgentHostImpl* agent_host,
+    DevToolsAgentHostClient* client,
     int session_id)
     : agent_host_(agent_host),
+      client_(client),
       session_id_(session_id),
+      host_(nullptr),
       dispatcher_(new protocol::UberDispatcher(this)) {
 }
 
-DevToolsSession::~DevToolsSession() {}
-
-void DevToolsSession::ResetDispatcher() {
+DevToolsSession::~DevToolsSession() {
   dispatcher_.reset();
+  for (auto& pair : handlers_)
+    pair.second->Disable();
+  handlers_.clear();
+}
+
+void DevToolsSession::AddHandler(
+    std::unique_ptr<protocol::DevToolsDomainHandler> handler) {
+  handler->Wire(dispatcher_.get());
+  handler->SetRenderFrameHost(host_);
+  handlers_[handler->name()] = std::move(handler);
+}
+
+void DevToolsSession::SetRenderFrameHost(RenderFrameHostImpl* host) {
+  host_ = host;
+  for (auto& pair : handlers_)
+    pair.second->SetRenderFrameHost(host_);
+}
+
+void DevToolsSession::SetFallThroughForNotFound(bool value) {
+  dispatcher_->setFallThroughForNotFound(value);
 }
 
 protocol::Response::Status DevToolsSession::Dispatch(
     const std::string& message,
+    bool offer_to_delegate,
     int* call_id,
     std::string* method) {
   std::unique_ptr<base::Value> value = base::JSONReader::Read(message);
 
-  DevToolsManagerDelegate* delegate =
-      DevToolsManager::GetInstance()->delegate();
+  DevToolsManagerDelegate* delegate = offer_to_delegate ?
+      DevToolsManager::GetInstance()->delegate() : nullptr;
   if (value && value->IsType(base::Value::Type::DICTIONARY) && delegate) {
     std::unique_ptr<base::DictionaryValue> response(delegate->HandleCommand(
         agent_host_,
@@ -65,4 +87,12 @@
 void DevToolsSession::flushProtocolNotifications() {
 }
 
+protocol::DevToolsDomainHandler* DevToolsSession::GetHandlerByName(
+    const std::string& name) {
+  auto it = handlers_.find(name);
+  if (it == handlers_.end())
+    return nullptr;
+  return it->second.get();
+}
+
 }  // namespace content
diff --git a/content/browser/devtools/devtools_session.h b/content/browser/devtools/devtools_session.h
index c02fc56..e568dd2 100644
--- a/content/browser/devtools/devtools_session.h
+++ b/content/browser/devtools/devtools_session.h
@@ -2,25 +2,36 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/protocol.h"
 
 namespace content {
 
 class DevToolsAgentHostImpl;
+class DevToolsAgentHostClient;
+class RenderFrameHostImpl;
 
 class DevToolsSession : public protocol::FrontendChannel {
  public:
-  DevToolsSession(DevToolsAgentHostImpl* agent_host, int session_id);
+  DevToolsSession(DevToolsAgentHostImpl* agent_host,
+                  DevToolsAgentHostClient* client,
+                  int session_id);
   ~DevToolsSession() override;
 
-  void ResetDispatcher();
+  int session_id() const { return session_id_; }
+  void AddHandler(std::unique_ptr<protocol::DevToolsDomainHandler> handler);
+  void SetRenderFrameHost(RenderFrameHostImpl* host);
+  void SetFallThroughForNotFound(bool value);
+  protocol::DevToolsDomainHandler* GetHandlerByName(const std::string& name);
+
   protocol::Response::Status Dispatch(
       const std::string& message,
+      bool offer_to_delegate,
       int* call_id,
       std::string* method);
 
-  int session_id() { return session_id_; }
-  protocol::UberDispatcher* dispatcher() { return dispatcher_.get(); }
+  // Only used by DevToolsAgentHostImpl.
+  DevToolsAgentHostClient* client() const { return client_; }
 
  private:
   // protocol::FrontendChannel implementation.
@@ -32,7 +43,11 @@
   void flushProtocolNotifications() override;
 
   DevToolsAgentHostImpl* agent_host_;
+  DevToolsAgentHostClient* client_;
   int session_id_;
+  std::unordered_map<std::string,
+      std::unique_ptr<protocol::DevToolsDomainHandler>> handlers_;
+  RenderFrameHostImpl* host_;
   std::unique_ptr<protocol::UberDispatcher> dispatcher_;
 };
 
diff --git a/content/browser/devtools/forwarding_agent_host.cc b/content/browser/devtools/forwarding_agent_host.cc
index 98b8954..808759d 100644
--- a/content/browser/devtools/forwarding_agent_host.cc
+++ b/content/browser/devtools/forwarding_agent_host.cc
@@ -26,18 +26,19 @@
 }
 
 void ForwardingAgentHost::ConnectionClosed() {
-  HostClosed();
+  ForceDetach(false);
 }
 
-void ForwardingAgentHost::Attach() {
+void ForwardingAgentHost::AttachSession(DevToolsSession* session) {
   delegate_->Attach(this);
 }
 
-void ForwardingAgentHost::Detach() {
+void ForwardingAgentHost::DetachSession(int session_id) {
   delegate_->Detach();
 }
 
 bool ForwardingAgentHost::DispatchProtocolMessage(
+    DevToolsSession* session,
     const std::string& message) {
   delegate_->SendMessageToBackend(message);
   return true;
diff --git a/content/browser/devtools/forwarding_agent_host.h b/content/browser/devtools/forwarding_agent_host.h
index c14ddb7..36263cd 100644
--- a/content/browser/devtools/forwarding_agent_host.h
+++ b/content/browser/devtools/forwarding_agent_host.h
@@ -30,9 +30,11 @@
   void ConnectionClosed() override;
 
   // DevToolsAgentHostImpl implementation.
-  void Attach() override;
-  void Detach() override;
-  bool DispatchProtocolMessage(const std::string& message) override;
+  void AttachSession(DevToolsSession* session) override;
+  void DetachSession(int session_id) override;
+  bool DispatchProtocolMessage(
+      DevToolsSession* session,
+      const std::string& message) override;
 
   // DevToolsAgentHost implementation
   std::string GetType() override;
diff --git a/content/browser/devtools/protocol/devtools_domain_handler.cc b/content/browser/devtools/protocol/devtools_domain_handler.cc
new file mode 100644
index 0000000..d1521bef
--- /dev/null
+++ b/content/browser/devtools/protocol/devtools_domain_handler.cc
@@ -0,0 +1,30 @@
+// 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.
+
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
+
+#include "content/browser/devtools/protocol/protocol.h"
+
+namespace content {
+namespace protocol {
+
+DevToolsDomainHandler::DevToolsDomainHandler(const std::string& name)
+    : name_(name) {
+}
+
+DevToolsDomainHandler::~DevToolsDomainHandler() {
+}
+
+void DevToolsDomainHandler::SetRenderFrameHost(RenderFrameHostImpl* host) {
+}
+
+void DevToolsDomainHandler::Wire(UberDispatcher* dispatcher) {
+}
+
+Response DevToolsDomainHandler::Disable() {
+  return Response::OK();
+}
+
+}  // namespace protocol
+}  // namespace content
diff --git a/content/browser/devtools/protocol/devtools_domain_handler.h b/content/browser/devtools/protocol/devtools_domain_handler.h
new file mode 100644
index 0000000..6eb27b5
--- /dev/null
+++ b/content/browser/devtools/protocol/devtools_domain_handler.h
@@ -0,0 +1,36 @@
+// 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 CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_DOMAIN_HANDLER_H_
+#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_DOMAIN_HANDLER_H_
+
+#include "content/browser/devtools/protocol/forward.h"
+
+namespace content {
+
+class RenderFrameHostImpl;
+
+namespace protocol {
+
+class DevToolsDomainHandler {
+ public:
+  explicit DevToolsDomainHandler(const std::string& name);
+  virtual ~DevToolsDomainHandler();
+
+  virtual void SetRenderFrameHost(RenderFrameHostImpl* host);
+  virtual void Wire(UberDispatcher* dispatcher);
+  virtual Response Disable();
+
+  const std::string& name() const { return name_; }
+
+ private:
+  std::string name_;
+
+  DISALLOW_COPY_AND_ASSIGN(DevToolsDomainHandler);
+};
+
+}  // namespace protocol
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DEVTOOLS_DOMAIN_HANDLER_H_
diff --git a/content/browser/devtools/protocol/dom_handler.cc b/content/browser/devtools/protocol/dom_handler.cc
index 036ca49..31d37a94 100644
--- a/content/browser/devtools/protocol/dom_handler.cc
+++ b/content/browser/devtools/protocol/dom_handler.cc
@@ -12,7 +12,9 @@
 namespace content {
 namespace protocol {
 
-DOMHandler::DOMHandler() : host_(nullptr) {
+DOMHandler::DOMHandler()
+    : DevToolsDomainHandler(DOM::Metainfo::domainName),
+      host_(nullptr) {
 }
 
 DOMHandler::~DOMHandler() {
diff --git a/content/browser/devtools/protocol/dom_handler.h b/content/browser/devtools/protocol/dom_handler.h
index 808af9c7..9ccf1406 100644
--- a/content/browser/devtools/protocol/dom_handler.h
+++ b/content/browser/devtools/protocol/dom_handler.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_DOM_HANDLER_H_
 
 #include "base/macros.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/dom.h"
 
 namespace content {
@@ -14,13 +15,14 @@
 
 namespace protocol {
 
-class DOMHandler : public DOM::Backend {
+class DOMHandler : public DevToolsDomainHandler,
+                   public DOM::Backend {
  public:
   DOMHandler();
   ~DOMHandler() override;
 
-  void Wire(UberDispatcher*);
-  void SetRenderFrameHost(RenderFrameHostImpl* host);
+  void Wire(UberDispatcher* dispatcher) override;
+  void SetRenderFrameHost(RenderFrameHostImpl* host) override;
   Response Disable() override;
 
   Response SetFileInputFiles(
diff --git a/content/browser/devtools/protocol/emulation_handler.cc b/content/browser/devtools/protocol/emulation_handler.cc
index 7718aad..764dc5e 100644
--- a/content/browser/devtools/protocol/emulation_handler.cc
+++ b/content/browser/devtools/protocol/emulation_handler.cc
@@ -55,7 +55,8 @@
 }  // namespace
 
 EmulationHandler::EmulationHandler()
-    : touch_emulation_enabled_(false),
+    : DevToolsDomainHandler(Emulation::Metainfo::domainName),
+      touch_emulation_enabled_(false),
       device_emulation_enabled_(false),
       host_(nullptr) {
 }
diff --git a/content/browser/devtools/protocol/emulation_handler.h b/content/browser/devtools/protocol/emulation_handler.h
index b5ff169..2cd97be 100644
--- a/content/browser/devtools/protocol/emulation_handler.h
+++ b/content/browser/devtools/protocol/emulation_handler.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_EMULATION_HANDLER_H_
 
 #include "base/macros.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/emulation.h"
 #include "third_party/WebKit/public/web/WebDeviceEmulationParams.h"
 
@@ -16,13 +17,14 @@
 
 namespace protocol {
 
-class EmulationHandler : public Emulation::Backend {
+class EmulationHandler : public DevToolsDomainHandler,
+                         public Emulation::Backend {
  public:
   EmulationHandler();
   ~EmulationHandler() override;
 
-  void SetRenderFrameHost(RenderFrameHostImpl* host);
-  void Wire(UberDispatcher*);
+  void Wire(UberDispatcher* dispatcher) override;
+  void SetRenderFrameHost(RenderFrameHostImpl* host) override;
   Response Disable() override;
 
   Response SetGeolocationOverride(Maybe<double> latitude,
diff --git a/content/browser/devtools/protocol/input_handler.cc b/content/browser/devtools/protocol/input_handler.cc
index 12dd6bb..03add8b6 100644
--- a/content/browser/devtools/protocol/input_handler.cc
+++ b/content/browser/devtools/protocol/input_handler.cc
@@ -11,6 +11,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "cc/output/compositor_frame_metadata.h"
+#include "content/browser/devtools/devtools_session.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/common/input/synthetic_pinch_gesture_params.h"
@@ -180,7 +181,8 @@
 }  // namespace
 
 InputHandler::InputHandler()
-    : host_(NULL),
+    : DevToolsDomainHandler(Input::Metainfo::domainName),
+      host_(nullptr),
       page_scale_factor_(1.0),
       last_id_(0),
       weak_factory_(this) {
@@ -189,6 +191,12 @@
 InputHandler::~InputHandler() {
 }
 
+// static
+InputHandler* InputHandler::FromSession(DevToolsSession* session) {
+  return static_cast<InputHandler*>(
+      session->GetHandlerByName(Input::Metainfo::domainName));
+}
+
 void InputHandler::SetRenderFrameHost(RenderFrameHostImpl* host) {
   host_ = host;
 }
diff --git a/content/browser/devtools/protocol/input_handler.h b/content/browser/devtools/protocol/input_handler.h
index 253db3ee..098f1ed 100644
--- a/content/browser/devtools/protocol/input_handler.h
+++ b/content/browser/devtools/protocol/input_handler.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/input.h"
 #include "content/browser/renderer_host/input/synthetic_gesture.h"
 #include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
@@ -18,17 +19,21 @@
 
 namespace content {
 
+class DevToolsSession;
 class RenderFrameHostImpl;
 
 namespace protocol {
 
-class InputHandler : public Input::Backend {
+class InputHandler : public DevToolsDomainHandler,
+                     public Input::Backend {
  public:
   InputHandler();
   ~InputHandler() override;
 
-  void Wire(UberDispatcher*);
-  void SetRenderFrameHost(RenderFrameHostImpl* host);
+  static InputHandler* FromSession(DevToolsSession* session);
+
+  void Wire(UberDispatcher* dispatcher) override;
+  void SetRenderFrameHost(RenderFrameHostImpl* host) override;
   void OnSwapCompositorFrame(const cc::CompositorFrameMetadata& frame_metadata);
   Response Disable() override;
 
diff --git a/content/browser/devtools/protocol/inspector_handler.cc b/content/browser/devtools/protocol/inspector_handler.cc
index b3333153..10a4306 100644
--- a/content/browser/devtools/protocol/inspector_handler.cc
+++ b/content/browser/devtools/protocol/inspector_handler.cc
@@ -4,18 +4,26 @@
 
 #include "content/browser/devtools/protocol/inspector_handler.h"
 
+#include "content/browser/devtools/devtools_session.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 
 namespace content {
 namespace protocol {
 
 InspectorHandler::InspectorHandler()
-    : host_(nullptr) {
+    : DevToolsDomainHandler(Inspector::Metainfo::domainName),
+      host_(nullptr) {
 }
 
 InspectorHandler::~InspectorHandler() {
 }
 
+// static
+InspectorHandler* InspectorHandler::FromSession(DevToolsSession* session) {
+  return static_cast<InspectorHandler*>(
+      session->GetHandlerByName(Inspector::Metainfo::domainName));
+}
+
 void InspectorHandler::Wire(UberDispatcher* dispatcher) {
   frontend_.reset(new Inspector::Frontend(dispatcher->channel()));
   Inspector::Dispatcher::wire(dispatcher, this);
diff --git a/content/browser/devtools/protocol/inspector_handler.h b/content/browser/devtools/protocol/inspector_handler.h
index 6bd0c375..60337abe 100644
--- a/content/browser/devtools/protocol/inspector_handler.h
+++ b/content/browser/devtools/protocol/inspector_handler.h
@@ -6,21 +6,26 @@
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_INSPECTOR_HANDLER_H_
 
 #include "base/macros.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/inspector.h"
 
 namespace content {
 
+class DevToolsSession;
 class RenderFrameHostImpl;
 
 namespace protocol {
 
-class InspectorHandler : public Inspector::Backend {
+class InspectorHandler : public DevToolsDomainHandler,
+                         public Inspector::Backend {
  public:
   InspectorHandler();
   ~InspectorHandler() override;
 
-  void Wire(UberDispatcher*);
-  void SetRenderFrameHost(RenderFrameHostImpl* host);
+  static InspectorHandler* FromSession(DevToolsSession* session);
+
+  void Wire(UberDispatcher* dispatcher) override;
+  void SetRenderFrameHost(RenderFrameHostImpl* host) override;
 
   void TargetCrashed();
   void TargetDetached(const std::string& reason);
diff --git a/content/browser/devtools/protocol/io_handler.cc b/content/browser/devtools/protocol/io_handler.cc
index f8228e1..2b6a76d4 100644
--- a/content/browser/devtools/protocol/io_handler.cc
+++ b/content/browser/devtools/protocol/io_handler.cc
@@ -19,7 +19,8 @@
 namespace protocol {
 
 IOHandler::IOHandler(DevToolsIOContext* io_context)
-    : io_context_(io_context)
+    : DevToolsDomainHandler(IO::Metainfo::domainName),
+      io_context_(io_context)
     , weak_factory_(this) {}
 
 IOHandler::~IOHandler() {}
@@ -29,10 +30,6 @@
   IO::Dispatcher::wire(dispatcher, this);
 }
 
-Response IOHandler::Disable() {
-  return Response::OK();
-}
-
 void IOHandler::Read(
     const std::string& handle,
     Maybe<int> offset,
diff --git a/content/browser/devtools/protocol/io_handler.h b/content/browser/devtools/protocol/io_handler.h
index 647a270c..7ac6f80 100644
--- a/content/browser/devtools/protocol/io_handler.h
+++ b/content/browser/devtools/protocol/io_handler.h
@@ -7,6 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/io.h"
 
 namespace base {
@@ -18,13 +19,13 @@
 
 namespace protocol {
 
-class IOHandler : public IO::Backend {
+class IOHandler : public DevToolsDomainHandler,
+                  public IO::Backend {
  public:
   explicit IOHandler(DevToolsIOContext* io_context);
   ~IOHandler() override;
 
-  void Wire(UberDispatcher*);
-  Response Disable() override;
+  void Wire(UberDispatcher* dispatcher) override;
 
   // Protocol methods.
   void Read(
diff --git a/content/browser/devtools/protocol/memory_handler.cc b/content/browser/devtools/protocol/memory_handler.cc
index 2a92df14..bdc14bc 100644
--- a/content/browser/devtools/protocol/memory_handler.cc
+++ b/content/browser/devtools/protocol/memory_handler.cc
@@ -12,7 +12,9 @@
 namespace content {
 namespace protocol {
 
-MemoryHandler::MemoryHandler() {}
+MemoryHandler::MemoryHandler()
+    : DevToolsDomainHandler(Memory::Metainfo::domainName) {
+}
 
 MemoryHandler::~MemoryHandler() {}
 
@@ -20,10 +22,6 @@
   Memory::Dispatcher::wire(dispatcher, this);
 }
 
-Response MemoryHandler::Disable() {
-  return Response::OK();
-}
-
 Response MemoryHandler::SetPressureNotificationsSuppressed(
     bool suppressed) {
   if (base::FeatureList::IsEnabled(features::kMemoryCoordinator)) {
diff --git a/content/browser/devtools/protocol/memory_handler.h b/content/browser/devtools/protocol/memory_handler.h
index 193ee8e97..05c55ef 100644
--- a/content/browser/devtools/protocol/memory_handler.h
+++ b/content/browser/devtools/protocol/memory_handler.h
@@ -6,18 +6,19 @@
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_MEMORY_HANDLER_H_
 
 #include "base/macros.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/memory.h"
 
 namespace content {
 namespace protocol {
 
-class MemoryHandler : public Memory::Backend {
+class MemoryHandler : public DevToolsDomainHandler,
+                      public Memory::Backend {
  public:
   MemoryHandler();
   ~MemoryHandler() override;
 
-  void Wire(UberDispatcher*);
-  Response Disable() override;
+  void Wire(UberDispatcher* dispatcher) override;
 
   Response SetPressureNotificationsSuppressed(bool suppressed) override;
   Response SimulatePressureNotification(const std::string& level) override;
diff --git a/content/browser/devtools/protocol/network_handler.cc b/content/browser/devtools/protocol/network_handler.cc
index 1aa8efc..60f76e2 100644
--- a/content/browser/devtools/protocol/network_handler.cc
+++ b/content/browser/devtools/protocol/network_handler.cc
@@ -9,6 +9,7 @@
 #include "base/containers/hash_tables.h"
 #include "base/strings/stringprintf.h"
 #include "base/time/time.h"
+#include "content/browser/devtools/devtools_session.h"
 #include "content/browser/frame_host/frame_tree_node.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/public/browser/browser_context.h"
@@ -267,12 +268,20 @@
 }  // namespace
 
 NetworkHandler::NetworkHandler()
-    : host_(nullptr), enabled_(false) {
+    : DevToolsDomainHandler(Network::Metainfo::domainName),
+      host_(nullptr),
+      enabled_(false) {
 }
 
 NetworkHandler::~NetworkHandler() {
 }
 
+// static
+NetworkHandler* NetworkHandler::FromSession(DevToolsSession* session) {
+  return static_cast<NetworkHandler*>(
+      session->GetHandlerByName(Network::Metainfo::domainName));
+}
+
 void NetworkHandler::Wire(UberDispatcher* dispatcher) {
   Network::Dispatcher::wire(dispatcher, this);
 }
diff --git a/content/browser/devtools/protocol/network_handler.h b/content/browser/devtools/protocol/network_handler.h
index b588a16..ba3c536 100644
--- a/content/browser/devtools/protocol/network_handler.h
+++ b/content/browser/devtools/protocol/network_handler.h
@@ -6,22 +6,27 @@
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_NETWORK_HANDLER_H_
 
 #include "base/macros.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/network.h"
 #include "net/cookies/canonical_cookie.h"
 
 namespace content {
 
+class DevToolsSession;
 class RenderFrameHostImpl;
 
 namespace protocol {
 
-class NetworkHandler : public Network::Backend {
+class NetworkHandler : public DevToolsDomainHandler,
+                       public Network::Backend {
  public:
   NetworkHandler();
   ~NetworkHandler() override;
 
-  void SetRenderFrameHost(RenderFrameHostImpl* host);
-  void Wire(UberDispatcher*);
+  static NetworkHandler* FromSession(DevToolsSession* session);
+
+  void Wire(UberDispatcher* dispatcher) override;
+  void SetRenderFrameHost(RenderFrameHostImpl* host) override;
 
   Response Enable(Maybe<int> max_total_size,
                   Maybe<int> max_resource_size) override;
diff --git a/content/browser/devtools/protocol/page_handler.cc b/content/browser/devtools/protocol/page_handler.cc
index 99e6ad2..03e4af0 100644
--- a/content/browser/devtools/protocol/page_handler.cc
+++ b/content/browser/devtools/protocol/page_handler.cc
@@ -14,6 +14,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/threading/worker_pool.h"
+#include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/page_navigation_throttle.h"
 #include "content/browser/devtools/protocol/color_picker.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
@@ -90,7 +91,8 @@
 }  // namespace
 
 PageHandler::PageHandler()
-    : enabled_(false),
+    : DevToolsDomainHandler(Page::Metainfo::domainName),
+      enabled_(false),
       screencast_enabled_(false),
       screencast_quality_(kDefaultScreenshotQuality),
       screencast_max_width_(-1),
@@ -111,6 +113,12 @@
 PageHandler::~PageHandler() {
 }
 
+// static
+PageHandler* PageHandler::FromSession(DevToolsSession* session) {
+  return static_cast<PageHandler*>(
+      session->GetHandlerByName(Page::Metainfo::domainName));
+}
+
 void PageHandler::SetRenderFrameHost(RenderFrameHostImpl* host) {
   if (host_ == host)
     return;
diff --git a/content/browser/devtools/protocol/page_handler.h b/content/browser/devtools/protocol/page_handler.h
index 32f80267..fdb1ac5 100644
--- a/content/browser/devtools/protocol/page_handler.h
+++ b/content/browser/devtools/protocol/page_handler.h
@@ -12,6 +12,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "cc/output/compositor_frame_metadata.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/page.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -21,6 +22,7 @@
 
 namespace content {
 
+class DevToolsSession;
 class NavigationHandle;
 class PageNavigationThrottle;
 class RenderFrameHostImpl;
@@ -30,14 +32,17 @@
 
 class ColorPicker;
 
-class PageHandler : public Page::Backend,
+class PageHandler : public DevToolsDomainHandler,
+                    public Page::Backend,
                     public NotificationObserver {
  public:
   PageHandler();
   ~PageHandler() override;
 
-  void Wire(UberDispatcher*);
-  void SetRenderFrameHost(RenderFrameHostImpl* host);
+  static PageHandler* FromSession(DevToolsSession* session);
+
+  void Wire(UberDispatcher* dispatcher) override;
+  void SetRenderFrameHost(RenderFrameHostImpl* host) override;
   void OnSwapCompositorFrame(cc::CompositorFrameMetadata frame_metadata);
   void OnSynchronousSwapCompositorFrame(
       cc::CompositorFrameMetadata frame_metadata);
diff --git a/content/browser/devtools/protocol/schema_handler.cc b/content/browser/devtools/protocol/schema_handler.cc
index 6583de6..6cf5b21d 100644
--- a/content/browser/devtools/protocol/schema_handler.cc
+++ b/content/browser/devtools/protocol/schema_handler.cc
@@ -7,7 +7,8 @@
 namespace content {
 namespace protocol {
 
-SchemaHandler::SchemaHandler() {
+SchemaHandler::SchemaHandler()
+    : DevToolsDomainHandler(Schema::Metainfo::domainName) {
 }
 
 SchemaHandler::~SchemaHandler() {
@@ -17,10 +18,6 @@
   Schema::Dispatcher::wire(dispatcher, this);
 }
 
-Response SchemaHandler::Disable() {
-  return Response::OK();
-}
-
 Response SchemaHandler::GetDomains(
     std::unique_ptr<protocol::Array<Schema::Domain>>* domains) {
   // TODO(kozyatisnkiy): get this from the target instead of hardcoding a list.
diff --git a/content/browser/devtools/protocol/schema_handler.h b/content/browser/devtools/protocol/schema_handler.h
index 33991ae4..c57c7f24 100644
--- a/content/browser/devtools/protocol/schema_handler.h
+++ b/content/browser/devtools/protocol/schema_handler.h
@@ -6,18 +6,19 @@
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SCHEMA_HANDLER_H_
 
 #include "base/macros.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/schema.h"
 
 namespace content {
 namespace protocol {
 
-class SchemaHandler : public Schema::Backend {
+class SchemaHandler : public DevToolsDomainHandler,
+                      public Schema::Backend {
  public:
   SchemaHandler();
   ~SchemaHandler() override;
 
-  void Wire(UberDispatcher*);
-  Response Disable() override;
+  void Wire(UberDispatcher* dispatcher) override;
 
   Response GetDomains(
       std::unique_ptr<protocol::Array<Schema::Domain>>* domains) override;
diff --git a/content/browser/devtools/protocol/security_handler.cc b/content/browser/devtools/protocol/security_handler.cc
index 5511ef6..cf214a7 100644
--- a/content/browser/devtools/protocol/security_handler.cc
+++ b/content/browser/devtools/protocol/security_handler.cc
@@ -57,7 +57,8 @@
 }  // namespace
 
 SecurityHandler::SecurityHandler()
-    : enabled_(false),
+    : DevToolsDomainHandler(Security::Metainfo::domainName),
+      enabled_(false),
       host_(nullptr) {
 }
 
diff --git a/content/browser/devtools/protocol/security_handler.h b/content/browser/devtools/protocol/security_handler.h
index 1b5c53e..2d32c687 100644
--- a/content/browser/devtools/protocol/security_handler.h
+++ b/content/browser/devtools/protocol/security_handler.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_SECURITY_HANDLER_H_
 
 #include "base/macros.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/security.h"
 #include "content/public/browser/web_contents_observer.h"
 
@@ -15,14 +16,15 @@
 
 namespace protocol {
 
-class SecurityHandler : public Security::Backend,
+class SecurityHandler : public DevToolsDomainHandler,
+                        public Security::Backend,
                         public WebContentsObserver {
  public:
   SecurityHandler();
   ~SecurityHandler() override;
 
-  void Wire(UberDispatcher*);
-  void SetRenderFrameHost(RenderFrameHostImpl* host);
+  void Wire(UberDispatcher* dispatcher) override;
+  void SetRenderFrameHost(RenderFrameHostImpl* host) override;
 
   Response Enable() override;
   Response Disable() override;
diff --git a/content/browser/devtools/protocol/service_worker_handler.cc b/content/browser/devtools/protocol/service_worker_handler.cc
index 62a962d3..2c059a6 100644
--- a/content/browser/devtools/protocol/service_worker_handler.cc
+++ b/content/browser/devtools/protocol/service_worker_handler.cc
@@ -152,7 +152,10 @@
 }  // namespace
 
 ServiceWorkerHandler::ServiceWorkerHandler()
-    : enabled_(false), render_frame_host_(nullptr), weak_factory_(this) {
+    : DevToolsDomainHandler(ServiceWorker::Metainfo::domainName),
+      enabled_(false),
+      render_frame_host_(nullptr),
+      weak_factory_(this) {
 }
 
 ServiceWorkerHandler::~ServiceWorkerHandler() {
diff --git a/content/browser/devtools/protocol/service_worker_handler.h b/content/browser/devtools/protocol/service_worker_handler.h
index 359a08e..845c9af 100644
--- a/content/browser/devtools/protocol/service_worker_handler.h
+++ b/content/browser/devtools/protocol/service_worker_handler.h
@@ -11,6 +11,7 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/service_worker.h"
 #include "content/browser/devtools/service_worker_devtools_agent_host.h"
 #include "content/browser/devtools/service_worker_devtools_manager.h"
@@ -25,13 +26,14 @@
 
 namespace protocol {
 
-class ServiceWorkerHandler : public ServiceWorker::Backend {
+class ServiceWorkerHandler : public DevToolsDomainHandler,
+                             public ServiceWorker::Backend {
  public:
   ServiceWorkerHandler();
   ~ServiceWorkerHandler() override;
 
-  void Wire(UberDispatcher*);
-  void SetRenderFrameHost(RenderFrameHostImpl* render_frame_host);
+  void Wire(UberDispatcher* dispatcher) override;
+  void SetRenderFrameHost(RenderFrameHostImpl* host) override;
 
   Response Enable() override;
   Response Disable() override;
diff --git a/content/browser/devtools/protocol/storage_handler.cc b/content/browser/devtools/protocol/storage_handler.cc
index 9c3a06ce..6dc27ea 100644
--- a/content/browser/devtools/protocol/storage_handler.cc
+++ b/content/browser/devtools/protocol/storage_handler.cc
@@ -30,7 +30,8 @@
 }
 
 StorageHandler::StorageHandler()
-    : host_(nullptr) {
+    : DevToolsDomainHandler(Storage::Metainfo::domainName),
+      host_(nullptr) {
 }
 
 StorageHandler::~StorageHandler() = default;
@@ -39,14 +40,6 @@
   Storage::Dispatcher::wire(dispatcher, this);
 }
 
-void StorageHandler::SetRenderFrameHost(RenderFrameHostImpl* host) {
-  host_ = host;
-}
-
-Response StorageHandler::Disable() {
-  return Response::OK();
-}
-
 Response StorageHandler::ClearDataForOrigin(
     const std::string& origin,
     const std::string& storage_types) {
diff --git a/content/browser/devtools/protocol/storage_handler.h b/content/browser/devtools/protocol/storage_handler.h
index f203a12..683d92c 100644
--- a/content/browser/devtools/protocol/storage_handler.h
+++ b/content/browser/devtools/protocol/storage_handler.h
@@ -6,6 +6,7 @@
 #define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_STORAGE_HANDLER_H_
 
 #include "base/macros.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/storage.h"
 
 namespace content {
@@ -14,14 +15,13 @@
 
 namespace protocol {
 
-class StorageHandler : public Storage::Backend {
+class StorageHandler : public DevToolsDomainHandler,
+                       public Storage::Backend {
  public:
   StorageHandler();
   ~StorageHandler() override;
 
-  void Wire(UberDispatcher*);
-  void SetRenderFrameHost(RenderFrameHostImpl* host);
-  Response Disable() override;
+  void Wire(UberDispatcher* dispatcher) override;
 
   Response ClearDataForOrigin(
       const std::string& origin,
diff --git a/content/browser/devtools/protocol/system_info_handler.cc b/content/browser/devtools/protocol/system_info_handler.cc
index 8ad8b94..f0abfc1 100644
--- a/content/browser/devtools/protocol/system_info_handler.cc
+++ b/content/browser/devtools/protocol/system_info_handler.cc
@@ -174,7 +174,8 @@
   base::WeakPtrFactory<SystemInfoHandlerGpuObserver> weak_factory_;
 };
 
-SystemInfoHandler::SystemInfoHandler() {
+SystemInfoHandler::SystemInfoHandler()
+    : DevToolsDomainHandler(SystemInfo::Metainfo::domainName) {
 }
 
 SystemInfoHandler::~SystemInfoHandler() {
@@ -184,10 +185,6 @@
   SystemInfo::Dispatcher::wire(dispatcher, this);
 }
 
-Response SystemInfoHandler::Disable() {
-  return Response::OK();
-}
-
 void SystemInfoHandler::GetInfo(
     std::unique_ptr<GetInfoCallback> callback) {
   std::string reason;
diff --git a/content/browser/devtools/protocol/system_info_handler.h b/content/browser/devtools/protocol/system_info_handler.h
index 2abbd59..dbb64ae2 100644
--- a/content/browser/devtools/protocol/system_info_handler.h
+++ b/content/browser/devtools/protocol/system_info_handler.h
@@ -8,6 +8,7 @@
 #include <set>
 
 #include "base/macros.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/system_info.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/gpu_data_manager_observer.h"
@@ -15,14 +16,14 @@
 namespace content {
 namespace protocol {
 
-class SystemInfoHandler : public SystemInfo::Backend {
+class SystemInfoHandler : public DevToolsDomainHandler,
+                          public SystemInfo::Backend {
  public:
 
   SystemInfoHandler();
   ~SystemInfoHandler() override;
 
-  void Wire(UberDispatcher*);
-  Response Disable() override;
+  void Wire(UberDispatcher* dispatcher) override;
 
   void GetInfo(std::unique_ptr<GetInfoCallback> callback) override;
 
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
index 78778f4..c17b128 100644
--- a/content/browser/devtools/protocol/target_handler.cc
+++ b/content/browser/devtools/protocol/target_handler.cc
@@ -5,6 +5,7 @@
 #include "content/browser/devtools/protocol/target_handler.h"
 
 #include "content/browser/devtools/devtools_manager.h"
+#include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/service_worker_devtools_agent_host.h"
 #include "content/browser/frame_host/frame_tree.h"
 #include "content/browser/frame_host/frame_tree_node.h"
@@ -93,7 +94,8 @@
 }  // namespace
 
 TargetHandler::TargetHandler()
-    : discover_(false),
+    : DevToolsDomainHandler(Target::Metainfo::domainName),
+      discover_(false),
       auto_attach_(false),
       wait_for_debugger_on_start_(false),
       attach_to_frames_(false),
@@ -103,6 +105,12 @@
 TargetHandler::~TargetHandler() {
 }
 
+// static
+TargetHandler* TargetHandler::FromSession(DevToolsSession* session) {
+  return static_cast<TargetHandler*>(
+      session->GetHandlerByName(Target::Metainfo::domainName));
+}
+
 void TargetHandler::Wire(UberDispatcher* dispatcher) {
   frontend_.reset(new Target::Frontend(dispatcher->channel()));
   Target::Dispatcher::wire(dispatcher, this);
diff --git a/content/browser/devtools/protocol/target_handler.h b/content/browser/devtools/protocol/target_handler.h
index 0b31029..cb11a089 100644
--- a/content/browser/devtools/protocol/target_handler.h
+++ b/content/browser/devtools/protocol/target_handler.h
@@ -8,6 +8,7 @@
 #include <map>
 #include <set>
 
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/target.h"
 #include "content/browser/devtools/service_worker_devtools_manager.h"
 #include "content/public/browser/devtools_agent_host_client.h"
@@ -15,11 +16,13 @@
 
 namespace content {
 
+class DevToolsSession;
 class RenderFrameHostImpl;
 
 namespace protocol {
 
-class TargetHandler : public Target::Backend,
+class TargetHandler : public DevToolsDomainHandler,
+                      public Target::Backend,
                       public DevToolsAgentHostClient,
                       public ServiceWorkerDevToolsManager::Observer,
                       public DevToolsAgentHostObserver {
@@ -27,8 +30,10 @@
   TargetHandler();
   ~TargetHandler() override;
 
-  void Wire(UberDispatcher*);
-  void SetRenderFrameHost(RenderFrameHostImpl* render_frame_host);
+  static TargetHandler* FromSession(DevToolsSession* session);
+
+  void Wire(UberDispatcher* dispatcher) override;
+  void SetRenderFrameHost(RenderFrameHostImpl* host) override;
   Response Disable() override;
 
   void UpdateServiceWorkers();
diff --git a/content/browser/devtools/protocol/tethering_handler.cc b/content/browser/devtools/protocol/tethering_handler.cc
index 62f5606..d20b325 100644
--- a/content/browser/devtools/protocol/tethering_handler.cc
+++ b/content/browser/devtools/protocol/tethering_handler.cc
@@ -320,7 +320,8 @@
 TetheringHandler::TetheringHandler(
     const CreateServerSocketCallback& socket_callback,
     scoped_refptr<base::SingleThreadTaskRunner> task_runner)
-    : socket_callback_(socket_callback),
+    : DevToolsDomainHandler(Tethering::Metainfo::domainName),
+      socket_callback_(socket_callback),
       task_runner_(task_runner),
       is_active_(false),
       weak_factory_(this) {
@@ -338,10 +339,6 @@
   Tethering::Dispatcher::wire(dispatcher, this);
 }
 
-Response TetheringHandler::Disable() {
-  return Response::OK();
-}
-
 void TetheringHandler::Accepted(uint16_t port, const std::string& name) {
   frontend_->Accepted(port, name);
 }
diff --git a/content/browser/devtools/protocol/tethering_handler.h b/content/browser/devtools/protocol/tethering_handler.h
index 3d57b16..2c7fe31 100644
--- a/content/browser/devtools/protocol/tethering_handler.h
+++ b/content/browser/devtools/protocol/tethering_handler.h
@@ -13,6 +13,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/tethering.h"
 
 namespace net {
@@ -23,7 +24,8 @@
 namespace protocol {
 
 // This class implements reversed tethering handler.
-class TetheringHandler : public Tethering::Backend {
+class TetheringHandler : public DevToolsDomainHandler,
+                         public Tethering::Backend {
  public:
   using CreateServerSocketCallback =
       base::Callback<std::unique_ptr<net::ServerSocket>(std::string*)>;
@@ -32,8 +34,7 @@
                    scoped_refptr<base::SingleThreadTaskRunner> task_runner);
   ~TetheringHandler() override;
 
-  void Wire(UberDispatcher*);
-  Response Disable() override;
+  void Wire(UberDispatcher* dispatcher) override;
 
   void Bind(int port, std::unique_ptr<BindCallback> callback) override;
   void Unbind(int port, std::unique_ptr<UnbindCallback> callback) override;
diff --git a/content/browser/devtools/protocol/tracing_handler.cc b/content/browser/devtools/protocol/tracing_handler.cc
index eb6f29ca..4159af13 100644
--- a/content/browser/devtools/protocol/tracing_handler.cc
+++ b/content/browser/devtools/protocol/tracing_handler.cc
@@ -19,6 +19,7 @@
 #include "base/trace_event/tracing_agent.h"
 #include "components/tracing/browser/trace_config_file.h"
 #include "content/browser/devtools/devtools_io_context.h"
+#include "content/browser/devtools/devtools_session.h"
 #include "content/browser/tracing/tracing_controller_impl.h"
 
 namespace content {
@@ -118,7 +119,8 @@
 TracingHandler::TracingHandler(TracingHandler::Target target,
                                int frame_tree_node_id,
                                DevToolsIOContext* io_context)
-    : target_(target),
+    : DevToolsDomainHandler(Tracing::Metainfo::domainName),
+      target_(target),
       io_context_(io_context),
       frame_tree_node_id_(frame_tree_node_id),
       did_initiate_recording_(false),
@@ -128,6 +130,12 @@
 TracingHandler::~TracingHandler() {
 }
 
+// static
+TracingHandler* TracingHandler::FromSession(DevToolsSession* session) {
+  return static_cast<TracingHandler*>(
+      session->GetHandlerByName(Tracing::Metainfo::domainName));
+}
+
 void TracingHandler::Wire(UberDispatcher* dispatcher) {
   frontend_.reset(new Tracing::Frontend(dispatcher->channel()));
   Tracing::Dispatcher::wire(dispatcher, this);
diff --git a/content/browser/devtools/protocol/tracing_handler.h b/content/browser/devtools/protocol/tracing_handler.h
index 41250a7de..2b40a01d 100644
--- a/content/browser/devtools/protocol/tracing_handler.h
+++ b/content/browser/devtools/protocol/tracing_handler.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/trace_event/trace_event.h"
+#include "content/browser/devtools/protocol/devtools_domain_handler.h"
 #include "content/browser/devtools/protocol/tracing.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/tracing_controller.h"
@@ -26,10 +27,12 @@
 namespace content {
 
 class DevToolsIOContext;
+class DevToolsSession;
 
 namespace protocol {
 
-class TracingHandler : public Tracing::Backend {
+class TracingHandler : public DevToolsDomainHandler,
+                       public Tracing::Backend {
  public:
   enum Target { Browser, Renderer };
   TracingHandler(Target target,
@@ -37,7 +40,9 @@
                  DevToolsIOContext* io_context);
   ~TracingHandler() override;
 
-  void Wire(UberDispatcher*);
+  static TracingHandler* FromSession(DevToolsSession* session);
+
+  void Wire(UberDispatcher* dispatcher) override;
   Response Disable() override;
 
   void OnTraceDataCollected(const std::string& trace_fragment);
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.cc b/content/browser/devtools/render_frame_devtools_agent_host.cc
index c8bd6943..a4654300 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.cc
+++ b/content/browser/devtools/render_frame_devtools_agent_host.cc
@@ -10,6 +10,7 @@
 #include "base/guid.h"
 #include "base/json/json_reader.h"
 #include "base/lazy_instance.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
 #include "content/browser/bad_message.h"
@@ -103,9 +104,9 @@
 
   RenderFrameHostImpl* host() const { return host_; }
 
-  void Attach();
+  void Attach(DevToolsSession* session);
   void Reattach(FrameHostHolder* old);
-  void Detach();
+  void Detach(int session_id);
   void DispatchProtocolMessage(int session_id,
                                int call_id,
                                const std::string& method,
@@ -151,9 +152,10 @@
     RevokePolicy();
 }
 
-void RenderFrameDevToolsAgentHost::FrameHostHolder::Attach() {
+void RenderFrameDevToolsAgentHost::FrameHostHolder::Attach(
+    DevToolsSession* session) {
   host_->Send(new DevToolsAgentMsg_Attach(
-      host_->GetRoutingID(), agent_->GetId(), agent_->session()->session_id()));
+      host_->GetRoutingID(), agent_->GetId(), session->session_id()));
   GrantPolicy();
   attached_ = true;
 }
@@ -182,7 +184,7 @@
   attached_ = true;
 }
 
-void RenderFrameDevToolsAgentHost::FrameHostHolder::Detach() {
+void RenderFrameDevToolsAgentHost::FrameHostHolder::Detach(int session_id) {
   host_->Send(new DevToolsAgentMsg_Detach(host_->GetRoutingID()));
   RevokePolicy();
   attached_ = false;
@@ -381,28 +383,33 @@
   // Note Page.setControlNavigations is intended to control navigations in the
   // main frame and all child frames and |page_handler_| only exists for the
   // main frame.
-  if (agent_host && agent_host->page_handler_) {
-    return agent_host->page_handler_->CreateThrottleForNavigation(
-        navigation_handle);
-  }
-  return nullptr;
+  if (!agent_host || !agent_host->session())
+    return nullptr;
+  protocol::PageHandler* page_handler =
+      protocol::PageHandler::FromSession(agent_host->session());
+  if (!page_handler)
+    return nullptr;
+  return page_handler->CreateThrottleForNavigation(navigation_handle);
 }
 
 // static
 bool RenderFrameDevToolsAgentHost::IsNetworkHandlerEnabled(
     FrameTreeNode* frame_tree_node) {
   RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(frame_tree_node);
-  return agent_host && agent_host->network_handler_ &&
-         agent_host->network_handler_->enabled();
+  if (!agent_host || !agent_host->session())
+    return false;
+  return protocol::NetworkHandler::FromSession(agent_host->session())
+      ->enabled();
 }
 
 // static
 std::string RenderFrameDevToolsAgentHost::UserAgentOverride(
     FrameTreeNode* frame_tree_node) {
   RenderFrameDevToolsAgentHost* agent_host = FindAgentHost(frame_tree_node);
-  if (agent_host && agent_host->network_handler_)
-    return agent_host->network_handler_->UserAgentOverride();
-  return std::string();
+  if (!agent_host || !agent_host->session())
+    return std::string();
+  return protocol::NetworkHandler::FromSession(agent_host->session())
+      ->UserAgentOverride();
 }
 
 // static
@@ -483,120 +490,50 @@
   return web_contents();
 }
 
-void RenderFrameDevToolsAgentHost::Attach() {
-  session()->dispatcher()->setFallThroughForNotFound(true);
-
+void RenderFrameDevToolsAgentHost::AttachSession(DevToolsSession* session) {
+  session->SetFallThroughForNotFound(true);
+  session->SetRenderFrameHost(handlers_frame_host_);
   if (!frame_tree_node_->parent()) {
-    emulation_handler_.reset(new protocol::EmulationHandler());
-    emulation_handler_->Wire(session()->dispatcher());
-    emulation_handler_->SetRenderFrameHost(handlers_frame_host_);
+    session->AddHandler(base::WrapUnique(new protocol::EmulationHandler()));
+    session->AddHandler(base::WrapUnique(new protocol::PageHandler()));
+    session->AddHandler(base::WrapUnique(new protocol::SecurityHandler()));
   }
-
-  dom_handler_.reset(new protocol::DOMHandler());
-  dom_handler_->Wire(session()->dispatcher());
-  dom_handler_->SetRenderFrameHost(handlers_frame_host_);
-
-  input_handler_.reset(new protocol::InputHandler());
-  input_handler_->Wire(session()->dispatcher());
-  input_handler_->SetRenderFrameHost(handlers_frame_host_);
-
-  inspector_handler_.reset(new protocol::InspectorHandler());
-  inspector_handler_->Wire(session()->dispatcher());
-  inspector_handler_->SetRenderFrameHost(handlers_frame_host_);
-
-  io_handler_.reset(new protocol::IOHandler(GetIOContext()));
-  io_handler_->Wire(session()->dispatcher());
-
-  network_handler_.reset(new protocol::NetworkHandler());
-  network_handler_->Wire(session()->dispatcher());
-  network_handler_->SetRenderFrameHost(handlers_frame_host_);
-
-  if (!frame_tree_node_->parent()) {
-    page_handler_.reset(new protocol::PageHandler());
-    page_handler_->Wire(session()->dispatcher());
-    page_handler_->SetRenderFrameHost(handlers_frame_host_);
-  }
-
-  schema_handler_.reset(new protocol::SchemaHandler());
-  schema_handler_->Wire(session()->dispatcher());
-
-  if (!frame_tree_node_->parent()) {
-    security_handler_.reset(new protocol::SecurityHandler());
-    security_handler_->Wire(session()->dispatcher());
-    security_handler_->SetRenderFrameHost(handlers_frame_host_);
-  }
-
-  service_worker_handler_.reset(new protocol::ServiceWorkerHandler());
-  service_worker_handler_->Wire(session()->dispatcher());
-  service_worker_handler_->SetRenderFrameHost(handlers_frame_host_);
-
-  storage_handler_.reset(new protocol::StorageHandler());
-  storage_handler_->Wire(session()->dispatcher());
-  storage_handler_->SetRenderFrameHost(handlers_frame_host_);
-
-  target_handler_.reset(new protocol::TargetHandler());
-  target_handler_->Wire(session()->dispatcher());
-  target_handler_->SetRenderFrameHost(handlers_frame_host_);
-
-  tracing_handler_.reset(new protocol::TracingHandler(
+  session->AddHandler(base::WrapUnique(new protocol::DOMHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::InputHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::InspectorHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::IOHandler(
+      GetIOContext())));
+  session->AddHandler(base::WrapUnique(new protocol::NetworkHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::SchemaHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::ServiceWorkerHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::StorageHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::TargetHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::TracingHandler(
       protocol::TracingHandler::Renderer,
       frame_tree_node_->frame_tree_node_id(),
-      GetIOContext()));
-  tracing_handler_->Wire(session()->dispatcher());
+      GetIOContext())));
 
   if (current_)
-    current_->Attach();
+    current_->Attach(session);
   if (pending_)
-    pending_->Attach();
+    pending_->Attach(session);
   OnClientAttached();
 }
 
-void RenderFrameDevToolsAgentHost::Detach() {
-  dom_handler_->Disable();
-  dom_handler_.reset();
-  if (emulation_handler_) {
-    emulation_handler_->Disable();
-    emulation_handler_.reset();
-  }
-  input_handler_->Disable();
-  input_handler_.reset();
-  inspector_handler_->Disable();
-  inspector_handler_.reset();
-  io_handler_->Disable();
-  io_handler_.reset();
-  network_handler_->Disable();
-  network_handler_.reset();
-  if (page_handler_) {
-    page_handler_->Disable();
-    page_handler_.reset();
-  }
-  schema_handler_->Disable();
-  schema_handler_.reset();
-  if (security_handler_) {
-    security_handler_->Disable();
-    security_handler_.reset();
-  }
-  service_worker_handler_->Disable();
-  service_worker_handler_.reset();
-  storage_handler_->Disable();
-  storage_handler_.reset();
-  target_handler_->Disable();
-  target_handler_.reset();
-  tracing_handler_->Disable();
-  tracing_handler_.reset();
-
+void RenderFrameDevToolsAgentHost::DetachSession(int session_id) {
   if (current_)
-    current_->Detach();
+    current_->Detach(session_id);
   if (pending_)
-    pending_->Detach();
+    pending_->Detach(session_id);
   OnClientDetached();
 }
 
 bool RenderFrameDevToolsAgentHost::DispatchProtocolMessage(
+    DevToolsSession* session,
     const std::string& message) {
   int call_id = 0;
   std::string method;
-  if (session()->Dispatch(message, &call_id, &method) !=
+  if (session->Dispatch(message, true, &call_id, &method) !=
       protocol::Response::kFallThrough) {
     return true;
   }
@@ -604,26 +541,29 @@
   if (!navigating_handles_.empty()) {
     DCHECK(IsBrowserSideNavigationEnabled());
     in_navigation_protocol_message_buffer_[call_id] =
-        { session()->session_id(), method, message };
+        { session->session_id(), method, message };
     return true;
   }
 
   if (current_) {
     current_->DispatchProtocolMessage(
-        session()->session_id(), call_id, method, message);
+        session->session_id(), call_id, method, message);
   }
   if (pending_) {
     pending_->DispatchProtocolMessage(
-        session()->session_id(), call_id, method, message);
+        session->session_id(), call_id, method, message);
   }
   return true;
 }
 
-void RenderFrameDevToolsAgentHost::InspectElement(int x, int y) {
+void RenderFrameDevToolsAgentHost::InspectElement(
+    DevToolsSession* session,
+    int x,
+    int y) {
   if (current_)
-    current_->InspectElement(session()->session_id(), x, y);
+    current_->InspectElement(session->session_id(), x, y);
   if (pending_)
-    pending_->InspectElement(session()->session_id(), x, y);
+    pending_->InspectElement(session->session_id(), x, y);
 }
 
 void RenderFrameDevToolsAgentHost::OnClientAttached() {
@@ -713,8 +653,8 @@
   DispatchBufferedProtocolMessagesIfNecessary();
 
   DCHECK(CheckConsistency());
-  if (target_handler_ && navigation_handle->HasCommitted())
-    target_handler_->UpdateServiceWorkers();
+  if (session() && navigation_handle->HasCommitted())
+    protocol::TargetHandler::FromSession(session())->UpdateServiceWorkers();
 }
 
 void RenderFrameDevToolsAgentHost::AboutToNavigateRenderFrame(
@@ -760,8 +700,8 @@
   // CommitPending may destruct |this|.
   scoped_refptr<RenderFrameDevToolsAgentHost> protect(this);
 
-  if (target_handler_)
-    target_handler_->UpdateFrames();
+  if (session())
+    protocol::TargetHandler::FromSession(session())->UpdateFrames();
 
   if (IsBrowserSideNavigationEnabled())
     return;
@@ -805,7 +745,7 @@
   UpdateProtocolHandlers(nullptr);
   if (IsAttached())
     OnClientDetached();
-  HostClosed();
+  ForceDetach(false);
   pending_.reset();
   current_.reset();
   frame_tree_node_ = nullptr;
@@ -853,13 +793,15 @@
     case base::TERMINATION_STATUS_OOM_PROTECTED:
 #endif
     case base::TERMINATION_STATUS_LAUNCH_FAILED:
-      if (inspector_handler_)
-        inspector_handler_->TargetCrashed();
+      if (session())
+        protocol::InspectorHandler::FromSession(session())->TargetCrashed();
       current_frame_crashed_ = true;
       break;
     default:
-      if (inspector_handler_)
-        inspector_handler_->TargetDetached("Render process gone.");
+      if (session()) {
+        protocol::InspectorHandler::FromSession(session())
+            ->TargetDetached("Render process gone.");
+      }
       break;
   }
   DCHECK(CheckConsistency());
@@ -896,8 +838,10 @@
 }
 
 void RenderFrameDevToolsAgentHost::DidAttachInterstitialPage() {
-  if (page_handler_)
-    page_handler_->DidAttachInterstitialPage();
+  protocol::PageHandler* page_handler =
+      session() ? protocol::PageHandler::FromSession(session()) : nullptr;
+  if (page_handler)
+    page_handler->DidAttachInterstitialPage();
 
   // TODO(dgozman): this may break for cross-process subframes.
   if (!pending_) {
@@ -912,8 +856,10 @@
 }
 
 void RenderFrameDevToolsAgentHost::DidDetachInterstitialPage() {
-  if (page_handler_)
-    page_handler_->DidDetachInterstitialPage();
+  protocol::PageHandler* page_handler =
+      session() ? protocol::PageHandler::FromSession(session()) : nullptr;
+  if (page_handler)
+    page_handler->DidDetachInterstitialPage();
 }
 
 void RenderFrameDevToolsAgentHost::DidCommitProvisionalLoadForFrame(
@@ -928,8 +874,8 @@
   if (pending_ && pending_->host() == render_frame_host)
     CommitPending();
   DCHECK(CheckConsistency());
-  if (target_handler_)
-    target_handler_->UpdateServiceWorkers();
+  if (session())
+    protocol::TargetHandler::FromSession(session())->UpdateServiceWorkers();
 }
 
 void RenderFrameDevToolsAgentHost::DidFailProvisionalLoad(
@@ -978,26 +924,8 @@
     handlers_frame_host_->GetRenderWidgetHost()->GetRoutingID();
 #endif
   handlers_frame_host_ = host;
-  if (dom_handler_)
-    dom_handler_->SetRenderFrameHost(host);
-  if (emulation_handler_)
-    emulation_handler_->SetRenderFrameHost(host);
-  if (input_handler_)
-    input_handler_->SetRenderFrameHost(host);
-  if (inspector_handler_)
-    inspector_handler_->SetRenderFrameHost(host);
-  if (network_handler_)
-    network_handler_->SetRenderFrameHost(host);
-  if (page_handler_)
-    page_handler_->SetRenderFrameHost(host);
-  if (service_worker_handler_)
-    service_worker_handler_->SetRenderFrameHost(host);
-  if (security_handler_)
-    security_handler_->SetRenderFrameHost(host);
-  if (storage_handler_)
-    storage_handler_->SetRenderFrameHost(host);
-  if (target_handler_)
-    target_handler_->SetRenderFrameHost(host);
+  if (session())
+    session()->SetRenderFrameHost(host);
 }
 
 void RenderFrameDevToolsAgentHost::DisconnectWebContents() {
@@ -1005,7 +933,8 @@
     DiscardPending();
   UpdateProtocolHandlers(nullptr);
   disconnected_ = std::move(current_);
-  disconnected_->Detach();
+  if (session())
+    disconnected_->Detach(session()->session_id());
   frame_tree_node_ = nullptr;
   in_navigation_protocol_message_buffer_.clear();
   navigating_handles_.clear();
@@ -1135,13 +1064,19 @@
   ViewHostMsg_SwapCompositorFrame::Param param;
   if (!ViewHostMsg_SwapCompositorFrame::Read(&message, &param))
     return;
-  if (page_handler_) {
-    page_handler_->OnSwapCompositorFrame(
+  if (!session())
+    return;
+  protocol::PageHandler* page_handler =
+      protocol::PageHandler::FromSession(session());
+  if (page_handler) {
+    page_handler->OnSwapCompositorFrame(
         std::move(std::get<1>(param).metadata));
   }
-  if (input_handler_)
-    input_handler_->OnSwapCompositorFrame(std::get<1>(param).metadata);
-  if (frame_trace_recorder_ && tracing_handler_->did_initiate_recording()) {
+  protocol::InputHandler::FromSession(session())
+      ->OnSwapCompositorFrame(std::get<1>(param).metadata);
+  protocol::TracingHandler* tracing_handler =
+      protocol::TracingHandler::FromSession(session());
+  if (frame_trace_recorder_ && tracing_handler->did_initiate_recording()) {
     frame_trace_recorder_->OnSwapCompositorFrame(
         current_ ? current_->host() : nullptr, std::get<1>(param).metadata);
   }
@@ -1164,11 +1099,17 @@
 
 void RenderFrameDevToolsAgentHost::SynchronousSwapCompositorFrame(
     cc::CompositorFrameMetadata frame_metadata) {
-  if (page_handler_)
-    page_handler_->OnSynchronousSwapCompositorFrame(std::move(frame_metadata));
-  if (input_handler_)
-    input_handler_->OnSwapCompositorFrame(frame_metadata);
-  if (frame_trace_recorder_ && tracing_handler_->did_initiate_recording()) {
+  if (!session())
+    return;
+  protocol::PageHandler* page_handler =
+      protocol::PageHandler::FromSession(session());
+  if (page_handler)
+    page_handler->OnSynchronousSwapCompositorFrame(std::move(frame_metadata));
+  protocol::InputHandler::FromSession(session())
+      ->OnSwapCompositorFrame(frame_metadata);
+  protocol::TracingHandler* tracing_handler =
+      protocol::TracingHandler::FromSession(session());
+  if (frame_trace_recorder_ && tracing_handler->did_initiate_recording()) {
     frame_trace_recorder_->OnSynchronousSwapCompositorFrame(
         current_ ? current_->host() : nullptr,
         frame_metadata);
diff --git a/content/browser/devtools/render_frame_devtools_agent_host.h b/content/browser/devtools/render_frame_devtools_agent_host.h
index a351cf39..00e3cf4 100644
--- a/content/browser/devtools/render_frame_devtools_agent_host.h
+++ b/content/browser/devtools/render_frame_devtools_agent_host.h
@@ -38,22 +38,6 @@
 class NavigationThrottle;
 class RenderFrameHostImpl;
 
-namespace protocol {
-class DOMHandler;
-class EmulationHandler;
-class InputHandler;
-class InspectorHandler;
-class IOHandler;
-class NetworkHandler;
-class PageHandler;
-class SchemaHandler;
-class SecurityHandler;
-class ServiceWorkerHandler;
-class StorageHandler;
-class TargetHandler;
-class TracingHandler;
-}  // namespace protocol
-
 class CONTENT_EXPORT RenderFrameDevToolsAgentHost
     : public DevToolsAgentHostImpl,
       private WebContentsObserver {
@@ -97,8 +81,6 @@
   bool Close() override;
   base::TimeTicks GetLastActivityTime() override;
 
-  bool DispatchProtocolMessage(const std::string& message) override;
-
  private:
   friend class DevToolsAgentHost;
   explicit RenderFrameDevToolsAgentHost(RenderFrameHostImpl*);
@@ -111,9 +93,12 @@
       RenderFrameHost* host);
 
   // DevToolsAgentHostImpl overrides.
-  void Attach() override;
-  void Detach() override;
-  void InspectElement(int x, int y) override;
+  void AttachSession(DevToolsSession* session) override;
+  void DetachSession(int session_id) override;
+  void InspectElement(DevToolsSession* session, int x, int y) override;
+  bool DispatchProtocolMessage(
+      DevToolsSession* session,
+      const std::string& message) override;
 
   // WebContentsObserver overrides.
   void ReadyToCommitNavigation(NavigationHandle* navigation_handle) override;
@@ -180,19 +165,6 @@
   // Stores per-host state between DisconnectWebContents and ConnectWebContents.
   std::unique_ptr<FrameHostHolder> disconnected_;
 
-  std::unique_ptr<protocol::DOMHandler> dom_handler_;
-  std::unique_ptr<protocol::InputHandler> input_handler_;
-  std::unique_ptr<protocol::InspectorHandler> inspector_handler_;
-  std::unique_ptr<protocol::IOHandler> io_handler_;
-  std::unique_ptr<protocol::NetworkHandler> network_handler_;
-  std::unique_ptr<protocol::PageHandler> page_handler_;
-  std::unique_ptr<protocol::SchemaHandler> schema_handler_;
-  std::unique_ptr<protocol::SecurityHandler> security_handler_;
-  std::unique_ptr<protocol::ServiceWorkerHandler> service_worker_handler_;
-  std::unique_ptr<protocol::StorageHandler> storage_handler_;
-  std::unique_ptr<protocol::TargetHandler> target_handler_;
-  std::unique_ptr<protocol::TracingHandler> tracing_handler_;
-  std::unique_ptr<protocol::EmulationHandler> emulation_handler_;
   std::unique_ptr<DevToolsFrameTraceRecorder> frame_trace_recorder_;
 #if defined(OS_ANDROID)
   std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_;
diff --git a/content/browser/devtools/worker_devtools_agent_host.cc b/content/browser/devtools/worker_devtools_agent_host.cc
index 5b91959..e44544e 100644
--- a/content/browser/devtools/worker_devtools_agent_host.cc
+++ b/content/browser/devtools/worker_devtools_agent_host.cc
@@ -5,6 +5,7 @@
 #include "content/browser/devtools/worker_devtools_agent_host.h"
 
 #include "base/guid.h"
+#include "base/memory/ptr_util.h"
 #include "content/browser/devtools/devtools_session.h"
 #include "content/browser/devtools/protocol/inspector_handler.h"
 #include "content/browser/devtools/protocol/network_handler.h"
@@ -20,35 +21,25 @@
   return rph ? rph->GetBrowserContext() : nullptr;
 }
 
-void WorkerDevToolsAgentHost::Attach() {
+void WorkerDevToolsAgentHost::AttachSession(DevToolsSession* session) {
   if (state_ != WORKER_INSPECTED) {
     state_ = WORKER_INSPECTED;
     AttachToWorker();
   }
   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
     host->Send(new DevToolsAgentMsg_Attach(
-        worker_id_.second, GetId(), session()->session_id()));
+        worker_id_.second, GetId(), session->session_id()));
   }
-  session()->dispatcher()->setFallThroughForNotFound(true);
-  inspector_handler_.reset(new protocol::InspectorHandler());
-  inspector_handler_->Wire(session()->dispatcher());
-  network_handler_.reset(new protocol::NetworkHandler());
-  network_handler_->Wire(session()->dispatcher());
-  schema_handler_.reset(new protocol::SchemaHandler());
-  schema_handler_->Wire(session()->dispatcher());
-  session()->dispatcher()->setFallThroughForNotFound(true);
+  session->SetFallThroughForNotFound(true);
+  session->AddHandler(base::WrapUnique(new protocol::InspectorHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::NetworkHandler()));
+  session->AddHandler(base::WrapUnique(new protocol::SchemaHandler()));
   OnAttachedStateChanged(true);
 }
 
-void WorkerDevToolsAgentHost::Detach() {
+void WorkerDevToolsAgentHost::DetachSession(int session_id) {
   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first))
     host->Send(new DevToolsAgentMsg_Detach(worker_id_.second));
-  inspector_handler_->Disable();
-  inspector_handler_.reset();
-  network_handler_->Disable();
-  network_handler_.reset();
-  schema_handler_->Disable();
-  schema_handler_.reset();
   OnAttachedStateChanged(false);
   if (state_ == WORKER_INSPECTED) {
     state_ = WORKER_UNINSPECTED;
@@ -59,20 +50,21 @@
 }
 
 bool WorkerDevToolsAgentHost::DispatchProtocolMessage(
+    DevToolsSession* session,
     const std::string& message) {
   if (state_ != WORKER_INSPECTED)
     return true;
 
   int call_id = 0;
   std::string method;
-  if (session()->Dispatch(message, &call_id, &method) !=
+  if (session->Dispatch(message, true, &call_id, &method) !=
       protocol::Response::kFallThrough) {
     return true;
   }
 
   if (RenderProcessHost* host = RenderProcessHost::FromID(worker_id_.first)) {
     host->Send(new DevToolsAgentMsg_DispatchOnInspectorBackend(
-        worker_id_.second, session()->session_id(), call_id, method, message));
+        worker_id_.second, session->session_id(), call_id, method, message));
   }
   return true;
 }
@@ -123,7 +115,7 @@
   DCHECK_NE(WORKER_TERMINATED, state_);
   if (state_ == WORKER_INSPECTED) {
     DCHECK(IsAttached());
-    inspector_handler_->TargetCrashed();
+    protocol::InspectorHandler::FromSession(session())->TargetCrashed();
     DetachFromWorker();
   }
   state_ = WORKER_TERMINATED;
diff --git a/content/browser/devtools/worker_devtools_agent_host.h b/content/browser/devtools/worker_devtools_agent_host.h
index d0926ef..df4f6cb 100644
--- a/content/browser/devtools/worker_devtools_agent_host.h
+++ b/content/browser/devtools/worker_devtools_agent_host.h
@@ -11,12 +11,6 @@
 
 namespace content {
 
-namespace protocol {
-class InspectorHandler;
-class NetworkHandler;
-class SchemaHandler;
-}
-
 class BrowserContext;
 
 class WorkerDevToolsAgentHost : public DevToolsAgentHostImpl,
@@ -26,11 +20,13 @@
 
   // DevToolsAgentHost override.
   BrowserContext* GetBrowserContext() override;
-  bool DispatchProtocolMessage(const std::string& message) override;
 
   // DevToolsAgentHostImpl overrides.
-  void Attach() override;
-  void Detach() override;
+  void AttachSession(DevToolsSession* session) override;
+  void DetachSession(int session_id) override;
+  bool DispatchProtocolMessage(
+      DevToolsSession* session,
+      const std::string& message) override;
 
   // IPC::Listener implementation.
   bool OnMessageReceived(const IPC::Message& msg) override;
@@ -66,9 +62,6 @@
   void WorkerCreated();
   void OnDispatchOnInspectorFrontend(const DevToolsMessageChunk& message);
 
-  std::unique_ptr<protocol::InspectorHandler> inspector_handler_;
-  std::unique_ptr<protocol::NetworkHandler> network_handler_;
-  std::unique_ptr<protocol::SchemaHandler> schema_handler_;
   DevToolsMessageChunkProcessor chunk_processor_;
   WorkerState state_;
   WorkerId worker_id_;
diff --git a/content/browser/dom_storage/local_storage_context_mojo.cc b/content/browser/dom_storage/local_storage_context_mojo.cc
index 241daedd..fa68355 100644
--- a/content/browser/dom_storage/local_storage_context_mojo.cc
+++ b/content/browser/dom_storage/local_storage_context_mojo.cc
@@ -141,10 +141,13 @@
   // database.
   file_service_connection_->GetInterface(&leveldb_service_);
 
-  leveldb_service_->Open(std::move(directory_), "leveldb",
-                         MakeRequest(&database_),
-                         base::Bind(&LocalStorageContextMojo::OnDatabaseOpened,
-                                    weak_ptr_factory_.GetWeakPtr()));
+  auto options = leveldb::mojom::OpenOptions::New();
+  options->create_if_missing = true;
+  leveldb_service_->OpenWithOptions(
+      std::move(options), std::move(directory_), "leveldb",
+      MakeRequest(&database_),
+      base::Bind(&LocalStorageContextMojo::OnDatabaseOpened,
+                 weak_ptr_factory_.GetWeakPtr()));
 }
 
 void LocalStorageContextMojo::OnDatabaseOpened(
diff --git a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
index 0da3bd6..aa9242b 100644
--- a/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
+++ b/content/browser/dom_storage/local_storage_context_mojo_unittest.cc
@@ -4,11 +4,24 @@
 
 #include "content/browser/dom_storage/local_storage_context_mojo.h"
 
+#include "base/files/file_enumerator.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/run_loop.h"
+#include "components/filesystem/public/interfaces/file_system.mojom.h"
 #include "components/leveldb/public/cpp/util.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/test/mock_leveldb_database.h"
 #include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/file/file_service.h"
+#include "services/file/public/interfaces/constants.mojom.h"
+#include "services/file/user_id_map.h"
+#include "services/service_manager/public/cpp/interface_factory.h"
+#include "services/service_manager/public/cpp/interface_registry.h"
+#include "services/service_manager/public/cpp/service_context.h"
+#include "services/service_manager/public/cpp/service_test.h"
+#include "services/service_manager/public/interfaces/service_factory.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using leveldb::StdStringToUint8Vector;
@@ -59,6 +72,8 @@
   mojo::Binding<leveldb::mojom::LevelDBDatabase> db_binding_;
 
   std::unique_ptr<LocalStorageContextMojo> context_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocalStorageContextMojoTest);
 };
 
 TEST_F(LocalStorageContextMojoTest, Basic) {
@@ -139,7 +154,6 @@
   mojom::LevelDBWrapperPtr wrapper;
   context()->OpenLocalStorage(url::Origin(GURL("http://foobar.com")),
                               MakeRequest(&wrapper));
-
   base::RunLoop run_loop;
   bool success = false;
   std::vector<uint8_t> result;
@@ -154,4 +168,208 @@
   EXPECT_TRUE(mock_data().empty());
 }
 
+namespace {
+
+class ServiceTestClient : public service_manager::test::ServiceTestClient,
+                          public service_manager::mojom::ServiceFactory,
+                          public service_manager::InterfaceFactory<
+                              service_manager::mojom::ServiceFactory> {
+ public:
+  explicit ServiceTestClient(service_manager::test::ServiceTest* test)
+      : service_manager::test::ServiceTestClient(test) {}
+  ~ServiceTestClient() override {}
+
+ protected:
+  bool OnConnect(const service_manager::ServiceInfo& remote_info,
+                 service_manager::InterfaceRegistry* registry) override {
+    registry->AddInterface<service_manager::mojom::ServiceFactory>(this);
+    return true;
+  }
+
+  void CreateService(service_manager::mojom::ServiceRequest request,
+                     const std::string& name) override {
+    if (name == file::mojom::kServiceName) {
+      file_service_context_.reset(new service_manager::ServiceContext(
+          file::CreateFileService(
+              BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE),
+              BrowserThread::GetTaskRunnerForThread(BrowserThread::DB)),
+          std::move(request)));
+    }
+  }
+
+  void Create(const service_manager::Identity& remote_identity,
+              service_manager::mojom::ServiceFactoryRequest request) override {
+    service_factory_bindings_.AddBinding(this, std::move(request));
+  }
+
+ private:
+  mojo::BindingSet<service_manager::mojom::ServiceFactory>
+      service_factory_bindings_;
+  std::unique_ptr<service_manager::ServiceContext> file_service_context_;
+};
+
+}  // namespace
+
+class LocalStorageContextMojoTestWithService
+    : public service_manager::test::ServiceTest {
+ public:
+  LocalStorageContextMojoTestWithService()
+      : ServiceTest("content_unittests", false) {}
+  ~LocalStorageContextMojoTestWithService() override {}
+
+ protected:
+  void SetUp() override {
+    ServiceTest::SetUp();
+    ASSERT_TRUE(temp_path_.CreateUniqueTempDir());
+    file::AssociateServiceUserIdWithUserDir(test_userid(),
+                                            temp_path_.GetPath());
+  }
+
+  void TearDown() override {
+    temp_path_.Take();
+    ServiceTest::TearDown();
+  }
+
+  std::unique_ptr<service_manager::Service> CreateService() override {
+    return base::MakeUnique<ServiceTestClient>(this);
+  }
+
+  std::unique_ptr<base::MessageLoop> CreateMessageLoop() override {
+    return nullptr;
+  }
+
+  const base::FilePath& temp_path() { return temp_path_.GetPath(); }
+
+  base::FilePath FirstEntryInDir() {
+    base::FileEnumerator enumerator(
+        temp_path(), false /* recursive */,
+        base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
+    return enumerator.Next();
+  }
+
+  void DoTestPut(LocalStorageContextMojo* context,
+                 const std::vector<uint8_t>& key,
+                 const std::vector<uint8_t>& value) {
+    mojom::LevelDBWrapperPtr wrapper;
+    context->OpenLocalStorage(url::Origin(GURL("http://foobar.com")),
+                              MakeRequest(&wrapper));
+    wrapper->Put(key, value, "source", base::Bind(&NoOpSuccess));
+    wrapper.reset();
+    base::RunLoop().RunUntilIdle();
+  }
+
+  bool DoTestGet(LocalStorageContextMojo* context,
+                 const std::vector<uint8_t>& key,
+                 std::vector<uint8_t>* result) {
+    mojom::LevelDBWrapperPtr wrapper;
+    context->OpenLocalStorage(url::Origin(GURL("http://foobar.com")),
+                              MakeRequest(&wrapper));
+    base::RunLoop run_loop;
+    bool success = false;
+    wrapper->Get(key, base::Bind(&GetCallback, run_loop.QuitClosure(), &success,
+                                 result));
+    run_loop.Run();
+    return success;
+  }
+
+ private:
+  TestBrowserThreadBundle thread_bundle_;
+  base::ScopedTempDir temp_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(LocalStorageContextMojoTestWithService);
+};
+
+// Enable when http://crbug.com/677194 is fixed and ServiceTest works
+// correctly on Android.
+#if defined(OS_ANDROID)
+#define MAYBE_InMemory DISABLED_InMemory
+#else
+#define MAYBE_InMemory InMemory
+#endif
+TEST_F(LocalStorageContextMojoTestWithService, MAYBE_InMemory) {
+  auto context =
+      base::MakeUnique<LocalStorageContextMojo>(connector(), base::FilePath());
+  auto key = StdStringToUint8Vector("key");
+  auto value = StdStringToUint8Vector("value");
+
+  mojom::LevelDBWrapperPtr wrapper;
+  context->OpenLocalStorage(url::Origin(GURL("http://foobar.com")),
+                            MakeRequest(&wrapper));
+
+  DoTestPut(context.get(), key, value);
+  std::vector<uint8_t> result;
+  EXPECT_TRUE(DoTestGet(context.get(), key, &result));
+  EXPECT_EQ(value, result);
+
+  context.reset();
+  base::RunLoop().RunUntilIdle();
+
+  // Should not have created any files.
+  EXPECT_TRUE(FirstEntryInDir().empty());
+
+  // Re-opening should get fresh data.
+  context.reset(new LocalStorageContextMojo(connector(), base::FilePath()));
+  EXPECT_FALSE(DoTestGet(context.get(), key, &result));
+}
+
+// Enable when http://crbug.com/677194 is fixed and ServiceTest works
+// correctly on Android.
+#if defined(OS_ANDROID)
+#define MAYBE_InMemoryInvalidPath DISABLED_InMemoryInvalidPath
+#else
+#define MAYBE_InMemoryInvalidPath InMemoryInvalidPath
+#endif
+TEST_F(LocalStorageContextMojoTestWithService, MAYBE_InMemoryInvalidPath) {
+  auto context = base::MakeUnique<LocalStorageContextMojo>(
+      connector(), base::FilePath(FILE_PATH_LITERAL("../../")));
+  auto key = StdStringToUint8Vector("key");
+  auto value = StdStringToUint8Vector("value");
+
+  mojom::LevelDBWrapperPtr wrapper;
+  context->OpenLocalStorage(url::Origin(GURL("http://foobar.com")),
+                            MakeRequest(&wrapper));
+
+  DoTestPut(context.get(), key, value);
+  std::vector<uint8_t> result;
+  EXPECT_TRUE(DoTestGet(context.get(), key, &result));
+  EXPECT_EQ(value, result);
+
+  context.reset();
+  base::RunLoop().RunUntilIdle();
+
+  // Should not have created any files.
+  EXPECT_TRUE(FirstEntryInDir().empty());
+}
+
+// Enable when http://crbug.com/677194 is fixed and ServiceTest works
+// correctly on Android.
+#if defined(OS_ANDROID)
+#define MAYBE_OnDisk DISABLED_OnDisk
+#else
+#define MAYBE_OnDisk OnDisk
+#endif
+TEST_F(LocalStorageContextMojoTestWithService, MAYBE_OnDisk) {
+  base::FilePath test_path(FILE_PATH_LITERAL("test_path"));
+  auto context =
+      base::MakeUnique<LocalStorageContextMojo>(connector(), test_path);
+  auto key = StdStringToUint8Vector("key");
+  auto value = StdStringToUint8Vector("value");
+
+  DoTestPut(context.get(), key, value);
+  std::vector<uint8_t> result;
+  EXPECT_TRUE(DoTestGet(context.get(), key, &result));
+  EXPECT_EQ(value, result);
+
+  context.reset();
+  base::RunLoop().RunUntilIdle();
+
+  // Should have created files.
+  EXPECT_EQ(test_path, FirstEntryInDir().BaseName());
+
+  // Should be able to re-open.
+  context.reset(new LocalStorageContextMojo(connector(), test_path));
+  EXPECT_TRUE(DoTestGet(context.get(), key, &result));
+  EXPECT_EQ(value, result);
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 2853176d..c6d8cdd5 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -1336,7 +1336,9 @@
 }
 
 // Verify that reloading a page with url anchor scrolls to correct position.
-IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, ReloadWithUrlAnchor) {
+// Disabled due to flakiness: https://crbug.com/672545.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+                       DISABLED_ReloadWithUrlAnchor) {
   GURL url1(embedded_test_server()->GetURL(
       "/navigation_controller/reload-with-url-anchor.html#d2"));
   EXPECT_TRUE(NavigateToURL(shell(), url1));
diff --git a/content/browser/media/android/media_web_contents_observer_android.cc b/content/browser/media/android/media_web_contents_observer_android.cc
index cde2d8e..c61a0b0a 100644
--- a/content/browser/media/android/media_web_contents_observer_android.cc
+++ b/content/browser/media/android/media_web_contents_observer_android.cc
@@ -45,11 +45,11 @@
     RenderFrameHost* render_frame_host) {
   auto it = media_player_managers_.find(render_frame_host);
   if (it != media_player_managers_.end())
-    return it->second;
+    return it->second.get();
 
   BrowserMediaPlayerManager* manager =
       BrowserMediaPlayerManager::Create(render_frame_host);
-  media_player_managers_.set(render_frame_host, base::WrapUnique(manager));
+  media_player_managers_[render_frame_host] = base::WrapUnique(manager);
   return manager;
 }
 
@@ -58,11 +58,11 @@
     RenderFrameHost* render_frame_host) {
   auto it = surface_view_managers_.find(render_frame_host);
   if (it != surface_view_managers_.end())
-    return it->second;
+    return it->second.get();
 
   BrowserSurfaceViewManager* manager =
       new BrowserSurfaceViewManager(render_frame_host);
-  surface_view_managers_.set(render_frame_host, base::WrapUnique(manager));
+  surface_view_managers_[render_frame_host] = base::WrapUnique(manager);
   return manager;
 }
 
diff --git a/content/browser/media/android/media_web_contents_observer_android.h b/content/browser/media/android/media_web_contents_observer_android.h
index 14ea142..e330e450 100644
--- a/content/browser/media/android/media_web_contents_observer_android.h
+++ b/content/browser/media/android/media_web_contents_observer_android.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <memory>
+#include <unordered_map>
 
 #include "base/macros.h"
 #include "content/browser/media/media_web_contents_observer.h"
@@ -76,13 +77,13 @@
 
   // Map from RenderFrameHost* to BrowserMediaPlayerManager.
   using MediaPlayerManagerMap =
-      base::ScopedPtrHashMap<RenderFrameHost*,
-                             std::unique_ptr<BrowserMediaPlayerManager>>;
+      std::unordered_map<RenderFrameHost*,
+                         std::unique_ptr<BrowserMediaPlayerManager>>;
   MediaPlayerManagerMap media_player_managers_;
 
   using SurfaceViewManagerMap =
-      base::ScopedPtrHashMap<RenderFrameHost*,
-                             std::unique_ptr<BrowserSurfaceViewManager>>;
+      std::unordered_map<RenderFrameHost*,
+                         std::unique_ptr<BrowserSurfaceViewManager>>;
   SurfaceViewManagerMap surface_view_managers_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaWebContentsObserverAndroid);
diff --git a/content/renderer/android/synchronous_compositor_filter.cc b/content/renderer/android/synchronous_compositor_filter.cc
index 6e48013f..98ede7b 100644
--- a/content/renderer/android/synchronous_compositor_filter.cc
+++ b/content/renderer/android/synchronous_compositor_filter.cc
@@ -7,6 +7,7 @@
 #include <utility>
 
 #include "base/callback.h"
+#include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "content/common/android/sync_compositor_messages.h"
@@ -64,7 +65,7 @@
   if (itr == sync_compositor_map_.end()) {
     return nullptr;
   }
-  return itr->second;
+  return itr->second.get();
 }
 
 bool SynchronousCompositorFilter::GetSupportedMessageClasses(
@@ -184,11 +185,11 @@
 void SynchronousCompositorFilter::CreateSynchronousCompositorProxy(
     int routing_id,
     ui::SynchronousInputHandlerProxy* synchronous_input_handler_proxy) {
-  DCHECK(!sync_compositor_map_.contains(routing_id));
-  std::unique_ptr<SynchronousCompositorProxy> proxy(
-      new SynchronousCompositorProxy(routing_id, this,
-                                     synchronous_input_handler_proxy));
-  sync_compositor_map_.add(routing_id, std::move(proxy));
+  DCHECK(sync_compositor_map_.find(routing_id) == sync_compositor_map_.end());
+  std::unique_ptr<SynchronousCompositorProxy> proxy =
+      base::MakeUnique<SynchronousCompositorProxy>(
+          routing_id, this, synchronous_input_handler_proxy);
+  sync_compositor_map_[routing_id] = std::move(proxy);
 }
 
 void SynchronousCompositorFilter::SetProxyCompositorFrameSink(
@@ -224,7 +225,6 @@
   DCHECK(compositor_task_runner_->BelongsToCurrentThread());
   if (base::ContainsKey(sync_compositor_map_, routing_id)) {
     DCHECK(compositor_task_runner_->BelongsToCurrentThread());
-    DCHECK(sync_compositor_map_.contains(routing_id));
     sync_compositor_map_.erase(routing_id);
   }
   if (base::ContainsKey(synchronous_input_handler_proxy_map_, routing_id))
diff --git a/content/renderer/android/synchronous_compositor_filter.h b/content/renderer/android/synchronous_compositor_filter.h
index 9ed6ec64..1e973bdd8 100644
--- a/content/renderer/android/synchronous_compositor_filter.h
+++ b/content/renderer/android/synchronous_compositor_filter.h
@@ -8,9 +8,9 @@
 #include <stdint.h>
 
 #include <memory>
+#include <unordered_map>
 #include <vector>
 
-#include "base/containers/scoped_ptr_hash_map.h"
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
 #include "content/renderer/android/synchronous_compositor_registry.h"
@@ -92,8 +92,8 @@
 
   // Compositor thread-only fields.
   using SyncCompositorMap =
-      base::ScopedPtrHashMap<int /* routing_id */,
-                             std::unique_ptr<SynchronousCompositorProxy>>;
+      std::unordered_map<int /* routing_id */,
+                         std::unique_ptr<SynchronousCompositorProxy>>;
   SyncCompositorMap sync_compositor_map_;
 
   bool filter_ready_;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index bf3ff46e..ca7f97f1 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -10,6 +10,7 @@
 import("//media/media_options.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//ppapi/features/features.gni")
+import("//services/service_manager/public/service_manifest.gni")
 import("//testing/test.gni")
 import("//third_party/WebKit/public/public_features.gni")
 import("//v8/gni/v8.gni")
@@ -1442,6 +1443,9 @@
     "//ppapi/c",
     "//ppapi/features",
     "//printing",
+    "//services/file:lib",
+    "//services/file/public/interfaces",
+    "//services/service_manager/public/cpp:service_test_support",
     "//skia",
     "//sql",
     "//sql:test_support",
@@ -1472,6 +1476,8 @@
   ]
 
   data_deps = [
+    ":content_unittests_manifest",
+    "//components/filesystem:filesystem",
     "//third_party/mesa:osmesa",
   ]
 
@@ -1710,6 +1716,15 @@
   }
 }
 
+service_manifest("content_unittests_manifest") {
+  name = "content_unittests"
+  source = "unittests_manifest.json"
+  packaged_services = [ "file" ]
+  deps = [
+    "//services/file:manifest",
+  ]
+}
+
 test("content_perftests") {
   # See comment at the top of //content/BUILD.gn for why this is disabled in
   # component builds.
diff --git a/content/test/unittests_manifest.json b/content/test/unittests_manifest.json
new file mode 100644
index 0000000..94cb81e
--- /dev/null
+++ b/content/test/unittests_manifest.json
@@ -0,0 +1,16 @@
+{
+  "name": "content_unittests",
+  "display_name": "Content Unittests",
+  "interface_provider_specs": {
+    "service_manager:connector": {
+      "provides": {
+        "service_manager:service_factory": [
+          "service_manager::mojom::ServiceFactory"
+         ]
+      },
+      "requires": {
+        "file": [ "file:filesystem", "file:leveldb" ]
+      }
+    }
+  }
+}
diff --git a/docs/clang_tool_refactoring.md b/docs/clang_tool_refactoring.md
index 40a8dae..b9d7c9a 100644
--- a/docs/clang_tool_refactoring.md
+++ b/docs/clang_tool_refactoring.md
@@ -69,14 +69,14 @@
 be `r` (for replacement). In the future, this may be extended to handle header
 insertion/removal. A deletion is an edit with no replacement text.
 
-The edits are applied by [`run_tool.py`](#Running), which understands certain
+The edits are applied by [`apply_edits.py`](#Running), which understands certain
 conventions:
 
-*   The tool should munge newlines in replacement text to `\0`. The script
+*   The clang tool should munge newlines in replacement text to `\0`. The script
     knows to translate `\0` back to newlines when applying edits.
 *   When removing an element from a 'list' (e.g. function parameters,
-    initializers), the tool should emit a deletion for just the element. The
-    script understands how to extend the deletion to remove commas, etc. as
+    initializers), the clang tool should emit a deletion for just the element.
+    The script understands how to extend the deletion to remove commas, etc. as
     needed.
 
 TODO: Document more about `SourceLocation` and how spelling loc differs from
@@ -118,6 +118,12 @@
 ```shell
 ninja -C out/Debug  # For non-Windows
 ninja -d keeprsp -C out/Debug  # For Windows
+
+# experimental alternative:
+$gen_targets = $(ninja -C out/gn -t targets all \
+                 | grep '^gen/[^: ]*\.[ch][pc]*:' \
+                 | cut -f 1 -d :`)
+ninja -C out/Debug $gen_targets
 ```
 
 On Windows, generate the compile DB first, and after making any source changes.
@@ -127,28 +133,53 @@
 tools/clang/scripts/generate_win_compdb.py out/Debug
 ```
 
-Then run the actual tool:
+Then run the actual clang tool to generate a list of edits:
 
 ```shell
 tools/clang/scripts/run_tool.py <toolname> \
   --generate-compdb
-  out/Debug <path 1> <path 2> ...
+  out/Debug <path 1> <path 2> ... >/tmp/list-of-edits.debug
 ```
 
 `--generate-compdb` can be omitted if the compile DB was already generated and
 the list of build flags and source files has not changed since generation.
 
 `<path 1>`, `<path 2>`, etc are optional arguments to filter the files to run
-the tool across. This is helpful when sharding global refactorings into smaller
+the tool against. This is helpful when sharding global refactorings into smaller
 chunks. For example, the following command will run the `empty_string` tool
-across just the files in `//base`:
+against just the `.c`, `.cc`, `.cpp`, `.m`, `.mm` files in `//net`.  Note that
+the filtering is not applied to the *output* of the tool - the tool can emit
+edits that apply to files outside of `//cc` (i.e. edits that apply to headers
+from `//base` that got included by source files in `//cc`).
 
 ```shell
 tools/clang/scripts/run_tool.py empty_string  \
   --generated-compdb \
-  out/Debug base
+  out/Debug net >/tmp/list-of-edits.debug
 ```
 
+Note that some header files might only be included from generated files (e.g.
+from only from some `.cpp` files under out/Debug/gen).  To make sure that
+contents of such header files are processed by the clang tool, the clang tool
+needs to be run against the generated files.  The only way to accomplish this
+today is to pass `--all` switch to `run_tool.py` - this will run the clang tool
+against all the sources from the compilation database.
+
+Finally, apply the edits as follows:
+
+```shell
+cat /tmp/list-of-edits.debug \
+  | tools/clang/scripts/extract_edits.py \
+  | tools/clang/scripts/apply_edits.py out/Debug <path 1> <path 2> ...
+```
+
+The apply_edits.py tool will only apply edits to files actually under control of
+`git`.  `<path 1>`, `<path 2>`, etc are optional arguments to further filter the
+files that the edits are applied to.  Note that semantics of these filters is
+distinctly different from the arguments of `run_tool.py` filters - one set of
+filters controls which files are edited, the other set of filters controls which
+files the clang tool is run against.
+
 ## Debugging
 Dumping the AST for a file:
 
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 86abfabd..da5c3dd 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -436,6 +436,9 @@
   using base::trace_event::MemoryAllocatorDump;
   using base::trace_event::MemoryDumpLevelOfDetail;
 
+  // Dump owned MappedMemoryManager memory as well.
+  mapped_memory_->OnMemoryDump(args, pmd);
+
   if (!transfer_buffer_->HaveBuffer())
     return true;
 
diff --git a/gpu/command_buffer/client/mapped_memory.cc b/gpu/command_buffer/client/mapped_memory.cc
index 0501d57..708e121f3 100644
--- a/gpu/command_buffer/client/mapped_memory.cc
+++ b/gpu/command_buffer/client/mapped_memory.cc
@@ -47,19 +47,9 @@
       max_free_bytes_(unused_memory_reclaim_limit),
       max_allocated_bytes_(SharedMemoryLimits::kNoLimit),
       tracing_id_(g_next_mapped_memory_manager_tracing_id.GetNext()) {
-  // In certain cases, ThreadTaskRunnerHandle isn't set (Android Webview).
-  // Don't register a dump provider in these cases.
-  // TODO(ericrk): Get this working in Android Webview. crbug.com/517156
-  if (base::ThreadTaskRunnerHandle::IsSet()) {
-    base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
-        this, "gpu::MappedMemoryManager", base::ThreadTaskRunnerHandle::Get());
-  }
 }
 
 MappedMemoryManager::~MappedMemoryManager() {
-  base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
-      this);
-
   CommandBuffer* cmd_buf = helper_->command_buffer();
   for (auto& chunk : chunks_) {
     cmd_buf->DestroyTransferBuffer(chunk->shm_id());
diff --git a/gpu/command_buffer/client/mapped_memory.h b/gpu/command_buffer/client/mapped_memory.h
index 0af38b5..72a96764 100644
--- a/gpu/command_buffer/client/mapped_memory.h
+++ b/gpu/command_buffer/client/mapped_memory.h
@@ -121,8 +121,7 @@
 };
 
 // Manages MemoryChunks.
-class GPU_EXPORT MappedMemoryManager
-    : public base::trace_event::MemoryDumpProvider {
+class GPU_EXPORT MappedMemoryManager {
  public:
   enum MemoryLimit {
     kNoLimit = 0,
@@ -133,7 +132,7 @@
   MappedMemoryManager(CommandBufferHelper* helper,
                       size_t unused_memory_reclaim_limit);
 
-  ~MappedMemoryManager() override;
+  ~MappedMemoryManager();
 
   unsigned int chunk_size_multiple() const {
     return chunk_size_multiple_;
@@ -179,9 +178,9 @@
   // Free Any Shared memory that is not in use.
   void FreeUnused();
 
-  // Overridden from base::trace_event::MemoryDumpProvider:
+  // Dump memory usage - called from GLES2Implementation.
   bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
-                    base::trace_event::ProcessMemoryDump* pmd) override;
+                    base::trace_event::ProcessMemoryDump* pmd);
 
   // Used for testing
   size_t num_chunks() const {
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.cc b/gpu/ipc/service/gpu_command_buffer_stub.cc
index 13bc2617..e480daa 100644
--- a/gpu/ipc/service/gpu_command_buffer_stub.cc
+++ b/gpu/ipc/service/gpu_command_buffer_stub.cc
@@ -11,8 +11,10 @@
 #include "base/hash.h"
 #include "base/json/json_writer.h"
 #include "base/macros.h"
+#include "base/memory/memory_pressure_listener.h"
 #include "base/memory/ptr_util.h"
 #include "base/memory/shared_memory.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
@@ -54,6 +56,27 @@
 #include "gpu/ipc/service/stream_texture_android.h"
 #endif
 
+// Macro to reduce code duplication when logging memory in
+// GpuCommandBufferMemoryTracker. This is needed as the UMA_HISTOGRAM_* macros
+// require a unique call-site per histogram (you can't funnel multiple strings
+// into the same call-site).
+#define GPU_COMMAND_BUFFER_MEMORY_BLOCK(category)                          \
+  do {                                                                     \
+    uint64_t mb_used = tracking_group_->GetSize() / (1024 * 1024);         \
+    switch (context_type_) {                                               \
+      case gles2::CONTEXT_TYPE_WEBGL1:                                     \
+      case gles2::CONTEXT_TYPE_WEBGL2:                                     \
+        UMA_HISTOGRAM_MEMORY_LARGE_MB("GPU.ContextMemory.WebGL." category, \
+                                      mb_used);                            \
+        break;                                                             \
+      case gles2::CONTEXT_TYPE_OPENGLES2:                                  \
+      case gles2::CONTEXT_TYPE_OPENGLES3:                                  \
+        UMA_HISTOGRAM_MEMORY_LARGE_MB("GPU.ContextMemory.GLES." category,  \
+                                      mb_used);                            \
+        break;                                                             \
+    }                                                                      \
+  } while (false)
+
 namespace gpu {
 struct WaitForCommandState {
   WaitForCommandState(int32_t start, int32_t end, IPC::Message* reply)
@@ -70,15 +93,29 @@
 // ContextGroup's memory type managers and the GpuMemoryManager class.
 class GpuCommandBufferMemoryTracker : public gles2::MemoryTracker {
  public:
-  explicit GpuCommandBufferMemoryTracker(GpuChannel* channel,
-                                         uint64_t share_group_tracing_guid)
+  explicit GpuCommandBufferMemoryTracker(
+      GpuChannel* channel,
+      uint64_t share_group_tracing_guid,
+      gles2::ContextType context_type,
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner)
       : tracking_group_(
             channel->gpu_channel_manager()
                 ->gpu_memory_manager()
                 ->CreateTrackingGroup(channel->GetClientPID(), this)),
         client_tracing_id_(channel->client_tracing_id()),
         client_id_(channel->client_id()),
-        share_group_tracing_guid_(share_group_tracing_guid) {}
+        share_group_tracing_guid_(share_group_tracing_guid),
+        context_type_(context_type),
+        memory_pressure_listener_(new base::MemoryPressureListener(
+            base::Bind(&GpuCommandBufferMemoryTracker::LogMemoryStatsPressure,
+                       base::Unretained(this)))) {
+    // Set up |memory_stats_timer_| to call LogMemoryPeriodic periodically
+    // via the provided |task_runner|.
+    memory_stats_timer_.SetTaskRunner(std::move(task_runner));
+    memory_stats_timer_.Start(
+        FROM_HERE, base::TimeDelta::FromSeconds(30), this,
+        &GpuCommandBufferMemoryTracker::LogMemoryStatsPeriodic);
+  }
 
   void TrackMemoryAllocatedChange(
       size_t old_size, size_t new_size) override {
@@ -88,7 +125,7 @@
 
   bool EnsureGPUMemoryAvailable(size_t size_needed) override {
     return tracking_group_->EnsureGPUMemoryAvailable(size_needed);
-  };
+  }
 
   uint64_t ClientTracingId() const override { return client_tracing_id_; }
   int ClientId() const override { return client_id_; }
@@ -97,12 +134,29 @@
   }
 
  private:
-  ~GpuCommandBufferMemoryTracker() override {}
+  ~GpuCommandBufferMemoryTracker() override { LogMemoryStatsShutdown(); }
+
+  void LogMemoryStatsPeriodic() { GPU_COMMAND_BUFFER_MEMORY_BLOCK("Periodic"); }
+  void LogMemoryStatsShutdown() { GPU_COMMAND_BUFFER_MEMORY_BLOCK("Shutdown"); }
+  void LogMemoryStatsPressure(
+      base::MemoryPressureListener::MemoryPressureLevel pressure_level) {
+    // Only log on CRITICAL memory pressure.
+    if (pressure_level ==
+        base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
+      GPU_COMMAND_BUFFER_MEMORY_BLOCK("Pressure");
+    }
+  }
+
   std::unique_ptr<GpuMemoryTrackingGroup> tracking_group_;
   const uint64_t client_tracing_id_;
   const int client_id_;
   const uint64_t share_group_tracing_guid_;
 
+  // Variables used in memory stat histogram logging.
+  const gles2::ContextType context_type_;
+  base::RepeatingTimer memory_stats_timer_;
+  std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+
   DISALLOW_COPY_AND_ASSIGN(GpuCommandBufferMemoryTracker);
 };
 
@@ -508,8 +562,9 @@
         channel_->gpu_channel_manager()->gpu_memory_buffer_factory();
     context_group_ = new gles2::ContextGroup(
         manager->gpu_preferences(), channel_->mailbox_manager(),
-        new GpuCommandBufferMemoryTracker(channel_,
-                                          command_buffer_id_.GetUnsafeValue()),
+        new GpuCommandBufferMemoryTracker(
+            channel_, command_buffer_id_.GetUnsafeValue(),
+            init_params.attribs.context_type, channel_->task_runner()),
         manager->shader_translator_cache(),
         manager->framebuffer_completeness_cache(), feature_info,
         init_params.attribs.bind_generates_resource,
diff --git a/ios/chrome/browser/ui/autofill/cells/BUILD.gn b/ios/chrome/browser/ui/autofill/cells/BUILD.gn
index 8bd7c3e..0867196 100644
--- a/ios/chrome/browser/ui/autofill/cells/BUILD.gn
+++ b/ios/chrome/browser/ui/autofill/cells/BUILD.gn
@@ -17,6 +17,7 @@
     "//components/strings",
     "//ios/chrome/app/strings",
     "//ios/chrome/app/theme",
+    "//ios/chrome/browser/ui",
     "//ios/chrome/browser/ui/collection_view/cells",
     "//ios/chrome/browser/ui/colors",
     "//ios/public/provider/chrome/browser",
diff --git a/ios/chrome/browser/ui/autofill/cells/cvc_item.mm b/ios/chrome/browser/ui/autofill/cells/cvc_item.mm
index 7a69184..62de222a 100644
--- a/ios/chrome/browser/ui/autofill/cells/cvc_item.mm
+++ b/ios/chrome/browser/ui/autofill/cells/cvc_item.mm
@@ -6,13 +6,13 @@
 
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #import "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #import "ios/public/provider/chrome/browser/ui/text_field_styling.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -88,9 +88,7 @@
 
   cell.buttonForNewCard.hidden = !self.showNewCardButton;
 
-  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-  cell.CVCImageView.image =
-      rb.GetNativeImageNamed(self.CVCImageResourceID).ToUIImage();
+  cell.CVCImageView.image = NativeImage(self.CVCImageResourceID);
 }
 
 @end
diff --git a/ios/chrome/browser/ui/autofill/cells/status_item.mm b/ios/chrome/browser/ui/autofill/cells/status_item.mm
index b2baa65..a9664472 100644
--- a/ios/chrome/browser/ui/autofill/cells/status_item.mm
+++ b/ios/chrome/browser/ui/autofill/cells/status_item.mm
@@ -6,11 +6,11 @@
 
 #include "base/logging.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MaterialActivityIndicator.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
-#include "ui/base/resource/resource_bundle.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -71,19 +71,17 @@
     _activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
     [verticalCenteringView addSubview:_activityIndicator];
 
-    _verifiedImageView = [[UIImageView alloc] init];
-    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
     // TODO(crbug.com/508925): Get rid of IDR_IOS_CHECKMARK, use a vector icon
     // instead.
-    _verifiedImageView.image =
-        rb.GetNativeImageNamed(IDR_IOS_CHECKMARK).ToUIImage();
+    _verifiedImageView =
+        [[UIImageView alloc] initWithImage:NativeImage(IDR_IOS_CHECKMARK)];
     _verifiedImageView.contentMode = UIViewContentModeScaleAspectFit;
     _verifiedImageView.hidden = YES;
     _verifiedImageView.translatesAutoresizingMaskIntoConstraints = NO;
     [verticalCenteringView addSubview:_verifiedImageView];
 
-    _errorImageView = [[UIImageView alloc] init];
-    _errorImageView.image = rb.GetNativeImageNamed(IDR_IOS_ERROR).ToUIImage();
+    _errorImageView =
+        [[UIImageView alloc] initWithImage:NativeImage(IDR_IOS_ERROR)];
     _errorImageView.contentMode = UIViewContentModeScaleAspectFit;
     _errorImageView.hidden = YES;
     _errorImageView.translatesAutoresizingMaskIntoConstraints = NO;
diff --git a/ios/chrome/browser/ui/autofill/cells/storage_switch_item.mm b/ios/chrome/browser/ui/autofill/cells/storage_switch_item.mm
index cc702bd..560e4c8 100644
--- a/ios/chrome/browser/ui/autofill/cells/storage_switch_item.mm
+++ b/ios/chrome/browser/ui/autofill/cells/storage_switch_item.mm
@@ -7,10 +7,10 @@
 #include "components/grit/components_scaled_resources.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/resource/resource_bundle.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -84,13 +84,10 @@
 
     _switchView.onTintColor = [[MDCPalette cr_bluePalette] tint500];
 
-    ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
-    UIImage* highlightedImage =
-        rb.GetNativeImageNamed(IDR_AUTOFILL_TOOLTIP_ICON_H).ToUIImage();
-    [_tooltipButton setImage:highlightedImage forState:UIControlStateSelected];
-    UIImage* normalImage =
-        rb.GetNativeImageNamed(IDR_AUTOFILL_TOOLTIP_ICON).ToUIImage();
-    [_tooltipButton setImage:normalImage forState:UIControlStateNormal];
+    [_tooltipButton setImage:NativeImage(IDR_AUTOFILL_TOOLTIP_ICON_H)
+                    forState:UIControlStateSelected];
+    [_tooltipButton setImage:NativeImage(IDR_AUTOFILL_TOOLTIP_ICON)
+                    forState:UIControlStateNormal];
 
     // Set up the constraints.
     [NSLayoutConstraint activateConstraints:@[
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_collection_cells.mm b/ios/chrome/browser/ui/bookmarks/bookmark_collection_cells.mm
index 9d7be019..38ea805 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_collection_cells.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_collection_cells.mm
@@ -19,7 +19,6 @@
 #import "ios/third_party/material_components_ios/src/components/Ink/src/MaterialInk.h"
 #import "ios/third_party/material_components_ios/src/components/Typography/src/MaterialTypography.h"
 #include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/resource/resource_bundle.h"
 #import "ui/gfx/ios/NSString+CrStringDrawing.h"
 #include "url/gurl.h"
 
@@ -286,10 +285,8 @@
       break;
 
     case bookmark_cell::ButtonMenu: {
-      ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-      UIImage* bgImage =
-          rb.GetNativeImageNamed(IDR_IOS_TOOLBAR_LIGHT_TOOLS).ToUIImage();
-      [self addButtonWithImage:bgImage animated:animated];
+      [self addButtonWithImage:NativeImage(IDR_IOS_TOOLBAR_LIGHT_TOOLS)
+                      animated:animated];
       break;
     }
   }
diff --git a/ios/chrome/browser/ui/infobars/infobar_view.mm b/ios/chrome/browser/ui/infobars/infobar_view.mm
index 7b2ffc0..23d4b1a 100644
--- a/ios/chrome/browser/ui/infobars/infobar_view.mm
+++ b/ios/chrome/browser/ui/infobars/infobar_view.mm
@@ -658,8 +658,7 @@
                        target:(id)target
                        action:(SEL)action {
   DCHECK(!closeButton_);
-  // TODO(jeanfrancoisg): Add IDR_ constant and use GetNativeImageNamed().
-  // crbug/228611
+  // TODO(crbug/228611): Add IDR_ constant and use GetNativeImageNamed().
   NSString* imagePath =
       [[NSBundle mainBundle] pathForResource:@"infobar_close" ofType:@"png"];
   UIImage* image = [UIImage imageWithContentsOfFile:imagePath];
diff --git a/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm b/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
index de08655..5364fe2 100644
--- a/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
+++ b/ios/chrome/browser/ui/ntp/new_tab_page_header_view.mm
@@ -11,9 +11,9 @@
 #import "ios/chrome/browser/ui/image_util.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_header_constants.h"
 #import "ios/chrome/browser/ui/ntp/new_tab_page_toolbar_controller.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/common/material_timing.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
-#include "ui/base/resource/resource_bundle.h"
 #import "ui/gfx/ios/uikit_util.h"
 
 namespace {
@@ -110,9 +110,7 @@
                                         UIViewAutoresizingFlexibleHeight];
   [searchField insertSubview:_searchBoxBorder atIndex:0];
 
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  UIImage* fullBleedShadow =
-      rb.GetNativeImageNamed(IDR_IOS_TOOLBAR_SHADOW_FULL_BLEED).ToUIImage();
+  UIImage* fullBleedShadow = NativeImage(IDR_IOS_TOOLBAR_SHADOW_FULL_BLEED);
   _shadow.reset([[UIImageView alloc] initWithImage:fullBleedShadow]);
   CGRect shadowFrame = [searchField bounds];
   shadowFrame.origin.y =
diff --git a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_panel_view_controller.mm b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_panel_view_controller.mm
index 6cda5ab..36e86a0 100644
--- a/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_panel_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/recent_tabs/recent_tabs_panel_view_controller.mm
@@ -11,7 +11,6 @@
 #include "ios/chrome/grit/ios_theme_resources.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/resource/resource_bundle.h"
 
 // A UIViewController that forces the status bar to be visible.
 @interface RecentTabsWrapperViewController : UIViewController
@@ -43,10 +42,8 @@
   PanelBarView* panelBarView = [[[PanelBarView alloc] init] autorelease];
   rtpvc->_panelBarView.reset([panelBarView retain]);
   [panelBarView setCloseTarget:rtpvc action:@selector(didFinish)];
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  gfx::Image shadowImage = rb.GetNativeImageNamed(IDR_IOS_TOOLBAR_SHADOW);
   base::scoped_nsobject<UIImageView> shadow(
-      [[UIImageView alloc] initWithImage:shadowImage.ToUIImage()]);
+      [[UIImageView alloc] initWithImage:NativeImage(IDR_IOS_TOOLBAR_SHADOW)]);
 
   [panelBarView setTranslatesAutoresizingMaskIntoConstraints:NO];
   [rtpvc.view setTranslatesAutoresizingMaskIntoConstraints:NO];
diff --git a/ios/chrome/browser/ui/omnibox/location_bar_view_ios.mm b/ios/chrome/browser/ui/omnibox/location_bar_view_ios.mm
index a5a29732..ae05807 100644
--- a/ios/chrome/browser/ui/omnibox/location_bar_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/location_bar_view_ios.mm
@@ -29,9 +29,6 @@
 #include "ios/web/public/ssl_status.h"
 #include "ios/web/public/web_state/web_state.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/image/image.h"
 
 namespace {
 const CGFloat kClearTextButtonWidth = 28;
@@ -260,10 +257,8 @@
 
 void LocationBarViewIOS::InstallLocationIcon() {
   // Set the placeholder for empty omnibox.
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  gfx::Image magImage = rb.GetNativeImageNamed(IDR_IOS_OMNIBOX_SEARCH);
   UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
-  UIImage* image = magImage.ToUIImage();
+  UIImage* image = NativeImage(IDR_IOS_OMNIBOX_SEARCH);
   [button setImage:image forState:UIControlStateNormal];
   [button setFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
   [button addTarget:nil
@@ -291,17 +286,13 @@
 }
 
 void LocationBarViewIOS::CreateClearTextIcon(bool is_incognito) {
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
-  UIImage* omniBoxClearImage =
-      is_incognito
-          ? rb.GetNativeImageNamed(IDR_IOS_OMNIBOX_CLEAR_OTR).ToUIImage()
-          : rb.GetNativeImageNamed(IDR_IOS_OMNIBOX_CLEAR).ToUIImage();
+  UIImage* omniBoxClearImage = is_incognito
+                                   ? NativeImage(IDR_IOS_OMNIBOX_CLEAR_OTR)
+                                   : NativeImage(IDR_IOS_OMNIBOX_CLEAR);
   UIImage* omniBoxClearPressedImage =
-      is_incognito
-          ? rb.GetNativeImageNamed(IDR_IOS_OMNIBOX_CLEAR_OTR_PRESSED)
-                .ToUIImage()
-          : rb.GetNativeImageNamed(IDR_IOS_OMNIBOX_CLEAR_PRESSED).ToUIImage();
+      is_incognito ? NativeImage(IDR_IOS_OMNIBOX_CLEAR_OTR_PRESSED)
+                   : NativeImage(IDR_IOS_OMNIBOX_CLEAR_PRESSED);
   [button setImage:omniBoxClearImage forState:UIControlStateNormal];
   [button setImage:omniBoxClearPressedImage forState:UIControlStateHighlighted];
 
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_row.h b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_row.h
index f53141a..334b758 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_row.h
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_row.h
@@ -30,7 +30,7 @@
 
 // Update the match type icon with the supplied image ID and adjust its position
 // based on the current size of the row.
-- (void)updateLeftImage:(int)imageId;
+- (void)updateLeftImage:(int)imageID;
 
 @end
 
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_row.mm b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_row.mm
index 445950f..be53f8a6 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_material_row.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_material_row.mm
@@ -11,7 +11,6 @@
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
-#include "ui/base/resource/resource_bundle.h"
 
 namespace {
 const CGFloat kImageDimensionLength = 19.0;
@@ -28,9 +27,6 @@
 // Set the append button normal and highlighted images.
 - (void)updateAppendButtonImages;
 
-// Set the Physical Web image view image.
-- (void)updatePhysicalWebImage;
-
 @end
 
 @implementation OmniboxPopupMaterialRow
@@ -80,7 +76,7 @@
     _physicalWebImageView = [[UIImageView alloc] initWithFrame:CGRectZero];
     _physicalWebImageView.userInteractionEnabled = NO;
     _physicalWebImageView.contentMode = UIViewContentModeCenter;
-    [self updatePhysicalWebImage];
+    _physicalWebImageView.image = NativeImage(IDR_IOS_OMNIBOX_PHYSICAL_WEB);
     [self addSubview:_physicalWebImageView];
 
     // Left icon is only displayed on iPad.
@@ -127,11 +123,8 @@
   _physicalWebImageView.frame = LayoutRectGetRect(rightAccessoryLayout);
 }
 
-- (void)updateLeftImage:(int)imageId {
-  // Update the image.
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  UIImage* image = rb.GetNativeImageNamed(imageId).ToUIImage();
-  _imageView.image = image;
+- (void)updateLeftImage:(int)imageID {
+  _imageView.image = NativeImage(imageID);
 
   // Adjust the vertical position based on the current size of the row.
   CGRect frame = _imageView.frame;
@@ -161,32 +154,20 @@
 }
 
 - (void)updateAppendButtonImages {
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
   int appendResourceID = _incognito
                              ? IDR_IOS_OMNIBOX_KEYBOARD_VIEW_APPEND_INCOGNITO
                              : IDR_IOS_OMNIBOX_KEYBOARD_VIEW_APPEND;
-  UIImage* appendImage = rb.GetNativeImageNamed(appendResourceID).ToUIImage();
-  if (UseRTLLayout()) {
-    appendImage = [appendImage imageFlippedForRightToLeftLayoutDirection];
-  }
+  UIImage* appendImage = NativeReversableImage(appendResourceID, YES);
 
   [_appendButton setImage:appendImage forState:UIControlStateNormal];
   int appendSelectedResourceID =
       _incognito ? IDR_IOS_OMNIBOX_KEYBOARD_VIEW_APPEND_INCOGNITO_HIGHLIGHTED
                  : IDR_IOS_OMNIBOX_KEYBOARD_VIEW_APPEND_HIGHLIGHTED;
-  UIImage* appendImageSelected =
-      rb.GetNativeImageNamed(appendSelectedResourceID).ToUIImage();
+  UIImage* appendImageSelected = NativeImage(appendSelectedResourceID);
   [_appendButton setImage:appendImageSelected
                  forState:UIControlStateHighlighted];
 }
 
-- (void)updatePhysicalWebImage {
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  UIImage* physicalWebImage =
-      rb.GetNativeImageNamed(IDR_IOS_OMNIBOX_PHYSICAL_WEB).ToUIImage();
-  _physicalWebImageView.image = physicalWebImage;
-}
-
 - (NSString*)accessibilityLabel {
   return _textTruncatingLabel.attributedText.string;
 }
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
index 12d521e..a27ab4490 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_popup_view_ios.mm
@@ -22,13 +22,12 @@
 #include "ios/chrome/browser/ui/omnibox/omnibox_util.h"
 #include "ios/chrome/browser/ui/omnibox/omnibox_view_ios.h"
 #include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #include "ios/web/public/image_fetcher/image_data_fetcher.h"
 #include "ios/web/public/web_thread.h"
 #include "net/url_request/url_request_context_getter.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/image/image.h"
 
 namespace {
 const CGFloat kExpandAnimationDuration = 0.1;
@@ -74,11 +73,8 @@
   [popupView_ addSubview:popupControllerView];
   if (IsIPadIdiom()) {
     [popupView_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
-    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-    gfx::Image shadowImage =
-        rb.GetNativeImageNamed(IDR_IOS_TOOLBAR_SHADOW_FULL_BLEED);
-    base::scoped_nsobject<UIImageView> shadowView(
-        [[UIImageView alloc] initWithImage:shadowImage.ToUIImage()]);
+    base::scoped_nsobject<UIImageView> shadowView([[UIImageView alloc]
+        initWithImage:NativeImage(IDR_IOS_TOOLBAR_SHADOW_FULL_BLEED)]);
     [shadowView setUserInteractionEnabled:NO];
     [shadowView setTranslatesAutoresizingMaskIntoConstraints:NO];
     [popupView_ addSubview:shadowView];
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
index e67c3ab..f95f24fe 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_text_field_ios.mm
@@ -28,7 +28,6 @@
 #include "skia/ext/skia_utils_ios.h"
 #include "third_party/google_toolbox_for_mac/src/iPhone/GTMFadeTruncatingLabel.h"
 #include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/image/image.h"
 #import "ui/gfx/ios/NSString+CrStringDrawing.h"
@@ -408,9 +407,7 @@
     // For iPhone, the left view is only updated when not in editing mode (i.e.
     // the text field is not first responder).
   } else if (_leftViewImageId && (IsIPadIdiom() || ![self isFirstResponder])) {
-    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-    gfx::Image defaultImage = rb.GetNativeImageNamed(_leftViewImageId);
-    UIImage* image = [defaultImage.ToUIImage()
+    UIImage* image = [NativeImage(_leftViewImageId)
         imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
     UIImageView* imageView =
         [[[UIImageView alloc] initWithImage:image] autorelease];
diff --git a/ios/chrome/browser/ui/overscroll_actions/BUILD.gn b/ios/chrome/browser/ui/overscroll_actions/BUILD.gn
index ab71ac6..5d8fee9 100644
--- a/ios/chrome/browser/ui/overscroll_actions/BUILD.gn
+++ b/ios/chrome/browser/ui/overscroll_actions/BUILD.gn
@@ -45,7 +45,6 @@
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/ui/voice",
     "//ios/web",
-    "//ui/base",
   ]
   allow_circular_includes_from = [ "//ios/chrome/browser/ui/static_content" ]
   libs = [
diff --git a/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_view.mm b/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_view.mm
index 44aa1eca..3f9e91d 100644
--- a/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_view.mm
+++ b/ios/chrome/browser/ui/overscroll_actions/overscroll_actions_view.mm
@@ -10,8 +10,8 @@
 #include "base/mac/objc_property_releaser.h"
 #include "base/mac/scoped_nsobject.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
+#include "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
-#include "ui/base/resource/resource_bundle.h"
 
 namespace {
 // Actions images.
@@ -285,10 +285,8 @@
     [_highlightMaskLayer addSublayer:_refreshActionImageViewHighlighted.layer];
     [_highlightMaskLayer addSublayer:_closeTabActionImageViewHighlighted.layer];
 
-    _shadowView = [[UIImageView alloc] initWithFrame:CGRectZero];
-    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-    gfx::Image shadow = rb.GetNativeImageNamed(IDR_IOS_TOOLBAR_SHADOW);
-    [_shadowView setImage:shadow.ToUIImage()];
+    _shadowView =
+        [[UIImageView alloc] initWithImage:NativeImage(IDR_IOS_TOOLBAR_SHADOW)];
     [self addSubview:_shadowView];
 
     _backgroundView = [[UIView alloc] initWithFrame:CGRectZero];
diff --git a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
index f791f5d..f9cd409 100644
--- a/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
+++ b/ios/chrome/browser/ui/sad_tab/sad_tab_view.mm
@@ -17,6 +17,7 @@
 #import "ios/chrome/browser/ui/commands/open_url_command.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #import "ios/chrome/browser/ui/url_loader.h"
 #import "ios/chrome/browser/ui/util/label_link_controller.h"
 #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h"
@@ -26,8 +27,6 @@
 #include "ios/web/public/web_state/web_state.h"
 #import "net/base/mac/url_conversions.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
-#include "ui/gfx/image/image.h"
 
 namespace {
 // Color constants.
@@ -137,11 +136,8 @@
 
 - (UIImageView*)imageView {
   if (!_imageView) {
-    ui::ResourceBundle& resourceBundle =
-        ui::ResourceBundle::GetSharedInstance();
-    UIImage* image =
-        resourceBundle.GetNativeImageNamed(IDR_CRASH_SAD_TAB).ToUIImage();
-    _imageView.reset([[UIImageView alloc] initWithImage:image]);
+    _imageView.reset(
+        [[UIImageView alloc] initWithImage:NativeImage(IDR_CRASH_SAD_TAB)]);
     [_imageView setBackgroundColor:self.backgroundColor];
   }
   return _imageView.get();
diff --git a/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm b/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm
index 4f2a3e7d..bc8f6c7 100644
--- a/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm
+++ b/ios/chrome/browser/ui/side_swipe/card_side_swipe_view.mm
@@ -23,7 +23,6 @@
 #import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/web/web_state/ui/crw_web_controller.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "url/gurl.h"
 
 using base::UserMetricsAction;
@@ -56,9 +55,7 @@
     [self addSubview:toolbarHolder_];
 
     shadowView_.reset([[UIImageView alloc] initWithFrame:self.bounds]);
-    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-    gfx::Image shadow = rb.GetNativeImageNamed(IDR_IOS_TOOLBAR_SHADOW);
-    [shadowView_ setImage:shadow.ToUIImage()];
+    [shadowView_ setImage:NativeImage(IDR_IOS_TOOLBAR_SHADOW)];
     [self addSubview:shadowView_];
 
     // All subviews are as wide as the parent
diff --git a/ios/chrome/browser/ui/tab_switcher/BUILD.gn b/ios/chrome/browser/ui/tab_switcher/BUILD.gn
index 55c1d92..e235c27 100644
--- a/ios/chrome/browser/ui/tab_switcher/BUILD.gn
+++ b/ios/chrome/browser/ui/tab_switcher/BUILD.gn
@@ -152,6 +152,7 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/favicon",
     "//ios/chrome/browser/sync",
+    "//ios/chrome/browser/ui",
     "//ui/base",
   ]
 }
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
index 1819df60..16060190 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_controller.mm
@@ -45,6 +45,7 @@
 #import "ios/chrome/browser/ui/toolbar/toolbar_controller.h"
 #import "ios/chrome/browser/ui/toolbar/toolbar_owner.h"
 #include "ios/chrome/browser/ui/ui_util.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/third_party/material_components_ios/src/components/Palettes/src/MaterialPalettes.h"
@@ -53,7 +54,6 @@
 #import "ios/web/web_state/ui/crw_web_controller.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/resource/resource_bundle.h"
 
 namespace {
 
@@ -672,10 +672,8 @@
 
   base::scoped_nsobject<UIImageView> toolbarShadowImageView(
       [[UIImageView alloc] initWithFrame:shadowInitialFrame]);
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  gfx::Image shadow = rb.GetNativeImageNamed(IDR_IOS_TOOLBAR_SHADOW);
   [toolbarShadowImageView setAutoresizingMask:UIViewAutoresizingNone];
-  [toolbarShadowImageView setImage:shadow.ToUIImage()];
+  [toolbarShadowImageView setImage:NativeImage(IDR_IOS_TOOLBAR_SHADOW)];
   [placeholderView addSubview:toolbarShadowImageView];
 
   [self.view addSubview:placeholderView];
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
index 6b9072a..d38f3245 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.mm
@@ -18,7 +18,6 @@
 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
 #import "ios/third_party/material_text_accessibility_ios/src/src/MDFTextAccessibility.h"
 #include "ui/base/l10n/l10n_util.h"
-#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/image/image.h"
 #include "url/gurl.h"
 
@@ -136,9 +135,7 @@
     // Shadow view.
     _shadow.reset([[UIImageView alloc] initWithFrame:CGRectZero]);
     [_shadow setTranslatesAutoresizingMaskIntoConstraints:NO];
-    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-    gfx::Image shadow = rb.GetNativeImageNamed(IDR_IOS_TOOLBAR_SHADOW);
-    [_shadow setImage:shadow.ToUIImage()];
+    [_shadow setImage:NativeImage(IDR_IOS_TOOLBAR_SHADOW)];
     [[self containerView] addSubview:_shadow];
 
     // Constraints on the Top bar, snapshot view, and shadow view.
@@ -226,10 +223,7 @@
   if (tab.favicon) {
     [_favicon setImage:tab.favicon];
   } else {
-    // No favicon is available, use placeholder instead.
-    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-    [_favicon
-        setImage:rb.GetNativeImageNamed(IDR_IOS_OMNIBOX_HTTP).ToUIImage()];
+    [_favicon setImage:NativeImage(IDR_IOS_OMNIBOX_HTTP)];
   }
 
   CGSize snapshotSize = cellSize;
diff --git a/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.mm b/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.mm
index 76237df8..c6a3afd 100644
--- a/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.mm
+++ b/ios/chrome/browser/ui/tab_switcher/tab_switcher_utils.mm
@@ -15,14 +15,13 @@
 #import "ios/chrome/browser/favicon/favicon_loader.h"
 #include "ios/chrome/browser/favicon/ios_chrome_favicon_loader_factory.h"
 #include "ios/chrome/browser/sync/ios_chrome_profile_sync_service_factory.h"
+#import "ios/chrome/browser/ui/uikit_ui_util.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
-#include "ui/base/resource/resource_bundle.h"
 
 namespace ios_internal {
 
 UIImage* DefaultFaviconImage() {
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  return rb.GetNativeImageNamed(IDR_IOS_OMNIBOX_HTTP).ToUIImage();
+  return NativeImage(IDR_IOS_OMNIBOX_HTTP);
 }
 
 void GetFavicon(GURL const& url,
diff --git a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
index 759f031..a4bc62b5 100644
--- a/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/toolbar_controller.mm
@@ -34,7 +34,6 @@
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/chrome/grit/ios_theme_resources.h"
 #import "ios/third_party/material_roboto_font_loader_ios/src/src/MaterialRobotoFontLoader.h"
-#include "ui/base/resource/resource_bundle.h"
 
 using base::UserMetricsAction;
 using ios::material::TimingFunction;
@@ -223,7 +222,7 @@
 }
 
 // Returns the background image that should be used for |style|.
-- (const gfx::Image&)getBackgroundImageForStyle:(ToolbarControllerStyle)style;
+- (UIImage*)getBackgroundImageForStyle:(ToolbarControllerStyle)style;
 
 // Whether the share button should be visible in the toolbar.
 - (BOOL)shareButtonShouldBeVisible;
@@ -316,9 +315,7 @@
     [shadowView_ setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
     [shadowView_ setUserInteractionEnabled:NO];
     [view_ addSubview:shadowView_];
-    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-    gfx::Image shadow = rb.GetNativeImageNamed(IDR_IOS_TOOLBAR_SHADOW);
-    [shadowView_ setImage:shadow.ToUIImage()];
+    [shadowView_ setImage:NativeImage(IDR_IOS_TOOLBAR_SHADOW)];
 
     if (idiom == IPHONE_IDIOM) {
       // iPad omnibox does not expand to full bleed.
@@ -331,9 +328,8 @@
       [fullBleedShadowView_ setUserInteractionEnabled:NO];
       [fullBleedShadowView_ setAlpha:0];
       [view_ addSubview:fullBleedShadowView_];
-      gfx::Image fullBleedShadow =
-          rb.GetNativeImageNamed(IDR_IOS_TOOLBAR_SHADOW_FULL_BLEED);
-      [fullBleedShadowView_ setImage:fullBleedShadow.ToUIImage()];
+      [fullBleedShadowView_
+          setImage:NativeImage(IDR_IOS_TOOLBAR_SHADOW_FULL_BLEED)];
     }
 
     transitionLayers_.reset(
@@ -343,9 +339,9 @@
     [view_ setUserInteractionEnabled:YES];
     [backgroundView_ setUserInteractionEnabled:YES];
 
-    gfx::Image tile = [self getBackgroundImageForStyle:style];
+    UIImage* tile = [self getBackgroundImageForStyle:style];
     [[self backgroundView]
-        setImage:StretchableImageFromUIImage(tile.ToUIImage(), 0.0, 3.0)];
+        setImage:StretchableImageFromUIImage(tile, 0.0, 3.0)];
 
     if (idiom == IPHONE_IDIOM) {
       stackButton_.reset(
@@ -485,16 +481,10 @@
 
 - (UIImage*)imageForImageEnum:(int)imageEnum
                      forState:(ToolbarButtonUIState)state {
-  int imageId =
+  int imageID =
       [self imageIdForImageEnum:imageEnum style:[self style] forState:state];
-  DCHECK(imageId);
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  gfx::Image tile = rb.GetNativeImageNamed(imageId);
-  UIImage* image = tile.ToUIImage();
-  return (UseRTLLayout() &&
-          [self imageShouldFlipForRightToLeftLayoutDirection:imageEnum])
-             ? [image imageFlippedForRightToLeftLayoutDirection]
-             : image;
+  return NativeReversableImage(
+      imageID, [self imageShouldFlipForRightToLeftLayoutDirection:imageEnum]);
 }
 
 - (int)imageEnumForButton:(UIButton*)button {
@@ -640,15 +630,14 @@
                     object:nil];
 }
 
-- (const gfx::Image&)getBackgroundImageForStyle:(ToolbarControllerStyle)style {
-  int backgroundImageId;
+- (UIImage*)getBackgroundImageForStyle:(ToolbarControllerStyle)style {
+  int backgroundImageID;
   if (style == ToolbarControllerStyleLightMode)
-    backgroundImageId = IDR_IOS_TOOLBAR_LIGHT_BACKGROUND;
+    backgroundImageID = IDR_IOS_TOOLBAR_LIGHT_BACKGROUND;
   else
-    backgroundImageId = IDR_IOS_TOOLBAR_DARK_BACKGROUND;
+    backgroundImageID = IDR_IOS_TOOLBAR_DARK_BACKGROUND;
 
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  return rb.GetNativeImageNamed(backgroundImageId);
+  return NativeImage(backgroundImageID);
 }
 
 - (CGRect)specificControlsArea {
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
index 48d0475..2fd6f3a 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -67,7 +67,6 @@
 #import "net/base/mac/url_conversions.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/page_transition_types.h"
-#include "ui/base/resource/resource_bundle.h"
 #import "ui/gfx/ios/NSString+CrStringDrawing.h"
 
 using base::UserMetricsAction;
diff --git a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
index 0f19ea97..421e2cda 100644
--- a/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
+++ b/ios/chrome/browser/ui/tools_menu/tools_menu_view_controller.mm
@@ -35,7 +35,6 @@
 #import "ios/third_party/material_components_ios/src/components/Ink/src/MaterialInk.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
-#include "ui/base/resource/resource_bundle.h"
 
 using ios::material::TimingFunction;
 
@@ -341,19 +340,6 @@
   [self addConstraints];
 }
 
-- (UIImage*)imageForImageId:(int)imageId reversed:(BOOL)reversed {
-  if (imageId == 0) {
-    return nil;
-  }
-  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
-  gfx::Image image = rb.GetNativeImageNamed(imageId);
-  if (reversed) {
-    return [image.ToUIImage() imageFlippedForRightToLeftLayoutDirection];
-  } else {
-    return image.ToUIImage();
-  }
-}
-
 - (ToolsMenuButton*)newButtonForImageIds:(int[2][3])imageIds
                                commandID:(int)commandID
                     accessibilityLabelID:(int)labelID
@@ -372,9 +358,8 @@
                            reverseForRTL:(BOOL)reverseForRTL {
   ToolsMenuButton* button = [[ToolsMenuButton alloc] initWithFrame:CGRectZero];
   [button setTranslatesAutoresizingMaskIntoConstraints:NO];
-  BOOL reverseImage = reverseForRTL && UseRTLLayout();
 
-  [button setImage:[self imageForImageId:imageIds[0][0] reversed:reverseImage]
+  [button setImage:NativeReversableImage(imageIds[0][0], reverseForRTL)
           forState:UIControlStateNormal];
   [[button imageView] setContentMode:UIViewContentModeCenter];
   [button setBackgroundColor:[self backgroundColor]];
@@ -383,14 +368,12 @@
 
   SetA11yLabelAndUiAutomationName(button, labelID, name);
 
-  UIImage* pressedImage =
-      [self imageForImageId:imageIds[0][1] reversed:reverseImage];
+  UIImage* pressedImage = NativeReversableImage(imageIds[0][1], reverseForRTL);
   if (pressedImage) {
     [button setImage:pressedImage forState:UIControlStateHighlighted];
   }
 
-  UIImage* disabledImage =
-      [self imageForImageId:imageIds[0][2] reversed:reverseImage];
+  UIImage* disabledImage = NativeReversableImage(imageIds[0][2], reverseForRTL);
   if (disabledImage) {
     [button setImage:disabledImage forState:UIControlStateDisabled];
   }
diff --git a/ios/chrome/browser/ui/uikit_ui_util.h b/ios/chrome/browser/ui/uikit_ui_util.h
index 20ffbbb..9179f3e 100644
--- a/ios/chrome/browser/ui/uikit_ui_util.h
+++ b/ios/chrome/browser/ui/uikit_ui_util.h
@@ -104,6 +104,15 @@
 // Intended for use in debug.
 BOOL ImageHasAlphaChannel(UIImage* image);
 
+// Returns the image from the shared resource bundle with the image id
+// |imageID|. If |reversable| is YES and RTL layout is in use, the image
+// will be flipped for RTL.
+UIImage* NativeReversableImage(int imageID, BOOL reversable);
+
+// Convenience version of NativeReversableImage for images that are never
+// reversable; equivalent to NativeReversableImage(imageID, NO).
+UIImage* NativeImage(int imageID);
+
 // Returns an image resized to |targetSize|. It first calculate the projection
 // by calling CalculateProjection() and then create a new image of the desired
 // size and project the correct subset of the original image onto it.
diff --git a/ios/chrome/browser/ui/uikit_ui_util.mm b/ios/chrome/browser/ui/uikit_ui_util.mm
index 2384568..b82122d 100644
--- a/ios/chrome/browser/ui/uikit_ui_util.mm
+++ b/ios/chrome/browser/ui/uikit_ui_util.mm
@@ -16,10 +16,12 @@
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
 #include "ios/chrome/browser/experimental_flags.h"
+#include "ios/chrome/browser/ui/rtl_geometry.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #include "ios/web/public/web_thread.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/l10n/l10n_util_mac.h"
+#include "ui/base/resource/resource_bundle.h"
 #include "ui/gfx/ios/uikit_util.h"
 #include "ui/gfx/scoped_cg_context_save_gstate_mac.h"
 
@@ -225,6 +227,19 @@
   }
 }
 
+UIImage* NativeReversableImage(int imageID, BOOL reversable) {
+  DCHECK(imageID);
+  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+  UIImage* image = rb.GetNativeImageNamed(imageID).ToUIImage();
+  return (reversable && UseRTLLayout())
+             ? [image imageFlippedForRightToLeftLayoutDirection]
+             : image;
+}
+
+UIImage* NativeImage(int imageID) {
+  return NativeReversableImage(imageID, NO);
+}
+
 UIImage* ResizeImage(UIImage* image,
                      CGSize targetSize,
                      ProjectionMode projectionMode) {
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index f408317..09a10af 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -155,7 +155,8 @@
       quic_do_not_fragment(false),
       proxy_delegate(NULL),
       enable_token_binding(false),
-      http_09_on_non_default_ports_enabled(false) {
+      http_09_on_non_default_ports_enabled(false),
+      restrict_to_one_preconnect_for_proxies(false) {
   quic_supported_versions.push_back(QUIC_VERSION_35);
 }
 
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 4676fcf..0987d548 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -203,6 +203,10 @@
     // Enable HTTP/0.9 for HTTP/HTTPS on ports other than the default one for
     // each protocol.
     bool http_09_on_non_default_ports_enabled;
+
+    // If true, only one pending preconnect is allowed to proxies that support
+    // request priorities.
+    bool restrict_to_one_preconnect_for_proxies;
   };
 
   enum SocketPoolType {
diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
index c090016e..577a990 100644
--- a/net/http/http_stream_factory_impl.cc
+++ b/net/http/http_stream_factory_impl.cc
@@ -8,7 +8,6 @@
 
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
@@ -89,23 +88,13 @@
   }
 };
 
-// Returns true if only one preconnect to proxy servers is allowed via field
-// trial.
-bool AllowOnlyOnePreconnectToProxyServers() {
-  return base::StartsWith(base::FieldTrialList::FindFullName(
-                              "NetAllowOnlyOnePreconnectToProxyServers"),
-                          "Enabled", base::CompareCase::INSENSITIVE_ASCII);
-}
-
 }  // anonymous namespace
 
 HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session,
                                              bool for_websockets)
     : session_(session),
       job_factory_(new DefaultJobFactory()),
-      for_websockets_(for_websockets),
-      allow_only_one_preconnect_to_proxy_servers_(
-          AllowOnlyOnePreconnectToProxyServers()) {}
+      for_websockets_(for_websockets) {}
 
 HttpStreamFactoryImpl::~HttpStreamFactoryImpl() {
   DCHECK(request_map_.empty());
@@ -261,7 +250,7 @@
     return false;
   }
 
-  if (!allow_only_one_preconnect_to_proxy_servers_ ||
+  if (!session_->params().restrict_to_one_preconnect_for_proxies ||
       !ProxyServerSupportsPriorities(proxy_info)) {
     return false;
   }
diff --git a/net/http/http_stream_factory_impl.h b/net/http/http_stream_factory_impl.h
index 99aaf22..b61b8abe 100644
--- a/net/http/http_stream_factory_impl.h
+++ b/net/http/http_stream_factory_impl.h
@@ -168,10 +168,6 @@
 
   const bool for_websockets_;
 
-  // True if only one preconnect is allowed to proxy servers that support
-  // request priorities.
-  const bool allow_only_one_preconnect_to_proxy_servers_;
-
   DISALLOW_COPY_AND_ASSIGN(HttpStreamFactoryImpl);
 };
 
diff --git a/net/http/http_stream_factory_impl_job.cc b/net/http/http_stream_factory_impl_job.cc
index 0e69de8..731d4d29 100644
--- a/net/http/http_stream_factory_impl_job.cc
+++ b/net/http/http_stream_factory_impl_job.cc
@@ -386,7 +386,7 @@
 
   MaybeCopyConnectionAttemptsFromSocketOrHandle();
 
-  delegate_->OnStreamReady(this, server_ssl_config_, proxy_info_);
+  delegate_->OnStreamReady(this, server_ssl_config_);
   // |this| may be deleted after this call.
 }
 
diff --git a/net/http/http_stream_factory_impl_job.h b/net/http/http_stream_factory_impl_job.h
index 27b8a049..ffb55813 100644
--- a/net/http/http_stream_factory_impl_job.h
+++ b/net/http/http_stream_factory_impl_job.h
@@ -51,9 +51,7 @@
     virtual ~Delegate() {}
 
     // Invoked when |job| has an HttpStream ready.
-    virtual void OnStreamReady(Job* job,
-                               const SSLConfig& used_ssl_config,
-                               const ProxyInfo& used_proxy_info) = 0;
+    virtual void OnStreamReady(Job* job, const SSLConfig& used_ssl_config) = 0;
 
     // Invoked when |job| has a BidirectionalStream ready.
     virtual void OnBidirectionalStreamImplReady(
diff --git a/net/http/http_stream_factory_impl_job_controller.cc b/net/http/http_stream_factory_impl_job_controller.cc
index 38b9428..7e76ce5c 100644
--- a/net/http/http_stream_factory_impl_job_controller.cc
+++ b/net/http/http_stream_factory_impl_job_controller.cc
@@ -172,12 +172,8 @@
 
 void HttpStreamFactoryImpl::JobController::OnStreamReady(
     Job* job,
-    const SSLConfig& used_ssl_config,
-    const ProxyInfo& used_proxy_info) {
+    const SSLConfig& used_ssl_config) {
   DCHECK(job);
-  // TODO(tbansal): Remove |used_proxy_info| from the method arguments.
-  DCHECK(job->proxy_info().is_empty() == used_proxy_info.is_empty() ||
-         job->proxy_info().proxy_server() == used_proxy_info.proxy_server());
 
   factory_->OnStreamReady(job->proxy_info());
 
@@ -197,7 +193,7 @@
   DCHECK(!factory_->for_websockets_);
   DCHECK_EQ(HttpStreamRequest::HTTP_STREAM, request_->stream_type());
   OnJobSucceeded(job);
-  request_->OnStreamReady(used_ssl_config, used_proxy_info, stream.release());
+  request_->OnStreamReady(used_ssl_config, job->proxy_info(), stream.release());
 }
 
 void HttpStreamFactoryImpl::JobController::OnBidirectionalStreamImplReady(
diff --git a/net/http/http_stream_factory_impl_job_controller.h b/net/http/http_stream_factory_impl_job_controller.h
index c4edf161..bb18c2f 100644
--- a/net/http/http_stream_factory_impl_job_controller.h
+++ b/net/http/http_stream_factory_impl_job_controller.h
@@ -69,9 +69,7 @@
 
   // From HttpStreamFactoryImpl::Job::Delegate.
   // Invoked when |job| has an HttpStream ready.
-  void OnStreamReady(Job* job,
-                     const SSLConfig& used_ssl_config,
-                     const ProxyInfo& used_proxy_info) override;
+  void OnStreamReady(Job* job, const SSLConfig& used_ssl_config) override;
 
   // Invoked when |job| has a BidirectionalStream ready.
   void OnBidirectionalStreamImplReady(
diff --git a/net/http/http_stream_factory_impl_job_controller_unittest.cc b/net/http/http_stream_factory_impl_job_controller_unittest.cc
index 54ec51319..83049f5 100644
--- a/net/http/http_stream_factory_impl_job_controller_unittest.cc
+++ b/net/http/http_stream_factory_impl_job_controller_unittest.cc
@@ -239,8 +239,7 @@
 
   EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
       .WillOnce(Invoke(DeleteHttpStreamPointer));
-  job_controller_->OnStreamReady(job_factory_.main_job(), SSLConfig(),
-                                 ProxyInfo());
+  job_controller_->OnStreamReady(job_factory_.main_job(), SSLConfig());
 }
 
 // Test we cancel Jobs correctly when the Request is explicitly canceled
@@ -358,8 +357,7 @@
 
   EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
       .WillOnce(Invoke(DeleteHttpStreamPointer));
-  job_controller_->OnStreamReady(job_factory_.main_job(), SSLConfig(),
-                                 ProxyInfo());
+  job_controller_->OnStreamReady(job_factory_.main_job(), SSLConfig());
 
   // JobController shouldn't report the status of second job as request
   // is already successfully served.
@@ -413,8 +411,7 @@
 
   EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
       .WillOnce(Invoke(DeleteHttpStreamPointer));
-  job_controller_->OnStreamReady(job_factory_.alternative_job(), SSLConfig(),
-                                 ProxyInfo());
+  job_controller_->OnStreamReady(job_factory_.alternative_job(), SSLConfig());
   VerifyBrokenAlternateProtocolMapping(request_info, false);
 }
 
@@ -458,8 +455,7 @@
 
   EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
       .WillOnce(Invoke(DeleteHttpStreamPointer));
-  job_controller_->OnStreamReady(job_factory_.main_job(), SSLConfig(),
-                                 ProxyInfo());
+  job_controller_->OnStreamReady(job_factory_.main_job(), SSLConfig());
 
   VerifyBrokenAlternateProtocolMapping(request_info, true);
 }
@@ -509,8 +505,7 @@
 
   EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
       .WillOnce(Invoke(DeleteHttpStreamPointer));
-  job_controller_->OnStreamReady(job_factory_.alternative_job(), SSLConfig(),
-                                 ProxyInfo());
+  job_controller_->OnStreamReady(job_factory_.alternative_job(), SSLConfig());
 }
 
 TEST_F(HttpStreamFactoryImplJobControllerTest, DoNotResumeMainJobBeforeWait) {
@@ -935,8 +930,7 @@
 
   EXPECT_CALL(request_delegate_, OnStreamReady(_, _, http_stream))
       .WillOnce(Invoke(DeleteHttpStreamPointer));
-  job_controller_->OnStreamReady(job_factory_.main_job(), SSLConfig(),
-                                 job_factory_.main_job()->proxy_info());
+  job_controller_->OnStreamReady(job_factory_.main_job(), SSLConfig());
 
   // JobController shouldn't report the status of alternative server job as
   // request is already successfully served.
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index a3364909..26b305a 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -14,7 +14,6 @@
 #include "base/compiler_specific.h"
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
-#include "base/metrics/field_trial.h"
 #include "base/run_loop.h"
 #include "base/test/histogram_tester.h"
 #include "net/base/port_util.h"
@@ -1218,13 +1217,9 @@
   }
 }
 
-// Verify that the proxy delegate can disable preconnect jobs to only the proxy
-// servers that support request priorities.
-TEST_F(HttpStreamFactoryTest, ProxyDelegateDisablesPreconnect) {
-  base::FieldTrialList field_trial_list(nullptr);
-  base::FieldTrialList::CreateFieldTrial(
-      "NetAllowOnlyOnePreconnectToProxyServers", "Enabled");
-
+// Verify that only one preconnect job succeeds to a proxy server that supports
+// request priorities.
+TEST_F(HttpStreamFactoryTest, OnlyOnePreconnectToProxyServer) {
   for (bool set_http_server_properties : {false, true}) {
     for (int num_streams = 1; num_streams < 3; ++num_streams) {
       base::HistogramTester histogram_tester;
@@ -1245,6 +1240,7 @@
       params.enable_quic = true;
       params.proxy_service = proxy_service.get();
       params.http_server_properties = &http_server_properties;
+      ASSERT_TRUE(params.restrict_to_one_preconnect_for_proxies);
 
       std::unique_ptr<HttpNetworkSession> session(
           new HttpNetworkSession(params));
@@ -1610,10 +1606,6 @@
 // Verifies that once a stream has been created to a proxy server (that supports
 // request priorities) the next preconnect job can again open new sockets.
 TEST_F(HttpStreamFactoryTest, RequestHttpStreamOverProxyWithPreconnects) {
-  base::FieldTrialList field_trial_list(nullptr);
-  base::FieldTrialList::CreateFieldTrial(
-      "NetAllowOnlyOnePreconnectToProxyServers", "Enabled");
-
   SpdySessionDependencies session_deps(
       ProxyService::CreateFixed("https://myproxy.org:443"));
 
diff --git a/net/spdy/hpack/hpack_decoder_test.cc b/net/spdy/hpack/hpack_decoder_test.cc
index b6bbcbe..a0fe74f 100644
--- a/net/spdy/hpack/hpack_decoder_test.cc
+++ b/net/spdy/hpack/hpack_decoder_test.cc
@@ -351,9 +351,6 @@
   EXPECT_FALSE(DecodeHeaderBlock(StringPiece("\xbe", 1)));
 }
 
-// Test that a header block with a pseudo-header field following a regular one
-// is treated as malformed.  (HTTP2 draft-14 8.1.2.1., HPACK draft-09 3.1.)
-
 TEST_P(HpackDecoderTest, ContextUpdateMaximumSize) {
   EXPECT_EQ(kDefaultHeaderTableSizeSetting,
             decoder_peer_.header_table()->max_size());
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index ec69ba4..0bf76c6 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -402,6 +402,7 @@
   params.net_log = session_deps->net_log;
   params.http_09_on_non_default_ports_enabled =
       session_deps->http_09_on_non_default_ports_enabled;
+  params.restrict_to_one_preconnect_for_proxies = true;
   return params;
 }
 
diff --git a/services/service_manager/public/cpp/lib/service_test.cc b/services/service_manager/public/cpp/lib/service_test.cc
index 4031c0c5..054c8a8 100644
--- a/services/service_manager/public/cpp/lib/service_test.cc
+++ b/services/service_manager/public/cpp/lib/service_test.cc
@@ -31,8 +31,8 @@
 
 ServiceTest::ServiceTest() {}
 
-ServiceTest::ServiceTest(const std::string& test_name)
-    : test_name_(test_name) {}
+ServiceTest::ServiceTest(const std::string& test_name, bool init_edk)
+    : test_name_(test_name), init_edk_(init_edk) {}
 
 ServiceTest::~ServiceTest() {}
 
@@ -62,7 +62,9 @@
   message_loop_ = CreateMessageLoop();
   background_service_manager_.reset(
       new service_manager::BackgroundServiceManager);
-  background_service_manager_->Init(nullptr);
+  auto init_params = base::MakeUnique<BackgroundServiceManager::InitParams>();
+  init_params->init_edk = init_edk_;
+  background_service_manager_->Init(std::move(init_params));
 
   // Create the service manager connection. We don't proceed until we get our
   // Service's OnStart() method is called.
diff --git a/services/service_manager/public/cpp/service_test.h b/services/service_manager/public/cpp/service_test.h
index 2cdde3d9..d466634 100644
--- a/services/service_manager/public/cpp/service_test.h
+++ b/services/service_manager/public/cpp/service_test.h
@@ -52,7 +52,7 @@
   // Once set via this constructor, it cannot be changed later by calling
   // InitTestName(). The test executable must provide a manifest in the
   // appropriate location that specifies this name also.
-  explicit ServiceTest(const std::string& test_name);
+  explicit ServiceTest(const std::string& test_name, bool init_edk = true);
   ~ServiceTest() override;
 
  protected:
@@ -92,6 +92,7 @@
 
   // See constructor.
   std::string test_name_;
+  bool init_edk_ = true;
 
   Connector* connector_ = nullptr;
   std::string initialize_name_;
diff --git a/storage/browser/blob/blob_storage_registry.cc b/storage/browser/blob/blob_storage_registry.cc
index 47b4bd8d..9aa836b1 100644
--- a/storage/browser/blob/blob_storage_registry.cc
+++ b/storage/browser/blob/blob_storage_registry.cc
@@ -11,7 +11,7 @@
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/logging.h"
-#include "base/stl_util.h"
+#include "base/memory/ptr_util.h"
 #include "storage/browser/blob/blob_entry.h"
 #include "url/gurl.h"
 
@@ -49,11 +49,11 @@
     const std::string& uuid,
     const std::string& content_type,
     const std::string& content_disposition) {
-  DCHECK(!ContainsKey(blob_map_, uuid));
-  std::unique_ptr<BlobEntry> entry(
-      new BlobEntry(content_type, content_disposition));
+  DCHECK(blob_map_.find(uuid) == blob_map_.end());
+  std::unique_ptr<BlobEntry> entry =
+      base::MakeUnique<BlobEntry>(content_type, content_disposition);
   BlobEntry* entry_ptr = entry.get();
-  blob_map_.add(uuid, std::move(entry));
+  blob_map_[uuid] = std::move(entry);
   return entry_ptr;
 }
 
@@ -66,10 +66,10 @@
 }
 
 BlobEntry* BlobStorageRegistry::GetEntry(const std::string& uuid) {
-  BlobMap::iterator found = blob_map_.find(uuid);
+  auto found = blob_map_.find(uuid);
   if (found == blob_map_.end())
     return nullptr;
-  return found->second;
+  return found->second.get();
 }
 
 const BlobEntry* BlobStorageRegistry::GetEntry(const std::string& uuid) const {
@@ -88,7 +88,7 @@
 bool BlobStorageRegistry::DeleteURLMapping(const GURL& blob_url,
                                            std::string* uuid) {
   DCHECK(!BlobUrlHasRef(blob_url));
-  URLMap::iterator found = url_to_uuid_.find(blob_url);
+  auto found = url_to_uuid_.find(blob_url);
   if (found == url_to_uuid_.end())
     return false;
   if (uuid)
@@ -98,12 +98,12 @@
 }
 
 bool BlobStorageRegistry::IsURLMapped(const GURL& blob_url) const {
-  return base::ContainsKey(url_to_uuid_, blob_url);
+  return url_to_uuid_.find(blob_url) != url_to_uuid_.end();
 }
 
 BlobEntry* BlobStorageRegistry::GetEntryFromURL(const GURL& url,
                                                 std::string* uuid) {
-  URLMap::iterator found =
+  auto found =
       url_to_uuid_.find(BlobUrlHasRef(url) ? ClearBlobUrlRef(url) : url);
   if (found == url_to_uuid_.end())
     return nullptr;
diff --git a/storage/browser/blob/blob_storage_registry.h b/storage/browser/blob/blob_storage_registry.h
index f27e7ea..26d391fb 100644
--- a/storage/browser/blob/blob_storage_registry.h
+++ b/storage/browser/blob/blob_storage_registry.h
@@ -10,10 +10,10 @@
 #include <map>
 #include <memory>
 #include <string>
+#include <unordered_map>
 #include <vector>
 
 #include "base/callback_forward.h"
-#include "base/containers/scoped_ptr_hash_map.h"
 #include "base/macros.h"
 #include "storage/browser/storage_browser_export.h"
 #include "storage/common/blob_storage/blob_storage_constants.h"
@@ -70,12 +70,9 @@
 
  private:
   friend class ViewBlobInternalsJob;
-  using BlobMap =
-      base::ScopedPtrHashMap<std::string, std::unique_ptr<BlobEntry>>;
-  using URLMap = std::map<GURL, std::string>;
 
-  BlobMap blob_map_;
-  URLMap url_to_uuid_;
+  std::unordered_map<std::string, std::unique_ptr<BlobEntry>> blob_map_;
+  std::map<GURL, std::string> url_to_uuid_;
 
   DISALLOW_COPY_AND_ASSIGN(BlobStorageRegistry);
 };
diff --git a/storage/browser/blob/view_blob_internals_job.cc b/storage/browser/blob/view_blob_internals_job.cc
index a076321..095376b3 100644
--- a/storage/browser/blob/view_blob_internals_job.cc
+++ b/storage/browser/blob/view_blob_internals_job.cc
@@ -153,8 +153,7 @@
 }
 
 void ViewBlobInternalsJob::GenerateHTML(std::string* out) const {
-  for (BlobStorageRegistry::BlobMap::const_iterator iter =
-           blob_storage_context_->registry().blob_map_.begin();
+  for (auto iter = blob_storage_context_->registry().blob_map_.begin();
        iter != blob_storage_context_->registry().blob_map_.end(); ++iter) {
     AddHTMLBoldText(iter->first, out);
     GenerateHTMLForBlobData(*iter->second, iter->second->content_type(),
@@ -163,8 +162,7 @@
   }
   if (!blob_storage_context_->registry().url_to_uuid_.empty()) {
     AddHorizontalRule(out);
-    for (BlobStorageRegistry::URLMap::const_iterator iter =
-             blob_storage_context_->registry().url_to_uuid_.begin();
+    for (auto iter = blob_storage_context_->registry().url_to_uuid_.begin();
          iter != blob_storage_context_->registry().url_to_uuid_.end(); ++iter) {
       AddHTMLBoldText(iter->first.spec(), out);
       StartHTMLList(out);
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 4f7d585f..cb81d82 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -2234,7 +2234,7 @@
 crbug.com/663855 fast/text/ellipsis-rtl-text-in-rtl-flow-underline-composition.html [ Pass Failure ]
 
 # Possible duplicate of crbug.com/498021
-# crbug.com/663855 fast/text/ellipsis-stroked.html [ Pass Failure ]
+crbug.com/663855 [ Win ] fast/text/ellipsis-stroked.html [ Pass Failure ]
 # crbug.com/663858 fast/text/emphasis.html [ Pass Failure ]
 
 crbug.com/663858 fast/text/emphasis-vertical.html [ Pass Failure ]
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
index 85274ea8..b37cac6 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
@@ -24,8 +24,8 @@
 
 InspectorTest.startDumpingProtocolMessages = function()
 {
-    InspectorBackendClass.Connection.prototype._dumpProtocolMessage = testRunner.logToStderr.bind(testRunner);
-    InspectorBackendClass.Options.dumpInspectorProtocolMessages = 1;
+    Protocol.InspectorBackend.Connection.prototype._dumpProtocolMessage = testRunner.logToStderr.bind(testRunner);
+    Protocol.InspectorBackend.Options.dumpInspectorProtocolMessages = 1;
 }
 
 InspectorTest.completeTest = function()
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/protocol-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/protocol-test.js
index 973efe7..8c0f315 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/protocol-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/protocol-test.js
@@ -79,7 +79,7 @@
         InspectorTest.addResult("===========================================================");
         InspectorTest.addResult("Coverage for " + this._agentName);
         InspectorTest.addObject(this._agentCoverage);
-        InspectorBackend.dispatch = this._originalDispatch;
+        Protocol.inspectorBackend.dispatch = this._originalDispatch;
         InspectorFrontendHost.sendMessageToBackend = this._originalSendMessageToBackend;
         this.completeTest();
     }
@@ -99,7 +99,7 @@
         this._agentCoverage[key] = "not checked";
 
     var domain = agentName.replace(/Agent$/,"");
-    var domainMessagesHandler = InspectorBackend._domainDispatchers[domain];
+    var domainMessagesHandler = Protocol.inspectorBackend._domainDispatchers[domain];
     for (var eventName in domainMessagesHandler) {
         if (typeof domainMessagesHandler[eventName] !== "function")
             continue;
@@ -107,11 +107,11 @@
         domainMessagesHandler[eventName] = InspectorTest._dumpEvent.bind(domainMessagesHandler, eventName, domainMessagesHandler[eventName]);
     }
 
-    this._originalDispatch = InspectorBackend.dispatch;
-    InspectorBackend.dispatch = function(message)
+    this._originalDispatch = Protocol.inspectorBackend.dispatch;
+    Protocol.inspectorBackend.dispatch = function(message)
     {
         InspectorTest._lastReceivedMessage = (typeof message === "string") ? JSON.parse(message) : message;
-        InspectorTest._originalDispatch.apply(InspectorBackend, [message]);
+        InspectorTest._originalDispatch.apply(Protocol.inspectorBackend, [message]);
     }
 
     this._originalSendMessageToBackend = InspectorFrontendHost.sendMessageToBackend;
diff --git a/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt b/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt
index 6b7b38e..03533b8 100644
--- a/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/initial-modules-load-expected.txt
@@ -12,6 +12,7 @@
     main
     persistence
     platform
+    protocol
     sdk
     services
     ui
@@ -29,6 +30,7 @@
     main
     persistence
     platform
+    protocol
     sdk
     services
     ui
@@ -50,6 +52,7 @@
     network
     persistence
     platform
+    protocol
     sdk
     services
     snippets
@@ -76,6 +79,7 @@
     network
     persistence
     platform
+    protocol
     sdk
     services
     snippets
@@ -102,6 +106,7 @@
     network
     persistence
     platform
+    protocol
     sdk
     services
     snippets
diff --git a/third_party/WebKit/LayoutTests/inspector/inspector-backend-commands.html b/third_party/WebKit/LayoutTests/inspector/inspector-backend-commands.html
index 8fb87e4..0ee46a2 100644
--- a/third_party/WebKit/LayoutTests/inspector/inspector-backend-commands.html
+++ b/third_party/WebKit/LayoutTests/inspector/inspector-backend-commands.html
@@ -66,12 +66,12 @@
         }]
     }]};
     // The protocol definition above is not used, but is left as a reference for commands below.
-    InspectorBackend.registerCommand("Profiler.commandArgs0", [], [], false);
-    InspectorBackend.registerCommand("Profiler.commandArgs1Rets0", [{"name": "arg1", "type": "number", "optional": false}], [], false);
-    InspectorBackend.registerCommand("Profiler.commandArgs1Rets1", [{"name": "arg1", "type": "object", "optional": false}], ["arg1"], false);
-    InspectorBackend.registerCommand("Profiler.commandArgs3Rets3",
+    Protocol.inspectorBackend.registerCommand("Profiler.commandArgs0", [], [], false);
+    Protocol.inspectorBackend.registerCommand("Profiler.commandArgs1Rets0", [{"name": "arg1", "type": "number", "optional": false}], [], false);
+    Protocol.inspectorBackend.registerCommand("Profiler.commandArgs1Rets1", [{"name": "arg1", "type": "object", "optional": false}], ["arg1"], false);
+    Protocol.inspectorBackend.registerCommand("Profiler.commandArgs3Rets3",
         [{"name": "arg1", "type": "object", "optional": false}, {"name": "arg2", "type": "number", "optional": true}, {"name": "arg3", "type": "string", "optional": true}], ["arg1", "arg2", "arg3"], false);
-    InspectorBackend.registerCommand("Profiler.commandError", [{"name": "error", "type": "object", "optional": false}], [], false);
+    Protocol.inspectorBackend.registerCommand("Profiler.commandError", [{"name": "error", "type": "object", "optional": false}], [], false);
 
     var sendMessageToBackendOriginal = InspectorFrontendHost.sendMessageToBackend;
     InspectorFrontendHost.sendMessageToBackend = sendMessageToBackendLoopback;
diff --git a/third_party/WebKit/LayoutTests/inspector/open-with-rendering-option-enabled-expected.txt b/third_party/WebKit/LayoutTests/inspector/open-with-rendering-option-enabled-expected.txt
index 72258e86..f5b671c 100644
--- a/third_party/WebKit/LayoutTests/inspector/open-with-rendering-option-enabled-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/open-with-rendering-option-enabled-expected.txt
@@ -10,6 +10,7 @@
     main
     persistence
     platform
+    protocol
     sdk
     services
     ui
diff --git a/third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check.html b/third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check.html
index 37c528a..4da046c 100644
--- a/third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check.html
+++ b/third_party/WebKit/LayoutTests/inspector/profiler/agents-disabled-check.html
@@ -12,7 +12,7 @@
         messages.push(message);
     }
     Protocol.TargetBase.prototype._dumpProtocolMessage = collectMessages;
-    InspectorBackendClass.Options.dumpInspectorProtocolMessages = 1;
+    Protocol.InspectorBackend.Options.dumpInspectorProtocolMessages = 1;
     messages.push("--> SDK.targetManager.suspendAllTargets();");
     SDK.targetManager.suspendAllTargets();
     messages.push("");
@@ -20,7 +20,7 @@
     SDK.targetManager.resumeAllTargets();
     messages.push("");
     messages.push("--> done");
-    InspectorBackendClass.Options.dumpInspectorProtocolMessages = 0;
+    Protocol.InspectorBackend.Options.dumpInspectorProtocolMessages = 0;
     for (var i = 0; i < messages.length; ++i) {
         var message = messages[i];
         message = message.replace(/"id":\d+,/, '"id":<number>,');
diff --git a/third_party/WebKit/LayoutTests/inspector/report-protocol-errors.html b/third_party/WebKit/LayoutTests/inspector/report-protocol-errors.html
index 5a2ffec..fd3bdff 100644
--- a/third_party/WebKit/LayoutTests/inspector/report-protocol-errors.html
+++ b/third_party/WebKit/LayoutTests/inspector/report-protocol-errors.html
@@ -29,7 +29,7 @@
 
     var numberOfReports = 0;
 
-    InspectorBackendClass.reportProtocolError = function(error, message)
+    Protocol.InspectorBackend.reportProtocolError = function(error, message)
     {
         if (numberOfReports < messages.length) {
             InspectorTest.addObject(message);
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index cb0c1fc2..970f656 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -631,6 +631,9 @@
     if (layer->m_needsDescendantDependentFlagsUpdate)
       break;
     layer->m_needsDescendantDependentFlagsUpdate = true;
+
+    if (RuntimeEnabledFeatures::slimmingPaintInvalidationEnabled())
+      layer->layoutObject()->setNeedsPaintPropertyUpdate();
   }
 }
 
@@ -1012,11 +1015,6 @@
   // dependent flags udpate. Reduce call sites after SPv2 launch allows
   /// removal of CompositingInputsUpdater.
   markAncestorChainForDescendantDependentFlagsUpdate();
-  if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) {
-    // This update is needed in order to re-compute sticky position constraints,
-    // not for any other reason.
-    layoutObject()->setNeedsPaintPropertyUpdate();
-  }
 }
 
 void PaintLayer::setNeedsCompositingInputsUpdateInternal() {
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index cc8e633..49a500d 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -350,6 +350,7 @@
   "front_end/profiler/ProfileView.js",
   "front_end/profiler/TargetsComboBoxController.js",
   "front_end/profiler/TopDownProfileDataGrid.js",
+  "front_end/protocol/InspectorBackend.js",
   "front_end/resources/ApplicationCacheItemsView.js",
   "front_end/resources/appManifestView.css",
   "front_end/resources/AppManifestView.js",
@@ -402,7 +403,6 @@
   "front_end/sdk/DOMModel.js",
   "front_end/sdk/HAREntry.js",
   "front_end/sdk/HeapProfilerModel.js",
-  "front_end/sdk/InspectorBackend.js",
   "front_end/sdk/LayerTreeBase.js",
   "front_end/sdk/module.json",
   "front_end/sdk/NetworkLog.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/Tests.js b/third_party/WebKit/Source/devtools/front_end/Tests.js
index 5e94b31..1ea0f3e 100644
--- a/third_party/WebKit/Source/devtools/front_end/Tests.js
+++ b/third_party/WebKit/Source/devtools/front_end/Tests.js
@@ -567,7 +567,7 @@
     this._waitForTargets(2, callback.bind(this));
 
     function callback() {
-      InspectorBackendClass.deprecatedRunAfterPendingDispatches(this.releaseControl.bind(this));
+      Protocol.InspectorBackend.deprecatedRunAfterPendingDispatches(this.releaseControl.bind(this));
     }
   };
 
diff --git a/third_party/WebKit/Source/devtools/front_end/externs.js b/third_party/WebKit/Source/devtools/front_end/externs.js
index eba7edbfb..eb14878 100644
--- a/third_party/WebKit/Source/devtools/front_end/externs.js
+++ b/third_party/WebKit/Source/devtools/front_end/externs.js
@@ -828,6 +828,7 @@
 var Persistence = {};
 var Platform = {};
 var Profiler = {};
+var Protocol = {};
 var Resources = {};
 var Sass = {};
 var Screencast = {};
diff --git a/third_party/WebKit/Source/devtools/front_end/inspector.json b/third_party/WebKit/Source/devtools/front_end/inspector.json
index 55f66e4..978168d 100644
--- a/third_party/WebKit/Source/devtools/front_end/inspector.json
+++ b/third_party/WebKit/Source/devtools/front_end/inspector.json
@@ -5,6 +5,7 @@
         { "name": "components", "type": "autostart"},
         { "name": "ui", "type": "autostart" },
         { "name": "sdk", "type": "autostart" },
+        { "name": "protocol", "type": "autostart" },
         { "name": "host", "type": "autostart" },
         { "name": "common", "type": "autostart" },
         { "name": "emulation", "type": "autostart" },
diff --git a/third_party/WebKit/Source/devtools/front_end/layers/LayerTreeModel.js b/third_party/WebKit/Source/devtools/front_end/layers/LayerTreeModel.js
index 09505922..e79eeab8 100644
--- a/third_party/WebKit/Source/devtools/front_end/layers/LayerTreeModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/layers/LayerTreeModel.js
@@ -414,7 +414,7 @@
       return;
     }
 
-    var wrappedCallback = InspectorBackend.wrapClientCallback(
+    var wrappedCallback = Protocol.inspectorBackend.wrapClientCallback(
         callback, 'Protocol.LayerTree.reasonsForCompositingLayer(): ', undefined, []);
     this._target.layerTreeAgent().compositingReasons(this.id(), wrappedCallback);
   }
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js
index 23660a1..5f50eb2b 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -844,7 +844,7 @@
  */
 Main.sendOverProtocol = function(method, params) {
   return new Promise((resolve, reject) => {
-    InspectorBackendClass.sendRawMessageForTesting(method, params, (err, result) => {
+    Protocol.InspectorBackend.sendRawMessageForTesting(method, params, (err, result) => {
       if (err)
         return reject(err);
       return resolve(result);
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/InspectorBackend.js b/third_party/WebKit/Source/devtools/front_end/protocol/InspectorBackend.js
similarity index 83%
rename from third_party/WebKit/Source/devtools/front_end/sdk/InspectorBackend.js
rename to third_party/WebKit/Source/devtools/front_end/protocol/InspectorBackend.js
index d9bef3c..3c01fe9 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/InspectorBackend.js
+++ b/third_party/WebKit/Source/devtools/front_end/protocol/InspectorBackend.js
@@ -28,15 +28,13 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-var Protocol = {};
-
 /** @typedef {string} */
 Protocol.Error;
 
 /**
  * @unrestricted
  */
-var InspectorBackendClass = class {
+Protocol.InspectorBackend = class {
   constructor() {
     this._agentPrototypes = {};
     this._dispatcherPrototypes = {};
@@ -89,11 +87,11 @@
 
   /**
    * @param {string} domain
-   * @return {!InspectorBackendClass._AgentPrototype}
+   * @return {!Protocol.InspectorBackend._AgentPrototype}
    */
   _agentPrototype(domain) {
     if (!this._agentPrototypes[domain]) {
-      this._agentPrototypes[domain] = new InspectorBackendClass._AgentPrototype(domain);
+      this._agentPrototypes[domain] = new Protocol.InspectorBackend._AgentPrototype(domain);
       this._addAgentGetterMethodToProtocolTargetPrototype(domain);
     }
 
@@ -102,11 +100,11 @@
 
   /**
    * @param {string} domain
-   * @return {!InspectorBackendClass._DispatcherPrototype}
+   * @return {!Protocol.InspectorBackend._DispatcherPrototype}
    */
   _dispatcherPrototype(domain) {
     if (!this._dispatcherPrototypes[domain])
-      this._dispatcherPrototypes[domain] = new InspectorBackendClass._DispatcherPrototype();
+      this._dispatcherPrototypes[domain] = new Protocol.InspectorBackend._DispatcherPrototype();
     return this._dispatcherPrototypes[domain];
   }
 
@@ -175,18 +173,18 @@
   }
 };
 
-InspectorBackendClass._ConnectionClosedErrorCode = -32000;
-InspectorBackendClass.DevToolsStubErrorCode = -32015;
+Protocol.InspectorBackend._ConnectionClosedErrorCode = -32000;
+Protocol.InspectorBackend.DevToolsStubErrorCode = -32015;
 
 
-var InspectorBackend = new InspectorBackendClass();
+Protocol.inspectorBackend = new Protocol.InspectorBackend();
 
 /**
  * @interface
  */
-InspectorBackendClass.Connection = function() {};
+Protocol.InspectorBackend.Connection = function() {};
 
-InspectorBackendClass.Connection.prototype = {
+Protocol.InspectorBackend.Connection.prototype = {
   /**
    * @param {string} message
    */
@@ -204,19 +202,19 @@
  *   onDisconnect: function(string)
  * }}
  */
-InspectorBackendClass.Connection.Params;
+Protocol.InspectorBackend.Connection.Params;
 
 /**
- * @typedef {function(!InspectorBackendClass.Connection.Params):!InspectorBackendClass.Connection}
+ * @typedef {function(!Protocol.InspectorBackend.Connection.Params):!Protocol.InspectorBackend.Connection}
  */
-InspectorBackendClass.Connection.Factory;
+Protocol.InspectorBackend.Connection.Factory;
 
 /**
  * @unrestricted
  */
 Protocol.TargetBase = class {
   /**
-   *  @param {!InspectorBackendClass.Connection.Factory} connectionFactory
+   *  @param {!Protocol.InspectorBackend.Connection.Factory} connectionFactory
    */
   constructor(connectionFactory) {
     this._connection =
@@ -226,16 +224,18 @@
     this._agents = {};
     this._dispatchers = {};
     this._callbacks = {};
-    this._initialize(InspectorBackend._agentPrototypes, InspectorBackend._dispatcherPrototypes);
-    if (!InspectorBackendClass.deprecatedRunAfterPendingDispatches)
-      InspectorBackendClass.deprecatedRunAfterPendingDispatches = this._deprecatedRunAfterPendingDispatches.bind(this);
-    if (!InspectorBackendClass.sendRawMessageForTesting)
-      InspectorBackendClass.sendRawMessageForTesting = this._sendRawMessageForTesting.bind(this);
+    this._initialize(Protocol.inspectorBackend._agentPrototypes, Protocol.inspectorBackend._dispatcherPrototypes);
+    if (!Protocol.InspectorBackend.deprecatedRunAfterPendingDispatches) {
+      Protocol.InspectorBackend.deprecatedRunAfterPendingDispatches =
+          this._deprecatedRunAfterPendingDispatches.bind(this);
+    }
+    if (!Protocol.InspectorBackend.sendRawMessageForTesting)
+      Protocol.InspectorBackend.sendRawMessageForTesting = this._sendRawMessageForTesting.bind(this);
   }
 
   /**
-   * @param {!Object.<string, !InspectorBackendClass._AgentPrototype>} agentPrototypes
-   * @param {!Object.<string, !InspectorBackendClass._DispatcherPrototype>} dispatcherPrototypes
+   * @param {!Object.<string, !Protocol.InspectorBackend._AgentPrototype>} agentPrototypes
+   * @param {!Object.<string, !Protocol.InspectorBackend._DispatcherPrototype>} dispatcherPrototypes
    */
   _initialize(agentPrototypes, dispatcherPrototypes) {
     for (var domain in agentPrototypes) {
@@ -256,7 +256,7 @@
 
   /**
    * @param {string} domain
-   * @return {!InspectorBackendClass._AgentPrototype}
+   * @return {!Protocol.InspectorBackend._AgentPrototype}
    */
   _agent(domain) {
     return this._agents[domain];
@@ -285,7 +285,7 @@
     var wrappedCallback = this._wrap(callback, domain, method);
     var message = JSON.stringify(messageObject);
 
-    if (InspectorBackendClass.Options.dumpInspectorProtocolMessages)
+    if (Protocol.InspectorBackend.Options.dumpInspectorProtocolMessages)
       this._dumpProtocolMessage('frontend: ' + message);
 
     this._connection.sendMessage(message);
@@ -305,7 +305,7 @@
 
     callback.methodName = method;
     callback.domain = domain;
-    if (InspectorBackendClass.Options.dumpInspectorTimeStats)
+    if (Protocol.InspectorBackend.Options.dumpInspectorTimeStats)
       callback.sendRequestTime = Date.now();
 
     return callback;
@@ -325,7 +325,7 @@
    * @param {!Object|string} message
    */
   _onMessage(message) {
-    if (InspectorBackendClass.Options.dumpInspectorProtocolMessages)
+    if (Protocol.InspectorBackend.Options.dumpInspectorProtocolMessages)
       this._dumpProtocolMessage('backend: ' + ((typeof message === 'string') ? message : JSON.stringify(message)));
 
     var messageObject = /** @type {!Object} */ ((typeof message === 'string') ? JSON.parse(message) : message);
@@ -333,33 +333,33 @@
     if ('id' in messageObject) {  // just a response for some request
       var callback = this._callbacks[messageObject.id];
       if (!callback) {
-        InspectorBackendClass.reportProtocolError('Protocol Error: the message with wrong id', messageObject);
+        Protocol.InspectorBackend.reportProtocolError('Protocol Error: the message with wrong id', messageObject);
         return;
       }
 
       var timingLabel = 'time-stats: ' + callback.methodName;
-      if (InspectorBackendClass.Options.dumpInspectorTimeStats)
+      if (Protocol.InspectorBackend.Options.dumpInspectorTimeStats)
         console.time(timingLabel);
 
       this._agent(callback.domain).dispatchResponse(messageObject, callback.methodName, callback);
       --this._pendingResponsesCount;
       delete this._callbacks[messageObject.id];
 
-      if (InspectorBackendClass.Options.dumpInspectorTimeStats)
+      if (Protocol.InspectorBackend.Options.dumpInspectorTimeStats)
         console.timeEnd(timingLabel);
 
       if (this._scripts && !this._pendingResponsesCount)
         this._deprecatedRunAfterPendingDispatches();
     } else {
       if (!('method' in messageObject)) {
-        InspectorBackendClass.reportProtocolError('Protocol Error: the message without method', messageObject);
+        Protocol.InspectorBackend.reportProtocolError('Protocol Error: the message without method', messageObject);
         return;
       }
 
       var method = messageObject.method.split('.');
       var domainName = method[0];
       if (!(domainName in this._dispatchers)) {
-        InspectorBackendClass.reportProtocolError(
+        Protocol.InspectorBackend.reportProtocolError(
             'Protocol Error: the message ' + messageObject.method + ' is for non-existing domain \'' + domainName +
                 '\'',
             messageObject);
@@ -457,12 +457,12 @@
   _dispatchConnectionErrorResponse(domain, methodName, callback) {
     var error = {
       message: 'Connection is closed, can\'t dispatch pending ' + methodName,
-      code: InspectorBackendClass._ConnectionClosedErrorCode,
+      code: Protocol.InspectorBackend._ConnectionClosedErrorCode,
       data: null
     };
     var messageObject = {error: error};
     setTimeout(
-        InspectorBackendClass._AgentPrototype.prototype.dispatchResponse.bind(
+        Protocol.InspectorBackend._AgentPrototype.prototype.dispatchResponse.bind(
             this._agent(domain), messageObject, methodName, callback),
         0);
   }
@@ -471,7 +471,7 @@
 /**
  * @unrestricted
  */
-InspectorBackendClass._AgentPrototype = class {
+Protocol.InspectorBackend._AgentPrototype = class {
   /**
    * @param {string} domain
    */
@@ -499,12 +499,12 @@
 
     /**
      * @param {...*} vararg
-     * @this {InspectorBackendClass._AgentPrototype}
+     * @this {Protocol.InspectorBackend._AgentPrototype}
      * @return {!Promise.<*>}
      */
     function sendMessagePromise(vararg) {
       var params = Array.prototype.slice.call(arguments);
-      return InspectorBackendClass._AgentPrototype.prototype._sendMessageToBackendPromise.call(
+      return Protocol.InspectorBackend._AgentPrototype.prototype._sendMessageToBackendPromise.call(
           this, domainAndMethod, signature, params);
     }
 
@@ -512,11 +512,11 @@
 
     /**
      * @param {...*} vararg
-     * @this {InspectorBackendClass._AgentPrototype}
+     * @this {Protocol.InspectorBackend._AgentPrototype}
      */
     function invoke(vararg) {
       var params = [domainAndMethod].concat(Array.prototype.slice.call(arguments));
-      InspectorBackendClass._AgentPrototype.prototype._invoke.apply(this, params);
+      Protocol.InspectorBackend._AgentPrototype.prototype._invoke.apply(this, params);
     }
 
     this['invoke_' + methodName] = invoke;
@@ -605,7 +605,7 @@
     /**
      * @param {function(?)} resolve
      * @param {function(!Error)} reject
-     * @this {InspectorBackendClass._AgentPrototype}
+     * @this {Protocol.InspectorBackend._AgentPrototype}
      */
     function promiseAction(resolve, reject) {
       /**
@@ -634,10 +634,10 @@
    * @param {function(*)|function(?Protocol.Error, ?Object)} callback
    */
   dispatchResponse(messageObject, methodName, callback) {
-    if (messageObject.error && messageObject.error.code !== InspectorBackendClass._ConnectionClosedErrorCode &&
-        messageObject.error.code !== InspectorBackendClass.DevToolsStubErrorCode &&
-        !InspectorBackendClass.Options.suppressRequestErrors) {
-      var id = InspectorBackendClass.Options.dumpInspectorProtocolMessages ? ' with id = ' + messageObject.id : '';
+    if (messageObject.error && messageObject.error.code !== Protocol.InspectorBackend._ConnectionClosedErrorCode &&
+        messageObject.error.code !== Protocol.InspectorBackend.DevToolsStubErrorCode &&
+        !Protocol.InspectorBackend.Options.suppressRequestErrors) {
+      var id = Protocol.InspectorBackend.Options.dumpInspectorProtocolMessages ? ' with id = ' + messageObject.id : '';
       console.error('Request ' + methodName + id + ' failed. ' + JSON.stringify(messageObject.error));
     }
 
@@ -660,7 +660,7 @@
 /**
  * @unrestricted
  */
-InspectorBackendClass._DispatcherPrototype = class {
+Protocol.InspectorBackend._DispatcherPrototype = class {
   constructor() {
     this._eventArgs = {};
     this._dispatcher = null;
@@ -690,14 +690,14 @@
       return;
 
     if (!(functionName in this._dispatcher)) {
-      InspectorBackendClass.reportProtocolError(
+      Protocol.InspectorBackend.reportProtocolError(
           'Protocol Error: Attempted to dispatch an unimplemented method \'' + messageObject.method + '\'',
           messageObject);
       return;
     }
 
     if (!this._eventArgs[messageObject.method]) {
-      InspectorBackendClass.reportProtocolError(
+      Protocol.InspectorBackend.reportProtocolError(
           'Protocol Error: Attempted to dispatch an unspecified method \'' + messageObject.method + '\'',
           messageObject);
       return;
@@ -711,17 +711,17 @@
     }
 
     var timingLabel = 'time-stats: ' + messageObject.method;
-    if (InspectorBackendClass.Options.dumpInspectorTimeStats)
+    if (Protocol.InspectorBackend.Options.dumpInspectorTimeStats)
       console.time(timingLabel);
 
     this._dispatcher[functionName].apply(this._dispatcher, params);
 
-    if (InspectorBackendClass.Options.dumpInspectorTimeStats)
+    if (Protocol.InspectorBackend.Options.dumpInspectorTimeStats)
       console.timeEnd(timingLabel);
   }
 };
 
-InspectorBackendClass.Options = {
+Protocol.InspectorBackend.Options = {
   dumpInspectorTimeStats: false,
   dumpInspectorProtocolMessages: false,
   suppressRequestErrors: false
diff --git a/third_party/WebKit/Source/devtools/front_end/protocol/module.json b/third_party/WebKit/Source/devtools/front_end/protocol/module.json
new file mode 100644
index 0000000..6023250
--- /dev/null
+++ b/third_party/WebKit/Source/devtools/front_end/protocol/module.json
@@ -0,0 +1,9 @@
+{
+  "scripts": [
+    "InspectorBackend.js",
+    "../InspectorBackendCommands.js"
+  ],
+  "skip_compilation": [
+    "../InspectorBackendCommands.js"
+  ]
+}
diff --git a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js
index f154fd65..fd1ddb4 100644
--- a/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js
+++ b/third_party/WebKit/Source/devtools/front_end/resources/ApplicationCacheItemsView.js
@@ -252,7 +252,7 @@
 
   _deleteCallback(node) {
     // FIXME: Should we delete a single (selected) resource or all resources?
-    // InspectorBackend.deleteCachedResource(...)
+    // Protocol.inspectorBackend.deleteCachedResource(...)
     // this._update();
   }
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/Connections.js b/third_party/WebKit/Source/devtools/front_end/sdk/Connections.js
index 2b0b7314..06a0cfb 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/Connections.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/Connections.js
@@ -2,12 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 /**
- * @implements {InspectorBackendClass.Connection}
+ * @implements {Protocol.InspectorBackend.Connection}
  * @unrestricted
  */
 SDK.MainConnection = class {
   /**
-   * @param {!InspectorBackendClass.Connection.Params} params
+   * @param {!Protocol.InspectorBackend.Connection.Params} params
    */
   constructor(params) {
     this._onMessage = params.onMessage;
@@ -79,7 +79,7 @@
       }
     }
 
-    InspectorBackendClass.deprecatedRunAfterPendingDispatches(invokeMethod);
+    Protocol.InspectorBackend.deprecatedRunAfterPendingDispatches(invokeMethod);
   }
 
   /**
@@ -104,14 +104,14 @@
 };
 
 /**
- * @implements {InspectorBackendClass.Connection}
+ * @implements {Protocol.InspectorBackend.Connection}
  * @unrestricted
  */
 SDK.WebSocketConnection = class {
   /**
    * @param {string} url
    * @param {function()} onWebSocketDisconnect
-   * @param {!InspectorBackendClass.Connection.Params} params
+   * @param {!Protocol.InspectorBackend.Connection.Params} params
    */
   constructor(url, onWebSocketDisconnect, params) {
     this._socket = new WebSocket(url);
@@ -187,12 +187,12 @@
 };
 
 /**
- * @implements {InspectorBackendClass.Connection}
+ * @implements {Protocol.InspectorBackend.Connection}
  * @unrestricted
  */
 SDK.StubConnection = class {
   /**
-   * @param {!InspectorBackendClass.Connection.Params} params
+   * @param {!Protocol.InspectorBackend.Connection.Params} params
    */
   constructor(params) {
     this._onMessage = params.onMessage;
@@ -214,7 +214,7 @@
     var messageObject = JSON.parse(message);
     var error = {
       message: 'This is a stub connection, can\'t dispatch message.',
-      code: InspectorBackendClass.DevToolsStubErrorCode,
+      code: Protocol.InspectorBackend.DevToolsStubErrorCode,
       data: messageObject
     };
     this._onMessage.call(null, {id: messageObject.id, error: error});
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js b/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js
index b2e478c6..6f07ce2 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/PaintProfiler.js
@@ -100,7 +100,8 @@
    * @param {function(!Array.<!Protocol.LayerTree.PaintProfile>=)} callback
    */
   profile(clipRect, callback) {
-    var wrappedCallback = InspectorBackend.wrapClientCallback(callback, 'Protocol.LayerTree.profileSnapshot(): ');
+    var wrappedCallback =
+        Protocol.inspectorBackend.wrapClientCallback(callback, 'Protocol.LayerTree.profileSnapshot(): ');
     this._target.layerTreeAgent().profileSnapshot(this._id, 5, 1, clipRect || undefined, wrappedCallback);
   }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/SubTargetsManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/SubTargetsManager.js
index ee930ca..3fdf12b 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/SubTargetsManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/SubTargetsManager.js
@@ -172,8 +172,8 @@
 
   /**
    * @param {string} targetId
-   * @param {!InspectorBackendClass.Connection.Params} params
-   * @return {!InspectorBackendClass.Connection}
+   * @param {!Protocol.InspectorBackend.Connection.Params} params
+   * @return {!Protocol.InspectorBackend.Connection}
    */
   _createConnection(targetId, params) {
     var connection = new SDK.SubTargetConnection(this._agent, targetId, params);
@@ -317,14 +317,14 @@
 };
 
 /**
- * @implements {InspectorBackendClass.Connection}
+ * @implements {Protocol.InspectorBackend.Connection}
  * @unrestricted
  */
 SDK.SubTargetConnection = class {
   /**
    * @param {!Protocol.TargetAgent} agent
    * @param {string} targetId
-   * @param {!InspectorBackendClass.Connection.Params} params
+   * @param {!Protocol.InspectorBackend.Connection.Params} params
    */
   constructor(agent, targetId, params) {
     this._agent = agent;
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/Target.js b/third_party/WebKit/Source/devtools/front_end/sdk/Target.js
index 64ddbdda..3d0c173 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/Target.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/Target.js
@@ -12,7 +12,7 @@
    * @param {!SDK.TargetManager} targetManager
    * @param {string} name
    * @param {number} capabilitiesMask
-   * @param {!InspectorBackendClass.Connection.Factory} connectionFactory
+   * @param {!Protocol.InspectorBackend.Connection.Factory} connectionFactory
    * @param {?SDK.Target} parentTarget
    */
   constructor(targetManager, name, capabilitiesMask, connectionFactory, parentTarget) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
index 09497a0d..e170ff5 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/TargetManager.js
@@ -157,7 +157,7 @@
   /**
    * @param {string} name
    * @param {number} capabilitiesMask
-   * @param {!InspectorBackendClass.Connection.Factory} connectionFactory
+   * @param {!Protocol.InspectorBackend.Connection.Factory} connectionFactory
    * @param {?SDK.Target} parentTarget
    * @return {!SDK.Target}
    */
@@ -354,8 +354,8 @@
   }
 
   /**
-   * @param {!InspectorBackendClass.Connection.Params} params
-   * @return {!InspectorBackendClass.Connection}
+   * @param {!Protocol.InspectorBackend.Connection.Params} params
+   * @return {!Protocol.InspectorBackend.Connection}
    */
   _createMainConnection(params) {
     if (Runtime.queryParam('ws')) {
@@ -371,7 +371,7 @@
 
   /**
    * @param {function(string)} onMessage
-   * @return {!Promise<!InspectorBackendClass.Connection>}
+   * @return {!Promise<!Protocol.InspectorBackend.Connection>}
    */
   interceptMainConnection(onMessage) {
     var params = {onMessage: onMessage, onDisconnect: this._connectAndCreateMainTarget.bind(this)};
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/module.json b/third_party/WebKit/Source/devtools/front_end/sdk/module.json
index 4094fb4..f81ef9190 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/module.json
@@ -2,7 +2,8 @@
     "dependencies": [
         "common",
         "host",
-        "platform"
+        "platform",
+        "protocol"
     ],
     "extensions": [
         {
@@ -71,8 +72,6 @@
         }
     ],
     "scripts": [
-        "InspectorBackend.js",
-        "../InspectorBackendCommands.js",
         "Target.js",
         "TargetManager.js",
         "ApplicationCacheModel.js",
@@ -116,7 +115,6 @@
         "../SupportedCSSProperties.js"
     ],
     "skip_compilation": [
-        "../InspectorBackendCommands.js",
         "../SupportedCSSProperties.js"
     ]
 }
diff --git a/third_party/WebKit/Source/devtools/scripts/build/code_generator_frontend.py b/third_party/WebKit/Source/devtools/scripts/build/code_generator_frontend.py
index 873461a..7db33174 100755
--- a/third_party/WebKit/Source/devtools/scripts/build/code_generator_frontend.py
+++ b/third_party/WebKit/Source/devtools/scripts/build/code_generator_frontend.py
@@ -223,7 +223,7 @@
         for member in json_enum["enum"]:
             enum_members.append("%s: \"%s\"" % (fix_camel_case(member), member))
 
-        Generator.backend_js_domain_initializer_list.append("InspectorBackend.registerEnum(\"%s\", {%s});\n" % (
+        Generator.backend_js_domain_initializer_list.append("Protocol.inspectorBackend.registerEnum(\"%s\", {%s});\n" % (
             enum_name, ", ".join(enum_members)))
 
     @staticmethod
@@ -238,7 +238,7 @@
                 parameter_name = parameter["name"]
                 backend_js_event_param_list.append("\"%s\"" % parameter_name)
 
-        Generator.backend_js_domain_initializer_list.append("InspectorBackend.registerEvent(\"%s.%s\", [%s]);\n" % (
+        Generator.backend_js_domain_initializer_list.append("Protocol.inspectorBackend.registerEvent(\"%s.%s\", [%s]);\n" % (
             domain_name, event_name, ", ".join(backend_js_event_param_list)))
 
     @staticmethod
@@ -279,7 +279,7 @@
         else:
             has_error_data_param = "false"
 
-        Generator.backend_js_domain_initializer_list.append("InspectorBackend.registerCommand(\"%s.%s\", [%s], %s, %s);\n" % (domain_name, json_command_name, js_parameters_text, js_reply_list, has_error_data_param))
+        Generator.backend_js_domain_initializer_list.append("Protocol.inspectorBackend.registerCommand(\"%s.%s\", [%s], %s, %s);\n" % (domain_name, json_command_name, js_parameters_text, js_reply_list, has_error_data_param))
 
 Generator.go()
 
diff --git a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
index a33f8dd..e7d9f0fc 100755
--- a/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
+++ b/third_party/WebKit/Source/devtools/scripts/compile_frontend.py
@@ -327,8 +327,7 @@
     command += module_arg(name) + ':'
     filtered_scripts = descriptors.module_compiled_files(name)
     filtered_scripts = [path.join(devtools_frontend_path, name, script) for script in filtered_scripts]
-    # TODO(dgozman): move to separate module
-    if name == 'sdk':
+    if name == 'protocol':
         filtered_scripts.append(protocol_externs_file)
     command += str(len(filtered_scripts))
     first_dependency = True
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
index dc79044..1f8effd 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
@@ -121,9 +121,12 @@
         """
         # `git status -z` is a version of `git status -s`, that's recommended
         # for machine parsing. Lines are terminated with NUL rather than LF.
+        change_lines = self._run_git(['status', '-z']).rstrip('\x00')
+        if not change_lines:
+            return {}  # No changes.
         unstaged_changes = {}
-        change_lines = self._run_git(['status', '-z']).rstrip('\x00').split('\x00')
-        for line in change_lines:
+        for line in change_lines.split('\x00'):
+            assert len(line) > 4, 'Unexpected change line format %s' % line
             if line[1] == ' ':
                 continue  # Already staged for commit.
             path = line[3:]
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py
index 000aa153..c3507e01 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py
@@ -255,7 +255,7 @@
 
     def test_unstaged_files(self):
         scm = self.make_scm()
-        status_lines = [
+        lines = [
             ' M d/modified.txt',
             ' D d/deleted.txt',
             '?? d/untracked.txt',
@@ -263,8 +263,7 @@
             'M  d/modified-staged.txt',
             'A  d/added-staged.txt',
         ]
-        # pylint: disable=protected-access
-        scm._run_git = lambda args: '\x00'.join(status_lines) + '\x00'
+        scm._run_git = lambda _: '\x00'.join(lines) + '\x00'  # pylint: disable=protected-access
         self.assertEqual(
             scm.unstaged_changes(),
             {
@@ -272,3 +271,8 @@
                 'd/deleted.txt': 'D',
                 'd/untracked.txt': '?',
             })
+
+    def test_unstaged_files_with_no_changes(self):
+        scm = self.make_scm()
+        scm._run_git = lambda _: '\x00'  # pylint: disable=protected-access
+        self.assertEqual(scm.unstaged_changes(), {})
diff --git a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
index a268739c..83c6eb22 100644
--- a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
+++ b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
@@ -207,16 +207,34 @@
   return false;
 }
 
-bool IsBlacklistedFunction(const clang::FunctionDecl& decl) {
-  // swap() functions should match the signature of std::swap for ADL tricks.
-  return decl.getName() == "swap";
+bool IsBlacklistedFunctionName(llvm::StringRef name) {
+  // https://crbug.com/672902: Method names with an underscore are typically
+  // mimicked after std library / are typically not originating from Blink.
+  // Do not rewrite such names (like push_back, emplace_back, etc.).
+  if (name.find('_') != llvm::StringRef::npos)
+    return true;
+
+  // https://crbug.com/677166: Have to avoid renaming |hash| -> |Hash| to avoid
+  // colliding with a struct already named |Hash|.
+  return name == "hash";
 }
 
-bool IsBlacklistedMethodName(llvm::StringRef name) {
+bool IsBlacklistedFreeFunctionName(llvm::StringRef name) {
+  // swap() functions should match the signature of std::swap for ADL tricks.
+  return name == "swap";
+}
+
+bool IsBlacklistedInstanceMethodName(llvm::StringRef name) {
   static const char* kBlacklistedNames[] = {
-      "hash",
-      "lock", "unlock", "try_lock",
-      "begin", "end", "rbegin", "rend",
+      // We should avoid renaming the method names listed below, because
+      // 1. They are used in templated code (e.g. in <algorithms>)
+      // 2. They (begin+end) are used in range-based for syntax sugar
+      //    - for (auto x : foo) { ... }  // <- foo.begin() will be called.
+      "begin", "end", "rbegin", "rend", "lock", "unlock", "try_lock",
+
+      // https://crbug.com/672902: Should not rewrite names that mimick methods
+      // from std library.
+      "back", "empty", "erase", "front", "insert",
   };
   for (const auto& b : kBlacklistedNames) {
     if (name == b)
@@ -225,13 +243,27 @@
   return false;
 }
 
+bool IsBlacklistedMethodName(llvm::StringRef name) {
+  return IsBlacklistedFunctionName(name) ||
+         IsBlacklistedInstanceMethodName(name);
+}
+
+bool IsBlacklistedFunction(const clang::FunctionDecl& decl) {
+  clang::StringRef name = decl.getName();
+  return IsBlacklistedFunctionName(name) || IsBlacklistedFreeFunctionName(name);
+}
+
 bool IsBlacklistedMethod(const clang::CXXMethodDecl& decl) {
+  clang::StringRef name = decl.getName();
+  if (IsBlacklistedFunctionName(name))
+    return true;
+
+  // Remaining cases are only applicable to instance methods.
   if (decl.isStatic())
     return false;
 
-  clang::StringRef name = decl.getName();
-  if (IsBlacklistedMethodName(name))
-      return true;
+  if (IsBlacklistedInstanceMethodName(name))
+    return true;
 
   // Subclasses of InspectorAgent will subclass "disable()" from both blink and
   // from gen/, which is problematic, but DevTools folks don't want to rename
diff --git a/tools/clang/rewrite_to_chrome_style/tests/function-templates-expected.cc b/tools/clang/rewrite_to_chrome_style/tests/function-templates-expected.cc
index 8d064a1..402ae44 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/function-templates-expected.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/function-templates-expected.cc
@@ -36,7 +36,7 @@
 };
 
 template <typename To, typename From>
-To Bitwise_cast(From from) {
+To bitwise_cast(From from) {
   static_assert(sizeof(To) == sizeof(From), "msg");
   return reinterpret_cast<To>(from);
 }
@@ -60,5 +60,5 @@
 
 }  // namespace mojo
 
-using WTF::Bitwise_cast;
+using WTF::bitwise_cast;
 using WTF::SafeCast;
diff --git a/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc b/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc
index c632cd5..50b6700 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc
@@ -235,6 +235,48 @@
 
 }  // namespace get_prefix_vs_inheritance
 
+namespace blacklisting_of_method_and_function_names {
+
+class Foo {
+  // Expecting |swap| method to be renamed to |Swap| - we blacklist renaming of
+  // |swap| *function*, because it needs to have the same casing as std::swap,
+  // so that ADL can kick-in and pull it from another namespace depending on the
+  // bargument.  We have a choice to rename or not rename |swap| *methods* - we
+  // chose to rename to be consistent (i.e. we rename |clear| -> |Clear|) and
+  // because Google C++ Styke Guide uses "Swap" in examples.
+  void Swap() {}
+  static void Swap(Foo& x, Foo& y) {}
+
+  // We don't rename |begin|, so that <algorithms> and other templates that
+  // expect |begin|, |end|, etc. continue to work.  This is only necessary
+  // for instance methods - renaming static methods and funcitons is okay.
+  void begin() {}
+  static void Begin(int x) {}
+
+  // https://crbug.com/677166: We blacklist renaming of |hash|, because it
+  // collides with a struct named Hash.  Blacklisting therefore should be broad
+  // and should cover both instance and static methods as well as functions.
+  int hash() const { return 123; }
+  static int hash(const Foo& x) { return x.hash(); }
+
+  // https://crbug.com672902: std-like names should not be rewritten.
+  void emplace_back(int x) {}
+  void insert(int x) {}
+  void push_back(int x) {}
+  int* back() { return nullptr; }
+  int* front() { return nullptr; }
+  void erase() {}
+  bool empty() { return true; }
+};
+
+void Begin(int x) {}
+int hash(int x) {
+  return 123 * x;
+}
+void swap(Foo& x, Foo& y) {}
+
+}  // blacklisting_of_method_and_function_names
+
 }  // namespace blink
 
 namespace WTF {
diff --git a/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc b/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc
index 3dd8b73aa..b75233b 100644
--- a/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc
+++ b/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc
@@ -239,6 +239,48 @@
 
 }  // namespace get_prefix_vs_inheritance
 
+namespace blacklisting_of_method_and_function_names {
+
+class Foo {
+  // Expecting |swap| method to be renamed to |Swap| - we blacklist renaming of
+  // |swap| *function*, because it needs to have the same casing as std::swap,
+  // so that ADL can kick-in and pull it from another namespace depending on the
+  // bargument.  We have a choice to rename or not rename |swap| *methods* - we
+  // chose to rename to be consistent (i.e. we rename |clear| -> |Clear|) and
+  // because Google C++ Styke Guide uses "Swap" in examples.
+  void swap() {}
+  static void swap(Foo& x, Foo& y) {}
+
+  // We don't rename |begin|, so that <algorithms> and other templates that
+  // expect |begin|, |end|, etc. continue to work.  This is only necessary
+  // for instance methods - renaming static methods and funcitons is okay.
+  void begin() {}
+  static void begin(int x) {}
+
+  // https://crbug.com/677166: We blacklist renaming of |hash|, because it
+  // collides with a struct named Hash.  Blacklisting therefore should be broad
+  // and should cover both instance and static methods as well as functions.
+  int hash() const { return 123; }
+  static int hash(const Foo& x) { return x.hash(); }
+
+  // https://crbug.com672902: std-like names should not be rewritten.
+  void emplace_back(int x) {}
+  void insert(int x) {}
+  void push_back(int x) {}
+  int* back() { return nullptr; }
+  int* front() { return nullptr; }
+  void erase() {}
+  bool empty() { return true; }
+};
+
+void begin(int x) {}
+int hash(int x) {
+  return 123 * x;
+}
+void swap(Foo& x, Foo& y) {}
+
+}  // blacklisting_of_method_and_function_names
+
 }  // namespace blink
 
 namespace WTF {
diff --git a/tools/clang/scripts/apply_edits.py b/tools/clang/scripts/apply_edits.py
new file mode 100755
index 0000000..7d373a9
--- /dev/null
+++ b/tools/clang/scripts/apply_edits.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+"""Applies edits generated by a clang tool that was run on Chromium code.
+
+Synopsis:
+
+  cat run_tool.out | extract_edits.py | apply_edits.py <build dir> <filters...>
+
+For example - to apply edits only to WTF sources:
+
+  ... | apply_edits.py out/gn third_party/WebKit/Source/wtf
+
+In addition to filters specified on the command line, the tool also skips edits
+that apply to files that are not covered by git.
+"""
+
+import argparse
+import collections
+import functools
+import multiprocessing
+import os
+import os.path
+import subprocess
+import sys
+
+script_dir = os.path.dirname(os.path.realpath(__file__))
+tool_dir = os.path.abspath(os.path.join(script_dir, '../pylib'))
+sys.path.insert(0, tool_dir)
+
+from clang import compile_db
+
+Edit = collections.namedtuple('Edit',
+                              ('edit_type', 'offset', 'length', 'replacement'))
+
+
+def _GetFilesFromGit(paths=None):
+  """Gets the list of files in the git repository.
+
+  Args:
+    paths: Prefix filter for the returned paths. May contain multiple entries.
+  """
+  args = []
+  if sys.platform == 'win32':
+    args.append('git.bat')
+  else:
+    args.append('git')
+  args.append('ls-files')
+  if paths:
+    args.extend(paths)
+  command = subprocess.Popen(args, stdout=subprocess.PIPE)
+  output, _ = command.communicate()
+  return [os.path.realpath(p) for p in output.splitlines()]
+
+
+def _ParseEditsFromStdin(build_directory):
+  """Extracts generated list of edits from the tool's stdout.
+
+  The expected format is documented at the top of this file.
+
+  Args:
+    build_directory: Directory that contains the compile database. Used to
+      normalize the filenames.
+    stdout: The stdout from running the clang tool.
+
+  Returns:
+    A dictionary mapping filenames to the associated edits.
+  """
+  path_to_resolved_path = {}
+  def _ResolvePath(path):
+    if path in path_to_resolved_path:
+      return path_to_resolved_path[path]
+
+    if not os.path.isfile(path):
+      resolved_path = os.path.realpath(os.path.join(build_directory, path))
+    else:
+      resolved_path = path
+
+    if not os.path.isfile(resolved_path):
+      sys.stderr.write('Edit applies to a non-existent file: %s\n' % path)
+      resolved_path = None
+
+    path_to_resolved_path[path] = resolved_path
+    return resolved_path
+
+  edits = collections.defaultdict(list)
+  for line in sys.stdin:
+    line = line.rstrip("\n\r")
+    try:
+      edit_type, path, offset, length, replacement = line.split(':::', 4)
+      replacement = replacement.replace('\0', '\n')
+      path = _ResolvePath(path)
+      if not path: continue
+      edits[path].append(Edit(edit_type, int(offset), int(length), replacement))
+    except ValueError:
+      sys.stderr.write('Unable to parse edit: %s\n' % line)
+  return edits
+
+
+def _ApplyEditsToSingleFile(filename, edits):
+  # Sort the edits and iterate through them in reverse order. Sorting allows
+  # duplicate edits to be quickly skipped, while reversing means that
+  # subsequent edits don't need to have their offsets updated with each edit
+  # applied.
+  edit_count = 0
+  error_count = 0
+  edits.sort()
+  last_edit = None
+  with open(filename, 'rb+') as f:
+    contents = bytearray(f.read())
+    for edit in reversed(edits):
+      if edit == last_edit:
+        continue
+      if (last_edit is not None and edit.edit_type == last_edit.edit_type and
+          edit.offset == last_edit.offset and edit.length == last_edit.length):
+        sys.stderr.write(
+            'Conflicting edit: %s at offset %d, length %d: "%s" != "%s"\n' %
+            (filename, edit.offset, edit.length, edit.replacement,
+             last_edit.replacement))
+        error_count += 1
+        continue
+
+      last_edit = edit
+      contents[edit.offset:edit.offset + edit.length] = edit.replacement
+      if not edit.replacement:
+        _ExtendDeletionIfElementIsInList(contents, edit.offset)
+      edit_count += 1
+    f.seek(0)
+    f.truncate()
+    f.write(contents)
+  return (edit_count, error_count)
+
+
+def _ApplyEdits(edits):
+  """Apply the generated edits.
+
+  Args:
+    edits: A dict mapping filenames to Edit instances that apply to that file.
+  """
+  edit_count = 0
+  error_count = 0
+  done_files = 0
+  for k, v in edits.iteritems():
+    tmp_edit_count, tmp_error_count = _ApplyEditsToSingleFile(k, v)
+    edit_count += tmp_edit_count
+    error_count += tmp_error_count
+    done_files += 1
+    percentage = (float(done_files) / len(edits)) * 100
+    sys.stderr.write('Applied %d edits (%d errors) to %d files [%.2f%%]\r' %
+                     (edit_count, error_count, done_files, percentage))
+
+  sys.stderr.write('\n')
+  return -error_count
+
+
+_WHITESPACE_BYTES = frozenset((ord('\t'), ord('\n'), ord('\r'), ord(' ')))
+
+
+def _ExtendDeletionIfElementIsInList(contents, offset):
+  """Extends the range of a deletion if the deleted element was part of a list.
+
+  This rewriter helper makes it easy for refactoring tools to remove elements
+  from a list. Even if a matcher callback knows that it is removing an element
+  from a list, it may not have enough information to accurately remove the list
+  element; for example, another matcher callback may end up removing an adjacent
+  list element, or all the list elements may end up being removed.
+
+  With this helper, refactoring tools can simply remove the list element and not
+  worry about having to include the comma in the replacement.
+
+  Args:
+    contents: A bytearray with the deletion already applied.
+    offset: The offset in the bytearray where the deleted range used to be.
+  """
+  char_before = char_after = None
+  left_trim_count = 0
+  for byte in reversed(contents[:offset]):
+    left_trim_count += 1
+    if byte in _WHITESPACE_BYTES:
+      continue
+    if byte in (ord(','), ord(':'), ord('('), ord('{')):
+      char_before = chr(byte)
+    break
+
+  right_trim_count = 0
+  for byte in contents[offset:]:
+    right_trim_count += 1
+    if byte in _WHITESPACE_BYTES:
+      continue
+    if byte == ord(','):
+      char_after = chr(byte)
+    break
+
+  if char_before:
+    if char_after:
+      del contents[offset:offset + right_trim_count]
+    elif char_before in (',', ':'):
+      del contents[offset - left_trim_count:offset]
+
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument(
+      'build_directory',
+      help='path to the build dir (dir that edit paths are relative to)')
+  parser.add_argument(
+      'path_filter',
+      nargs='*',
+      help='optional paths to filter what files the tool is run on')
+  args = parser.parse_args()
+
+  filenames = set(_GetFilesFromGit(args.path_filter))
+  edits = _ParseEditsFromStdin(args.build_directory)
+  return _ApplyEdits(
+      {k: v for k, v in edits.iteritems()
+            if os.path.realpath(k) in filenames})
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/clang/scripts/extract_edits.py b/tools/clang/scripts/extract_edits.py
new file mode 100755
index 0000000..b0df9c3
--- /dev/null
+++ b/tools/clang/scripts/extract_edits.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python
+# Copyright (c) 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.
+"""Script to extract edits from clang tool output.
+
+If a clang tool emits edits, then the edits should look like this:
+    ...
+    ==== BEGIN EDITS ====
+    <edit1>
+    <edit2>
+    ...
+    ==== END EDITS ====
+    ...
+
+extract_edits.py takes input that is concatenated from multiple tool invocations
+and extract just the edits.  In other words, given the following input:
+    ...
+    ==== BEGIN EDITS ====
+    <edit1>
+    <edit2>
+    ==== END EDITS ====
+    ...
+    ==== BEGIN EDITS ====
+    <yet another edit1>
+    <yet another edit2>
+    ==== END EDITS ====
+    ...
+extract_edits.py would emit the following output:
+    <edit1>
+    <edit2>
+    <yet another edit1>
+    <yet another edit2>
+
+This python script is mainly needed on Windows.
+On unix this script can be replaced with running sed as follows:
+
+    $ cat run_tool.debug.out \
+        | sed '/^==== BEGIN EDITS ====$/,/^==== END EDITS ====$/{//!b};d'
+        | sort | uniq
+"""
+
+
+import sys
+
+
+def main():
+  unique_lines = set()
+  inside_marker_lines = False
+  for line in sys.stdin:
+    line = line.rstrip("\n\r")
+    if line == '==== BEGIN EDITS ====':
+      inside_marker_lines = True
+      continue
+    if line == '==== END EDITS ====':
+      inside_marker_lines = False
+      continue
+    if inside_marker_lines and line not in unique_lines:
+      unique_lines.add(line)
+      print line
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main())
diff --git a/tools/clang/scripts/run_tool.py b/tools/clang/scripts/run_tool.py
index 42b085e..c3482df0 100755
--- a/tools/clang/scripts/run_tool.py
+++ b/tools/clang/scripts/run_tool.py
@@ -4,41 +4,50 @@
 # found in the LICENSE file.
 """Wrapper script to help run clang tools across Chromium code.
 
-How to use this tool:
-If you want to run the tool across all Chromium code:
+How to use run_tool.py:
+If you want to run a clang tool across all Chromium code:
 run_tool.py <tool> <path/to/compiledb>
 
-If you want to include all files mentioned in the compilation database:
+If you want to include all files mentioned in the compilation database
+(this will also include generated files, unlike the previous command):
 run_tool.py <tool> <path/to/compiledb> --all
 
-If you only want to run the tool across just chrome/browser and content/browser:
+If you want to run the clang tool across only chrome/browser and
+content/browser:
 run_tool.py <tool> <path/to/compiledb> chrome/browser content/browser
 
-Please see https://chromium.googlesource.com/chromium/src/+/master/docs/clang_tool_refactoring.md for more
-information, which documents the entire automated refactoring flow in Chromium.
+Please see docs/clang_tool_refactoring.md for more information, which documents
+the entire automated refactoring flow in Chromium.
 
-Why use this tool:
+Why use run_tool.py (instead of running a clang tool directly):
 The clang tool implementation doesn't take advantage of multiple cores, and if
 it fails mysteriously in the middle, all the generated replacements will be
-lost.
+lost. Additionally, if the work is simply sharded across multiple cores by
+running multiple RefactoringTools, problems arise when they attempt to rewrite a
+file at the same time.
 
-Unfortunately, if the work is simply sharded across multiple cores by running
-multiple RefactoringTools, problems arise when they attempt to rewrite a file at
-the same time. To work around that, clang tools that are run using this tool
-should output edits to stdout in the following format:
+run_tool.py will
+1) run multiple instances of clang tool in parallel
+2) gather stdout from clang tool invocations
+3) "atomically" forward #2 to stdout
 
-==== BEGIN EDITS ====
-r:<file path>:<offset>:<length>:<replacement text>
-r:<file path>:<offset>:<length>:<replacement text>
-...etc...
-==== END EDITS ====
+Output of run_tool.py can be piped into extract_edits.py and then into
+apply_edits.py. These tools will extract individual edits and apply them to the
+source files. These tools assume the clang tool emits the edits in the
+following format:
+    ...
+    ==== BEGIN EDITS ====
+    r:::<file path>:::<offset>:::<length>:::<replacement text>
+    r:::<file path>:::<offset>:::<length>:::<replacement text>
+    ...etc...
+    ==== END EDITS ====
+    ...
 
-Any generated edits are applied once the clang tool has finished running
-across Chromium, regardless of whether some instances failed or not.
+extract_edits.py extracts only lines between BEGIN/END EDITS markers
+apply_edits.py reads edit lines from stdin and applies the edits
 """
 
 import argparse
-import collections
 import functools
 import multiprocessing
 import os
@@ -52,9 +61,6 @@
 
 from clang import compile_db
 
-Edit = collections.namedtuple('Edit',
-                              ('edit_type', 'offset', 'length', 'replacement'))
-
 
 def _GetFilesFromGit(paths=None):
   """Gets the list of files in the git repository.
@@ -85,68 +91,38 @@
           for entry in compile_db.Read(build_directory)]
 
 
-def _ExtractEditsFromStdout(build_directory, stdout):
-  """Extracts generated list of edits from the tool's stdout.
-
-  The expected format is documented at the top of this file.
-
-  Args:
-    build_directory: Directory that contains the compile database. Used to
-      normalize the filenames.
-    stdout: The stdout from running the clang tool.
-
-  Returns:
-    A dictionary mapping filenames to the associated edits.
-  """
-  lines = stdout.splitlines()
-  start_index = lines.index('==== BEGIN EDITS ====')
-  end_index = lines.index('==== END EDITS ====')
-  edits = collections.defaultdict(list)
-  for line in lines[start_index + 1:end_index]:
-    try:
-      edit_type, path, offset, length, replacement = line.split(':::', 4)
-      replacement = replacement.replace('\0', '\n')
-      # Normalize the file path emitted by the clang tool.
-      path = os.path.realpath(os.path.join(build_directory, path))
-      edits[path].append(Edit(edit_type, int(offset), int(length), replacement))
-    except ValueError:
-      print 'Unable to parse edit: %s' % line
-  return edits
-
-
 def _ExecuteTool(toolname, tool_args, build_directory, filename):
-  """Executes the tool.
+  """Executes the clang tool.
 
   This is defined outside the class so it can be pickled for the multiprocessing
   module.
 
   Args:
-    toolname: Path to the tool to execute.
-    tool_args: Arguments to be passed to the tool. Can be None.
+    toolname: Name of the clang tool to execute.
+    tool_args: Arguments to be passed to the clang tool. Can be None.
     build_directory: Directory that contains the compile database.
-    filename: The file to run the tool over.
+    filename: The file to run the clang tool over.
 
   Returns:
     A dictionary that must contain the key "status" and a boolean value
     associated with it.
 
-    If status is True, then the generated edits are stored with the key "edits"
-    in the dictionary.
+    If status is True, then the generated output is stored with the key
+    "stdout_text" in the dictionary.
 
     Otherwise, the filename and the output from stderr are associated with the
-    keys "filename" and "stderr" respectively.
+    keys "filename" and "stderr_text" respectively.
   """
   args = [toolname, '-p', build_directory, filename]
   if (tool_args):
     args.extend(tool_args)
   command = subprocess.Popen(
       args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-  stdout, stderr = command.communicate()
+  stdout_text, stderr_text = command.communicate()
   if command.returncode != 0:
-    return {'status': False, 'filename': filename, 'stderr': stderr}
+    return {'status': False, 'filename': filename, 'stderr_text': stderr_text}
   else:
-    return {'status': True,
-            'edits': _ExtractEditsFromStdout(build_directory, stdout)}
+    return {'status': True, 'filename': filename, 'stdout_text': stdout_text}
 
 
 class _CompilerDispatcher(object):
@@ -167,12 +143,6 @@
     self.__filenames = filenames
     self.__success_count = 0
     self.__failed_count = 0
-    self.__edit_count = 0
-    self.__edits = collections.defaultdict(list)
-
-  @property
-  def edits(self):
-    return self.__edits
 
   @property
   def failed_count(self):
@@ -187,8 +157,7 @@
                           self.__filenames)
     for result in result_iterator:
       self.__ProcessResult(result)
-    sys.stdout.write('\n')
-    sys.stdout.flush()
+    sys.stderr.write('\n')
 
   def __ProcessResult(self, result):
     """Handles result processing.
@@ -198,95 +167,17 @@
     """
     if result['status']:
       self.__success_count += 1
-      for k, v in result['edits'].iteritems():
-        self.__edits[k].extend(v)
-        self.__edit_count += len(v)
+      sys.stdout.write(result['stdout_text'])
     else:
       self.__failed_count += 1
-      sys.stdout.write('\nFailed to process %s\n' % result['filename'])
-      sys.stdout.write(result['stderr'])
-      sys.stdout.write('\n')
-    percentage = (float(self.__success_count + self.__failed_count) /
-                  len(self.__filenames)) * 100
-    sys.stdout.write('Succeeded: %d, Failed: %d, Edits: %d [%.2f%%]\r' %
-                     (self.__success_count, self.__failed_count,
-                      self.__edit_count, percentage))
-    sys.stdout.flush()
-
-
-def _ApplyEdits(edits):
-  """Apply the generated edits.
-
-  Args:
-    edits: A dict mapping filenames to Edit instances that apply to that file.
-  """
-  edit_count = 0
-  for k, v in edits.iteritems():
-    # Sort the edits and iterate through them in reverse order. Sorting allows
-    # duplicate edits to be quickly skipped, while reversing means that
-    # subsequent edits don't need to have their offsets updated with each edit
-    # applied.
-    v.sort()
-    last_edit = None
-    with open(k, 'rb+') as f:
-      contents = bytearray(f.read())
-      for edit in reversed(v):
-        if edit == last_edit:
-          continue
-        last_edit = edit
-        contents[edit.offset:edit.offset + edit.length] = edit.replacement
-        if not edit.replacement:
-          _ExtendDeletionIfElementIsInList(contents, edit.offset)
-        edit_count += 1
-      f.seek(0)
-      f.truncate()
-      f.write(contents)
-  print 'Applied %d edits to %d files' % (edit_count, len(edits))
-
-
-_WHITESPACE_BYTES = frozenset((ord('\t'), ord('\n'), ord('\r'), ord(' ')))
-
-
-def _ExtendDeletionIfElementIsInList(contents, offset):
-  """Extends the range of a deletion if the deleted element was part of a list.
-
-  This rewriter helper makes it easy for refactoring tools to remove elements
-  from a list. Even if a matcher callback knows that it is removing an element
-  from a list, it may not have enough information to accurately remove the list
-  element; for example, another matcher callback may end up removing an adjacent
-  list element, or all the list elements may end up being removed.
-
-  With this helper, refactoring tools can simply remove the list element and not
-  worry about having to include the comma in the replacement.
-
-  Args:
-    contents: A bytearray with the deletion already applied.
-    offset: The offset in the bytearray where the deleted range used to be.
-  """
-  char_before = char_after = None
-  left_trim_count = 0
-  for byte in reversed(contents[:offset]):
-    left_trim_count += 1
-    if byte in _WHITESPACE_BYTES:
-      continue
-    if byte in (ord(','), ord(':'), ord('('), ord('{')):
-      char_before = chr(byte)
-    break
-
-  right_trim_count = 0
-  for byte in contents[offset:]:
-    right_trim_count += 1
-    if byte in _WHITESPACE_BYTES:
-      continue
-    if byte == ord(','):
-      char_after = chr(byte)
-    break
-
-  if char_before:
-    if char_after:
-      del contents[offset:offset + right_trim_count]
-    elif char_before in (',', ':'):
-      del contents[offset - left_trim_count:offset]
+      sys.stderr.write('\nFailed to process %s\n' % result['filename'])
+      sys.stderr.write(result['stderr_text'])
+      sys.stderr.write('\n')
+    done_count = self.__success_count + self.__failed_count
+    percentage = (float(done_count) / len(self.__filenames)) * 100
+    sys.stderr.write(
+        'Processed %d files with %s tool (%d failures) [%.2f%%]\r' %
+        (done_count, self.__toolname, self.__failed_count, percentage))
 
 
 def main():
@@ -319,25 +210,20 @@
   if args.generate_compdb:
     compile_db.GenerateWithNinja(args.compile_database)
 
-  filenames = set(_GetFilesFromGit(args.path_filter))
   if args.all:
     source_filenames = set(_GetFilesFromCompileDB(args.compile_database))
   else:
+    git_filenames = set(_GetFilesFromGit(args.path_filter))
     # Filter out files that aren't C/C++/Obj-C/Obj-C++.
     extensions = frozenset(('.c', '.cc', '.cpp', '.m', '.mm'))
     source_filenames = [f
-                        for f in filenames
+                        for f in git_filenames
                         if os.path.splitext(f)[1] in extensions]
+
   dispatcher = _CompilerDispatcher(args.tool, args.tool_args,
                                    args.compile_database,
                                    source_filenames)
   dispatcher.Run()
-  # Filter out edits to files that aren't in the git repository, since it's not
-  # useful to modify files that aren't under source control--typically, these
-  # are generated files or files in a git submodule that's not part of Chromium.
-  _ApplyEdits({k: v
-               for k, v in dispatcher.edits.iteritems()
-               if os.path.realpath(k) in filenames})
   return -dispatcher.failed_count
 
 
diff --git a/tools/clang/scripts/test_tool.py b/tools/clang/scripts/test_tool.py
index 18031f68..ce15db6 100755
--- a/tools/clang/scripts/test_tool.py
+++ b/tools/clang/scripts/test_tool.py
@@ -42,6 +42,60 @@
   return '%d test%s' % (tests, 's' if tests != 1 else '')
 
 
+def _RunToolAndApplyEdits(tools_clang_scripts_directory,
+                          tool_to_test,
+                          test_directory_for_tool,
+                          actual_files):
+  try:
+    # Stage the test files in the git index. If they aren't staged, then
+    # run_tool.py will skip them when applying replacements.
+    args = ['add']
+    args.extend(actual_files)
+    _RunGit(args)
+
+    # Launch the following pipeline:
+    #     run_tool.py ... | extract_edits.py | apply_edits.py ...
+    args = ['python',
+            os.path.join(tools_clang_scripts_directory, 'run_tool.py'),
+            tool_to_test,
+            test_directory_for_tool]
+    args.extend(actual_files)
+    run_tool = subprocess.Popen(args, stdout=subprocess.PIPE)
+
+    args = ['python',
+            os.path.join(tools_clang_scripts_directory, 'extract_edits.py')]
+    extract_edits = subprocess.Popen(args, stdin=run_tool.stdout,
+                                     stdout=subprocess.PIPE)
+
+    args = ['python',
+            os.path.join(tools_clang_scripts_directory, 'apply_edits.py'),
+            test_directory_for_tool]
+    apply_edits = subprocess.Popen(args, stdin=extract_edits.stdout,
+                                   stdout=subprocess.PIPE)
+
+    # Wait for the pipeline to finish running + check exit codes.
+    stdout, _ = apply_edits.communicate()
+    for process in [run_tool, extract_edits, apply_edits]:
+      process.wait()
+      if process.returncode != 0:
+        print "Failure while running the tool."
+        return process.returncode
+
+    # Reformat the resulting edits via: git cl format.
+    args = ['cl', 'format']
+    args.extend(actual_files)
+    _RunGit(args)
+
+    return 0
+
+  finally:
+    # No matter what, unstage the git changes we made earlier to avoid polluting
+    # the index.
+    args = ['reset', '--quiet', 'HEAD']
+    args.extend(actual_files)
+    _RunGit(args)
+
+
 def main(argv):
   if len(argv) < 1:
     print 'Usage: test_tool.py <clang tool>'
@@ -76,72 +130,52 @@
     print 'Tool "%s" does not have compatible test files.' % tool_to_test
     return 1
 
-  try:
-    # Set up the test environment.
-    for source, actual in zip(source_files, actual_files):
-      shutil.copyfile(source, actual)
-    # Stage the test files in the git index. If they aren't staged, then
-    # run_tools.py will skip them when applying replacements.
-    args = ['add']
-    args.extend(actual_files)
-    _RunGit(args)
-    # Generate a temporary compilation database to run the tool over.
-    with open(compile_database, 'w') as f:
-      f.write(_GenerateCompileCommands(actual_files, include_paths))
+  # Set up the test environment.
+  for source, actual in zip(source_files, actual_files):
+    shutil.copyfile(source, actual)
+  # Generate a temporary compilation database to run the tool over.
+  with open(compile_database, 'w') as f:
+    f.write(_GenerateCompileCommands(actual_files, include_paths))
 
-    args = ['python',
-            os.path.join(tools_clang_scripts_directory, 'run_tool.py'),
-            tool_to_test,
-            test_directory_for_tool]
-    args.extend(actual_files)
-    run_tool = subprocess.Popen(args, stdout=subprocess.PIPE)
-    stdout, _ = run_tool.communicate()
-    if run_tool.returncode != 0:
-      print 'run_tool failed:\n%s' % stdout
-      return 1
+  # Run the tool.
+  exitcode = _RunToolAndApplyEdits(tools_clang_scripts_directory, tool_to_test,
+                                   test_directory_for_tool, actual_files)
+  if (exitcode != 0):
+    return exitcode
 
-    args = ['cl', 'format']
-    args.extend(actual_files)
-    _RunGit(args)
+  # Compare actual-vs-expected results.
+  passed = 0
+  failed = 0
+  for expected, actual in zip(expected_files, actual_files):
+    print '[ RUN      ] %s' % os.path.relpath(actual)
+    expected_output = actual_output = None
+    with open(expected, 'r') as f:
+      expected_output = f.readlines()
+    with open(actual, 'r') as f:
+      actual_output = f.readlines()
+    if actual_output != expected_output:
+      failed += 1
+      for line in difflib.unified_diff(expected_output, actual_output,
+                                       fromfile=os.path.relpath(expected),
+                                       tofile=os.path.relpath(actual)):
+        sys.stdout.write(line)
+      print '[  FAILED  ] %s' % os.path.relpath(actual)
+      # Don't clean up the file on failure, so the results can be referenced
+      # more easily.
+      continue
+    print '[       OK ] %s' % os.path.relpath(actual)
+    passed += 1
+    os.remove(actual)
 
-    passed = 0
-    failed = 0
-    for expected, actual in zip(expected_files, actual_files):
-      print '[ RUN      ] %s' % os.path.relpath(actual)
-      expected_output = actual_output = None
-      with open(expected, 'r') as f:
-        expected_output = f.readlines()
-      with open(actual, 'r') as f:
-        actual_output = f.readlines()
-      if actual_output != expected_output:
-        failed += 1
-        for line in difflib.unified_diff(expected_output, actual_output,
-                                         fromfile=os.path.relpath(expected),
-                                         tofile=os.path.relpath(actual)):
-          sys.stdout.write(line)
-        print '[  FAILED  ] %s' % os.path.relpath(actual)
-        # Don't clean up the file on failure, so the results can be referenced
-        # more easily.
-        continue
-      print '[       OK ] %s' % os.path.relpath(actual)
-      passed += 1
-      os.remove(actual)
+  if failed == 0:
+    os.remove(compile_database)
 
-    if failed == 0:
-      os.remove(compile_database)
-
-    print '[==========] %s ran.' % _NumberOfTestsToString(len(source_files))
-    if passed > 0:
-      print '[  PASSED  ] %s.' % _NumberOfTestsToString(passed)
-    if failed > 0:
-      print '[  FAILED  ] %s.' % _NumberOfTestsToString(failed)
-      return 1
-  finally:
-    # No matter what, unstage the git changes we made earlier to avoid polluting
-    # the index.
-    args = ['reset', '--quiet', 'HEAD']
-    args.extend(actual_files)
-    _RunGit(args)
+  print '[==========] %s ran.' % _NumberOfTestsToString(len(source_files))
+  if passed > 0:
+    print '[  PASSED  ] %s.' % _NumberOfTestsToString(passed)
+  if failed > 0:
+    print '[  FAILED  ] %s.' % _NumberOfTestsToString(failed)
+    return 1
 
 
 if __name__ == '__main__':
diff --git a/tools/clang/translation_unit/TranslationUnitGenerator.cpp b/tools/clang/translation_unit/TranslationUnitGenerator.cpp
index 4d7524d9..e6be43e50 100644
--- a/tools/clang/translation_unit/TranslationUnitGenerator.cpp
+++ b/tools/clang/translation_unit/TranslationUnitGenerator.cpp
@@ -265,9 +265,5 @@
       clang::tooling::newFrontendActionFactory<CompilationIndexerAction>();
   clang::tooling::ClangTool tool(options.getCompilations(),
                                  options.getSourcePathList());
-  // This clang tool does not actually produce edits, but run_tool.py expects
-  // this. So we just print an empty edit block.
-  llvm::outs() << "==== BEGIN EDITS ====\n";
-  llvm::outs() << "==== END EDITS ====\n";
   return tool.run(frontend_factory.get());
 }
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 56a2c095..984189d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -19886,6 +19886,11 @@
   </summary>
 </histogram>
 
+<histogram name="GPU.ContextMemory" units="MB">
+  <owner>ericrk@chromium.org</owner>
+  <summary>The amount of memory used by a GL Context.</summary>
+</histogram>
+
 <histogram name="GPU.CreateBrowserCompositor" units="microseconds">
   <owner>vmiura@chromium.org</owner>
   <summary>
@@ -48917,6 +48922,12 @@
   <summary>The amount of time that elapsed during CreateProfilePrefs.</summary>
 </histogram>
 
+<histogram name="PrefService.PersistentLogRecallProtobufs"
+    enum="PersistedLogsLogReadStatus">
+  <owner>holte@chromium.org</owner>
+  <summary>The status when loading PersistedLogs from Prefs.</summary>
+</histogram>
+
 <histogram name="PreloadScanner.Counts" units="preloads">
   <obsolete>
     Deprecated 5/25/2016 in favor of PreloadScanner.Counts2
@@ -99130,6 +99141,19 @@
   <int value="11" label="PERMISSION_FLASH"/>
 </enum>
 
+<enum name="PersistedLogsLogReadStatus" type="int">
+  <int value="0" label="RECALL_SUCCESS"/>
+  <int value="1" label="LIST_EMPTY"/>
+  <int value="2" label="LIST_SIZE_MISSING"/>
+  <int value="3" label="LIST_SIZE_TOO_SMALL"/>
+  <int value="4" label="LIST_SIZE_CORRUPTION"/>
+  <int value="5" label="LOG_STRING_CORRUPTION"/>
+  <int value="6" label="CHECKSUM_CORRUPTION"/>
+  <int value="7" label="CHECKSUM_STRING_CORRUPTION"/>
+  <int value="8" label="DECODE_FAIL"/>
+  <int value="9" label="DEPRECATED_XML_PROTO_MISMATCH"/>
+</enum>
+
 <enum name="PersistentHistogramsInitResult" type="int">
   <int value="0" label="Local-Memory Success"/>
   <int value="1" label="Local-Memory Failure"/>
@@ -110404,6 +110428,20 @@
   <affected-histogram name="GoogleSearch.AccessPoint"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="GPU.ContextType" separator=".">
+  <suffix name="WebGL" label="WebGL Context."/>
+  <suffix name="GLES" label="GLES Context."/>
+  <affected-histogram name="GPU.ContextMemory"/>
+</histogram_suffixes>
+
+<histogram_suffixes name="GPU.MemorySamplingTime" separator=".">
+  <suffix name="Periodic" label="Sampled periodically."/>
+  <suffix name="Shutdown" label="Sampled at shutdown."/>
+  <suffix name="Pressure" label="Sampled on CRITICAL memory pressure signal."/>
+  <affected-histogram name="GPU.ContextMemory.GLES"/>
+  <affected-histogram name="GPU.ContextMemory.WebGL"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="GWSChromeJointExperiment">
   <suffix name="Experiment1"
       label="Only page loads that are a result of a navigation from a web
diff --git a/tools/metrics/histograms/pretty_print.py b/tools/metrics/histograms/pretty_print.py
index d6bb862..e18b259 100755
--- a/tools/metrics/histograms/pretty_print.py
+++ b/tools/metrics/histograms/pretty_print.py
@@ -40,6 +40,10 @@
   'kB': 'KB',
   'kilobytes': 'KB',
   'kbits/s': 'kbps',
+  'mb': 'MB',
+  'mB': 'MB',
+  'megabytes': 'MB',
+  'mbits/s': 'mbps',
   'percent': '%',
   'Percent': '%',
   'percentage': '%',
diff --git a/ui/webui/resources/.clang-format b/ui/webui/resources/.clang-format
index 8fd4c4a..2baaa8d 100644
--- a/ui/webui/resources/.clang-format
+++ b/ui/webui/resources/.clang-format
@@ -1,13 +1,8 @@
+# Please keep this file the same as chrome/browser/resources/.clang-format.
 BasedOnStyle: Chromium
 
 # Renaming quotes in <include> and <if> break things.
 # For normal JS code, please prefer ' to ".
 JavaScriptQuotes: Leave
 
-AllowShortBlocksOnASingleLine: false
-AllowShortCaseLabelsOnASingleLine: false
 AllowShortFunctionsOnASingleLine: Empty
-AllowShortIfStatementsOnASingleLine: false
-AllowShortLoopsOnASingleLine: false
-SpacesInContainerLiterals: false
-SpacesInSquareBrackets: false