diff --git a/DEPS b/DEPS
index b62fcb3..39509e7 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,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': 'c7165c239a0068b0b79b1bbe63e2a22bcb53ae38',
+  'skia_revision': 'a634b742320ae1c14ddb296e45569947daced9fc',
   # 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': '55eb1195b010521a1e005f2aad1494cef0c3d1d4',
+  'v8_revision': 'ec7987147a99c0102a282559cd18a4a6b75d8a5c',
   # 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.
@@ -63,7 +63,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': '6c659ab22988716c0f578460a2048663ab93805a',
+  'pdfium_revision': 'd66f9d0b1fb0af57960f9c7163c475968505ee4a',
   # 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.
@@ -95,7 +95,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '5b5774b1223d05518b1d75da409297ebcf93e24a',
+  'catapult_revision': 'e310b666b43f0ac98d4c9c46e0e9df3569ef69aa',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/ash/common/wm/forwarding_layer_delegate.cc b/ash/common/wm/forwarding_layer_delegate.cc
index 55a1204..50d33c4 100644
--- a/ash/common/wm/forwarding_layer_delegate.cc
+++ b/ash/common/wm/forwarding_layer_delegate.cc
@@ -5,7 +5,6 @@
 #include "ash/common/wm/forwarding_layer_delegate.h"
 
 #include "ash/common/wm_window.h"
-#include "base/callback.h"
 #include "ui/compositor/layer.h"
 #include "ui/compositor/layer_owner.h"
 
@@ -36,10 +35,6 @@
   // on cloned layer because the original layer is still on the same display.
 }
 
-base::Closure ForwardingLayerDelegate::PrepareForLayerBoundsChange() {
-  return base::Closure();
-}
-
 void ForwardingLayerDelegate::DidPaintLayer(ui::Layer* layer,
                                             const gfx::Rect& rect) {
   client_layer_->SchedulePaint(rect);
diff --git a/ash/common/wm/forwarding_layer_delegate.h b/ash/common/wm/forwarding_layer_delegate.h
index 446db9c..7c68f18 100644
--- a/ash/common/wm/forwarding_layer_delegate.h
+++ b/ash/common/wm/forwarding_layer_delegate.h
@@ -33,7 +33,6 @@
   void OnPaintLayer(const ui::PaintContext& context) override;
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
   void OnDeviceScaleFactorChanged(float device_scale_factor) override;
-  base::Closure PrepareForLayerBoundsChange() override;
 
   // ui::LayerObserver:
   void DidPaintLayer(ui::Layer* layer, const gfx::Rect& rect) override;
diff --git a/ash/magnifier/partial_magnification_controller.cc b/ash/magnifier/partial_magnification_controller.cc
index d9abb5c..784ed1f5 100644
--- a/ash/magnifier/partial_magnification_controller.cc
+++ b/ash/magnifier/partial_magnification_controller.cc
@@ -129,10 +129,6 @@
     // Redrawing will take care of scale factor change.
   }
 
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
-
   ui::Layer layer_;
   bool is_border_;
   DISALLOW_COPY_AND_ASSIGN(ContentMask);
@@ -201,10 +197,6 @@
 
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
 
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
-
   gfx::Rect magnifier_window_bounds_;
   std::vector<gfx::ShadowValue> magnifier_shadows_;
 
diff --git a/ash/utility/screenshot_controller.cc b/ash/utility/screenshot_controller.cc
index e0c8d43..7411372 100644
--- a/ash/utility/screenshot_controller.cc
+++ b/ash/utility/screenshot_controller.cc
@@ -145,10 +145,6 @@
 
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
 
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
-
   // Mouse cursor may move sub DIP, so paint pseudo cursor instead of
   // using platform cursor so that it's aliend with the region.
   void DrawPseudoCursor(gfx::Canvas* canvas) {
diff --git a/ash/wm/boot_splash_screen_chromeos.cc b/ash/wm/boot_splash_screen_chromeos.cc
index 2e4fd783..7582ae09 100644
--- a/ash/wm/boot_splash_screen_chromeos.cc
+++ b/ash/wm/boot_splash_screen_chromeos.cc
@@ -55,10 +55,6 @@
 
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
 
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
-
  private:
 #if defined(USE_X11)
   aura::WindowTreeHost* host_;  // not owned
diff --git a/ash/wm/drag_window_resizer_unittest.cc b/ash/wm/drag_window_resizer_unittest.cc
index 56ed6a36..e0bca7e 100644
--- a/ash/wm/drag_window_resizer_unittest.cc
+++ b/ash/wm/drag_window_resizer_unittest.cc
@@ -53,9 +53,6 @@
   }
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
 
   int paint_count_ = 0;
 
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc
index 45ee22d..4f3e0c76 100644
--- a/base/metrics/field_trial.cc
+++ b/base/metrics/field_trial.cc
@@ -7,7 +7,10 @@
 #include <algorithm>
 #include <utility>
 
+#include "base/base_switches.h"
 #include "base/build_time.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/logging.h"
 #include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -28,6 +31,14 @@
 // command line which forces its activation.
 const char kActivationMarker = '*';
 
+// Use shared memory to communicate field trial (experiment) state. Set to false
+// for now while the implementation is fleshed out (e.g. data format, single
+// shared memory segment). See https://codereview.chromium.org/2365273004/ and
+// crbug.com/653874
+#if defined(OS_WIN)
+const bool kUseSharedMemoryForFieldTrials = false;
+#endif
+
 // Created a time value based on |year|, |month| and |day_of_month| parameters.
 Time CreateTimeFromParams(int year, int month, int day_of_month) {
   DCHECK_GT(year, 1970);
@@ -558,6 +569,77 @@
 }
 
 // static
+void FieldTrialList::CreateTrialsFromCommandLine(
+    const base::CommandLine& cmd_line,
+    const char* field_trial_handle_switch) {
+  DCHECK(global_);
+
+#if defined(OS_WIN)
+  if (cmd_line.HasSwitch(field_trial_handle_switch)) {
+    std::string arg = cmd_line.GetSwitchValueASCII(field_trial_handle_switch);
+    size_t token = arg.find(",");
+    int field_trial_handle = std::stoi(arg.substr(0, token));
+    int field_trial_length = std::stoi(arg.substr(token + 1, arg.length()));
+
+    HANDLE handle = reinterpret_cast<HANDLE>(field_trial_handle);
+    base::SharedMemoryHandle shm_handle =
+        base::SharedMemoryHandle(handle, base::GetCurrentProcId());
+
+    // Gets deleted when it gets out of scope, but that's OK because we need it
+    // only for the duration of this call currently anyway.
+    base::SharedMemory shared_memory(shm_handle, false);
+    shared_memory.Map(field_trial_length);
+
+    char* field_trial_state = static_cast<char*>(shared_memory.memory());
+    bool result = FieldTrialList::CreateTrialsFromString(
+        std::string(field_trial_state), std::set<std::string>());
+    DCHECK(result);
+    return;
+  }
+#endif
+
+  if (cmd_line.HasSwitch(switches::kForceFieldTrials)) {
+    bool result = FieldTrialList::CreateTrialsFromString(
+        cmd_line.GetSwitchValueASCII(switches::kForceFieldTrials),
+        std::set<std::string>());
+    DCHECK(result);
+  }
+}
+
+// static
+std::unique_ptr<base::SharedMemory> FieldTrialList::CopyFieldTrialStateToFlags(
+    const char* field_trial_handle_switch,
+    base::CommandLine* cmd_line) {
+  std::string field_trial_states;
+  base::FieldTrialList::AllStatesToString(&field_trial_states);
+  if (!field_trial_states.empty()) {
+// Use shared memory to pass the state if the feature is enabled, otherwise
+// fallback to passing it via the command line as a string.
+#if defined(OS_WIN)
+    if (kUseSharedMemoryForFieldTrials) {
+      std::unique_ptr<base::SharedMemory> shm(new base::SharedMemory());
+      size_t length = field_trial_states.size() + 1;
+      shm->CreateAndMapAnonymous(length);
+      memcpy(shm->memory(), field_trial_states.c_str(), length);
+
+      // HANDLE is just typedef'd to void *
+      auto uintptr_handle =
+          reinterpret_cast<std::uintptr_t>(shm->handle().GetHandle());
+      std::string field_trial_handle =
+          std::to_string(uintptr_handle) + "," + std::to_string(length);
+
+      cmd_line->AppendSwitchASCII(field_trial_handle_switch,
+                                  field_trial_handle);
+      return shm;
+    }
+#endif
+    cmd_line->AppendSwitchASCII(switches::kForceFieldTrials,
+                                field_trial_states);
+  }
+  return std::unique_ptr<base::SharedMemory>(nullptr);
+}
+
+// static
 FieldTrial* FieldTrialList::CreateFieldTrial(
     const std::string& name,
     const std::string& group_name) {
diff --git a/base/metrics/field_trial.h b/base/metrics/field_trial.h
index 2b88949..99e705a1 100644
--- a/base/metrics/field_trial.h
+++ b/base/metrics/field_trial.h
@@ -64,9 +64,11 @@
 #include <vector>
 
 #include "base/base_export.h"
+#include "base/command_line.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
 #include "base/observer_list_threadsafe.h"
 #include "base/strings/string_piece.h"
 #include "base/synchronization/lock.h"
@@ -464,6 +466,28 @@
       const std::string& trials_string,
       const std::set<std::string>& ignored_trial_names);
 
+  // Achieves the same thing as CreateTrialsFromString, except wraps the logic
+  // by taking in the trials from the command line, either via shared memory
+  // handle or command line argument.
+  // If using shared memory to pass around the list of field trials, then
+  // expects |field_trial_handle_switch| command line argument to
+  // contain the shared memory handle.
+  // If not, then create the trials as before (using the kForceFieldTrials
+  // switch). Needs the |field_trial_handle_switch| argument to be passed in
+  // since base/ can't depend on content/.
+  static void CreateTrialsFromCommandLine(
+      const base::CommandLine& cmd_line,
+      const char* field_trial_handle_switch);
+
+  // Adds a switch to the command line containing the field trial state as a
+  // string (if not using shared memory to share field trial state), or the
+  // shared memory handle + length.
+  // Needs the |field_trial_handle_switch| argument to be passed in since base/
+  // can't depend on content/.
+  static std::unique_ptr<base::SharedMemory> CopyFieldTrialStateToFlags(
+      const char* field_trial_handle_switch,
+      base::CommandLine* cmd_line);
+
   // Create a FieldTrial with the given |name| and using 100% probability for
   // the FieldTrial, force FieldTrial to have the same group string as
   // |group_name|. This is commonly used in a non-browser process, to carry
diff --git a/base/metrics/field_trial_unittest.cc b/base/metrics/field_trial_unittest.cc
index caa00e8..bb45bd71 100644
--- a/base/metrics/field_trial_unittest.cc
+++ b/base/metrics/field_trial_unittest.cc
@@ -6,14 +6,18 @@
 
 #include <stddef.h>
 
+#include "base/base_switches.h"
 #include "base/build_time.h"
+#include "base/feature_list.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/rand_util.h"
 #include "base/run_loop.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
 #include "base/test/gtest_util.h"
+#include "base/test/mock_entropy_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace base {
@@ -1132,4 +1136,19 @@
       "");
 }
 
+TEST(FieldTrialListTest, TestCopyFieldTrialStateToFlags) {
+  base::FieldTrialList field_trial_list(
+      base::MakeUnique<base::MockEntropyProvider>());
+  base::FieldTrialList::CreateFieldTrial("Trial1", "Group1");
+  base::FilePath test_file_path = base::FilePath(FILE_PATH_LITERAL("Program"));
+  base::CommandLine cmd_line = base::CommandLine(test_file_path);
+
+  std::unique_ptr<base::SharedMemory> field_trial_state =
+      base::FieldTrialList::CopyFieldTrialStateToFlags("field-trial-handle",
+                                                       &cmd_line);
+
+  EXPECT_TRUE(field_trial_state.get() == nullptr);
+  EXPECT_TRUE(cmd_line.HasSwitch(switches::kForceFieldTrials));
+}
+
 }  // namespace base
diff --git a/base/synchronization/lock_impl_win.cc b/base/synchronization/lock_impl_win.cc
index ef03267..31f95f4 100644
--- a/base/synchronization/lock_impl_win.cc
+++ b/base/synchronization/lock_impl_win.cc
@@ -18,8 +18,7 @@
 }
 
 void LockImpl::Lock() {
-  // Commented out pending https://crbug.com/652432
-  // base::debug::ScopedLockAcquireActivity lock_activity(this);
+  base::debug::ScopedLockAcquireActivity lock_activity(this);
   ::AcquireSRWLockExclusive(&native_handle_);
 }
 
diff --git a/base/test/launcher/test_launcher.cc b/base/test/launcher/test_launcher.cc
index e6880fa54f..1e2a95b0 100644
--- a/base/test/launcher/test_launcher.cc
+++ b/base/test/launcher/test_launcher.cc
@@ -90,6 +90,10 @@
 // the infrastructure.
 const size_t kOutputSnippetLinesLimit = 5000;
 
+// Limit of output snippet size. Exceeding this limit
+// results in truncating the output and failing the test.
+const size_t kOutputSnippetBytesLimit = 2.5 * 1024 * 1024;
+
 // Set of live launch test processes with corresponding lock (it is allowed
 // for callers to launch processes on different threads).
 LazyInstance<std::map<ProcessHandle, CommandLine> > g_live_processes
@@ -568,9 +572,21 @@
            launched_callback));
 }
 
-void TestLauncher::OnTestFinished(const TestResult& result) {
+void TestLauncher::OnTestFinished(const TestResult& original_result) {
   ++test_finished_count_;
 
+  TestResult result(original_result);
+
+  if (result.output_snippet.length() > kOutputSnippetBytesLimit) {
+    if (result.status == TestResult::TEST_SUCCESS)
+      result.status = TestResult::TEST_EXCESSIVE_OUTPUT;
+    result.output_snippet = StringPrintf(
+        "<truncated (%" PRIuS " bytes)>\n", result.output_snippet.length()) +
+        result.output_snippet.substr(
+            result.output_snippet.length() - kOutputSnippetLinesLimit) +
+        "\n";
+  }
+
   bool print_snippet = false;
   std::string print_test_stdio("auto");
   if (CommandLine::ForCurrentProcess()->HasSwitch(
diff --git a/base/test/launcher/test_result.cc b/base/test/launcher/test_result.cc
index e7320258..39e20e7 100644
--- a/base/test/launcher/test_result.cc
+++ b/base/test/launcher/test_result.cc
@@ -32,6 +32,8 @@
       return "TIMEOUT";
     case TEST_SKIPPED:
       return "SKIPPED";
+    case TEST_EXCESSIVE_OUTPUT:
+      return "EXCESSIVE_OUTPUT";
      // Rely on compiler warnings to ensure all possible values are handled.
   }
 
diff --git a/base/test/launcher/test_result.h b/base/test/launcher/test_result.h
index b61cdd4..19c6ba5 100644
--- a/base/test/launcher/test_result.h
+++ b/base/test/launcher/test_result.h
@@ -14,13 +14,14 @@
 // Structure containing result of a single test.
 struct TestResult {
   enum Status {
-    TEST_UNKNOWN,          // Status not set.
-    TEST_SUCCESS,          // Test passed.
-    TEST_FAILURE,          // Assertion failure (think EXPECT_TRUE, not DCHECK).
-    TEST_FAILURE_ON_EXIT,  // Test passed but executable exit code was non-zero.
-    TEST_TIMEOUT,          // Test timed out and was killed.
-    TEST_CRASH,            // Test crashed (includes CHECK/DCHECK failures).
-    TEST_SKIPPED,          // Test skipped (not run at all).
+    TEST_UNKNOWN,           // Status not set.
+    TEST_SUCCESS,           // Test passed.
+    TEST_FAILURE,           // Assertion failure (e.g. EXPECT_TRUE, not DCHECK).
+    TEST_FAILURE_ON_EXIT,   // Passed but executable exit code was non-zero.
+    TEST_TIMEOUT,           // Test timed out and was killed.
+    TEST_CRASH,             // Test crashed (includes CHECK/DCHECK failures).
+    TEST_SKIPPED,           // Test skipped (not run at all).
+    TEST_EXCESSIVE_OUTPUT,  // Test exceeded output limit.
   };
 
   TestResult();
@@ -41,7 +42,8 @@
   bool completed() const {
     return status == TEST_SUCCESS ||
         status == TEST_FAILURE ||
-        status == TEST_FAILURE_ON_EXIT;
+        status == TEST_FAILURE_ON_EXIT ||
+        status == TEST_EXCESSIVE_OUTPUT;
   }
 
   // Full name of the test (e.g. "A.B").
diff --git a/base/test/launcher/test_results_tracker.cc b/base/test/launcher/test_results_tracker.cc
index a8611ae..6b56761 100644
--- a/base/test/launcher/test_results_tracker.cc
+++ b/base/test/launcher/test_results_tracker.cc
@@ -65,6 +65,7 @@
       case TestResult::TEST_FAILURE:
         failures++;
         break;
+      case TestResult::TEST_EXCESSIVE_OUTPUT:
       case TestResult::TEST_FAILURE_ON_EXIT:
       case TestResult::TEST_TIMEOUT:
       case TestResult::TEST_CRASH:
@@ -247,6 +248,9 @@
   PrintTests(tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].begin(),
              tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].end(),
              "failed on exit");
+  PrintTests(tests_by_status[TestResult::TEST_EXCESSIVE_OUTPUT].begin(),
+             tests_by_status[TestResult::TEST_EXCESSIVE_OUTPUT].end(),
+             "produced excessive output");
   PrintTests(tests_by_status[TestResult::TEST_TIMEOUT].begin(),
              tests_by_status[TestResult::TEST_TIMEOUT].end(),
              "timed out");
@@ -275,6 +279,9 @@
   PrintTests(tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].begin(),
              tests_by_status[TestResult::TEST_FAILURE_ON_EXIT].end(),
              "failed on exit");
+  PrintTests(tests_by_status[TestResult::TEST_EXCESSIVE_OUTPUT].begin(),
+             tests_by_status[TestResult::TEST_EXCESSIVE_OUTPUT].end(),
+             "produced excessive output");
   PrintTests(tests_by_status[TestResult::TEST_TIMEOUT].begin(),
              tests_by_status[TestResult::TEST_TIMEOUT].end(),
              "timed out");
diff --git a/base/trace_event/common/trace_event_common.h b/base/trace_event/common/trace_event_common.h
index 182ed5f..e87665b8 100644
--- a/base/trace_event/common/trace_event_common.h
+++ b/base/trace_event/common/trace_event_common.h
@@ -953,15 +953,15 @@
   INTERNAL_TRACE_EVENT_SCOPED_CONTEXT(category_group, name, context)
 
 // Macro to specify that two trace IDs are identical. For example,
-// TRACE_BIND_IDS(
+// TRACE_LINK_IDS(
 //     "category", "name",
 //     TRACE_ID_WITH_SCOPE("net::URLRequest", 0x1000),
 //     TRACE_ID_WITH_SCOPE("blink::ResourceFetcher::FetchRequest", 0x2000))
 // tells the trace consumer that events with ID ("net::URLRequest", 0x1000) from
 // the current process have the same ID as events with ID
 // ("blink::ResourceFetcher::FetchRequest", 0x2000).
-#define TRACE_BIND_IDS(category_group, name, id, bind_id) \
-  INTERNAL_TRACE_EVENT_ADD_BIND_IDS(category_group, name, id, bind_id);
+#define TRACE_LINK_IDS(category_group, name, id, linked_id) \
+  INTERNAL_TRACE_EVENT_ADD_LINK_IDS(category_group, name, id, linked_id);
 
 // Macro to efficiently determine if a given category group is enabled.
 #define TRACE_EVENT_CATEGORY_GROUP_ENABLED(category_group, ret)             \
@@ -1028,7 +1028,7 @@
 #define TRACE_EVENT_PHASE_CLOCK_SYNC ('c')
 #define TRACE_EVENT_PHASE_ENTER_CONTEXT ('(')
 #define TRACE_EVENT_PHASE_LEAVE_CONTEXT (')')
-#define TRACE_EVENT_PHASE_BIND_IDS ('=')
+#define TRACE_EVENT_PHASE_LINK_IDS ('=')
 
 // Flags for changing the behavior of TRACE_EVENT_API_ADD_TRACE_EVENT.
 #define TRACE_EVENT_FLAG_NONE (static_cast<unsigned int>(0))
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index eca7c070..20ce662e 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -335,29 +335,20 @@
     }                                                                       \
   } while (0)
 
-// This macro ignores whether the bind_id is local, global, or mangled.
-#define INTERNAL_TRACE_EVENT_ADD_BIND_IDS(category_group, name, id, bind_id,  \
-                                          ...)                                \
+// The linked ID will not be mangled.
+#define INTERNAL_TRACE_EVENT_ADD_LINK_IDS(category_group, name, id1, id2)     \
     do {                                                                      \
       INTERNAL_TRACE_EVENT_GET_CATEGORY_INFO(category_group);                 \
       if (INTERNAL_TRACE_EVENT_CATEGORY_GROUP_ENABLED_FOR_RECORDING_MODE()) { \
-        trace_event_internal::TraceID source_id((id));                        \
+        trace_event_internal::TraceID source_id((id1));                       \
         unsigned int source_flags = source_id.id_flags();                     \
-        trace_event_internal::TraceID target_id((bind_id));                   \
-        if (target_id.scope() == trace_event_internal::kGlobalScope) {        \
-          trace_event_internal::AddTraceEvent(                                \
-              TRACE_EVENT_PHASE_BIND_IDS,                                     \
-              INTERNAL_TRACE_EVENT_UID(category_group_enabled),               \
-              name, source_id.scope(), source_id.raw_id(),                    \
-              source_flags, target_id.raw_id(), ##__VA_ARGS__);               \
-        } else {                                                              \
-          trace_event_internal::AddTraceEvent(                                \
-              TRACE_EVENT_PHASE_BIND_IDS,                                     \
-              INTERNAL_TRACE_EVENT_UID(category_group_enabled),               \
-              name, source_id.scope(), source_id.raw_id(),                    \
-              source_flags, target_id.raw_id(),                               \
-              "bind_scope", target_id.scope(), ##__VA_ARGS__);                \
-        }                                                                     \
+        trace_event_internal::TraceID target_id((id2));                       \
+        trace_event_internal::AddTraceEvent(                                  \
+            TRACE_EVENT_PHASE_LINK_IDS,                                       \
+            INTERNAL_TRACE_EVENT_UID(category_group_enabled),                 \
+            name, source_id.scope(), source_id.raw_id(), source_flags,        \
+            trace_event_internal::kNoId,                                      \
+            "linked_id", target_id.AsConvertableToTraceFormat());             \
       }                                                                       \
     } while (0)
 
@@ -415,7 +406,7 @@
 // TraceID encapsulates an ID that can either be an integer or pointer. Pointers
 // are by default mangled with the Process ID so that they are unlikely to
 // collide when the same pointer is used on different processes.
-class TraceID {
+class BASE_EXPORT TraceID {
  public:
   // Can be combined with WithScope.
   class LocalId {
@@ -541,6 +532,9 @@
   const char* scope() const { return scope_; }
   unsigned int id_flags() const { return id_flags_; }
 
+  std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+  AsConvertableToTraceFormat() const;
+
  private:
   const char* scope_ = nullptr;
   unsigned long long raw_id_;
diff --git a/base/trace_event/trace_event_impl.cc b/base/trace_event/trace_event_impl.cc
index d41500d..f9792d0d 100644
--- a/base/trace_event/trace_event_impl.cc
+++ b/base/trace_event/trace_event_impl.cc
@@ -8,6 +8,7 @@
 
 #include "base/format_macros.h"
 #include "base/json/string_escape.h"
+#include "base/memory/ptr_util.h"
 #include "base/process/process_handle.h"
 #include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
@@ -15,6 +16,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/trace_event/trace_event.h"
+#include "base/trace_event/trace_event_argument.h"
 #include "base/trace_event/trace_log.h"
 
 namespace base {
@@ -391,8 +393,7 @@
     StringAppendF(out, ",\"bp\":\"e\"");
 
   if ((flags_ & TRACE_EVENT_FLAG_FLOW_OUT) ||
-      (flags_ & TRACE_EVENT_FLAG_FLOW_IN) ||
-      phase_ == TRACE_EVENT_PHASE_BIND_IDS) {
+      (flags_ & TRACE_EVENT_FLAG_FLOW_IN)) {
     StringAppendF(out, ",\"bind_id\":\"0x%" PRIx64 "\"",
                   static_cast<uint64_t>(bind_id_));
   }
@@ -448,3 +449,40 @@
 
 }  // namespace trace_event
 }  // namespace base
+
+namespace trace_event_internal {
+
+std::unique_ptr<base::trace_event::ConvertableToTraceFormat>
+TraceID::AsConvertableToTraceFormat() const {
+  auto value = base::MakeUnique<base::trace_event::TracedValue>();
+
+  if (scope_ != kGlobalScope)
+    value->SetString("scope", scope_);
+  switch (id_flags_) {
+    case TRACE_EVENT_FLAG_HAS_ID:
+      value->SetString(
+          "id",
+          base::StringPrintf("0x%" PRIx64, static_cast<uint64_t>(raw_id_)));
+      break;
+    case TRACE_EVENT_FLAG_HAS_GLOBAL_ID:
+      value->BeginDictionary("id2");
+      value->SetString(
+          "global",
+          base::StringPrintf("0x%" PRIx64, static_cast<uint64_t>(raw_id_)));
+      value->EndDictionary();
+      break;
+    case TRACE_EVENT_FLAG_HAS_LOCAL_ID:
+      value->BeginDictionary("id2");
+      value->SetString(
+          "local",
+          base::StringPrintf("0x%" PRIx64, static_cast<uint64_t>(raw_id_)));
+      value->EndDictionary();
+      break;
+    default:
+      NOTREACHED() << "Unrecognized ID flag";
+  }
+
+  return std::move(value);
+}
+
+}  // namespace trace_event_internal
diff --git a/base/trace_event/trace_event_unittest.cc b/base/trace_event/trace_event_unittest.cc
index cec48b78..84553781 100644
--- a/base/trace_event/trace_event_unittest.cc
+++ b/base/trace_event/trace_event_unittest.cc
@@ -31,6 +31,7 @@
 #include "base/threading/thread.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_buffer.h"
+#include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_synthetic_delay.h"
 #include "base/values.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -520,10 +521,14 @@
     TRACE_EVENT_SCOPED_CONTEXT("all", "TRACE_EVENT_SCOPED_CONTEXT call",
                                context_id);
 
-    TRACE_BIND_IDS("all", "TRACE_BIND_IDS simple call", 0x1000, 0x2000);
-    TRACE_BIND_IDS("all", "TRACE_BIND_IDS scoped call",
+    TRACE_LINK_IDS("all", "TRACE_LINK_IDS simple call", 0x1000, 0x2000);
+    TRACE_LINK_IDS("all", "TRACE_LINK_IDS scoped call",
                    TRACE_ID_WITH_SCOPE("scope 1", 0x1000),
                    TRACE_ID_WITH_SCOPE("scope 2", 0x2000));
+    TRACE_LINK_IDS("all", "TRACE_LINK_IDS to a local ID", 0x1000,
+                   TRACE_ID_LOCAL(0x2000));
+    TRACE_LINK_IDS("all", "TRACE_LINK_IDS to a global ID", 0x1000,
+                   TRACE_ID_GLOBAL(0x2000));
 
     TRACE_EVENT_ASYNC_BEGIN0("all", "async default process scope", 0x1000);
     TRACE_EVENT_ASYNC_BEGIN0("all", "async local id", TRACE_ID_LOCAL(0x2000));
@@ -972,42 +977,76 @@
     EXPECT_EQ("0x20151021", id);
   }
 
-  EXPECT_FIND_("TRACE_BIND_IDS simple call");
+  EXPECT_FIND_("TRACE_LINK_IDS simple call");
   {
     std::string ph;
     EXPECT_TRUE((item && item->GetString("ph", &ph)));
     EXPECT_EQ("=", ph);
 
     EXPECT_FALSE((item && item->HasKey("scope")));
-    std::string id;
-    EXPECT_TRUE((item && item->GetString("id", &id)));
-    EXPECT_EQ("0x1000", id);
+    std::string id1;
+    EXPECT_TRUE((item && item->GetString("id", &id1)));
+    EXPECT_EQ("0x1000", id1);
 
-    EXPECT_FALSE((item && item->HasKey("args.bind_scope")));
-    std::string bind_id;
-    EXPECT_TRUE((item && item->GetString("bind_id", &id)));
-    EXPECT_EQ("0x2000", id);
+    EXPECT_FALSE((item && item->HasKey("args.linked_id.scope")));
+    std::string id2;
+    EXPECT_TRUE((item && item->GetString("args.linked_id.id", &id2)));
+    EXPECT_EQ("0x2000", id2);
   }
 
-  EXPECT_FIND_("TRACE_BIND_IDS scoped call");
+  EXPECT_FIND_("TRACE_LINK_IDS scoped call");
   {
     std::string ph;
     EXPECT_TRUE((item && item->GetString("ph", &ph)));
     EXPECT_EQ("=", ph);
 
-    std::string id_scope;
-    EXPECT_TRUE((item && item->GetString("scope", &id_scope)));
-    EXPECT_EQ("scope 1", id_scope);
-    std::string id;
-    EXPECT_TRUE((item && item->GetString("id", &id)));
-    EXPECT_EQ("0x1000", id);
+    std::string scope1;
+    EXPECT_TRUE((item && item->GetString("scope", &scope1)));
+    EXPECT_EQ("scope 1", scope1);
+    std::string id1;
+    EXPECT_TRUE((item && item->GetString("id", &id1)));
+    EXPECT_EQ("0x1000", id1);
 
-    std::string bind_scope;
-    EXPECT_TRUE((item && item->GetString("args.bind_scope", &bind_scope)));
-    EXPECT_EQ("scope 2", bind_scope);
-    std::string bind_id;
-    EXPECT_TRUE((item && item->GetString("bind_id", &id)));
-    EXPECT_EQ("0x2000", id);
+    std::string scope2;
+    EXPECT_TRUE((item && item->GetString("args.linked_id.scope", &scope2)));
+    EXPECT_EQ("scope 2", scope2);
+    std::string id2;
+    EXPECT_TRUE((item && item->GetString("args.linked_id.id", &id2)));
+    EXPECT_EQ("0x2000", id2);
+  }
+
+  EXPECT_FIND_("TRACE_LINK_IDS to a local ID");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("=", ph);
+
+    EXPECT_FALSE((item && item->HasKey("scope")));
+    std::string id1;
+    EXPECT_TRUE((item && item->GetString("id", &id1)));
+    EXPECT_EQ("0x1000", id1);
+
+    EXPECT_FALSE((item && item->HasKey("args.linked_id.scope")));
+    std::string id2;
+    EXPECT_TRUE((item && item->GetString("args.linked_id.id2.local", &id2)));
+    EXPECT_EQ("0x2000", id2);
+  }
+
+  EXPECT_FIND_("TRACE_LINK_IDS to a global ID");
+  {
+    std::string ph;
+    EXPECT_TRUE((item && item->GetString("ph", &ph)));
+    EXPECT_EQ("=", ph);
+
+    EXPECT_FALSE((item && item->HasKey("scope")));
+    std::string id1;
+    EXPECT_TRUE((item && item->GetString("id", &id1)));
+    EXPECT_EQ("0x1000", id1);
+
+    EXPECT_FALSE((item && item->HasKey("args.linked_id.scope")));
+    std::string id2;
+    EXPECT_TRUE((item && item->GetString("args.linked_id.id2.global", &id2)));
+    EXPECT_EQ("0x2000", id2);
   }
 
   EXPECT_FIND_("async default process scope");
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index 4bf52d5..9b96db7 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -155,6 +155,7 @@
   virtual void MouseMoveAt(const gfx::Point& mouse_position) = 0;
   virtual void MouseDown() = 0;
   virtual void MouseUp() = 0;
+  virtual void MouseLeave() = 0;
 
   // Stop scrolling the selected layer. Should only be called if ScrollBegin()
   // returned SCROLL_STARTED.
diff --git a/cc/input/scrollbar_animation_controller_thinning.cc b/cc/input/scrollbar_animation_controller_thinning.cc
index 4324a43..74352996 100644
--- a/cc/input/scrollbar_animation_controller_thinning.cc
+++ b/cc/input/scrollbar_animation_controller_thinning.cc
@@ -82,6 +82,9 @@
 }
 
 void ScrollbarAnimationControllerThinning::DidMouseMoveOffScrollbar() {
+  if (!mouse_is_over_scrollbar_ && !mouse_is_near_scrollbar_)
+    return;
+
   mouse_is_over_scrollbar_ = false;
   mouse_is_near_scrollbar_ = false;
 
diff --git a/cc/input/scrollbar_animation_controller_thinning_unittest.cc b/cc/input/scrollbar_animation_controller_thinning_unittest.cc
index 4824879..64096b7 100644
--- a/cc/input/scrollbar_animation_controller_thinning_unittest.cc
+++ b/cc/input/scrollbar_animation_controller_thinning_unittest.cc
@@ -518,5 +518,40 @@
   }
 }
 
+// Move mouse on scrollbar and capture then move out of window. Confirm that
+// the bar stays thick and dark.
+TEST_F(ScrollbarAnimationControllerThinningTest,
+       MouseCapturedAndExitWindowFromScrollbar) {
+  base::TimeTicks time;
+  time += base::TimeDelta::FromSeconds(1);
+
+  // Move in
+  scrollbar_controller_->DidMouseMoveNear(0);
+
+  scrollbar_controller_->Animate(time);
+  time += base::TimeDelta::FromSeconds(kDuration);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // Capture
+  scrollbar_controller_->DidCaptureScrollbarBegin();
+  time += base::TimeDelta::FromSeconds(1);
+  scrollbar_controller_->Animate(time);
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+  EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+
+  // move out of window
+  scrollbar_controller_->DidMouseMoveOffScrollbar();
+
+  // test for 10 seconds, stay thick and dark
+  for (int i = 0; i < 10; ++i) {
+    time += base::TimeDelta::FromSeconds(1);
+    scrollbar_controller_->Animate(time);
+    EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->Opacity());
+    EXPECT_FLOAT_EQ(1.0f, scrollbar_layer_->thumb_thickness_scale_factor());
+  }
+}
+
 }  // namespace
 }  // namespace cc
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index 16ee4d6b..e320425 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -322,7 +322,6 @@
   int prepare_tiles_funnel_;
 
   int consecutive_checkerboard_animations_;
-  int max_pending_swaps_;
   int pending_swaps_;
   int swaps_with_current_compositor_frame_sink_;
   bool needs_redraw_;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 784693e8..1ed7cfb 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -3279,6 +3279,13 @@
                                          active_tree_->device_scale_factor());
 }
 
+void LayerTreeHostImpl::MouseLeave() {
+  for (auto& pair : scrollbar_animation_controllers_)
+    pair.second->DidMouseMoveOffScrollbar();
+
+  scroll_layer_id_when_mouse_over_scrollbar_ = Layer::INVALID_ID;
+}
+
 void LayerTreeHostImpl::HandleMouseOverScrollbar(LayerImpl* layer_impl) {
   int new_id = Layer::INVALID_ID;
   if (layer_impl && layer_impl->ToScrollbarLayer())
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 23db006..cdb2573 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -180,6 +180,7 @@
   void MouseDown() override;
   void MouseUp() override;
   void MouseMoveAt(const gfx::Point& viewport_point) override;
+  void MouseLeave() override;
 
   void PinchGestureBegin() override;
   void PinchGestureUpdate(float magnify_delta,
diff --git a/chrome/android/java/res/layout/bottom_control_container.xml b/chrome/android/java/res/layout/bottom_control_container.xml
new file mode 100644
index 0000000..4c433af
--- /dev/null
+++ b/chrome/android/java/res/layout/bottom_control_container.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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. -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="match_parent"
+    android:layout_width="wrap_content">
+    <org.chromium.chrome.browser.toolbar.ToolbarControlContainer
+        android:id="@+id/control_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:gravity="bottom"
+        android:minHeight="@dimen/control_container_height" >
+        <view
+            class="org.chromium.chrome.browser.toolbar.ToolbarControlContainer$ToolbarViewResourceFrameLayout"
+            android:id="@+id/toolbar_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+            <ImageView
+                android:id="@+id/toolbar_shadow"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/toolbar_shadow_height"
+                android:src="@drawable/toolbar_shadow"
+                android:scaleType="fitXY"
+                android:scaleY="-1"
+                android:contentDescription="@null" />
+            <ViewStub
+                android:id="@+id/toolbar_stub"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/toolbar_height_no_shadow"
+                android:layout_marginTop="@dimen/toolbar_shadow_height" />
+            <ViewStub
+                android:id="@+id/find_toolbar_stub"
+                android:inflatedId="@+id/find_toolbar"
+                android:visibility="gone"
+                android:layout_marginTop="@dimen/toolbar_shadow_height"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/toolbar_height_no_shadow"
+                android:layout="@layout/find_toolbar" />
+        </view>
+    </org.chromium.chrome.browser.toolbar.ToolbarControlContainer>
+</RelativeLayout>
diff --git a/chrome/android/java/res/layout/control_container.xml b/chrome/android/java/res/layout/control_container.xml
index a771aff..03f5294 100644
--- a/chrome/android/java/res/layout/control_container.xml
+++ b/chrome/android/java/res/layout/control_container.xml
@@ -12,12 +12,11 @@
         android:id="@+id/toolbar_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
-        <include
-            android:id="@+id/toolbar"
+        <ViewStub
+            android:id="@+id/toolbar_stub"
             android:layout_width="match_parent"
             android:layout_marginTop="@dimen/tab_strip_height"
-            android:layout_height="@dimen/toolbar_height_no_shadow"
-            layout="@layout/toolbar" />
+            android:layout_height="@dimen/toolbar_height_no_shadow" />
         <ImageView
             android:id="@+id/toolbar_shadow"
             android:src="@drawable/toolbar_shadow"
diff --git a/chrome/android/java/res/layout/custom_tabs_control_container.xml b/chrome/android/java/res/layout/custom_tabs_control_container.xml
index 87b45c7..1b2662db 100644
--- a/chrome/android/java/res/layout/custom_tabs_control_container.xml
+++ b/chrome/android/java/res/layout/custom_tabs_control_container.xml
@@ -12,11 +12,10 @@
         android:id="@+id/toolbar_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content">
-        <include
-            android:id="@+id/toolbar"
+        <ViewStub
+            android:id="@+id/toolbar_stub"
             android:layout_width="match_parent"
-            android:layout_height="@dimen/custom_tabs_control_container_height"
-            layout="@layout/custom_tabs_toolbar" />
+            android:layout_height="@dimen/custom_tabs_control_container_height" />
         <ImageView
             android:id="@+id/toolbar_shadow"
             android:src="@drawable/toolbar_shadow"
diff --git a/chrome/android/java/res/layout/custom_tabs_toolbar.xml b/chrome/android/java/res/layout/custom_tabs_toolbar.xml
index c2d9ce5..ae41340 100644
--- a/chrome/android/java/res/layout/custom_tabs_toolbar.xml
+++ b/chrome/android/java/res/layout/custom_tabs_toolbar.xml
@@ -5,7 +5,10 @@
 
 <org.chromium.chrome.browser.toolbar.CustomTabToolbar
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:chrome="http://schemas.android.com/apk/res-auto" >
+    xmlns:chrome="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/toolbar"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/custom_tabs_control_container_height" >
     <ImageButton
         android:id="@+id/close_button"
         style="@style/ToolbarButton"
diff --git a/chrome/android/java/res/layout/toolbar.xml b/chrome/android/java/res/layout/toolbar_phone.xml
similarity index 86%
rename from chrome/android/java/res/layout/toolbar.xml
rename to chrome/android/java/res/layout/toolbar_phone.xml
index 6c26288f..6c6fbfd 100644
--- a/chrome/android/java/res/layout/toolbar.xml
+++ b/chrome/android/java/res/layout/toolbar_phone.xml
@@ -8,9 +8,10 @@
 
 <org.chromium.chrome.browser.toolbar.ToolbarPhone
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/toolbar"
     android:layout_width="match_parent"
     android:layout_height="@dimen/toolbar_height_no_shadow" >
 
-    <include layout="@layout/toolbar_common"/>
+    <include layout="@layout/toolbar_phone_common"/>
 
 </org.chromium.chrome.browser.toolbar.ToolbarPhone>
diff --git a/chrome/android/java/res/layout/toolbar_common.xml b/chrome/android/java/res/layout/toolbar_phone_common.xml
similarity index 100%
rename from chrome/android/java/res/layout/toolbar_common.xml
rename to chrome/android/java/res/layout/toolbar_phone_common.xml
diff --git a/chrome/android/java/res/layout-sw600dp/toolbar.xml b/chrome/android/java/res/layout/toolbar_tablet.xml
similarity index 98%
rename from chrome/android/java/res/layout-sw600dp/toolbar.xml
rename to chrome/android/java/res/layout/toolbar_tablet.xml
index f93f93f7..9699ff3 100644
--- a/chrome/android/java/res/layout-sw600dp/toolbar.xml
+++ b/chrome/android/java/res/layout/toolbar_tablet.xml
@@ -8,6 +8,7 @@
 
 <org.chromium.chrome.browser.toolbar.ToolbarTablet
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/toolbar"
     android:layout_width="match_parent"
     android:layout_height="@dimen/toolbar_height_no_shadow"
     android:layout_marginTop="@dimen/tab_strip_height"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index de2c8202..a1b5e3dd 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -218,6 +218,7 @@
     <dimen name="toolbar_tab_count_text_size_1_digit">12dp</dimen>
     <dimen name="toolbar_tab_count_text_size_2_digit">10dp</dimen>
     <dimen name="toolbar_height_no_shadow">56dp</dimen>
+    <dimen name="toolbar_shadow_height">8dp</dimen>
     <dimen name="toolbar_progress_bar_height">2dp</dimen>
     <dimen name="toolbar_button_width">48dp</dimen>
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 3c7cb47..da94f43 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -166,6 +166,11 @@
      */
     static final int NO_CONTROL_CONTAINER = -1;
 
+    /**
+     * No toolbar layout to inflate during initialization.
+     */
+    static final int NO_TOOLBAR_LAYOUT = -1;
+
     private static final int RECORD_MULTI_WINDOW_SCREEN_WIDTH_DELAY_MS = 5000;
 
     /**
@@ -351,12 +356,19 @@
             // of our control, so we have to disable StrictMode to work. See crbug.com/639352.
             StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
             try {
+                ControlContainer controlContainer = null;
                 setContentView(R.layout.main);
                 if (controlContainerLayoutId != NO_CONTROL_CONTAINER) {
                     ViewStub toolbarContainerStub =
                             ((ViewStub) findViewById(R.id.control_container_stub));
                     toolbarContainerStub.setLayoutResource(controlContainerLayoutId);
-                    toolbarContainerStub.inflate();
+                    controlContainer = (ControlContainer) toolbarContainerStub.inflate();
+                }
+
+                // Inflate the correct toolbar layout for the device.
+                int toolbarLayoutId = getToolbarLayoutId();
+                if (toolbarLayoutId != NO_TOOLBAR_LAYOUT && controlContainer != null) {
+                    controlContainer.initWithToolbar(toolbarLayoutId);
                 }
             } finally {
                 StrictMode.setThreadPolicy(oldPolicy);
@@ -464,6 +476,13 @@
     }
 
     /**
+     * @return The layout ID for the toolbar to use.
+     */
+    protected int getToolbarLayoutId() {
+        return NO_TOOLBAR_LAYOUT;
+    }
+
+    /**
      * @return Whether contextual search is allowed for this activity or not.
      */
     protected boolean isContextualSearchAllowed() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
index aca7c21..b288ecbe 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -416,7 +416,7 @@
             }
             mMergeTabsOnResume = false;
         }
-        if (mVrShellDelegate.isInVR()) mVrShellDelegate.resumeVR();
+        mVrShellDelegate.maybeResumeVR();
 
         mLocaleManager.setSnackbarManager(getSnackbarManager());
         mLocaleManager.startObservingPhoneChanges();
@@ -426,7 +426,7 @@
     public void onPauseWithNative() {
         mTabModelSelectorImpl.commitAllTabClosures();
         CookiesFetcher.persistCookies(this);
-        if (mVrShellDelegate.isInVR()) mVrShellDelegate.pauseVR();
+        mVrShellDelegate.maybePauseVR();
 
         mLocaleManager.setSnackbarManager(null);
         mLocaleManager.stopObservingPhoneChanges();
@@ -937,10 +937,22 @@
 
     @Override
     protected int getControlContainerLayoutId() {
+        if (FeatureUtilities.isChromeHomeEnabled()) {
+            return R.layout.bottom_control_container;
+        }
         return R.layout.control_container;
     }
 
     @Override
+    protected int getToolbarLayoutId() {
+        if (DeviceFormFactor.isTablet(getApplicationContext())) return R.layout.toolbar_tablet;
+
+        // TODO(mdjones): Replace with bottom_toolbar layout when available.
+        if (FeatureUtilities.isChromeHomeEnabled()) return R.layout.toolbar_phone;
+        return R.layout.toolbar_phone;
+    }
+
+    @Override
     public void postInflationStartup() {
         super.postInflationStartup();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
index 2594698..4bda45b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/WarmupManager.java
@@ -22,6 +22,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.widget.ControlContainer;
 import org.chromium.content_public.browser.WebContents;
 
 import java.net.InetAddress;
@@ -69,8 +70,10 @@
      * Inflates and constructs the view hierarchy that the app will use.
      * @param baseContext The base context to use for creating the ContextWrapper.
      * @param toolbarContainerId Id of the toolbar container.
+     * @param toolbarId The toolbar's layout ID.
      */
-    public void initializeViewHierarchy(Context baseContext, int toolbarContainerId) {
+    public void initializeViewHierarchy(Context baseContext, int toolbarContainerId,
+            int toolbarId) {
         TraceEvent.begin("WarmupManager.initializeViewHierarchy");
         // Inflating the view hierarchy causes StrictMode violations on some
         // devices. Since layout inflation should happen on the UI thread, allow
@@ -88,7 +91,8 @@
             if (toolbarContainerId != ChromeActivity.NO_CONTROL_CONTAINER) {
                 ViewStub stub = (ViewStub) mMainView.findViewById(R.id.control_container_stub);
                 stub.setLayoutResource(toolbarContainerId);
-                stub.inflate();
+                ControlContainer controlContainer = (ControlContainer) stub.inflate();
+                controlContainer.initWithToolbar(toolbarId);
             }
         } catch (InflateException e) {
             // See crbug.com/606715.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 49875c2..e9e8d15 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -609,6 +609,11 @@
     }
 
     @Override
+    protected int getToolbarLayoutId() {
+        return R.layout.custom_tabs_toolbar;
+    }
+
+    @Override
     public int getControlContainerHeightResource() {
         return R.dimen.custom_tabs_control_container_height;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
index 641729d..16c6ff0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
@@ -128,10 +128,13 @@
                     pageLoadFinishedTimestamp - mIntentReceivedTimestamp;
 
             String histogramPrefix = mOpenedByChrome ? "ChromeGeneratedCustomTab" : "CustomTabs";
-            // Same bounds and bucket count as "Startup.FirstCommitNavigationTime"
             RecordHistogram.recordCustomTimesHistogram(
-                    histogramPrefix + ".IntentToFirstCommitNavigationTime", timeToPageLoadStartedMs,
-                    1, TimeUnit.MINUTES.toMillis(1), TimeUnit.MILLISECONDS, 225);
+                    histogramPrefix + ".IntentToFirstCommitNavigationTime2.ZoomedOut",
+                    timeToPageLoadStartedMs,
+                    50, TimeUnit.MINUTES.toMillis(10), TimeUnit.MILLISECONDS, 50);
+            RecordHistogram.recordCustomTimesHistogram(
+                    histogramPrefix + ".IntentToFirstCommitNavigationTime2.ZoomedIn",
+                    timeToPageLoadStartedMs, 200, 1000, TimeUnit.MILLISECONDS, 100);
             // Same bounds and bucket count as PLT histograms.
             RecordHistogram.recordCustomTimesHistogram(histogramPrefix + ".IntentToPageLoadedTime",
                     timeToPageLoadFinishedMs, 10, TimeUnit.MINUTES.toMillis(10),
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
index a8f48e9..c0c7e0c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabsConnection.java
@@ -205,7 +205,7 @@
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
         ChromeBrowserInitializer.initNetworkChangeNotifier(context);
         WarmupManager.getInstance().initializeViewHierarchy(
-                context, R.layout.custom_tabs_control_container);
+                context, R.layout.custom_tabs_control_container, R.layout.custom_tabs_toolbar);
     }
 
     public boolean warmup(long flags) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
index edf2894e..a452147 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/document/ChromeLauncherActivity.java
@@ -556,6 +556,7 @@
             // Add a PendingIntent so that the intent used to launch Chrome will be resent when
             // first run is completed or canceled.
             FirstRunFlowSequencer.addPendingIntent(this, freIntent, getIntent());
+            freIntent.putExtra(FirstRunActivity.EXTRA_FINISH_ON_TOUCH_OUTSIDE, !forTabbedMode);
             startActivity(freIntent);
         } else {
             Intent newIntent = new Intent(getIntent());
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
index 2fe285a..16bfa081 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandler.java
@@ -160,11 +160,6 @@
             return OverrideUrlLoadingResult.NO_OVERRIDE;
         }
 
-        // http://crbug.com/605302 : Allow Chrome to handle all pdf file downloads.
-        if (mDelegate.isPdfDownload(params.getUrl())) {
-            return OverrideUrlLoadingResult.NO_OVERRIDE;
-        }
-
         // pageTransition is a combination of an enumeration (core value) and bitmask.
         int pageTransitionCore = params.getPageTransition() & PageTransition.CORE_MASK;
         boolean isLink = pageTransitionCore == PageTransition.LINK;
@@ -195,6 +190,11 @@
             return OverrideUrlLoadingResult.NO_OVERRIDE;
         }
 
+        // http://crbug.com/605302 : Allow Chrome to handle all pdf file downloads.
+        if (!isExternalProtocol && mDelegate.isPdfDownload(params.getUrl())) {
+            return OverrideUrlLoadingResult.NO_OVERRIDE;
+        }
+
         // If accessing a file URL, ensure that the user has granted the necessary file access
         // to Chrome.  This check should happen for reloads, navigations, etc..., which is why
         // it occurs before the subsequent blocks.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
index 6f4d9827..d1e8033 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/FirstRunActivity.java
@@ -53,6 +53,7 @@
     public static final String EXTRA_USE_FRE_FLOW_SEQUENCER = "Extra.UseFreFlowSequencer";
     public static final String EXTRA_START_LIGHTWEIGHT_FRE = "Extra.StartLightweightFRE";
     public static final String EXTRA_CHROME_LAUNCH_INTENT = "Extra.FreChromeLaunchIntent";
+    public static final String EXTRA_FINISH_ON_TOUCH_OUTSIDE = "Extra.FreFinishOnTouchOutside";
 
     static final String SHOW_WELCOME_PAGE = "ShowWelcome";
     static final String SHOW_SIGNIN_PAGE = "ShowSignIn";
@@ -145,7 +146,6 @@
         initializeBrowserProcess();
 
         super.onCreate(savedInstanceState);
-        setFinishOnTouchOutside(false);
 
         if (savedInstanceState != null) {
             mFreProperties = savedInstanceState;
@@ -155,6 +155,9 @@
             mFreProperties = new Bundle();
         }
 
+        setFinishOnTouchOutside(
+                mFreProperties.getBoolean(FirstRunActivity.EXTRA_FINISH_ON_TOUCH_OUTSIDE));
+
         // Skip creating content view if it is to start a lightweight First Run Experience.
         if (mFreProperties.getBoolean(FirstRunActivity.EXTRA_START_LIGHTWEIGHT_FRE)) {
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
index 4242795..ce971ac 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/locale/LocaleManager.java
@@ -30,6 +30,8 @@
     public static final String PREF_WAS_IN_SPECIAL_LOCALE = "LocaleManager_WAS_IN_SPECIAL_LOCALE";
     public static final String SPECIAL_LOCALE_ID = "US";
 
+    private static final int SNACKBAR_DURATION_MS = 6000;
+
     private static LocaleManager sInstance;
 
     // LocaleManager is a singleton and it should not have strong reference to UI objects.
@@ -199,6 +201,7 @@
         Context context = ContextUtils.getApplicationContext();
         Snackbar snackbar = Snackbar.make(title, mSnackbarController, Snackbar.TYPE_NOTIFICATION,
                 Snackbar.UMA_SPECIAL_LOCALE);
+        snackbar.setDuration(SNACKBAR_DURATION_MS);
         snackbar.setAction(context.getString(R.string.preferences), null);
         manager.showSnackbar(snackbar);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/locale/SearchEnginePromoDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/locale/SearchEnginePromoDialog.java
index ee88c1f61..bc11aca1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/locale/SearchEnginePromoDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/locale/SearchEnginePromoDialog.java
@@ -10,6 +10,7 @@
 import android.content.DialogInterface.OnDismissListener;
 import android.content.Intent;
 import android.os.Bundle;
+import android.support.annotation.IntDef;
 import android.text.SpannableString;
 import android.text.method.LinkMovementMethod;
 import android.text.style.ClickableSpan;
@@ -17,6 +18,7 @@
 import android.widget.TextView;
 
 import org.chromium.base.ContextUtils;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.preferences.PreferencesLauncher;
 import org.chromium.chrome.browser.preferences.SearchEnginePreference;
@@ -24,25 +26,38 @@
 import org.chromium.ui.text.SpanApplier;
 import org.chromium.ui.text.SpanApplier.SpanInfo;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A promotion dialog showing that the default search provider will be set to Sogou.
  */
 public class SearchEnginePromoDialog extends Dialog
         implements View.OnClickListener, OnDismissListener {
+    // These constants are here to back a uma histogram. Append new constants at the end of this
+    // list (do not rearrange) and don't forget to update CHOICE_ENUM_COUNT.
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({CHOICE_USE_SOGOU, CHOICE_KEEP_GOOGLE, CHOICE_SETTINGS, CHOICE_BACK_KEY})
+    private @interface UserChoice {}
     private static final int CHOICE_USE_SOGOU = 0;
     private static final int CHOICE_KEEP_GOOGLE = 1;
+    private static final int CHOICE_SETTINGS = 2;
+    private static final int CHOICE_BACK_KEY = 3;
+
+    private static final int CHOICE_ENUM_COUNT = 4;
 
     private final LocaleManager mLocaleManager;
     private final ClickableSpan mSpan = new NoUnderlineClickableSpan() {
         @Override
         public void onClick(View widget) {
+            mChoice = CHOICE_SETTINGS;
             Intent intent = PreferencesLauncher.createIntentForSettingsPage(getContext(),
                     SearchEnginePreference.class.getName());
             getContext().startActivity(intent);
         }
     };
 
-    private int mChoice = CHOICE_USE_SOGOU;
+    @UserChoice private int mChoice = CHOICE_BACK_KEY;
 
     /**
      * Creates an instance of the dialog.
@@ -51,6 +66,7 @@
         super(context, R.style.SimpleDialog);
         mLocaleManager = localeManager;
         setOnDismissListener(this);
+        setCanceledOnTouchOutside(false);
     }
 
     @Override
@@ -100,12 +116,21 @@
 
     @Override
     public void onDismiss(DialogInterface dialog) {
-        if (mChoice == CHOICE_KEEP_GOOGLE) {
-            keepGoogle();
-        } else if (mChoice == CHOICE_USE_SOGOU) {
-            useSogou();
+        switch (mChoice) {
+            case CHOICE_KEEP_GOOGLE:
+            case CHOICE_SETTINGS:
+            case CHOICE_BACK_KEY:
+                keepGoogle();
+                break;
+            case CHOICE_USE_SOGOU:
+                useSogou();
+                break;
+            default:
+                assert false : "Unexpected choice";
         }
         ContextUtils.getAppSharedPreferences().edit()
                 .putBoolean(LocaleManager.PREF_PROMO_SHOWN, true).apply();
+        RecordHistogram.recordEnumeratedHistogram("SpecialLocale.PromotionDialog", mChoice,
+                CHOICE_ENUM_COUNT);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
index 20ce6a6..9bac136 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/ui/MediaSessionTabHelper.java
@@ -44,7 +44,12 @@
     private WebContentsObserver mWebContentsObserver;
     private int mPreviousVolumeControlStream = AudioManager.USE_DEFAULT_STREAM_TYPE;
     private MediaNotificationInfo.Builder mNotificationInfoBuilder = null;
-    private MediaMetadata mFallbackMetadata;
+    // The fallback title if |mPageMetadata| is null or its title is empty.
+    private String mFallbackTitle = null;
+    // The metadata set by the page.
+    private MediaMetadata mPageMetadata = null;
+    // The currently showing metadata.
+    private MediaMetadata mCurrentMetadata = null;
 
     private MediaNotificationListener mControlsListener = new MediaNotificationListener() {
         @Override
@@ -93,34 +98,22 @@
             }
 
             @Override
-            public void mediaSessionStateChanged(boolean isControllable, boolean isPaused,
-                    MediaMetadata metadata) {
+            public void mediaSessionStateChanged(boolean isControllable, boolean isPaused) {
                 if (!isControllable) {
                     hideNotification();
                     return;
                 }
 
-                mFallbackMetadata = null;
-
-                // The page's title is used as a placeholder if no title is specified in the
-                // metadata.
-                if (metadata == null || TextUtils.isEmpty(metadata.getTitle())) {
-                    mFallbackMetadata = new MediaMetadata(
-                            sanitizeMediaTitle(mTab.getTitle()),
-                            metadata == null ? "" : metadata.getArtist(),
-                            metadata == null ? "" : metadata.getAlbum());
-                    metadata = mFallbackMetadata;
-                }
-
                 Intent contentIntent = Tab.createBringTabToFrontIntent(mTab.getId());
                 if (contentIntent != null) {
                     contentIntent.putExtra(MediaNotificationUma.INTENT_EXTRA_NAME,
                             MediaNotificationUma.SOURCE_MEDIA);
                 }
 
+                mCurrentMetadata = getMetadata();
                 mNotificationInfoBuilder =
                         new MediaNotificationInfo.Builder()
-                                .setMetadata(metadata)
+                                .setMetadata(mCurrentMetadata)
                                 .setPaused(isPaused)
                                 .setOrigin(mOrigin)
                                 .setTabId(mTab.getId())
@@ -142,6 +135,12 @@
                     activity.setVolumeControlStream(AudioManager.STREAM_MUSIC);
                 }
             }
+
+            @Override
+            public void mediaSessionMetadataChanged(MediaMetadata metadata) {
+                mPageMetadata = metadata;
+                updateNotificationMetadata();
+            }
         };
     }
 
@@ -206,14 +205,11 @@
         @Override
         public void onTitleUpdated(Tab tab) {
             assert tab == mTab;
-            if (mNotificationInfoBuilder == null || mFallbackMetadata == null) return;
-
-            mFallbackMetadata = new MediaMetadata(mFallbackMetadata);
-            mFallbackMetadata.setTitle(sanitizeMediaTitle(mTab.getTitle()));
-            mNotificationInfoBuilder.setMetadata(mFallbackMetadata);
-
-            MediaNotificationManager.show(ContextUtils.getApplicationContext(),
-                    mNotificationInfoBuilder.build());
+            String newFallbackTitle = sanitizeMediaTitle(tab.getTitle());
+            if (!TextUtils.equals(mFallbackTitle, newFallbackTitle)) {
+                mFallbackTitle = newFallbackTitle;
+                updateNotificationMetadata();
+            }
         }
 
         @Override
@@ -303,4 +299,45 @@
         mFavicon = MediaNotificationManager.scaleIconForDisplay(icon);
         return true;
     }
+
+    /**
+     * Updates the metadata in media notification. This method should be called whenever
+     * |mPageMetadata| or |mFallbackTitle| is changed.
+     */
+    private void updateNotificationMetadata() {
+        if (mNotificationInfoBuilder == null) return;
+
+        MediaMetadata newMetadata = getMetadata();
+        if (mCurrentMetadata.equals(newMetadata)) return;
+
+        mCurrentMetadata = newMetadata;
+        mNotificationInfoBuilder.setMetadata(mCurrentMetadata);
+        MediaNotificationManager.show(
+                ContextUtils.getApplicationContext(), mNotificationInfoBuilder.build());
+    }
+
+    /**
+     * @return The up-to-date MediaSession metadata. Returns the cached object like |mPageMetadata|
+     * or |mCurrentMetadata| if it reflects the current state. Otherwise will return a new
+     * {@link MediaMetadata} object.
+     */
+    private MediaMetadata getMetadata() {
+        String title = mFallbackTitle;
+        String artist = "";
+        String album = "";
+        if (mPageMetadata != null) {
+            if (!TextUtils.isEmpty(mPageMetadata.getTitle())) return mPageMetadata;
+
+            artist = mPageMetadata.getArtist();
+            album = mPageMetadata.getAlbum();
+        }
+
+        if (mCurrentMetadata != null && TextUtils.equals(title, mCurrentMetadata.getTitle())
+                && TextUtils.equals(artist, mCurrentMetadata.getArtist())
+                && TextUtils.equals(album, mCurrentMetadata.getAlbum())) {
+            return mCurrentMetadata;
+        }
+
+        return new MediaMetadata(title, artist, album);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java
index 173f594..c9a7aef1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java
@@ -12,6 +12,7 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewStub;
 import android.widget.FrameLayout;
 
 import org.chromium.chrome.R;
@@ -81,9 +82,14 @@
     }
 
     @Override
-    public void onFinishInflate() {
+    public void initWithToolbar(int toolbarLayoutId) {
+        ViewStub toolbarStub = (ViewStub) findViewById(R.id.toolbar_stub);
+        toolbarStub.setLayoutResource(toolbarLayoutId);
+        toolbarStub.inflate();
+
         mToolbar = (Toolbar) findViewById(R.id.toolbar);
         mToolbarContainer = (ToolbarViewResourceFrameLayout) findViewById(R.id.toolbar_container);
+        mToolbarContainer.setToolbar(mToolbar);
         mMenuBtn = findViewById(R.id.menu_button);
 
         if (mToolbar instanceof ToolbarTablet) {
@@ -95,8 +101,6 @@
 
         assert mToolbar != null;
         assert mMenuBtn != null;
-
-        super.onFinishInflate();
     }
 
     @Override
@@ -141,8 +145,11 @@
 
         @Override
         protected ViewResourceAdapter createResourceAdapter() {
-            return new ToolbarViewResourceAdapter(
-                    this, (Toolbar) findViewById(R.id.toolbar));
+            return new ToolbarViewResourceAdapter(this);
+        }
+
+        public void setToolbar(Toolbar toolbar) {
+            ((ToolbarViewResourceAdapter) getResourceAdapter()).setToolbar(toolbar);
         }
 
         @Override
@@ -152,26 +159,32 @@
     }
 
     private static class ToolbarViewResourceAdapter extends ViewResourceAdapter {
-        private final int mToolbarActualHeightPx;
-        private final int mTabStripHeightPx;
         private final int[] mTempPosition = new int[2];
-
         private final View mToolbarContainer;
-        private final Toolbar mToolbar;
+
+        private Toolbar mToolbar;
+        private int mToolbarActualHeightPx;
+        private int mTabStripHeightPx;
 
         /** Builds the resource adapter for the toolbar. */
-        public ToolbarViewResourceAdapter(View toolbarContainer, Toolbar toolbar) {
+        public ToolbarViewResourceAdapter(View toolbarContainer) {
             super(toolbarContainer);
-
             mToolbarContainer = toolbarContainer;
+        }
+
+        /**
+         * Set the toolbar after it has been dynamically inflated.
+         * @param toolbar The browser's toolbar.
+         */
+        public void setToolbar(Toolbar toolbar) {
             mToolbar = toolbar;
             int containerHeightResId = R.dimen.control_container_height;
             if (mToolbar instanceof CustomTabToolbar) {
                 containerHeightResId = R.dimen.custom_tabs_control_container_height;
             }
-            mToolbarActualHeightPx = toolbarContainer.getResources().getDimensionPixelSize(
+            mToolbarActualHeightPx = mToolbarContainer.getResources().getDimensionPixelSize(
                     containerHeightResId);
-            mTabStripHeightPx = toolbarContainer.getResources().getDimensionPixelSize(
+            mTabStripHeightPx = mToolbarContainer.getResources().getDimensionPixelSize(
                     R.dimen.tab_strip_height);
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContext.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContext.java
new file mode 100644
index 0000000..99f30f2f
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContext.java
@@ -0,0 +1,57 @@
+// 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.
+
+package org.chromium.chrome.browser.vr_shell;
+
+import android.app.Activity;
+import android.os.StrictMode;
+
+import com.google.vr.ndk.base.GvrLayout;
+
+import org.chromium.base.Log;
+import org.chromium.base.annotations.UsedByReflection;
+
+/**
+ * Creates an active GvrContext from a detached GvrLayout. This is used by magic window mode.
+ */
+@UsedByReflection("VrShellDelegate.java")
+public class NonPresentingGvrContext implements NonPresentingGvrContextInterface {
+    private static final String TAG = "NPGvrContext";
+    private GvrLayout mGvrLayout;
+
+    @UsedByReflection("VrShellDelegate.java")
+    public NonPresentingGvrContext(Activity activity) {
+        mGvrLayout = new GvrLayout(activity);
+    }
+
+    @Override
+    public long getNativeGvrContext() {
+        long nativeGvrContext = 0;
+        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+        try {
+            nativeGvrContext = mGvrLayout.getGvrApi().getNativeGvrContext();
+        } catch (Exception ex) {
+            Log.e(TAG, "Unable to instantiate GvrApi", ex);
+            return 0;
+        } finally {
+            StrictMode.setThreadPolicy(oldPolicy);
+        }
+        return nativeGvrContext;
+    }
+
+    @Override
+    public void resume() {
+        mGvrLayout.onResume();
+    }
+
+    @Override
+    public void pause() {
+        mGvrLayout.onPause();
+    }
+
+    @Override
+    public void shutdown() {
+        mGvrLayout.shutdown();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContextInterface.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContextInterface.java
new file mode 100644
index 0000000..614e6fe6
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContextInterface.java
@@ -0,0 +1,31 @@
+// 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.
+
+package org.chromium.chrome.browser.vr_shell;
+
+/**
+ * Abstracts away the NonPresentingGvrContext class, which may or may not be present at runtime
+ * depending on compile flags.
+ */
+public interface NonPresentingGvrContextInterface {
+    /**
+     * Returns the native gvr context.
+     */
+    long getNativeGvrContext();
+
+    /**
+     * Must be called when activity resumes.
+     */
+    void resume();
+
+    /**
+     * Must be called when activity pauses.
+     */
+    void pause();
+
+    /**
+     * Shutdown the native gvr context.
+     */
+    void shutdown();
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java
index e7e2499..ec33e49 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java
@@ -11,6 +11,7 @@
 import static android.opengl.GLES20.glGenTextures;
 import static android.opengl.GLES20.glTexParameteri;
 
+import android.annotation.SuppressLint;
 import android.app.Activity;
 import android.graphics.SurfaceTexture;
 import android.graphics.SurfaceTexture.OnFrameAvailableListener;
@@ -26,9 +27,11 @@
 import com.google.vr.ndk.base.AndroidCompat;
 import com.google.vr.ndk.base.GvrLayout;
 
+import org.chromium.base.CommandLine;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.UsedByReflection;
+import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.ChromeVersionInfo;
 import org.chromium.chrome.browser.WebContentsFactory;
 import org.chromium.chrome.browser.tab.Tab;
@@ -127,6 +130,18 @@
         mNativeVrShell = nativeInit(mContentCVC.getWebContents(),
                 mContentVrWindowAndroid.getNativePointer(),
                 mUiContents, mUiVrWindowAndroid.getNativePointer());
+        mGlSurfaceView.setOnTouchListener(new View.OnTouchListener() {
+            @Override
+            @SuppressLint("ClickableViewAccessibility")
+            public boolean onTouch(View v, MotionEvent event) {
+                if (!CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_VR_SHELL_DEV)
+                        && event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                    nativeOnTriggerEvent(mNativeVrShell);
+                    return true;
+                }
+                return false;
+            }
+        });
 
         uiContentView.setVisibility(View.VISIBLE);
         mUiCVC.onShow();
@@ -251,11 +266,14 @@
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent event) {
-        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+        // Normally, touch event is dispatched to presentation view only if the phone is paired with
+        // a Cardboard viewer. This is annoying when we just want to quickly verify a Cardboard
+        // behavior. This allows us to trigger cardboard trigger event without pair to a Cardboard.
+        if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_VR_SHELL_DEV)
+                && event.getActionMasked() == MotionEvent.ACTION_DOWN) {
             nativeOnTriggerEvent(mNativeVrShell);
         }
-        // Don't mark this as handled so that Daydream screen alignment still functions.
-        return false;
+        return super.dispatchTouchEvent(event);
     }
 
     @Override
@@ -286,6 +304,7 @@
         super.shutdown();
         if (mNativeVrShell != 0) {
             nativeDestroy(mNativeVrShell);
+            mNativeVrShell = 0;
         }
         if (mContentFrameListener != null && mContentFrameListener.mSurfaceTexture != null) {
             mContentFrameListener.mSurfaceTexture.release();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
index 85cef3a..4ff15e4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java
@@ -32,10 +32,12 @@
 
     private ChromeTabbedActivity mActivity;
 
-    private boolean mVrShellEnabled;
+    private boolean mVrEnabled;
 
     private Class<? extends VrShellInterface> mVrShellClass;
+    private Class<? extends NonPresentingGvrContextInterface> mNonPresentingGvrContextClass;
     private VrShellInterface mVrShell;
+    private NonPresentingGvrContextInterface mNonPresentingGvrContext;
     private boolean mInVr;
     private int mRestoreSystemUiVisibilityFlag = -1;
     private String mVrExtra;
@@ -44,14 +46,13 @@
     public VrShellDelegate(ChromeTabbedActivity activity) {
         mActivity = activity;
 
-        mVrShellClass = maybeFindVrShell();
-        if (mVrShellClass != null) {
-            mVrShellEnabled = true;
+        mVrEnabled = maybeFindVrClasses();
+        if (mVrEnabled) {
             try {
                 mVrExtra = (String) mVrShellClass.getField("VR_EXTRA").get(null);
             } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException e) {
                 Log.e(TAG, "Unable to read VR_EXTRA field", e);
-                mVrShellEnabled = false;
+                mVrEnabled = false;
             }
         }
     }
@@ -61,18 +62,24 @@
      * class can be initialized.
      */
     public void onNativeLibraryReady() {
-        if (mVrShellEnabled) {
+        if (mVrEnabled) {
             mNativeVrShellDelegate = nativeInit();
         }
     }
 
     @SuppressWarnings("unchecked")
-    private Class<? extends VrShellInterface> maybeFindVrShell() {
+    private boolean maybeFindVrClasses() {
         try {
-            return (Class<? extends VrShellInterface>) Class
-                    .forName("org.chromium.chrome.browser.vr_shell.VrShell");
+            mVrShellClass = (Class<? extends VrShellInterface>) Class.forName(
+                    "org.chromium.chrome.browser.vr_shell.VrShell");
+            mNonPresentingGvrContextClass =
+                    (Class<? extends NonPresentingGvrContextInterface>) Class.forName(
+                            "org.chromium.chrome.browser.vr_shell.NonPresentingGvrContext");
+            return true;
         } catch (ClassNotFoundException e) {
-            return null;
+            mVrShellClass = null;
+            mNonPresentingGvrContextClass = null;
+            return false;
         }
     }
 
@@ -86,7 +93,7 @@
      */
     @CalledByNative
     public boolean enterVRIfNecessary(boolean inWebVR) {
-        if (!mVrShellEnabled || mNativeVrShellDelegate == 0) return false;
+        if (!mVrEnabled || mNativeVrShellDelegate == 0) return false;
         Tab tab = mActivity.getActivityTab();
         // TODO(mthiesse): When we have VR UI for opening new tabs, etc., allow VR Shell to be
         // entered without any current tabs.
@@ -124,23 +131,44 @@
     /**
      * Resumes VR Shell.
      */
-    public void resumeVR() {
-        setupVrModeWindowFlags();
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
-        try {
-            mVrShell.resume();
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "Unable to resume VrShell", e);
-        } finally {
-            StrictMode.setThreadPolicy(oldPolicy);
+    public void maybeResumeVR() {
+        // TODO(bshe): Ideally, we do not need two gvr context exist at the same time. We can
+        // probably shutdown non presenting gvr when presenting and create a new one after exit
+        // presenting. See crbug.com/655242
+        if (mNonPresentingGvrContext != null) {
+            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+            try {
+                mNonPresentingGvrContext.resume();
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Unable to resume mNonPresentingGvrContext", e);
+            } finally {
+                StrictMode.setThreadPolicy(oldPolicy);
+            }
+        }
+
+        if (mInVr) {
+            setupVrModeWindowFlags();
+            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
+            try {
+                mVrShell.resume();
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Unable to resume VrShell", e);
+            } finally {
+                StrictMode.setThreadPolicy(oldPolicy);
+            }
         }
     }
 
     /**
      * Pauses VR Shell.
      */
-    public void pauseVR() {
-        mVrShell.pause();
+    public void maybePauseVR() {
+        if (mNonPresentingGvrContext != null) {
+            mNonPresentingGvrContext.pause();
+        }
+        if (mInVr) {
+            mVrShell.pause();
+        }
     }
 
     /**
@@ -159,6 +187,30 @@
         return true;
     }
 
+    @CalledByNative
+    private long createNonPresentingNativeContext() {
+        if (!mVrEnabled) return 0;
+
+        try {
+            Constructor<?> nonPresentingGvrContextConstructor =
+                    mNonPresentingGvrContextClass.getConstructor(Activity.class);
+            mNonPresentingGvrContext =
+                    (NonPresentingGvrContextInterface)
+                            nonPresentingGvrContextConstructor.newInstance(mActivity);
+        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
+                | InvocationTargetException | NoSuchMethodException e) {
+            Log.e(TAG, "Unable to instantiate NonPresentingGvrContext", e);
+            return 0;
+        }
+        return mNonPresentingGvrContext.getNativeGvrContext();
+    }
+
+    @CalledByNative
+    private void shutdownNonPresentingNativeContext() {
+        mNonPresentingGvrContext.shutdown();
+        mNonPresentingGvrContext = null;
+    }
+
     /**
      * Exits VR Shell, performing all necessary cleanup.
      */
@@ -256,7 +308,7 @@
      * @return Whether or not VR Shell is currently enabled.
      */
     public boolean isVrShellEnabled() {
-        return mVrShellEnabled;
+        return mVrEnabled;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappControlContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappControlContainer.java
index ff13184..abbe8098 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappControlContainer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/webapps/WebappControlContainer.java
@@ -27,6 +27,10 @@
     }
 
     @Override
+    public void initWithToolbar(int toolbarLayoutId) {
+    }
+
+    @Override
     public ViewResourceAdapter getToolbarResourceAdapter() {
         return getResourceAdapter();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ControlContainer.java b/chrome/android/java/src/org/chromium/chrome/browser/widget/ControlContainer.java
index 23cb16d..ff803c5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ControlContainer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/widget/ControlContainer.java
@@ -16,6 +16,12 @@
  */
 public interface ControlContainer {
     /**
+     * Initialize the control container with the specified toolbar.
+     * @param toolbarLayoutId The ID of the toolbar layout to use.
+     */
+    void initWithToolbar(int toolbarLayoutId);
+
+    /**
      * @return The {@link ViewResourceAdapter} that exposes this {@link View} as a CC resource.
      */
     ViewResourceAdapter getToolbarResourceAdapter();
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 64e6b67..e9185f68 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -981,6 +981,7 @@
   "java/src/org/chromium/chrome/browser/util/PlatformUtil.java",
   "java/src/org/chromium/chrome/browser/util/UrlUtilities.java",
   "java/src/org/chromium/chrome/browser/util/ViewUtils.java",
+  "java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContextInterface.java",
   "java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java",
   "java/src/org/chromium/chrome/browser/vr_shell/VrShellInterface.java",
   "java/src/org/chromium/chrome/browser/webapps/ActivityAssigner.java",
@@ -1084,6 +1085,7 @@
 ]
 
 chrome_vr_java_sources = [
+  "java/src/org/chromium/chrome/browser/vr_shell/NonPresentingGvrContext.java",
   "java/src/org/chromium/chrome/browser/vr_shell/VrShell.java",
   "java/src/org/chromium/chrome/browser/vr_shell/VrWindowAndroid.java",
 ]
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
index 92420e8b..de7a9ad9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/ExternalNavigationHandlerTest.java
@@ -785,6 +785,21 @@
                 .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
     }
 
+
+    @SmallTest
+    public void testPdfDownloadHappensInChrome() {
+        checkUrl(CALENDAR_URL + "/file.pdf")
+            .expecting(OverrideUrlLoadingResult.NO_OVERRIDE, IGNORE);
+    }
+
+    @SmallTest
+    public void testIntentToPdfFileOpensApp() {
+        checkUrl("intent://yoursite.com/mypdf.pdf#Intent;action=VIEW;category=BROWSABLE;"
+                + "scheme=http;package=com.adobe.reader;end;")
+                .expecting(OverrideUrlLoadingResult.OVERRIDE_WITH_EXTERNAL_INTENT,
+                        START_OTHER_ACTIVITY);
+    }
+
     @SmallTest
     public void testReferrerExtra() {
         String referrer = "http://www.google.com";
@@ -1161,7 +1176,7 @@
 
         @Override
         public boolean isPdfDownload(String url) {
-            return false;
+            return url.endsWith(".pdf");
         }
 
         @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/NotificationTitleUpdatedTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/NotificationTitleUpdatedTest.java
index 3ebaf1e..2720de1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/NotificationTitleUpdatedTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/ui/NotificationTitleUpdatedTest.java
@@ -70,12 +70,14 @@
     }
 
     private void doTestMediaMetadataSetsTitle() throws InterruptedException {
-        simulateMediaSessionStateChanged(mTab, true, false, new MediaMetadata("title2", "", ""));
+        simulateMediaSessionStateChanged(mTab, true, false);
+        simulateMediaSessionMetadataChanged(mTab, new MediaMetadata("title2", "", ""));
         assertTitleMatches("title2");
     }
 
     private void doTestMediaMetadataOverridesTitle() throws InterruptedException {
-        simulateMediaSessionStateChanged(mTab, true, false, new MediaMetadata("title2", "", ""));
+        simulateMediaSessionStateChanged(mTab, true, false);
+        simulateMediaSessionMetadataChanged(mTab, new MediaMetadata("title2", "", ""));
         assertTitleMatches("title2");
 
         simulateUpdateTitle(mTab, "title3");
@@ -145,25 +147,31 @@
 
     private void simulateMediaSessionStateChanged(
             final Tab tab, final boolean isControllable, final boolean isSuspended) {
-        simulateMediaSessionStateChanged(
-                tab, isControllable, isSuspended, new MediaMetadata("", "", ""));
-    }
-
-    private void simulateMediaSessionStateChanged(final Tab tab, final boolean isControllable,
-            final boolean isSuspended, final MediaMetadata metadata) {
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
                 @Override
                 public void run() {
                     ObserverList.RewindableIterator<WebContentsObserver> observers =
                             tab.getWebContents().getObserversForTesting();
                     while (observers.hasNext()) {
-                        observers.next().mediaSessionStateChanged(
-                                isControllable, isSuspended, metadata);
+                        observers.next().mediaSessionStateChanged(isControllable, isSuspended);
                     }
                 }
             });
     }
 
+    private void simulateMediaSessionMetadataChanged(final Tab tab, final MediaMetadata metadata) {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                ObserverList.RewindableIterator<WebContentsObserver> observers =
+                        tab.getWebContents().getObserversForTesting();
+                while (observers.hasNext()) {
+                    observers.next().mediaSessionMetadataChanged(metadata);
+                }
+            }
+        });
+    }
+
     private void simulateUpdateTitle(Tab tab, String title) {
         try {
             TabTitleObserver observer = new TabTitleObserver(tab, title);
diff --git a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
index fd9e2c4..178d7d1 100644
--- a/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
+++ b/chrome/browser/android/offline_pages/downloads/offline_page_download_bridge.cc
@@ -46,16 +46,6 @@
 
 namespace {
 
-void SavePageCallback(const DownloadUIItem& item,
-                      OfflinePageModel::SavePageResult result,
-                      int64_t offline_id) {
-  OfflinePageNotificationBridge notification_bridge;
-  if (result == SavePageResult::SUCCESS)
-    notification_bridge.NotifyDownloadSuccessful(item);
-  else
-    notification_bridge.NotifyDownloadFailed(item);
-}
-
 // TODO(dewittj): Move to Download UI Adapter.
 content::WebContents* GetWebContentsFromJavaTab(
     const ScopedJavaGlobalRef<jobject>& j_tab_ref) {
@@ -81,74 +71,65 @@
   return OfflinePageModelFactory::GetForBrowserContext(profile);
 }
 
-void SavePageIfNavigatedToURL(const GURL& query_url,
-                              const ScopedJavaGlobalRef<jobject>& j_tab_ref) {
+void SavePageIfNotNavigatedAway(const GURL& original_url,
+                                const ScopedJavaGlobalRef<jobject>& j_tab_ref) {
   content::WebContents* web_contents = GetWebContentsFromJavaTab(j_tab_ref);
   if (!web_contents)
     return;
 
-  // This doesn't detect navigations to the same URL, only that we are looking
-  // at a completely different page.
+  // This ignores fragment differences in URLs, bails out only if tab has
+  // navigated away and not just scrolled to a fragment.
   GURL url = web_contents->GetLastCommittedURL();
-  if (!OfflinePageUtils::EqualsIgnoringFragment(url, query_url))
+  if (!OfflinePageUtils::EqualsIgnoringFragment(url, original_url))
     return;
 
   offline_pages::ClientId client_id;
   client_id.name_space = offline_pages::kDownloadNamespace;
   client_id.id = base::GenerateGUID();
+  int64_t request_id = OfflinePageModel::kInvalidOfflineId;
 
-  Profile* profile =
-      Profile::FromBrowserContext(web_contents->GetBrowserContext())
-          ->GetOriginalProfile();
-
-  OfflinePageNotificationBridge notification_bridge;
-
-  // If the page is not loaded enough to be captured, submit a background loader
-  // request instead.
-  offline_pages::RecentTabHelper* tab_helper =
-      RecentTabHelper::FromWebContents(web_contents);
-  if (tab_helper && !tab_helper->is_page_ready_for_snapshot() &&
-      offline_pages::IsBackgroundLoaderForDownloadsEnabled()) {
-    // TODO(dimich): Improve this to wait for the page load if it is still going
-    // on. Pre-submit the request and if the load finishes and capture happens,
-    // remove request.
+  if (offline_pages::IsBackgroundLoaderForDownloadsEnabled()) {
+    // Post disabled request before passing the download task to the tab helper.
+    // This will keep the request persisted in case Chrome is evicted from RAM
+    // or closed by the user.
+    // Note: the 'disabled' status is not persisted (stored in memory) so it
+    // automatically resets if Chrome is re-started.
     offline_pages::RequestCoordinator* request_coordinator =
-        offline_pages::RequestCoordinatorFactory::GetForBrowserContext(profile);
-    request_coordinator->SavePageLater(
+        offline_pages::RequestCoordinatorFactory::GetForBrowserContext(
+            web_contents->GetBrowserContext());
+    request_id = request_coordinator->SavePageLater(
         url, client_id, true,
-        RequestCoordinator::RequestAvailability::ENABLED_FOR_OFFLINER);
-
-    notification_bridge.ShowDownloadingToast();
-    return;
+        RequestCoordinator::RequestAvailability::DISABLED_FOR_OFFLINER);
   }
 
-  // Page is ready, capture it right from the tab.
-  offline_pages::OfflinePageModel* offline_page_model =
-      OfflinePageModelFactory::GetForBrowserContext(profile);
-  if (!offline_page_model)
+  // Pass request_id to the current tab's helper to attempt download right from
+  // the tab. If unsuccessful, it'll enable the already-queued request for
+  // background offliner. Same will happen if Chrome is terminated since
+  // 'disabled' status of the request is RAM-stored info.
+  offline_pages::RecentTabHelper* tab_helper =
+      RecentTabHelper::FromWebContents(web_contents);
+  if (!tab_helper) {
+    if (request_id != OfflinePageModel::kInvalidOfflineId) {
+      offline_pages::RequestCoordinator* request_coordinator =
+          offline_pages::RequestCoordinatorFactory::GetForBrowserContext(
+              web_contents->GetBrowserContext());
+      request_coordinator->EnableForOffliner(request_id);
+    }
     return;
+  }
+  tab_helper->ObserveAndDownloadCurrentPage(client_id, request_id);
 
-  auto archiver =
-      base::MakeUnique<offline_pages::OfflinePageMHTMLArchiver>(web_contents);
-
-  DownloadUIItem item;
-  item.guid = client_id.id;
-  item.url = url;
-
-  notification_bridge.NotifyDownloadProgress(item);
-
+  OfflinePageNotificationBridge notification_bridge;
   notification_bridge.ShowDownloadingToast();
-  offline_page_model->SavePage(url, client_id, 0l, std::move(archiver),
-                               base::Bind(&SavePageCallback, item));
 }
 
-void OnDeletePagesForInfoBar(const GURL& query_url,
+void OnDeletePagesForInfoBar(const GURL& original_url,
                              const ScopedJavaGlobalRef<jobject>& j_tab_ref,
                              DeletePageResult result) {
-  SavePageIfNavigatedToURL(query_url, j_tab_ref);
+  SavePageIfNotNavigatedAway(original_url, j_tab_ref);
 }
 
-void DeletePagesForOverwrite(const GURL& query_url,
+void DeletePagesForOverwrite(const GURL& original_url,
                              const ScopedJavaGlobalRef<jobject>& j_tab_ref,
                              const MultipleOfflinePageItemResult& pages) {
   OfflinePageModel* model = GetOfflinePageModelFromJavaTab(j_tab_ref);
@@ -164,15 +145,16 @@
   }
 
   model->DeletePagesByOfflineId(
-      offline_ids, base::Bind(&OnDeletePagesForInfoBar, query_url, j_tab_ref));
+      offline_ids, base::Bind(
+          &OnDeletePagesForInfoBar, original_url, j_tab_ref));
 }
 
-void OnInfoBarAction(const GURL& query_url,
+void OnInfoBarAction(const GURL& original_url,
                      const ScopedJavaGlobalRef<jobject>& j_tab_ref,
                      OfflinePageInfoBarDelegate::Action action) {
   switch (action) {
     case OfflinePageInfoBarDelegate::Action::CREATE_NEW:
-      SavePageIfNavigatedToURL(query_url, j_tab_ref);
+      SavePageIfNotNavigatedAway(original_url, j_tab_ref);
       break;
     case OfflinePageInfoBarDelegate::Action::OVERWRITE:
       OfflinePageModel* offline_page_model =
@@ -181,14 +163,14 @@
         return;
 
       offline_page_model->GetPagesByOnlineURL(
-          query_url,
-          base::Bind(&DeletePagesForOverwrite, query_url, j_tab_ref));
+          original_url,
+          base::Bind(&DeletePagesForOverwrite, original_url, j_tab_ref));
       break;
   }
 }
 
 void RequestQueueDuplicateCheckDone(
-    const GURL& query_url,
+    const GURL& original_url,
     const ScopedJavaGlobalRef<jobject>& j_tab_ref,
     bool has_duplicates) {
   if (has_duplicates) {
@@ -202,10 +184,10 @@
     return;
   }
 
-  SavePageIfNavigatedToURL(query_url, j_tab_ref);
+  SavePageIfNotNavigatedAway(original_url, j_tab_ref);
 }
 
-void ModelDuplicateCheckDone(const GURL& query_url,
+void ModelDuplicateCheckDone(const GURL& original_url,
                              const ScopedJavaGlobalRef<jobject>& j_tab_ref,
                              const std::string& downloads_label,
                              bool has_duplicates) {
@@ -215,16 +197,16 @@
 
   if (has_duplicates) {
     OfflinePageInfoBarDelegate::Create(
-        base::Bind(&OnInfoBarAction, query_url, j_tab_ref), downloads_label,
-        query_url.spec(), web_contents);
+        base::Bind(&OnInfoBarAction, original_url, j_tab_ref), downloads_label,
+        original_url.spec(), web_contents);
     return;
   }
 
   OfflinePageUtils::CheckExistenceOfRequestsWithURL(
       Profile::FromBrowserContext(web_contents->GetBrowserContext())
           ->GetOriginalProfile(),
-      kDownloadNamespace, query_url,
-      base::Bind(&RequestQueueDuplicateCheckDone, query_url, j_tab_ref));
+      kDownloadNamespace, original_url,
+      base::Bind(&RequestQueueDuplicateCheckDone, original_url, j_tab_ref));
 }
 
 void ToJavaOfflinePageDownloadItemList(
diff --git a/chrome/browser/android/offline_pages/recent_tab_helper.cc b/chrome/browser/android/offline_pages/recent_tab_helper.cc
index dd4badbc..9ab53f9 100644
--- a/chrome/browser/android/offline_pages/recent_tab_helper.cc
+++ b/chrome/browser/android/offline_pages/recent_tab_helper.cc
@@ -15,9 +15,12 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/time/time.h"
+#include "chrome/browser/android/offline_pages/downloads/offline_page_notification_bridge.h"
 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h"
 #include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
 #include "chrome/browser/android/offline_pages/offline_page_utils.h"
+#include "chrome/browser/android/offline_pages/request_coordinator_factory.h"
+#include "components/offline_pages/background/request_coordinator.h"
 #include "components/offline_pages/client_namespace_constants.h"
 #include "components/offline_pages/offline_page_feature.h"
 #include "components/offline_pages/offline_page_item.h"
@@ -70,6 +73,33 @@
   delegate_ = std::move(delegate);
 }
 
+void RecentTabHelper::ObserveAndDownloadCurrentPage(
+    const ClientId& client_id, int64_t request_id) {
+  EnsureInitialized();
+  download_info_ = base::MakeUnique<DownloadPageInfo>(client_id, request_id);
+
+  // If this tab helper is not enabled, immediately give the job back to
+  // RequestCoordinator.
+  if (!snapshots_enabled_ || !page_model_) {
+    ReportDownloadStatusToRequestCoordinator();
+    download_info_.reset();
+    return;
+  }
+
+  // No snapshots yet happened on the current page - return and wait for some.
+  if (!is_page_ready_for_snapshot_)
+    return;
+
+  // If snapshot already happened and we missed it, go ahead and snapshot now.
+  page_model_->SavePage(
+      web_contents()->GetLastCommittedURL(),
+      client_id,
+      request_id,
+      delegate_->CreatePageArchiver(web_contents()),
+      base::Bind(&RecentTabHelper::SavePageCallback,
+                 weak_ptr_factory_.GetWeakPtr()));
+}
+
 // Initialize lazily. It needs TabAndroid for initialization, which is also a
 // TabHelper - so can't initialize in constructor because of uncertain order
 // of creation of TabHelpers.
@@ -108,12 +138,26 @@
 
   // Cancel tasks in flight that relate to the previous page.
   weak_ptr_factory_.InvalidateWeakPtrs();
-  is_page_ready_for_snapshot_ = false;
 
   EnsureInitialized();
   if (!snapshots_enabled_)
     return;
 
+  // We navigated to a different page, lets report progress to Background
+  // Offliner.
+  if (download_info_ && !navigation_handle->IsSamePage()) {
+    ReportDownloadStatusToRequestCoordinator();
+  }
+
+  if (offline_pages::IsOffliningRecentPagesEnabled()) {
+    int64_t proposed_id = OfflinePageModel::kInvalidOfflineId;
+    download_info_ = base::MakeUnique<DownloadPageInfo>(
+        GetRecentPagesClientId(), proposed_id);
+  } else {
+    download_info_.reset();
+  }
+
+  is_page_ready_for_snapshot_ = false;
 
   // New navigation, new snapshot session.
   snapshot_url_ = web_contents()->GetLastCommittedURL();
@@ -141,6 +185,14 @@
   snapshot_controller_->DocumentOnLoadCompletedInMainFrame();
 }
 
+void RecentTabHelper::WebContentsDestroyed() {
+  // WebContents (and maybe Tab) is destroyed, report status to Offliner.
+  if (!download_info_)
+    return;
+  ReportDownloadStatusToRequestCoordinator();
+}
+
+
 // This starts a sequence of async operations chained through callbacks:
 // - compute the set of old 'last_n' pages that have to be purged
 // - delete the pages found in the previous step
@@ -152,39 +204,44 @@
 
   if (!snapshots_enabled_ ||
       !page_model_ ||
-      !offline_pages::IsOffliningRecentPagesEnabled()) {
+      !download_info_) {
     ReportSnapshotCompleted();
     return;
   }
 
   // Remove previously captured pages for this tab.
   page_model_->GetOfflineIdsForClientId(
-    client_id(),
+    GetRecentPagesClientId(),
     base::Bind(&RecentTabHelper::ContinueSnapshotWithIdsToPurge,
                weak_ptr_factory_.GetWeakPtr()));
 }
 
 void RecentTabHelper::ContinueSnapshotWithIdsToPurge(
     const std::vector<int64_t>& page_ids) {
+  if (!download_info_)
+    return;
+
+  // Also remove the download page if this is not a first snapshot.
+  std::vector<int64_t> ids(page_ids);
+  ids.push_back(download_info_->request_id_);
+
   page_model_->DeletePagesByOfflineId(
-      page_ids, base::Bind(&RecentTabHelper::ContinueSnapshotAfterPurge,
-                           weak_ptr_factory_.GetWeakPtr()));
+      ids, base::Bind(&RecentTabHelper::ContinueSnapshotAfterPurge,
+                      weak_ptr_factory_.GetWeakPtr()));
 }
 
 void RecentTabHelper::ContinueSnapshotAfterPurge(
     OfflinePageModel::DeletePageResult result) {
-  if (result != OfflinePageModel::DeletePageResult::SUCCESS) {
-    // If previous pages can't be deleted, don't add new ones.
+  if (!download_info_ ||
+      result != OfflinePageModel::DeletePageResult::SUCCESS ||
+      !IsSamePage()) {
     ReportSnapshotCompleted();
     return;
   }
 
-  if (!IsSamePage()) {
-    ReportSnapshotCompleted();
-    return;
-  }
-
-  page_model_->SavePage(snapshot_url_, client_id(), 0l,
+  page_model_->SavePage(snapshot_url_,
+                        download_info_->client_id_,
+                        download_info_->request_id_,
                         delegate_->CreatePageArchiver(web_contents()),
                         base::Bind(&RecentTabHelper::SavePageCallback,
                                    weak_ptr_factory_.GetWeakPtr()));
@@ -192,11 +249,39 @@
 
 void RecentTabHelper::SavePageCallback(OfflinePageModel::SavePageResult result,
                                        int64_t offline_id) {
+  if (!download_info_)
+    return;
+  download_info_->page_snapshot_completed_ =
+      (result == SavePageResult::SUCCESS);
   ReportSnapshotCompleted();
 }
 
 void RecentTabHelper::ReportSnapshotCompleted() {
   snapshot_controller_->PendingSnapshotCompleted();
+  // Tell RequestCoordinator how the request should be processed further.
+  ReportDownloadStatusToRequestCoordinator();
+}
+
+void RecentTabHelper::ReportDownloadStatusToRequestCoordinator() {
+  if (!download_info_)
+    return;
+
+  if (download_info_->request_id_ == OfflinePageModel::kInvalidOfflineId)
+    return;
+
+  RequestCoordinator* request_coordinator =
+      RequestCoordinatorFactory::GetForBrowserContext(
+          web_contents()->GetBrowserContext());
+  if (!request_coordinator)
+    return;
+
+  // It is OK to call these methods more then once, depending on
+  // number of snapshots attempted in this tab helper. If the request_id is not
+  // in the list of RequestCoordinator, these calls have no effect.
+  if (download_info_->page_snapshot_completed_)
+    request_coordinator->MarkRequestCompleted(download_info_->request_id_);
+  else
+    request_coordinator->EnableForOffliner(download_info_->request_id_);
 }
 
 bool RecentTabHelper::IsSamePage() const {
@@ -204,7 +289,7 @@
          (web_contents()->GetLastCommittedURL() == snapshot_url_);
 }
 
-ClientId RecentTabHelper::client_id() const {
+ClientId RecentTabHelper::GetRecentPagesClientId() const {
   return ClientId(kLastNNamespace, tab_id_);
 }
 
diff --git a/chrome/browser/android/offline_pages/recent_tab_helper.h b/chrome/browser/android/offline_pages/recent_tab_helper.h
index ceb9571..1aeffb1 100644
--- a/chrome/browser/android/offline_pages/recent_tab_helper.h
+++ b/chrome/browser/android/offline_pages/recent_tab_helper.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
+#include "components/offline_pages/downloads/download_ui_item.h"
 #include "components/offline_pages/offline_page_model.h"
 #include "components/offline_pages/snapshot_controller.h"
 #include "content/public/browser/web_contents_observer.h"
@@ -38,6 +39,7 @@
       content::NavigationHandle* navigation_handle) override;
   void DocumentAvailableInMainFrame() override;
   void DocumentOnLoadCompletedInMainFrame() override;
+  void WebContentsDestroyed() override;
 
   // SnapshotController::Client
   void StartSnapshot() override;
@@ -55,34 +57,69 @@
   };
   void SetDelegate(std::unique_ptr<RecentTabHelper::Delegate> delegate);
 
-  bool is_page_ready_for_snapshot() const {
-    return is_page_ready_for_snapshot_;
-  }
+  // Support for Download Page feature. The Download Page button does this:
+  // 1. Creates suspended request for Background Offliner.
+  // 2. Calls this method with properly filled ClientId.
+  // 3. This tab helper observes the page load and captures the page
+  //    if the load progresses far enough, as indicated by SnapshotController.
+  // 4. If capture is successful, this tab helper removes the suspended request.
+  //    Otherwise (navigation to other page, close tab) tab helper un-suspends
+  //    the request so the Background Offliner starts working on it.
+  // 5. If Chrome is killed at any point, next time Background Offliner loads
+  //    it converts all suspended requests from last session into active.
+  void ObserveAndDownloadCurrentPage(const ClientId& client_id,
+                                     int64_t request_id);
 
  private:
+  // Keeps client_id/request_id that will be used for the offline snapshot.
+  struct DownloadPageInfo {
+   public:
+    DownloadPageInfo(const ClientId& client_id,
+                     int64_t request_id)
+        : client_id_(client_id),
+          request_id_(request_id),
+          page_snapshot_completed_(false) {}
+
+    // The ClientID to go with the offline page.
+    ClientId client_id_;
+    // Id of the suspended request in Background Offliner. Used to un-suspend
+    // the request if the capture of the current page was not possible (e.g.
+    // the user navigated to another page before current one was loaded).
+    // 0 if this is a "last_1" info.
+    int64_t request_id_;
+    // True if there was at least one snapshot successfully completed.
+    bool page_snapshot_completed_;
+  };
+
   explicit RecentTabHelper(content::WebContents* web_contents);
   friend class content::WebContentsUserData<RecentTabHelper>;
 
-
   void EnsureInitialized();
   void ContinueSnapshotWithIdsToPurge(const std::vector<int64_t>& page_ids);
   void ContinueSnapshotAfterPurge(OfflinePageModel::DeletePageResult result);
   void SavePageCallback(OfflinePageModel::SavePageResult result,
                         int64_t offline_id);
-
   void ReportSnapshotCompleted();
+  void ReportDownloadStatusToRequestCoordinator();
   bool IsSamePage() const;
-  ClientId client_id() const;
+  ClientId GetRecentPagesClientId() const;
 
   // Page model is a service, no ownership. Can be null - for example, in
   // case when tab is in incognito profile.
   OfflinePageModel* page_model_;
+
   // If false, never make snapshots off the attached WebContents.
   // Not page-specific.
   bool snapshots_enabled_;
+
   // Becomes true during navigation if the page is ready for snapshot as
   // indicated by at least one callback from SnapshotController.
   bool is_page_ready_for_snapshot_;
+
+  // Info for the offline page to capture. Null if the tab is not capturing
+  // current page.
+  std::unique_ptr<DownloadPageInfo> download_info_;
+
   // If empty, the tab does not have AndroidId and can not capture pages.
   std::string tab_id_;
 
diff --git a/chrome/browser/android/offline_pages/recent_tab_helper_unittest.cc b/chrome/browser/android/offline_pages/recent_tab_helper_unittest.cc
index cc40733..8d484ebf2 100644
--- a/chrome/browser/android/offline_pages/recent_tab_helper_unittest.cc
+++ b/chrome/browser/android/offline_pages/recent_tab_helper_unittest.cc
@@ -211,10 +211,8 @@
 
 TEST_F(RecentTabHelperTest, SimpleCapture) {
   NavigateAndCommit(kTestPageUrl);
-  EXPECT_FALSE(recent_tab_helper()->is_page_ready_for_snapshot());
   recent_tab_helper()->DocumentOnLoadCompletedInMainFrame();
   RunUntilIdle();
-  EXPECT_TRUE(recent_tab_helper()->is_page_ready_for_snapshot());
   EXPECT_TRUE(model()->is_loaded());
   GetAllPages();
   EXPECT_EQ(1U, all_pages().size());
@@ -313,4 +311,20 @@
   EXPECT_EQ(0U, all_pages().size());
 }
 
+TEST_F(RecentTabHelperTest, DownloadRequest) {
+  NavigateAndCommit(kTestPageUrl);
+  recent_tab_helper()->ObserveAndDownloadCurrentPage(
+      ClientId("download", "id1"), 153l);
+  recent_tab_helper()->DocumentOnLoadCompletedInMainFrame();
+  RunUntilIdle();
+  EXPECT_TRUE(model()->is_loaded());
+  GetAllPages();
+  EXPECT_EQ(1U, all_pages().size());
+  const OfflinePageItem& page = all_pages()[0];
+  EXPECT_EQ(kTestPageUrl, page.url);
+  EXPECT_EQ("download", page.client_id.name_space);
+  EXPECT_EQ("id1", page.client_id.id);
+  EXPECT_EQ(153l, page.offline_id);
+}
+
 }  // namespace offline_pages
diff --git a/chrome/browser/android/vr_shell/vr_shell_delegate.cc b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
index 606a6417..af69ba1 100644
--- a/chrome/browser/android/vr_shell/vr_shell_delegate.cc
+++ b/chrome/browser/android/vr_shell/vr_shell_delegate.cc
@@ -13,6 +13,32 @@
 
 namespace vr_shell {
 
+// A non presenting delegate for magic window mode.
+class GvrNonPresentingDelegate : public device::GvrDelegate {
+ public:
+  explicit GvrNonPresentingDelegate(jlong context) {
+    gvr_api_ =
+        gvr::GvrApi::WrapNonOwned(reinterpret_cast<gvr_context*>(context));
+  }
+
+  virtual ~GvrNonPresentingDelegate() = default;
+
+  // GvrDelegate implementation
+  void SetWebVRSecureOrigin(bool secure_origin) override {}
+  void SubmitWebVRFrame() override {}
+  void UpdateWebVRTextureBounds(int eye,
+                                float left,
+                                float top,
+                                float width,
+                                float height) override {}
+  void SetGvrPoseForWebVr(const gvr::Mat4f& pose,
+                          uint32_t pose_index) override {}
+  gvr::GvrApi* gvr_api() override { return gvr_api_.get(); }
+
+ private:
+  std::unique_ptr<gvr::GvrApi> gvr_api_;
+};
+
 VrShellDelegate::VrShellDelegate(JNIEnv* env, jobject obj)
     : device_provider_(nullptr) {
   j_vr_shell_delegate_.Reset(env, obj);
@@ -62,6 +88,26 @@
   Java_VrShellDelegate_exitWebVR(env, j_vr_shell_delegate_.obj());
 }
 
+device::GvrDelegate* VrShellDelegate::GetNonPresentingDelegate() {
+  if (!non_presenting_delegate_) {
+    JNIEnv* env = AttachCurrentThread();
+    jlong context = Java_VrShellDelegate_createNonPresentingNativeContext(
+        env, j_vr_shell_delegate_.obj());
+    if (!context)
+      return nullptr;
+
+    non_presenting_delegate_.reset(new GvrNonPresentingDelegate(context));
+  }
+  return non_presenting_delegate_.get();
+}
+
+void VrShellDelegate::DestroyNonPresentingDelegate() {
+  non_presenting_delegate_.reset(nullptr);
+  JNIEnv* env = AttachCurrentThread();
+  Java_VrShellDelegate_shutdownNonPresentingNativeContext(
+      env, j_vr_shell_delegate_.obj());
+}
+
 void VrShellDelegate::OnVrShellReady(VrShell* vr_shell) {
   if (device_provider_)
     device_provider_->OnGvrDelegateReady(vr_shell);
diff --git a/chrome/browser/android/vr_shell/vr_shell_delegate.h b/chrome/browser/android/vr_shell/vr_shell_delegate.h
index 99fb77afd..bf591cc 100644
--- a/chrome/browser/android/vr_shell/vr_shell_delegate.h
+++ b/chrome/browser/android/vr_shell/vr_shell_delegate.h
@@ -29,11 +29,14 @@
   // device::vrDelegateProvider implementation
   bool RequestWebVRPresent(device::GvrDeviceProvider* device_provider) override;
   void ExitWebVRPresent() override;
+  device::GvrDelegate* GetNonPresentingDelegate() override;
+  void DestroyNonPresentingDelegate() override;
 
   // Called from VRShell
   void OnVrShellReady(VrShell* vr_shell);
 
  private:
+  std::unique_ptr<device::GvrDelegate> non_presenting_delegate_;
   base::android::ScopedJavaGlobalRef<jobject> j_vr_shell_delegate_;
   device::GvrDeviceProvider* device_provider_;
 
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 617072d4..b4f0b7b 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -237,6 +237,12 @@
     "arc/arc_tts_service.h",
     "arc/arc_wallpaper_service.cc",
     "arc/arc_wallpaper_service.h",
+    "arc/fileapi/arc_content_file_system_async_file_util.cc",
+    "arc/fileapi/arc_content_file_system_async_file_util.h",
+    "arc/fileapi/arc_content_file_system_backend_delegate.cc",
+    "arc/fileapi/arc_content_file_system_backend_delegate.h",
+    "arc/fileapi/arc_content_file_system_file_stream_reader.cc",
+    "arc/fileapi/arc_content_file_system_file_stream_reader.h",
     "arc/gpu_arc_video_service_host.cc",
     "arc/gpu_arc_video_service_host.h",
     "arc/page_transition_util.cc",
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
index ac4dfc4..147172f 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager.cc
@@ -259,8 +259,9 @@
   policy::BrowserPolicyConnectorChromeOS* connector =
       g_browser_process->platform_part()->browser_policy_connector_chromeos();
   connector->GetInstallAttributes()->LockDevice(
-      std::string(),  // user
       policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH,
+      std::string(),  // domain
+      std::string(),  // realm
       std::string(),  // device_id
       base::Bind(
           &KioskAppManager::OnLockDevice, base::Unretained(this), callback));
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc b/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc
index 6f47d91..7218eac 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_manager_browsertest.cc
@@ -292,8 +292,9 @@
     policy::BrowserPolicyConnectorChromeOS* connector =
         g_browser_process->platform_part()->browser_policy_connector_chromeos();
     connector->GetInstallAttributes()->LockDevice(
-        "user@domain.com",
         policy::DEVICE_MODE_ENTERPRISE,
+        "domain.com",
+        std::string(),  // realm
         "device-id",
         base::Bind(
             &OnEnterpriseDeviceLock, lock_result.get(), runner->QuitClosure()));
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.cc
new file mode 100644
index 0000000..07a160b
--- /dev/null
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.cc
@@ -0,0 +1,163 @@
+// 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 "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.h"
+
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/base/net_errors.h"
+#include "storage/browser/blob/shareable_file_reference.h"
+
+namespace arc {
+
+ArcContentFileSystemAsyncFileUtil::ArcContentFileSystemAsyncFileUtil() =
+    default;
+
+ArcContentFileSystemAsyncFileUtil::~ArcContentFileSystemAsyncFileUtil() =
+    default;
+
+void ArcContentFileSystemAsyncFileUtil::CreateOrOpen(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& url,
+    int file_flags,
+    const CreateOrOpenCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(callback, base::Passed(base::File()), base::Closure()));
+}
+
+void ArcContentFileSystemAsyncFileUtil::EnsureFileExists(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& url,
+    const EnsureFileExistsCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED, false));
+}
+
+void ArcContentFileSystemAsyncFileUtil::CreateDirectory(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& url,
+    bool exclusive,
+    bool recursive,
+    const StatusCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+}
+
+void ArcContentFileSystemAsyncFileUtil::GetFileInfo(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& url,
+    int fields,
+    const GetFileInfoCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(callback, base::File::FILE_ERROR_FAILED, base::File::Info()));
+}
+
+void ArcContentFileSystemAsyncFileUtil::ReadDirectory(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& url,
+    const ReadDirectoryCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::Bind(callback, base::File::FILE_ERROR_FAILED, EntryList(), false));
+}
+
+void ArcContentFileSystemAsyncFileUtil::Touch(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& url,
+    const base::Time& last_access_time,
+    const base::Time& last_modified_time,
+    const StatusCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+}
+
+void ArcContentFileSystemAsyncFileUtil::Truncate(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& url,
+    int64_t length,
+    const StatusCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+}
+
+void ArcContentFileSystemAsyncFileUtil::CopyFileLocal(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& src_url,
+    const storage::FileSystemURL& dest_url,
+    CopyOrMoveOption option,
+    const CopyFileProgressCallback& progress_callback,
+    const StatusCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+}
+
+void ArcContentFileSystemAsyncFileUtil::MoveFileLocal(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& src_url,
+    const storage::FileSystemURL& dest_url,
+    CopyOrMoveOption option,
+    const StatusCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+}
+
+void ArcContentFileSystemAsyncFileUtil::CopyInForeignFile(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const base::FilePath& src_file_path,
+    const storage::FileSystemURL& dest_url,
+    const StatusCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+}
+
+void ArcContentFileSystemAsyncFileUtil::DeleteFile(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& url,
+    const StatusCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+}
+
+void ArcContentFileSystemAsyncFileUtil::DeleteDirectory(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& url,
+    const StatusCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+}
+
+void ArcContentFileSystemAsyncFileUtil::DeleteRecursively(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& url,
+    const StatusCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED));
+}
+
+void ArcContentFileSystemAsyncFileUtil::CreateSnapshotFile(
+    std::unique_ptr<storage::FileSystemOperationContext> context,
+    const storage::FileSystemURL& url,
+    const CreateSnapshotFileCallback& callback) {
+  NOTIMPLEMENTED();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::File::FILE_ERROR_FAILED,
+                            base::File::Info(), base::FilePath(),
+                            scoped_refptr<storage::ShareableFileReference>()));
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.h b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.h
new file mode 100644
index 0000000..550c1ba
--- /dev/null
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.h
@@ -0,0 +1,90 @@
+// 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 CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_ASYNC_FILE_UTIL_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_ASYNC_FILE_UTIL_H_
+
+#include "storage/browser/fileapi/async_file_util.h"
+
+namespace arc {
+
+class ArcContentFileSystemAsyncFileUtil : public storage::AsyncFileUtil {
+ public:
+  ArcContentFileSystemAsyncFileUtil();
+  ~ArcContentFileSystemAsyncFileUtil() override;
+
+  // storage::AsyncFileUtil overrides.
+  void CreateOrOpen(
+      std::unique_ptr<storage::FileSystemOperationContext> context,
+      const storage::FileSystemURL& url,
+      int file_flags,
+      const CreateOrOpenCallback& callback) override;
+  void EnsureFileExists(
+      std::unique_ptr<storage::FileSystemOperationContext> context,
+      const storage::FileSystemURL& url,
+      const EnsureFileExistsCallback& callback) override;
+  void CreateDirectory(
+      std::unique_ptr<storage::FileSystemOperationContext> context,
+      const storage::FileSystemURL& url,
+      bool exclusive,
+      bool recursive,
+      const StatusCallback& callback) override;
+  void GetFileInfo(std::unique_ptr<storage::FileSystemOperationContext> context,
+                   const storage::FileSystemURL& url,
+                   int fields,
+                   const GetFileInfoCallback& callback) override;
+  void ReadDirectory(
+      std::unique_ptr<storage::FileSystemOperationContext> context,
+      const storage::FileSystemURL& url,
+      const ReadDirectoryCallback& callback) override;
+  void Touch(std::unique_ptr<storage::FileSystemOperationContext> context,
+             const storage::FileSystemURL& url,
+             const base::Time& last_access_time,
+             const base::Time& last_modified_time,
+             const StatusCallback& callback) override;
+  void Truncate(std::unique_ptr<storage::FileSystemOperationContext> context,
+                const storage::FileSystemURL& url,
+                int64_t length,
+                const StatusCallback& callback) override;
+  void CopyFileLocal(
+      std::unique_ptr<storage::FileSystemOperationContext> context,
+      const storage::FileSystemURL& src_url,
+      const storage::FileSystemURL& dest_url,
+      CopyOrMoveOption option,
+      const CopyFileProgressCallback& progress_callback,
+      const StatusCallback& callback) override;
+  void MoveFileLocal(
+      std::unique_ptr<storage::FileSystemOperationContext> context,
+      const storage::FileSystemURL& src_url,
+      const storage::FileSystemURL& dest_url,
+      CopyOrMoveOption option,
+      const StatusCallback& callback) override;
+  void CopyInForeignFile(
+      std::unique_ptr<storage::FileSystemOperationContext> context,
+      const base::FilePath& src_file_path,
+      const storage::FileSystemURL& dest_url,
+      const StatusCallback& callback) override;
+  void DeleteFile(std::unique_ptr<storage::FileSystemOperationContext> context,
+                  const storage::FileSystemURL& url,
+                  const StatusCallback& callback) override;
+  void DeleteDirectory(
+      std::unique_ptr<storage::FileSystemOperationContext> context,
+      const storage::FileSystemURL& url,
+      const StatusCallback& callback) override;
+  void DeleteRecursively(
+      std::unique_ptr<storage::FileSystemOperationContext> context,
+      const storage::FileSystemURL& url,
+      const StatusCallback& callback) override;
+  void CreateSnapshotFile(
+      std::unique_ptr<storage::FileSystemOperationContext> context,
+      const storage::FileSystemURL& url,
+      const CreateSnapshotFileCallback& callback) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ArcContentFileSystemAsyncFileUtil);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_ASYNC_FILE_UTIL_H_
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_backend_delegate.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_backend_delegate.cc
new file mode 100644
index 0000000..b003e70
--- /dev/null
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_backend_delegate.cc
@@ -0,0 +1,62 @@
+// 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 "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_backend_delegate.h"
+
+#include "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_async_file_util.h"
+#include "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.h"
+#include "content/public/browser/browser_thread.h"
+#include "storage/browser/fileapi/file_stream_writer.h"
+#include "storage/browser/fileapi/file_system_url.h"
+
+namespace arc {
+
+ArcContentFileSystemBackendDelegate::ArcContentFileSystemBackendDelegate()
+    : async_file_util_(new ArcContentFileSystemAsyncFileUtil()) {}
+
+ArcContentFileSystemBackendDelegate::~ArcContentFileSystemBackendDelegate() =
+    default;
+
+storage::AsyncFileUtil* ArcContentFileSystemBackendDelegate::GetAsyncFileUtil(
+    storage::FileSystemType type) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_EQ(storage::kFileSystemTypeArcContent, type);
+  return async_file_util_.get();
+}
+
+std::unique_ptr<storage::FileStreamReader>
+ArcContentFileSystemBackendDelegate::CreateFileStreamReader(
+    const storage::FileSystemURL& url,
+    int64_t offset,
+    int64_t max_bytes_to_read,
+    const base::Time& expected_modification_time,
+    storage::FileSystemContext* context) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+  DCHECK_EQ(storage::kFileSystemTypeArcContent, url.type());
+  return std::unique_ptr<storage::FileStreamReader>(
+      new ArcContentFileSystemFileStreamReader(url, offset, max_bytes_to_read));
+}
+
+std::unique_ptr<storage::FileStreamWriter>
+ArcContentFileSystemBackendDelegate::CreateFileStreamWriter(
+    const storage::FileSystemURL& url,
+    int64_t offset,
+    storage::FileSystemContext* context) {
+  NOTIMPLEMENTED();
+  return std::unique_ptr<storage::FileStreamWriter>();
+}
+
+storage::WatcherManager* ArcContentFileSystemBackendDelegate::GetWatcherManager(
+    storage::FileSystemType type) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
+void ArcContentFileSystemBackendDelegate::GetRedirectURLForContents(
+    const storage::FileSystemURL& url,
+    const storage::URLCallback& callback) {
+  NOTIMPLEMENTED();
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_backend_delegate.h b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_backend_delegate.h
new file mode 100644
index 0000000..66a6503d
--- /dev/null
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_backend_delegate.h
@@ -0,0 +1,49 @@
+// 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 CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_BACKEND_DELEGATE_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_BACKEND_DELEGATE_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "chrome/browser/chromeos/fileapi/file_system_backend_delegate.h"
+
+namespace arc {
+
+// Delegate implementation of the some methods in chromeos::FileSystemBackend
+// for ARC content file system.
+class ArcContentFileSystemBackendDelegate
+    : public chromeos::FileSystemBackendDelegate {
+ public:
+  ArcContentFileSystemBackendDelegate();
+  ~ArcContentFileSystemBackendDelegate() override;
+
+  // FileSystemBackend::Delegate overrides.
+  storage::AsyncFileUtil* GetAsyncFileUtil(
+      storage::FileSystemType type) override;
+  std::unique_ptr<storage::FileStreamReader> CreateFileStreamReader(
+      const storage::FileSystemURL& url,
+      int64_t offset,
+      int64_t max_bytes_to_read,
+      const base::Time& expected_modification_time,
+      storage::FileSystemContext* context) override;
+  std::unique_ptr<storage::FileStreamWriter> CreateFileStreamWriter(
+      const storage::FileSystemURL& url,
+      int64_t offset,
+      storage::FileSystemContext* context) override;
+  storage::WatcherManager* GetWatcherManager(
+      storage::FileSystemType type) override;
+  void GetRedirectURLForContents(const storage::FileSystemURL& url,
+                                 const storage::URLCallback& callback) override;
+
+ private:
+  std::unique_ptr<storage::AsyncFileUtil> async_file_util_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArcContentFileSystemBackendDelegate);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_BACKEND_DELEGATE_H_
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
new file mode 100644
index 0000000..fb41b95
--- /dev/null
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.cc
@@ -0,0 +1,33 @@
+// 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 "chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.h"
+
+#include "net/base/net_errors.h"
+
+namespace arc {
+
+ArcContentFileSystemFileStreamReader::ArcContentFileSystemFileStreamReader(
+    const storage::FileSystemURL& url,
+    int64_t offset,
+    int64_t max_bytes_to_read) {}
+
+ArcContentFileSystemFileStreamReader::~ArcContentFileSystemFileStreamReader() =
+    default;
+
+int ArcContentFileSystemFileStreamReader::Read(
+    net::IOBuffer* buffer,
+    int buffer_length,
+    const net::CompletionCallback& callback) {
+  NOTIMPLEMENTED();
+  return net::ERR_NOT_IMPLEMENTED;
+}
+
+int64_t ArcContentFileSystemFileStreamReader::GetLength(
+    const net::Int64CompletionCallback& callback) {
+  NOTIMPLEMENTED();
+  return net::ERR_NOT_IMPLEMENTED;
+}
+
+}  // namespace arc
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.h b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.h
new file mode 100644
index 0000000..2d946744
--- /dev/null
+++ b/chrome/browser/chromeos/arc/fileapi/arc_content_file_system_file_stream_reader.h
@@ -0,0 +1,31 @@
+// 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 CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_FILE_STREAM_READER_H_
+#define CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_FILE_STREAM_READER_H_
+
+#include "storage/browser/fileapi/file_stream_reader.h"
+
+namespace arc {
+
+class ArcContentFileSystemFileStreamReader : public storage::FileStreamReader {
+ public:
+  ArcContentFileSystemFileStreamReader(const storage::FileSystemURL& url,
+                                       int64_t offset,
+                                       int64_t max_bytes_to_read);
+  ~ArcContentFileSystemFileStreamReader() override;
+
+  // storage::FileStreamReader override:
+  int Read(net::IOBuffer* buffer,
+           int buffer_length,
+           const net::CompletionCallback& callback) override;
+  int64_t GetLength(const net::Int64CompletionCallback& callback) override;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ArcContentFileSystemFileStreamReader);
+};
+
+}  // namespace arc
+
+#endif  // CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_CONTENT_FILE_SYSTEM_FILE_STREAM_READER_H_
diff --git a/chrome/browser/chromeos/display/overscan_calibrator.cc b/chrome/browser/chromeos/display/overscan_calibrator.cc
index c2c7155b..9163dbfb 100644
--- a/chrome/browser/chromeos/display/overscan_calibrator.cc
+++ b/chrome/browser/chromeos/display/overscan_calibrator.cc
@@ -12,7 +12,6 @@
 #include "ash/display/display_manager.h"
 #include "ash/display/window_tree_host_manager.h"
 #include "ash/shell.h"
-#include "base/callback.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/core/SkPath.h"
@@ -159,8 +158,4 @@
   // configuration has changed.
 }
 
-base::Closure OverscanCalibrator::PrepareForLayerBoundsChange() {
-  return base::Closure();
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/display/overscan_calibrator.h b/chrome/browser/chromeos/display/overscan_calibrator.h
index cd4973cf..94765e8 100644
--- a/chrome/browser/chromeos/display/overscan_calibrator.h
+++ b/chrome/browser/chromeos/display/overscan_calibrator.h
@@ -45,7 +45,6 @@
   void OnPaintLayer(const ui::PaintContext& context) override;
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
   void OnDeviceScaleFactorChanged(float device_scale_factor) override;
-  base::Closure PrepareForLayerBoundsChange() override;
 
   // The target display.
   const display::Display display_;
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
index 706e039..edc3b62 100644
--- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
+++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -722,10 +722,7 @@
 class WizardControllerDeviceStateTest : public WizardControllerFlowTest {
  protected:
   WizardControllerDeviceStateTest()
-      : install_attributes_(std::string(),
-                            std::string(),
-                            std::string(),
-                            policy::DEVICE_MODE_NOT_SET) {
+      : install_attributes_(ScopedStubInstallAttributes::CreateUnset()) {
     fake_statistics_provider_.SetMachineStatistic(
         system::kSerialNumberKey, "test");
     fake_statistics_provider_.SetMachineStatistic(
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
index 2eb118e..b2f0134b 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
@@ -193,10 +193,9 @@
       profile_invalidation_service_(nullptr),
       fake_user_manager_(new chromeos::FakeChromeUserManager),
       user_manager_enabler_(fake_user_manager_),
-      install_attributes_("example.com",
-                          "user@example.com",
-                          "device_id",
-                          DEVICE_MODE_ENTERPRISE),
+      install_attributes_(
+          chromeos::ScopedStubInstallAttributes::CreateEnterprise(
+              "example.com", "device_id")),
       profile_manager_(TestingBrowserProcess::GetGlobal()) {
 }
 
diff --git a/chrome/browser/chromeos/policy/blocking_login_browsertest.cc b/chrome/browser/chromeos/policy/blocking_login_browsertest.cc
index bac4402..ca55ceb 100644
--- a/chrome/browser/chromeos/policy/blocking_login_browsertest.cc
+++ b/chrome/browser/chromeos/policy/blocking_login_browsertest.cc
@@ -138,11 +138,11 @@
         ->browser_policy_connector_chromeos();
   }
 
-  void EnrollDevice(const std::string& username) {
+  void EnrollDevice(const std::string& domain) {
     base::RunLoop loop;
     InstallAttributes::LockResult result;
     browser_policy_connector()->GetInstallAttributes()->LockDevice(
-        username, policy::DEVICE_MODE_ENTERPRISE, "100200300",
+        policy::DEVICE_MODE_ENTERPRISE, domain, std::string(), "100200300",
         base::Bind(&CopyLockResult, &loop, &result));
     loop.Run();
     EXPECT_EQ(InstallAttributes::LOCK_SUCCESS, result);
@@ -249,7 +249,7 @@
 
   // Enroll the device, if enrollment is enabled for this test instance.
   if (GetParam().enroll_device) {
-    EnrollDevice(kUsername);
+    EnrollDevice(kDomain);
 
     EXPECT_FALSE(user_manager->IsUserLoggedIn());
     EXPECT_TRUE(browser_policy_connector()->IsEnterpriseManaged());
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc
index a29cdcc..775d26b 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_initializer_unittest.cc
@@ -171,8 +171,7 @@
 
   // If the device is enterprise-managed, the management domain gets pulled from
   // install attributes.
-  install_attributes_.SetRegistrationUser("user@example.com");
-  install_attributes_.SetDomain("example.com");
+  install_attributes_.SetEnterprise("example.com", "fake-id");
   config = device_cloud_policy_initializer_.GetPrescribedEnrollmentConfig();
   EXPECT_EQ(EnrollmentConfig::MODE_NONE, config.mode);
   EXPECT_EQ("example.com", config.management_domain);
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index 77b76ef..441197a 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -197,8 +197,9 @@
     base::RunLoop loop;
     chromeos::InstallAttributes::LockResult result;
     install_attributes_->LockDevice(
-        PolicyBuilder::kFakeUsername,
         DEVICE_MODE_ENTERPRISE,
+        PolicyBuilder::kFakeDomain,
+        std::string(),  // realm
         PolicyBuilder::kFakeDeviceId,
         base::Bind(&CopyLockResult, &loop, &result));
     loop.Run();
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc
index 61d39ee..fdbb0b2 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_store_chromeos_unittest.cc
@@ -63,8 +63,9 @@
     base::RunLoop loop;
     chromeos::InstallAttributes::LockResult result;
     install_attributes_->LockDevice(
-        PolicyBuilder::kFakeUsername,
         DEVICE_MODE_ENTERPRISE,
+        PolicyBuilder::kFakeDomain,
+        std::string(),  // realm
         PolicyBuilder::kFakeDeviceId,
         base::Bind(&CopyLockResult, &loop, &result));
     loop.Run();
diff --git a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
index 711ecb1..65293fc 100644
--- a/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
+++ b/chrome/browser/chromeos/policy/device_local_account_policy_service.cc
@@ -423,7 +423,10 @@
       break;
     case chromeos::CrosSettingsProvider::TEMPORARILY_UNTRUSTED:
       waiting_for_cros_settings_ = true;
-      return;
+      // Purposely break to allow initialization with temporarily untrusted
+      // settings so that a crash-n-restart public session have its loader
+      // properly registered as ExtensionService's external provider.
+      break;
     case chromeos::CrosSettingsProvider::PERMANENTLY_UNTRUSTED:
       waiting_for_cros_settings_ = false;
       return;
diff --git a/chrome/browser/chromeos/policy/device_status_collector.cc b/chrome/browser/chromeos/policy/device_status_collector.cc
index 4802538..56bbbf3 100644
--- a/chrome/browser/chromeos/policy/device_status_collector.cc
+++ b/chrome/browser/chromeos/policy/device_status_collector.cc
@@ -472,6 +472,8 @@
   running_kiosk_app_subscription_ = cros_settings_->AddSettingsObserver(
       chromeos::kReportRunningKioskApp, callback);
 
+  report_arc_status_pref_.Init(prefs::kReportArcStatus, local_state_, callback);
+
   // Fetch the current values of the policies.
   UpdateReportingSettings();
 
@@ -498,6 +500,7 @@
 void DeviceStatusCollector::RegisterPrefs(PrefRegistrySimple* registry) {
   registry->RegisterDictionaryPref(prefs::kDeviceActivityTimes,
                                    new base::DictionaryValue);
+  registry->RegisterBooleanPref(prefs::kReportArcStatus, true);
 }
 
 void DeviceStatusCollector::CheckIdleState() {
@@ -551,8 +554,7 @@
     report_kiosk_session_status_ = true;
   }
 
-  // TODO(phweiss): Create policy to control this, and turn it on by default.
-  report_android_status_ = false;
+  report_android_status_ = local_state_->GetBoolean(prefs::kReportArcStatus);
 
   if (!report_hardware_status_) {
     ClearCachedResourceUsage();
diff --git a/chrome/browser/chromeos/policy/device_status_collector.h b/chrome/browser/chromeos/policy/device_status_collector.h
index 0d8ae27..702c78b 100644
--- a/chrome/browser/chromeos/policy/device_status_collector.h
+++ b/chrome/browser/chromeos/policy/device_status_collector.h
@@ -27,6 +27,7 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #include "chromeos/system/version_loader.h"
 #include "components/policy/proto/device_management_backend.pb.h"
+#include "components/prefs/pref_member.h"
 #include "mojo/public/cpp/bindings/string.h"
 #include "ui/base/idle/idle.h"
 
@@ -284,6 +285,7 @@
       os_update_status_subscription_;
   std::unique_ptr<chromeos::CrosSettings::ObserverSubscription>
       running_kiosk_app_subscription_;
+  BooleanPrefMember report_arc_status_pref_;
 
   // Task runner in the creation thread where responses are sent to.
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
diff --git a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
index 284cd440..a2629d0e 100644
--- a/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
+++ b/chrome/browser/chromeos/policy/device_status_collector_browsertest.cc
@@ -27,6 +27,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_data.h"
 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
+#include "chrome/browser/chromeos/arc/arc_auth_service.h"
 #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
 #include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
 #include "chrome/browser/chromeos/ownership/fake_owner_settings_service.h"
@@ -80,6 +81,12 @@
 const char kKioskAppId[] = "kiosk_app_id";
 const char kExternalMountPoint[] = "/a/b/c";
 const char kPublicAccountId[] = "public_user@localhost";
+const char kArcStatus[] = "{\"applications\":[ { "
+    "\"packageName\":\"com.android.providers.telephony\","
+    "\"versionName\":\"6.0.1\","
+    "\"permissions\": [\"android.permission.INTERNET\"] }],"
+    "\"userEmail\":\"xxx@google.com\"}";
+const char kDroidGuardInfo[] = "{\"droid_guard_info\":42}";
 
 class TestingDeviceStatusCollector : public policy::DeviceStatusCollector {
  public:
@@ -225,6 +232,17 @@
   receiver.Run(status, droid_guard_info);
 }
 
+bool GetFakeAndroidStatus(
+    mojo::String status,
+    mojo::String droid_guard_info,
+    const policy::DeviceStatusCollector::AndroidStatusReceiver& receiver) {
+  // Post it to the thread because this call is expected to be asynchronous.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(&CallAndroidStatusReceiver, receiver,
+          status, droid_guard_info));
+  return true;
+}
+
 bool GetEmptyAndroidStatus(
     const policy::DeviceStatusCollector::AndroidStatusReceiver& receiver) {
   // Post it to the thread because this call is expected to be asynchronous.
@@ -251,10 +269,10 @@
       : ui_thread_(content::BrowserThread::UI, &message_loop_),
         file_thread_(content::BrowserThread::FILE, &message_loop_),
         io_thread_(content::BrowserThread::IO, &message_loop_),
-        install_attributes_("managed.com",
-                            "user@managed.com",
-                            "device_id",
-                            DEVICE_MODE_ENTERPRISE),
+        install_attributes_(
+            chromeos::ScopedStubInstallAttributes::CreateEnterprise(
+                "managed.com",
+                "device_id")),
         settings_helper_(false),
         user_manager_(new chromeos::MockUserManager()),
         user_manager_enabler_(user_manager_),
@@ -982,9 +1000,40 @@
   EXPECT_EQ(0, device_status_.cpu_temp_info_size());
 }
 
-TEST_F(DeviceStatusCollectorTest, NoSessionStatusIfNotKioskMode) {
+TEST_F(DeviceStatusCollectorTest, TestAndroidReporting) {
+  RestartStatusCollector(base::Bind(&GetEmptyVolumeInfo),
+                         base::Bind(&GetEmptyCPUStatistics),
+                         base::Bind(&GetEmptyCPUTempInfo),
+                         base::Bind(&GetFakeAndroidStatus, kArcStatus,
+                             kDroidGuardInfo));
+  GetStatus();
+  EXPECT_EQ(kArcStatus, session_status_.android_status().status_payload());
+  EXPECT_EQ(kDroidGuardInfo,
+      session_status_.android_status().droid_guard_info());
+}
+
+TEST_F(DeviceStatusCollectorTest, NoAndroidReportingWhenDisabled) {
+  RestartStatusCollector(base::Bind(&GetEmptyVolumeInfo),
+                         base::Bind(&GetEmptyCPUStatistics),
+                         base::Bind(&GetEmptyCPUTempInfo),
+                         base::Bind(&GetFakeAndroidStatus, kArcStatus,
+                             kDroidGuardInfo));
+
+  prefs_.SetBoolean(prefs::kReportArcStatus, false);
+  // Mock Kiosk app, so some session status is reported
+  status_collector_->set_kiosk_account(
+      base::MakeUnique<DeviceLocalAccount>(fake_device_local_account_));
+  MockRunningKioskApp(fake_device_local_account_);
+
+  GetStatus();
+  EXPECT_TRUE(got_session_status_);
+  EXPECT_FALSE(session_status_.has_android_status());
+}
+
+TEST_F(DeviceStatusCollectorTest, NoSessionStatusIfNotKioskAndNoArcReporting) {
   // Should not report session status if we don't have an active kiosk app.
   settings_helper_.SetBoolean(chromeos::kReportDeviceSessionStatus, true);
+  prefs_.SetBoolean(prefs::kReportArcStatus, false);
   GetStatus();
   EXPECT_FALSE(got_session_status_);
 }
@@ -992,6 +1041,9 @@
 TEST_F(DeviceStatusCollectorTest, NoSessionStatusIfSessionReportingDisabled) {
   // Should not report session status if session status reporting is disabled.
   settings_helper_.SetBoolean(chromeos::kReportDeviceSessionStatus, false);
+  // ReportDeviceSessionStatus only controls Kiosk reporting, ARC reporting
+  // has to be disabled serarately.
+  prefs_.SetBoolean(prefs::kReportArcStatus, false);
   status_collector_->set_kiosk_account(
       base::MakeUnique<policy::DeviceLocalAccount>(fake_device_local_account_));
   // Set up a device-local account for single-app kiosk mode.
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
index f62fb55e..384259c 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.cc
@@ -23,6 +23,7 @@
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chromeos/attestation/attestation_flow.h"
+#include "google_apis/gaia/gaia_auth_util.h"
 #include "google_apis/gaia/gaia_urls.h"
 #include "net/http/http_status_code.h"
 
@@ -316,9 +317,10 @@
     DeviceCloudPolicyValidator* validator) {
   CHECK_EQ(STEP_VALIDATION, enrollment_step_);
   if (validator->success()) {
-    policy_ = std::move(validator->policy());
-    username_ = validator->policy_data()->username();
+    std::string username = validator->policy_data()->username();
+    domain_ = gaia::ExtractDomainName(gaia::CanonicalizeEmail(username));
     device_id_ = validator->policy_data()->device_id();
+    policy_ = std::move(validator->policy());
     request_token_ = validator->policy_data()->request_token();
     enrollment_step_ = STEP_ROBOT_AUTH_FETCH;
     client_->FetchRobotAuthCodes(auth_token_);
@@ -405,7 +407,7 @@
   weak_ptr_factory_.InvalidateWeakPtrs();
 
   install_attributes_->LockDevice(
-      username_, device_mode_, device_id_,
+      device_mode_, domain_, std::string() /* realm */, device_id_,
       base::Bind(&EnrollmentHandlerChromeOS::HandleLockDeviceResult,
                  weak_ptr_factory_.GetWeakPtr()));
 }
diff --git a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
index e12bfa8..4331f07 100644
--- a/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
+++ b/chrome/browser/chromeos/policy/enrollment_handler_chromeos.h
@@ -187,7 +187,7 @@
 
   // The validated policy response info to be installed in the store.
   std::unique_ptr<enterprise_management::PolicyFetchResponse> policy_;
-  std::string username_;
+  std::string domain_;
   std::string device_id_;
   std::string request_token_;
 
diff --git a/chrome/browser/chromeos/settings/install_attributes.cc b/chrome/browser/chromeos/settings/install_attributes.cc
index 45039d2..50eb658 100644
--- a/chrome/browser/chromeos/settings/install_attributes.cc
+++ b/chrome/browser/chromeos/settings/install_attributes.cc
@@ -25,6 +25,8 @@
 
 namespace chromeos {
 
+namespace cu = cryptohome_util;
+
 namespace {
 
 // Number of TPM lock state query retries during consistency check.
@@ -33,15 +35,20 @@
 // Interval of TPM lock state query retries during consistency check.
 int kDbusRetryIntervalInSeconds = 5;
 
-bool ReadMapKey(const std::map<std::string, std::string>& map,
-                const std::string& key,
-                std::string* value) {
+std::string ReadMapKey(const std::map<std::string, std::string>& map,
+                       const std::string& key) {
   std::map<std::string, std::string>::const_iterator entry = map.find(key);
-  if (entry == map.end())
-    return false;
+  if (entry != map.end()) {
+    return entry->second;
+  }
+  return std::string();
+}
 
-  *value = entry->second;
-  return true;
+void WarnIfNonempty(const std::map<std::string, std::string>& map,
+                    const std::string& key) {
+  if (!ReadMapKey(map, key).empty()) {
+    LOG(WARNING) << key << " expected to be empty.";
+  }
 }
 
 }  // namespace
@@ -65,11 +72,7 @@
 }
 
 InstallAttributes::InstallAttributes(CryptohomeClient* cryptohome_client)
-    : device_locked_(false),
-      consistency_check_running_(false),
-      device_lock_running_(false),
-      registration_mode_(policy::DEVICE_MODE_PENDING),
-      cryptohome_client_(cryptohome_client),
+    : cryptohome_client_(cryptohome_client),
       weak_ptr_factory_(this) {
 }
 
@@ -110,8 +113,8 @@
   for (entry = install_attrs_proto.attributes().begin();
        entry != install_attrs_proto.attributes().end();
        ++entry) {
-    // The protobuf values unfortunately contain terminating null characters, so
-    // we have to sanitize the value here.
+    // The protobuf values contain terminating null characters, so we have to
+    // sanitize the value here.
     attr_map.insert(std::make_pair(entry->name(),
                                    std::string(entry->value().c_str())));
   }
@@ -135,13 +138,14 @@
                                               bool result) {
   if (call_status == DBUS_METHOD_CALL_SUCCESS && result) {
     registration_mode_ = policy::DEVICE_MODE_NOT_SET;
-    if (!cryptohome_util::InstallAttributesIsInvalid() &&
-        !cryptohome_util::InstallAttributesIsFirstInstall()) {
+    if (!cu::InstallAttributesIsInvalid() &&
+        !cu::InstallAttributesIsFirstInstall()) {
       device_locked_ = true;
 
       static const char* const kEnterpriseAttributes[] = {
         kAttrEnterpriseDeviceId,
         kAttrEnterpriseDomain,
+        kAttrEnterpriseRealm,
         kAttrEnterpriseMode,
         kAttrEnterpriseOwned,
         kAttrEnterpriseUser,
@@ -150,8 +154,7 @@
       std::map<std::string, std::string> attr_map;
       for (size_t i = 0; i < arraysize(kEnterpriseAttributes); ++i) {
         std::string value;
-        if (cryptohome_util::InstallAttributesGet(kEnterpriseAttributes[i],
-                                                  &value))
+        if (cu::InstallAttributesGet(kEnterpriseAttributes[i], &value))
           attr_map[kEnterpriseAttributes[i]] = value;
       }
 
@@ -161,42 +164,34 @@
   callback.Run();
 }
 
-void InstallAttributes::LockDevice(const std::string& user,
-                                   policy::DeviceMode device_mode,
+void InstallAttributes::LockDevice(policy::DeviceMode device_mode,
+                                   const std::string& domain,
+                                   const std::string& realm,
                                    const std::string& device_id,
                                    const LockResultCallback& callback) {
+  CHECK((device_mode == policy::DEVICE_MODE_ENTERPRISE &&
+         !domain.empty() && realm.empty() && !device_id.empty()) ||
+        (device_mode == policy::DEVICE_MODE_ENTERPRISE_AD &&
+         domain.empty() && !realm.empty() && !device_id.empty()) ||
+        (device_mode == policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH &&
+         domain.empty() && realm.empty() && device_id.empty()));
   DCHECK(!callback.is_null());
   CHECK_EQ(device_lock_running_, false);
-  CHECK_NE(device_mode, policy::DEVICE_MODE_PENDING);
-  CHECK_NE(device_mode, policy::DEVICE_MODE_NOT_SET);
 
   // Check for existing lock first.
   if (device_locked_) {
     if (device_mode != registration_mode_) {
+      LOG(ERROR) << "Trying to re-lock with wrong mode.";
       callback.Run(LOCK_WRONG_MODE);
       return;
     }
 
-    switch (registration_mode_) {
-      case policy::DEVICE_MODE_ENTERPRISE:
-      case policy::DEVICE_MODE_LEGACY_RETAIL_MODE: {
-        // Check domain match for enterprise devices.
-        std::string domain = gaia::ExtractDomainName(user);
-        if (registration_domain_.empty() || domain != registration_domain_) {
-          callback.Run(LOCK_WRONG_DOMAIN);
-          return;
-        }
-        break;
-      }
-      case policy::DEVICE_MODE_NOT_SET:
-      case policy::DEVICE_MODE_PENDING:
-        // This case can't happen due to the CHECK_NE asserts above.
-        NOTREACHED();
-        break;
-      case policy::DEVICE_MODE_CONSUMER:
-      case policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH:
-        // The user parameter is ignored for consumer devices.
-        break;
+    if (domain != registration_domain_ ||
+        realm != registration_realm_ ||
+        device_id != registration_device_id_) {
+      LOG(ERROR) << "Trying to re-lock with non-matching parameters.";
+      callback.Run(LOCK_WRONG_DOMAIN);
+      return;
     }
 
     // Already locked in the right mode, signal success.
@@ -211,8 +206,9 @@
     CHECK(post_check_action_.is_null());
     post_check_action_ = base::Bind(&InstallAttributes::LockDevice,
                                     weak_ptr_factory_.GetWeakPtr(),
-                                    user,
                                     device_mode,
+                                    domain,
+                                    realm,
                                     device_id,
                                     callback);
     return;
@@ -222,15 +218,17 @@
   cryptohome_client_->InstallAttributesIsReady(
       base::Bind(&InstallAttributes::LockDeviceIfAttributesIsReady,
                  weak_ptr_factory_.GetWeakPtr(),
-                 user,
                  device_mode,
+                 domain,
+                 realm,
                  device_id,
                  callback));
 }
 
 void InstallAttributes::LockDeviceIfAttributesIsReady(
-    const std::string& user,
     policy::DeviceMode device_mode,
+    const std::string& domain,
+    const std::string& realm,
     const std::string& device_id,
     const LockResultCallback& callback,
     DBusMethodCallStatus call_status,
@@ -242,60 +240,47 @@
   }
 
   // Clearing the TPM password seems to be always a good deal.
-  if (cryptohome_util::TpmIsEnabled() &&
-      !cryptohome_util::TpmIsBeingOwned() &&
-      cryptohome_util::TpmIsOwned()) {
+  if (cu::TpmIsEnabled() && !cu::TpmIsBeingOwned() && cu::TpmIsOwned()) {
     cryptohome_client_->CallTpmClearStoredPasswordAndBlock();
   }
 
   // Make sure we really have a working InstallAttrs.
-  if (cryptohome_util::InstallAttributesIsInvalid()) {
+  if (cu::InstallAttributesIsInvalid()) {
     LOG(ERROR) << "Install attributes invalid.";
     device_lock_running_ = false;
     callback.Run(LOCK_BACKEND_INVALID);
     return;
   }
 
-  if (!cryptohome_util::InstallAttributesIsFirstInstall()) {
+  if (!cu::InstallAttributesIsFirstInstall()) {
     LOG(ERROR) << "Install attributes already installed.";
     device_lock_running_ = false;
     callback.Run(LOCK_ALREADY_LOCKED);
     return;
   }
 
-  std::string mode = GetDeviceModeString(device_mode);
-  std::string registration_user;
-  if (!user.empty())
-    registration_user = gaia::CanonicalizeEmail(user);
-
+  // Set values in the InstallAttrs.
+  std::string kiosk_enabled, enterprise_owned;
   if (device_mode == policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH) {
-    // Set values in the InstallAttrs and lock it.
-    if (!cryptohome_util::InstallAttributesSet(kAttrConsumerKioskEnabled,
-                                               "true")) {
-      LOG(ERROR) << "Failed writing attributes.";
-      device_lock_running_ = false;
-      callback.Run(LOCK_SET_ERROR);
-      return;
-    }
+    kiosk_enabled = "true";
   } else {
-    std::string domain = gaia::ExtractDomainName(registration_user);
-    // Set values in the InstallAttrs and lock it.
-    if (!cryptohome_util::InstallAttributesSet(kAttrEnterpriseOwned, "true") ||
-        !cryptohome_util::InstallAttributesSet(kAttrEnterpriseUser,
-                                               registration_user) ||
-        !cryptohome_util::InstallAttributesSet(kAttrEnterpriseDomain, domain) ||
-        !cryptohome_util::InstallAttributesSet(kAttrEnterpriseMode, mode) ||
-        !cryptohome_util::InstallAttributesSet(kAttrEnterpriseDeviceId,
-                                               device_id)) {
-      LOG(ERROR) << "Failed writing attributes.";
-      device_lock_running_ = false;
-      callback.Run(LOCK_SET_ERROR);
-      return;
-    }
+    enterprise_owned = "true";
+  }
+  std::string mode = GetDeviceModeString(device_mode);
+  if (!cu::InstallAttributesSet(kAttrConsumerKioskEnabled, kiosk_enabled) ||
+      !cu::InstallAttributesSet(kAttrEnterpriseOwned, enterprise_owned) ||
+      !cu::InstallAttributesSet(kAttrEnterpriseMode, mode) ||
+      !cu::InstallAttributesSet(kAttrEnterpriseDomain, domain) ||
+      !cu::InstallAttributesSet(kAttrEnterpriseRealm, realm) ||
+      !cu::InstallAttributesSet(kAttrEnterpriseDeviceId, device_id)) {
+    LOG(ERROR) << "Failed writing attributes.";
+    device_lock_running_ = false;
+    callback.Run(LOCK_SET_ERROR);
+    return;
   }
 
-  if (!cryptohome_util::InstallAttributesFinalize() ||
-      cryptohome_util::InstallAttributesIsFirstInstall()) {
+  if (!cu::InstallAttributesFinalize() ||
+      cu::InstallAttributesIsFirstInstall()) {
     LOG(ERROR) << "Failed locking.";
     device_lock_running_ = false;
     callback.Run(LOCK_FINALIZE_ERROR);
@@ -305,27 +290,39 @@
   ReadImmutableAttributes(
       base::Bind(&InstallAttributes::OnReadImmutableAttributes,
                  weak_ptr_factory_.GetWeakPtr(),
-                 registration_user,
+                 device_mode,
+                 domain,
+                 realm,
+                 device_id,
                  callback));
 }
 
 void InstallAttributes::OnReadImmutableAttributes(
-    const std::string& registration_user,
+    policy::DeviceMode mode,
+    const std::string& domain,
+    const std::string& realm,
+    const std::string& device_id,
     const LockResultCallback& callback) {
+  device_lock_running_ = false;
 
-  if (GetRegistrationUser() != registration_user) {
+  if (registration_mode_ != mode ||
+      registration_domain_ != domain ||
+      registration_realm_ != realm ||
+      registration_device_id_ != device_id) {
     LOG(ERROR) << "Locked data doesn't match.";
-    device_lock_running_ = false;
     callback.Run(LOCK_READBACK_ERROR);
     return;
   }
 
-  device_lock_running_ = false;
   callback.Run(LOCK_SUCCESS);
 }
 
 bool InstallAttributes::IsEnterpriseDevice() const {
-  return device_locked_ && !registration_user_.empty();
+  if (!device_locked_) {
+    return false;
+  }
+  return registration_mode_ == policy::DEVICE_MODE_ENTERPRISE ||
+      registration_mode_ == policy::DEVICE_MODE_ENTERPRISE_AD;
 }
 
 bool InstallAttributes::IsConsumerKioskDeviceWithAutoLaunch() {
@@ -333,24 +330,6 @@
          registration_mode_ == policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
 }
 
-std::string InstallAttributes::GetDomain() const {
-  if (!IsEnterpriseDevice())
-    return std::string();
-
-  return registration_domain_;
-}
-
-std::string InstallAttributes::GetDeviceId() {
-  if (!IsEnterpriseDevice())
-    return std::string();
-
-  return registration_device_id_;
-}
-
-policy::DeviceMode InstallAttributes::GetMode() {
-  return registration_mode_;
-}
-
 void InstallAttributes::TriggerConsistencyCheck(int dbus_retries) {
   cryptohome_client_->TpmIsOwned(
       base::Bind(&InstallAttributes::OnTpmOwnerCheckCompleted,
@@ -394,13 +373,14 @@
 // that all changes to the constants are reflected there as well.
 const char InstallAttributes::kConsumerDeviceMode[] = "consumer";
 const char InstallAttributes::kEnterpriseDeviceMode[] = "enterprise";
+const char InstallAttributes::kEnterpriseADDeviceMode[] = "enterprise_ad";
 const char InstallAttributes::kLegacyRetailDeviceMode[] = "kiosk";
 const char InstallAttributes::kConsumerKioskDeviceMode[] = "consumer_kiosk";
-const char InstallAttributes::kUnknownDeviceMode[] = "unknown";
 
 const char InstallAttributes::kAttrEnterpriseDeviceId[] =
     "enterprise.device_id";
 const char InstallAttributes::kAttrEnterpriseDomain[] = "enterprise.domain";
+const char InstallAttributes::kAttrEnterpriseRealm[] = "enterprise.realm";
 const char InstallAttributes::kAttrEnterpriseMode[] = "enterprise.mode";
 const char InstallAttributes::kAttrEnterpriseOwned[] = "enterprise.owned";
 const char InstallAttributes::kAttrEnterpriseUser[] = "enterprise.user";
@@ -423,6 +403,8 @@
       return InstallAttributes::kConsumerDeviceMode;
     case policy::DEVICE_MODE_ENTERPRISE:
       return InstallAttributes::kEnterpriseDeviceMode;
+    case policy::DEVICE_MODE_ENTERPRISE_AD:
+      return InstallAttributes::kEnterpriseADDeviceMode;
     case policy::DEVICE_MODE_LEGACY_RETAIL_MODE:
       return InstallAttributes::kLegacyRetailDeviceMode;
     case policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH:
@@ -432,7 +414,7 @@
       break;
   }
   NOTREACHED() << "Invalid device mode: " << mode;
-  return InstallAttributes::kUnknownDeviceMode;
+  return std::string();
 }
 
 policy::DeviceMode InstallAttributes::GetDeviceModeFromString(
@@ -441,59 +423,86 @@
     return policy::DEVICE_MODE_CONSUMER;
   else if (mode == InstallAttributes::kEnterpriseDeviceMode)
     return policy::DEVICE_MODE_ENTERPRISE;
+  else if (mode == InstallAttributes::kEnterpriseADDeviceMode)
+    return policy::DEVICE_MODE_ENTERPRISE_AD;
   else if (mode == InstallAttributes::kLegacyRetailDeviceMode)
     return policy::DEVICE_MODE_LEGACY_RETAIL_MODE;
   else if (mode == InstallAttributes::kConsumerKioskDeviceMode)
     return policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
-  NOTREACHED() << "Unknown device mode string: " << mode;
   return policy::DEVICE_MODE_NOT_SET;
 }
 
 void InstallAttributes::DecodeInstallAttributes(
     const std::map<std::string, std::string>& attr_map) {
-  std::string enterprise_owned;
-  std::string enterprise_user;
-  std::string consumer_kiosk_enabled;
-  if (ReadMapKey(attr_map, kAttrEnterpriseOwned, &enterprise_owned) &&
-      ReadMapKey(attr_map, kAttrEnterpriseUser, &enterprise_user) &&
-      enterprise_owned == "true" &&
-      !enterprise_user.empty()) {
-    registration_user_ = gaia::CanonicalizeEmail(enterprise_user);
+  // Start from a clean slate.
+  registration_mode_ = policy::DEVICE_MODE_NOT_SET;
+  registration_domain_.clear();
+  registration_realm_.clear();
+  registration_device_id_.clear();
 
-    // Initialize the mode to the legacy enterprise mode here and update
-    // below if more information is present.
-    registration_mode_ = policy::DEVICE_MODE_ENTERPRISE;
+  const std::string enterprise_owned =
+      ReadMapKey(attr_map, kAttrEnterpriseOwned);
+  const std::string consumer_kiosk_enabled =
+      ReadMapKey(attr_map, kAttrConsumerKioskEnabled);
+  const std::string mode = ReadMapKey(attr_map, kAttrEnterpriseMode);
+  const std::string domain = ReadMapKey(attr_map, kAttrEnterpriseDomain);
+  const std::string realm = ReadMapKey(attr_map, kAttrEnterpriseRealm);
+  const std::string device_id = ReadMapKey(attr_map, kAttrEnterpriseDeviceId);
+  const std::string user_deprecated = ReadMapKey(attr_map, kAttrEnterpriseUser);
 
-    // If we could extract basic setting we should try to extract the
-    // extended ones too. We try to set these to defaults as good as
-    // as possible if present, which could happen for device enrolled in
-    // pre 19 revisions of the code, before these new attributes were added.
-    if (ReadMapKey(attr_map, kAttrEnterpriseDomain, &registration_domain_))
-      registration_domain_ = gaia::CanonicalizeDomain(registration_domain_);
-    else
-      registration_domain_ = gaia::ExtractDomainName(registration_user_);
+  if (enterprise_owned == "true") {
+    WarnIfNonempty(attr_map, kAttrConsumerKioskEnabled);
+    registration_device_id_ = device_id;
 
-    ReadMapKey(attr_map, kAttrEnterpriseDeviceId, &registration_device_id_);
+    // Set registration_mode_.
+    registration_mode_ = GetDeviceModeFromString(mode);
+    if (registration_mode_ != policy::DEVICE_MODE_ENTERPRISE &&
+        registration_mode_ != policy::DEVICE_MODE_ENTERPRISE_AD) {
+      if (!mode.empty()) {
+        LOG(WARNING) << "Bad " << kAttrEnterpriseMode << ": " << mode;
+      }
+      registration_mode_ = policy::DEVICE_MODE_ENTERPRISE;
+    }
 
-    std::string mode;
-    if (ReadMapKey(attr_map, kAttrEnterpriseMode, &mode))
-      registration_mode_ = GetDeviceModeFromString(mode);
-  } else if (ReadMapKey(attr_map,
-                        kAttrConsumerKioskEnabled,
-                        &consumer_kiosk_enabled) &&
-             consumer_kiosk_enabled == "true") {
+    if (registration_mode_ == policy::DEVICE_MODE_ENTERPRISE) {
+      // Either set registration_domain_ ...
+      WarnIfNonempty(attr_map, kAttrEnterpriseRealm);
+      if (!domain.empty()) {
+        // The canonicalization is for compatibility with earlier versions.
+        registration_domain_ = gaia::CanonicalizeDomain(domain);
+      } else if (!user_deprecated.empty()) {
+        // Compatibility for pre M19 code.
+        registration_domain_ = gaia::ExtractDomainName(user_deprecated);
+      } else {
+        LOG(WARNING) << "Couldn't read domain.";
+      }
+    } else {
+      // ... or set registration_realm_.
+      WarnIfNonempty(attr_map, kAttrEnterpriseDomain);
+      if (!realm.empty()) {
+        registration_realm_ = realm;
+      } else {
+        LOG(WARNING) << "Couldn't read realm.";
+      }
+    }
+
+    return;
+  }
+
+  WarnIfNonempty(attr_map, kAttrEnterpriseOwned);
+  WarnIfNonempty(attr_map, kAttrEnterpriseDomain);
+  WarnIfNonempty(attr_map, kAttrEnterpriseRealm);
+  WarnIfNonempty(attr_map, kAttrEnterpriseDeviceId);
+  WarnIfNonempty(attr_map, kAttrEnterpriseUser);
+  if (consumer_kiosk_enabled == "true") {
     registration_mode_ = policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH;
-  } else if (enterprise_user.empty() && enterprise_owned != "true") {
-    // |registration_user_| is empty on consumer devices.
+    return;
+  }
+
+  WarnIfNonempty(attr_map, kAttrConsumerKioskEnabled);
+  if (user_deprecated.empty()) {
     registration_mode_ = policy::DEVICE_MODE_CONSUMER;
   }
 }
 
-std::string InstallAttributes::GetRegistrationUser() const {
-  if (!device_locked_)
-    return std::string();
-
-  return registration_user_;
-}
-
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/settings/install_attributes.h b/chrome/browser/chromeos/settings/install_attributes.h
index ba20b0c8..94ba7e4 100644
--- a/chrome/browser/chromeos/settings/install_attributes.h
+++ b/chrome/browser/chromeos/settings/install_attributes.h
@@ -35,7 +35,8 @@
     LOCK_SET_ERROR = 5,        // Failed to set attributes.
     LOCK_FINALIZE_ERROR = 6,   // Backend failed to lock.
     LOCK_READBACK_ERROR = 7,   // Inconsistency reading back registration data.
-    LOCK_WRONG_DOMAIN = 8,     // Device already registered to another domain.
+    LOCK_WRONG_DOMAIN = 8,     // Device already registered to another domain or
+                               // other mismatch of other attributes.
     LOCK_WRONG_MODE = 9,       // Device already locked to a different mode.
   };
 
@@ -51,7 +52,7 @@
 
   // Tries to read install attributes from the cache file which is created early
   // during the boot process.  The cache file is used to work around slow
-  // cryptohome startup, which takes a while to register its DBus interface.
+  // cryptohome startup, which takes a while to register its D-Bus interface.
   // (See http://crosbug.com/37367 for background on this.)
   void Init(const base::FilePath& cache_file);
 
@@ -61,13 +62,15 @@
   // ReadAttributesIfReady().
   void ReadImmutableAttributes(const base::Closure& callback);
 
-  // Locks the device to be an enterprise device registered by the given user.
-  // This can also be called after the lock has already been taken, in which
-  // case it checks that the passed user agrees with the locked attribute.
+  // Locks the device into |device_mode|.  Depending on |device_mode|, a
+  // specific subset of |domain|, |realm| and |device_id| must be set.  Can also
+  // be called after the lock has already been taken, in which case it checks
+  // that the passed parameters fully agree with the locked attributes.
   // |callback| must not be null and is called with the result.  Must not be
   // called while a previous LockDevice() invocation is still pending.
-  void LockDevice(const std::string& user,
-                  policy::DeviceMode device_mode,
+  void LockDevice(policy::DeviceMode device_mode,
+                  const std::string& domain,
+                  const std::string& realm,
                   const std::string& device_id,
                   const LockResultCallback& callback);
 
@@ -77,41 +80,46 @@
   // Checks whether this is a consumer kiosk enabled device.
   bool IsConsumerKioskDeviceWithAutoLaunch();
 
-  // Gets the domain this device belongs to or an empty string if the device is
-  // not an enterprise device.
-  std::string GetDomain() const;
+  // Return the mode the device was enrolled to. The return value for devices
+  // that are not locked yet is DEVICE_MODE_UNKNOWN.
+  policy::DeviceMode GetMode() const { return registration_mode_; }
 
-  // Gets the device id that was generated when the device was registered.
+  // Return the domain this device belongs to or an empty string if the device
+  // is not a cloud-managed enterprise device.
+  std::string GetDomain() const { return registration_domain_; }
+
+  // Return the realm this device belongs to or an empty string if the device is
+  // not an AD enterprise device.
+  std::string GetRealm() const { return registration_realm_; }
+
+  // Return the device id that was generated when the device was registered.
   // Returns an empty string if the device is not an enterprise device or the
   // device id was not stored in the lockbox (prior to R19).
-  std::string GetDeviceId();
-
-  // Gets the mode the device was enrolled to. The return value for devices that
-  // are not locked yet will be DEVICE_MODE_UNKNOWN.
-  policy::DeviceMode GetMode();
+  std::string GetDeviceId() const { return registration_device_id_; }
 
  protected:
   // True if install attributes have been read successfully.  False if read
   // failed or no read attempt was made.
-  bool device_locked_;
+  bool device_locked_ = false;
 
   // Whether the TPM / install attributes consistency check is running.
-  bool consistency_check_running_;
+  bool consistency_check_running_ = false;
 
   // To be run after the consistency check has finished.
   base::Closure post_check_action_;
 
   // Wether the LockDevice() initiated TPM calls are running.
-  bool device_lock_running_;
+  bool device_lock_running_ = false;
 
-  std::string registration_user_;
+  // The actual install attributes.  Populated by DecodeInstallAttributes()
+  // exclusively.
+  policy::DeviceMode registration_mode_ = policy::DEVICE_MODE_PENDING;
   std::string registration_domain_;
+  std::string registration_realm_;
   std::string registration_device_id_;
-  policy::DeviceMode registration_mode_;
 
  private:
   FRIEND_TEST_ALL_PREFIXES(InstallAttributesTest, DeviceLockedFromOlderVersion);
-  FRIEND_TEST_ALL_PREFIXES(InstallAttributesTest, GetRegistrationUser);
   FRIEND_TEST_ALL_PREFIXES(InstallAttributesTest, Init);
   FRIEND_TEST_ALL_PREFIXES(InstallAttributesTest, InitForConsumerKiosk);
   FRIEND_TEST_ALL_PREFIXES(InstallAttributesTest, LockCanonicalize);
@@ -121,13 +129,14 @@
   // Constants for the possible device modes that can be stored in the lockbox.
   static const char kConsumerDeviceMode[];
   static const char kEnterpriseDeviceMode[];
+  static const char kEnterpriseADDeviceMode[];
   static const char kLegacyRetailDeviceMode[];
   static const char kConsumerKioskDeviceMode[];
-  static const char kUnknownDeviceMode[];
 
   // Field names in the lockbox.
   static const char kAttrEnterpriseDeviceId[];
   static const char kAttrEnterpriseDomain[];
+  static const char kAttrEnterpriseRealm[];
   static const char kAttrEnterpriseMode[];
   static const char kAttrEnterpriseOwned[];
   static const char kAttrEnterpriseUser[];
@@ -143,7 +152,9 @@
   // Translates strings used in the lockbox to DeviceMode values.
   policy::DeviceMode GetDeviceModeFromString(const std::string& mode);
 
-  // Decodes the install attributes provided in |attr_map|.
+  // Decode the install attributes provided in |attr_map| (including some
+  // normalization and processing for backward compatibility) and guarantee that
+  // |registration_*| members are set self-consistently.
   void DecodeInstallAttributes(
       const std::map<std::string, std::string>& attr_map);
 
@@ -154,15 +165,19 @@
 
   // Helper for LockDevice(). Handles the result of InstallAttributesIsReady()
   // and continue processing LockDevice if the result is true.
-  void LockDeviceIfAttributesIsReady(const std::string& user,
-                                     policy::DeviceMode device_mode,
+  void LockDeviceIfAttributesIsReady(policy::DeviceMode device_mode,
+                                     const std::string& domain,
+                                     const std::string& realm,
                                      const std::string& device_id,
                                      const LockResultCallback& callback,
                                      DBusMethodCallStatus call_status,
                                      bool result);
 
   // Confirms the registered user and invoke the callback.
-  void OnReadImmutableAttributes(const std::string& user,
+  void OnReadImmutableAttributes(policy::DeviceMode mode,
+                                 const std::string& domain,
+                                 const std::string& realm,
+                                 const std::string& device_id,
                                  const LockResultCallback& callback);
 
   // Check state of install attributes against TPM lock state and generate UMA
@@ -176,10 +191,6 @@
                                 DBusMethodCallStatus call_status,
                                 bool result);
 
-  // Gets the user that registered the device. Returns an empty string if the
-  // device is not an enterprise device.
-  std::string GetRegistrationUser() const;
-
   CryptohomeClient* cryptohome_client_;
 
   base::WeakPtrFactory<InstallAttributes> weak_ptr_factory_;
diff --git a/chrome/browser/chromeos/settings/install_attributes_unittest.cc b/chrome/browser/chromeos/settings/install_attributes_unittest.cc
index c9c85bf..f5f5702 100644
--- a/chrome/browser/chromeos/settings/install_attributes_unittest.cc
+++ b/chrome/browser/chromeos/settings/install_attributes_unittest.cc
@@ -34,10 +34,10 @@
 
 }  // namespace
 
-static const char kTestUser[] = "test@example.com";
-static const char kTestUserCanonicalize[] = "UPPER.CASE@example.com";
 static const char kTestDomain[] = "example.com";
+static const char kTestRealm[] = "realm.example.com";
 static const char kTestDeviceId[] = "133750519";
+static const char kTestUserDeprecated[] = "test@example.com";
 
 class InstallAttributesTest : public testing::Test {
  protected:
@@ -74,14 +74,16 @@
   std::unique_ptr<InstallAttributes> install_attributes_;
 
   InstallAttributes::LockResult LockDeviceAndWaitForResult(
-      const std::string& user,
       policy::DeviceMode device_mode,
+      const std::string& domain,
+      const std::string& realm,
       const std::string& device_id) {
     base::RunLoop loop;
     InstallAttributes::LockResult result;
     install_attributes_->LockDevice(
-        user,
         device_mode,
+        domain,
+        realm,
         device_id,
         base::Bind(&CopyLockResult, &loop, &result));
     loop.Run();
@@ -91,96 +93,92 @@
 
 TEST_F(InstallAttributesTest, Lock) {
   EXPECT_EQ(InstallAttributes::LOCK_SUCCESS,
-            LockDeviceAndWaitForResult(kTestUser,
-                                       policy::DEVICE_MODE_ENTERPRISE,
+            LockDeviceAndWaitForResult(policy::DEVICE_MODE_ENTERPRISE,
+                                       kTestDomain,
+                                       std::string(),  // realm
                                        kTestDeviceId));
 
   // Locking an already locked device should succeed if the parameters match.
   EXPECT_EQ(InstallAttributes::LOCK_SUCCESS,
-            LockDeviceAndWaitForResult(kTestUser,
-                                       policy::DEVICE_MODE_ENTERPRISE,
-                                       kTestDeviceId));
-
-  // Another user from the same domain should also succeed.
-  EXPECT_EQ(InstallAttributes::LOCK_SUCCESS,
-            LockDeviceAndWaitForResult("test1@example.com",
-                                       policy::DEVICE_MODE_ENTERPRISE,
+            LockDeviceAndWaitForResult(policy::DEVICE_MODE_ENTERPRISE,
+                                       kTestDomain,
+                                       std::string(),  // realm
                                        kTestDeviceId));
 
   // But another domain should fail.
   EXPECT_EQ(InstallAttributes::LOCK_WRONG_DOMAIN,
-            LockDeviceAndWaitForResult("test@bluebears.com",
-                                       policy::DEVICE_MODE_ENTERPRISE,
+            LockDeviceAndWaitForResult(policy::DEVICE_MODE_ENTERPRISE,
+                                       "anotherexample.com",
+                                       std::string(),  // realm
                                        kTestDeviceId));
 
   // A non-matching mode should fail as well.
   EXPECT_EQ(InstallAttributes::LOCK_WRONG_MODE,
-            LockDeviceAndWaitForResult(kTestUser, policy::DEVICE_MODE_CONSUMER,
-                                       kTestDeviceId));
-}
-
-TEST_F(InstallAttributesTest, LockCanonicalize) {
-  EXPECT_EQ(InstallAttributes::LOCK_SUCCESS,
             LockDeviceAndWaitForResult(
-                kTestUserCanonicalize,
-                policy::DEVICE_MODE_ENTERPRISE,
-                kTestDeviceId));
-  EXPECT_EQ(gaia::CanonicalizeEmail(kTestUserCanonicalize),
-            install_attributes_->GetRegistrationUser());
+                policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH,
+                std::string(),    // domain
+                std::string(),    // realm
+                std::string()));  // device id
 }
 
-TEST_F(InstallAttributesTest, IsEnterpriseDevice) {
+TEST_F(InstallAttributesTest, IsEnterpriseDeviceCloud) {
   install_attributes_->Init(GetTempPath());
   EXPECT_FALSE(install_attributes_->IsEnterpriseDevice());
   ASSERT_EQ(InstallAttributes::LOCK_SUCCESS,
             LockDeviceAndWaitForResult(
-                kTestUser,
                 policy::DEVICE_MODE_ENTERPRISE,
+                kTestDomain,
+                std::string(),  // realm
                 kTestDeviceId));
   EXPECT_TRUE(install_attributes_->IsEnterpriseDevice());
 }
 
-TEST_F(InstallAttributesTest, GetDomain) {
+TEST_F(InstallAttributesTest, IsEnterpriseDeviceRealm) {
   install_attributes_->Init(GetTempPath());
+  EXPECT_FALSE(install_attributes_->IsEnterpriseDevice());
+  ASSERT_EQ(InstallAttributes::LOCK_SUCCESS,
+            LockDeviceAndWaitForResult(
+                policy::DEVICE_MODE_ENTERPRISE_AD,
+                std::string(),  // domain
+                kTestRealm,
+                kTestDeviceId));
+  EXPECT_TRUE(install_attributes_->IsEnterpriseDevice());
+}
+
+TEST_F(InstallAttributesTest, GettersCloud) {
+  install_attributes_->Init(GetTempPath());
+  EXPECT_EQ(policy::DEVICE_MODE_PENDING, install_attributes_->GetMode());
   EXPECT_EQ(std::string(), install_attributes_->GetDomain());
-  ASSERT_EQ(InstallAttributes::LOCK_SUCCESS,
-            LockDeviceAndWaitForResult(
-                kTestUser,
-                policy::DEVICE_MODE_ENTERPRISE,
-                kTestDeviceId));
-  EXPECT_EQ(kTestDomain, install_attributes_->GetDomain());
-}
-
-TEST_F(InstallAttributesTest, GetRegistrationUser) {
-  install_attributes_->Init(GetTempPath());
-  EXPECT_EQ(std::string(), install_attributes_->GetRegistrationUser());
-  ASSERT_EQ(InstallAttributes::LOCK_SUCCESS,
-            LockDeviceAndWaitForResult(
-                kTestUser,
-                policy::DEVICE_MODE_ENTERPRISE,
-                kTestDeviceId));
-  EXPECT_EQ(kTestUser, install_attributes_->GetRegistrationUser());
-}
-
-TEST_F(InstallAttributesTest, GetDeviceId) {
-  install_attributes_->Init(GetTempPath());
+  EXPECT_EQ(std::string(), install_attributes_->GetRealm());
   EXPECT_EQ(std::string(), install_attributes_->GetDeviceId());
   ASSERT_EQ(InstallAttributes::LOCK_SUCCESS,
             LockDeviceAndWaitForResult(
-                kTestUser,
                 policy::DEVICE_MODE_ENTERPRISE,
+                kTestDomain,
+                std::string(),  // realm
                 kTestDeviceId));
+  EXPECT_EQ(policy::DEVICE_MODE_ENTERPRISE, install_attributes_->GetMode());
+  EXPECT_EQ(kTestDomain, install_attributes_->GetDomain());
+  EXPECT_EQ(std::string(), install_attributes_->GetRealm());
   EXPECT_EQ(kTestDeviceId, install_attributes_->GetDeviceId());
 }
 
-TEST_F(InstallAttributesTest, GetMode) {
+TEST_F(InstallAttributesTest, GettersAD) {
   install_attributes_->Init(GetTempPath());
   EXPECT_EQ(policy::DEVICE_MODE_PENDING, install_attributes_->GetMode());
+  EXPECT_EQ(std::string(), install_attributes_->GetDomain());
+  EXPECT_EQ(std::string(), install_attributes_->GetRealm());
+  EXPECT_EQ(std::string(), install_attributes_->GetDeviceId());
   ASSERT_EQ(InstallAttributes::LOCK_SUCCESS,
-            LockDeviceAndWaitForResult(kTestUser,
-                                       policy::DEVICE_MODE_ENTERPRISE,
-                                       kTestDeviceId));
-  EXPECT_EQ(policy::DEVICE_MODE_ENTERPRISE, install_attributes_->GetMode());
+            LockDeviceAndWaitForResult(
+                policy::DEVICE_MODE_ENTERPRISE_AD,
+                std::string(),  // domain
+                kTestRealm,
+                kTestDeviceId));
+  EXPECT_EQ(policy::DEVICE_MODE_ENTERPRISE_AD, install_attributes_->GetMode());
+  EXPECT_EQ(std::string(), install_attributes_->GetDomain());
+  EXPECT_EQ(kTestRealm, install_attributes_->GetRealm());
+  EXPECT_EQ(kTestDeviceId, install_attributes_->GetDeviceId());
 }
 
 TEST_F(InstallAttributesTest, ConsumerDevice) {
@@ -194,6 +192,9 @@
 
   ASSERT_FALSE(cryptohome_util::InstallAttributesIsFirstInstall());
   EXPECT_EQ(policy::DEVICE_MODE_CONSUMER, install_attributes_->GetMode());
+  EXPECT_EQ(std::string(), install_attributes_->GetDomain());
+  EXPECT_EQ(std::string(), install_attributes_->GetRealm());
+  EXPECT_EQ(std::string(), install_attributes_->GetDeviceId());
 }
 
 TEST_F(InstallAttributesTest, ConsumerKioskDevice) {
@@ -202,13 +203,17 @@
   // Lock the attributes for consumer kiosk.
   ASSERT_EQ(InstallAttributes::LOCK_SUCCESS,
             LockDeviceAndWaitForResult(
-                std::string(),
                 policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH,
+                std::string(),
+                std::string(),
                 std::string()));
 
   ASSERT_FALSE(cryptohome_util::InstallAttributesIsFirstInstall());
   EXPECT_EQ(policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH,
             install_attributes_->GetMode());
+  EXPECT_EQ(std::string(), install_attributes_->GetDomain());
+  EXPECT_EQ(std::string(), install_attributes_->GetRealm());
+  EXPECT_EQ(std::string(), install_attributes_->GetDeviceId());
   ASSERT_TRUE(install_attributes_->IsConsumerKioskDeviceWithAutoLaunch());
 }
 
@@ -219,7 +224,7 @@
   ASSERT_TRUE(cryptohome_util::InstallAttributesSet(
       InstallAttributes::kAttrEnterpriseOwned, "true"));
   ASSERT_TRUE(cryptohome_util::InstallAttributesSet(
-      InstallAttributes::kAttrEnterpriseUser, kTestUser));
+      InstallAttributes::kAttrEnterpriseUser, kTestUserDeprecated));
   ASSERT_TRUE(cryptohome_util::InstallAttributesFinalize());
   base::RunLoop loop;
   install_attributes_->ReadImmutableAttributes(loop.QuitClosure());
@@ -228,8 +233,8 @@
   ASSERT_FALSE(cryptohome_util::InstallAttributesIsFirstInstall());
   EXPECT_EQ(policy::DEVICE_MODE_ENTERPRISE, install_attributes_->GetMode());
   EXPECT_EQ(kTestDomain, install_attributes_->GetDomain());
-  EXPECT_EQ(kTestUser, install_attributes_->GetRegistrationUser());
-  EXPECT_EQ("", install_attributes_->GetDeviceId());
+  EXPECT_EQ(std::string(), install_attributes_->GetRealm());
+  EXPECT_EQ(std::string(), install_attributes_->GetDeviceId());
 }
 
 TEST_F(InstallAttributesTest, Init) {
@@ -237,15 +242,15 @@
   SetAttribute(&install_attrs_proto,
                InstallAttributes::kAttrEnterpriseOwned, "true");
   SetAttribute(&install_attrs_proto,
-               InstallAttributes::kAttrEnterpriseUser, kTestUser);
+               InstallAttributes::kAttrEnterpriseUser, kTestUserDeprecated);
   const std::string blob(install_attrs_proto.SerializeAsString());
   ASSERT_EQ(static_cast<int>(blob.size()),
             base::WriteFile(GetTempPath(), blob.c_str(), blob.size()));
   install_attributes_->Init(GetTempPath());
   EXPECT_EQ(policy::DEVICE_MODE_ENTERPRISE, install_attributes_->GetMode());
   EXPECT_EQ(kTestDomain, install_attributes_->GetDomain());
-  EXPECT_EQ(kTestUser, install_attributes_->GetRegistrationUser());
-  EXPECT_EQ("", install_attributes_->GetDeviceId());
+  EXPECT_EQ(std::string(), install_attributes_->GetRealm());
+  EXPECT_EQ(std::string(), install_attributes_->GetDeviceId());
 }
 
 TEST_F(InstallAttributesTest, InitForConsumerKiosk) {
@@ -258,9 +263,9 @@
   install_attributes_->Init(GetTempPath());
   EXPECT_EQ(policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH,
             install_attributes_->GetMode());
-  EXPECT_EQ("", install_attributes_->GetDomain());
-  EXPECT_EQ("", install_attributes_->GetRegistrationUser());
-  EXPECT_EQ("", install_attributes_->GetDeviceId());
+  EXPECT_EQ(std::string(), install_attributes_->GetDomain());
+  EXPECT_EQ(std::string(), install_attributes_->GetRealm());
+  EXPECT_EQ(std::string(), install_attributes_->GetDeviceId());
 }
 
 TEST_F(InstallAttributesTest, VerifyFakeInstallAttributesCache) {
@@ -269,18 +274,21 @@
 
   // Verify that no attributes are initially set.
   install_attributes_->Init(GetTempPath());
-  EXPECT_EQ("", install_attributes_->GetRegistrationUser());
+  EXPECT_EQ(policy::DEVICE_MODE_PENDING, install_attributes_->GetMode());
 
   // Write test values.
   ASSERT_TRUE(cryptohome_util::InstallAttributesSet(
       InstallAttributes::kAttrEnterpriseOwned, "true"));
   ASSERT_TRUE(cryptohome_util::InstallAttributesSet(
-      InstallAttributes::kAttrEnterpriseUser, kTestUser));
+      InstallAttributes::kAttrEnterpriseUser, kTestUserDeprecated));
   ASSERT_TRUE(cryptohome_util::InstallAttributesFinalize());
 
   // Verify that InstallAttributes correctly decodes the stub cache file.
   install_attributes_->Init(GetTempPath());
-  EXPECT_EQ(kTestUser, install_attributes_->GetRegistrationUser());
+  EXPECT_EQ(policy::DEVICE_MODE_ENTERPRISE, install_attributes_->GetMode());
+  EXPECT_EQ(kTestDomain, install_attributes_->GetDomain());
+  EXPECT_EQ(std::string(), install_attributes_->GetRealm());
+  EXPECT_EQ(std::string(), install_attributes_->GetDeviceId());
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/settings/stub_install_attributes.cc b/chrome/browser/chromeos/settings/stub_install_attributes.cc
index 348b4fa1..aaafadcf 100644
--- a/chrome/browser/chromeos/settings/stub_install_attributes.cc
+++ b/chrome/browser/chromeos/settings/stub_install_attributes.cc
@@ -15,34 +15,58 @@
   device_locked_ = true;
 }
 
-void StubInstallAttributes::SetDomain(const std::string& domain) {
+void StubInstallAttributes::Clear() {
+  registration_mode_ = policy::DEVICE_MODE_NOT_SET;
+  registration_domain_.clear();
+  registration_realm_.clear();
+  registration_device_id_.clear();
+}
+
+void StubInstallAttributes::SetConsumer() {
+  registration_mode_ = policy::DEVICE_MODE_CONSUMER;
+  registration_domain_.clear();
+  registration_realm_.clear();
+  registration_device_id_.clear();
+}
+
+void StubInstallAttributes::SetEnterprise(const std::string& domain,
+                                          const std::string& device_id) {
+  registration_mode_ = policy::DEVICE_MODE_ENTERPRISE;
   registration_domain_ = domain;
+  registration_realm_.clear();
+  registration_device_id_ = device_id;
 }
 
-void StubInstallAttributes::SetRegistrationUser(const std::string& user) {
-  registration_user_ = user;
-}
-
-void StubInstallAttributes::SetDeviceId(const std::string& id) {
-  registration_device_id_ = id;
-}
-
-void StubInstallAttributes::SetMode(policy::DeviceMode mode) {
-  registration_mode_ = mode;
-}
-
-ScopedStubInstallAttributes::ScopedStubInstallAttributes(
-    const std::string& domain,
-    const std::string& registration_user,
-    const std::string& device_id,
-    policy::DeviceMode mode) {
+// static
+ScopedStubInstallAttributes ScopedStubInstallAttributes::CreateUnset() {
   StubInstallAttributes* attributes = new StubInstallAttributes();
-  attributes->SetDomain(domain);
-  attributes->SetRegistrationUser(registration_user);
-  attributes->SetDeviceId(device_id);
-  attributes->SetMode(mode);
+  attributes->Clear();
   policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
       attributes);
+  return ScopedStubInstallAttributes();
+}
+
+// static
+ScopedStubInstallAttributes ScopedStubInstallAttributes::CreateConsumer() {
+  StubInstallAttributes* attributes = new StubInstallAttributes();
+  attributes->SetConsumer();
+  policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
+      attributes);
+  return ScopedStubInstallAttributes();
+}
+
+// static
+ScopedStubInstallAttributes ScopedStubInstallAttributes::CreateEnterprise(
+    const std::string& domain,
+    const std::string& device_id) {
+  StubInstallAttributes* attributes = new StubInstallAttributes();
+  attributes->SetEnterprise(domain, device_id);
+  policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
+      attributes);
+  return ScopedStubInstallAttributes();
+}
+
+ScopedStubInstallAttributes::ScopedStubInstallAttributes() {
 }
 
 ScopedStubInstallAttributes::~ScopedStubInstallAttributes() {
diff --git a/chrome/browser/chromeos/settings/stub_install_attributes.h b/chrome/browser/chromeos/settings/stub_install_attributes.h
index 86a943a7..2358c2c3 100644
--- a/chrome/browser/chromeos/settings/stub_install_attributes.h
+++ b/chrome/browser/chromeos/settings/stub_install_attributes.h
@@ -13,17 +13,19 @@
 
 namespace chromeos {
 
-// This class allows tests to override specific values for easier testing.
-// To make IsEnterpriseDevice() return true, set a non-empty registration
-// user.
+// This class allows tests to set specific configurations for testing.
 class StubInstallAttributes : public InstallAttributes {
  public:
   StubInstallAttributes();
 
-  void SetDomain(const std::string& domain);
-  void SetRegistrationUser(const std::string& user);
-  void SetDeviceId(const std::string& id);
-  void SetMode(policy::DeviceMode mode);
+  // Setup as not-yet enrolled.
+  void Clear();
+
+  // Setup as consumer device.  (Clears existing configuration.)
+  void SetConsumer();
+
+  // Setup as enterprise enrolled.  (Clears existing configuration.)
+  void SetEnterprise(const std::string& domain, const std::string& device_id);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(StubInstallAttributes);
@@ -32,11 +34,21 @@
 // Helper class to set install attributes in the scope of a test.
 class ScopedStubInstallAttributes {
  public:
-  ScopedStubInstallAttributes(const std::string& domain,
-                              const std::string& registration_user,
-                              const std::string& device_id,
-                              policy::DeviceMode mode);
   ~ScopedStubInstallAttributes();
+
+  // Factory for empty (unset) ScopedStubInstallAttributes.
+  static ScopedStubInstallAttributes CreateUnset();
+
+  // Factory for consumer-type ScopedStubInstallAttributes.
+  static ScopedStubInstallAttributes CreateConsumer();
+
+  // Factory for enterprise-type ScopedStubInstallAttributes.
+  static ScopedStubInstallAttributes CreateEnterprise(
+      const std::string& domain,
+      const std::string& device_id);
+
+ private:
+  ScopedStubInstallAttributes();
 };
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc b/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc
index c8c5fa3..97482ca 100644
--- a/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc
+++ b/chrome/browser/chromeos/system/device_disabling_manager_unittest.cc
@@ -56,10 +56,6 @@
 
   virtual void CreateDeviceDisablingManager();
   virtual void DestroyDeviceDisablingManager();
-
-  void UpdateInstallAttributes(const std::string& enrollment_domain,
-                               const std::string& registration_user,
-                               policy::DeviceMode device_mode);
   void LogIn();
 
   // DeviceDisablingManager::Delegate:
@@ -70,7 +66,14 @@
     return device_disabling_manager_.get();
   }
 
+  // Configure install attributes.
+  void SetUnowned();
+  void SetEnterpriseOwned();
+  void SetConsumerOwned();
+
  private:
+  chromeos::StubInstallAttributes* GetInstallAttributes();
+
   chromeos::ScopedStubInstallAttributes install_attributes_;
   chromeos::ScopedTestDeviceSettingsService test_device_settings_service_;
   chromeos::ScopedTestCrosSettings test_cros_settings_;
@@ -81,7 +84,7 @@
 };
 
 DeviceDisablingManagerTestBase::DeviceDisablingManagerTestBase()
-    : install_attributes_("", "", "", policy::DEVICE_MODE_NOT_SET) {
+    : install_attributes_(ScopedStubInstallAttributes::CreateUnset()) {
 }
 
 void DeviceDisablingManagerTestBase::TearDown() {
@@ -99,25 +102,31 @@
   device_disabling_manager_.reset();
 }
 
-void DeviceDisablingManagerTestBase::UpdateInstallAttributes(
-    const std::string& enrollment_domain,
-    const std::string& registration_user,
-    policy::DeviceMode device_mode) {
-  chromeos::StubInstallAttributes* install_attributes =
-      static_cast<chromeos::StubInstallAttributes*>(
-          TestingBrowserProcess::GetGlobal()
-              ->platform_part()
-              ->browser_policy_connector_chromeos()
-              ->GetInstallAttributes());
-  install_attributes->SetDomain(enrollment_domain);
-  install_attributes->SetRegistrationUser(registration_user);
-  install_attributes->SetMode(device_mode);
-}
-
 void DeviceDisablingManagerTestBase::LogIn() {
   fake_user_manager_.AddUser(AccountId::FromUserEmail(kTestUser));
 }
 
+void DeviceDisablingManagerTestBase::SetUnowned() {
+  GetInstallAttributes()->Clear();
+}
+
+void DeviceDisablingManagerTestBase::SetEnterpriseOwned() {
+  GetInstallAttributes()->SetEnterprise(kEnrollmentDomain, "fake-id");
+}
+
+void DeviceDisablingManagerTestBase::SetConsumerOwned() {
+  GetInstallAttributes()->SetConsumer();
+}
+
+chromeos::StubInstallAttributes*
+DeviceDisablingManagerTestBase::GetInstallAttributes() {
+  return static_cast<chromeos::StubInstallAttributes*>(
+      TestingBrowserProcess::GetGlobal()
+      ->platform_part()
+      ->browser_policy_connector_chromeos()
+      ->GetInstallAttributes());
+}
+
 // Base class for tests that verify device disabling behavior during OOBE, when
 // the device is not owned yet.
 class DeviceDisablingManagerOOBETest : public DeviceDisablingManagerTestBase {
@@ -216,9 +225,7 @@
 // Verifies that the device is not considered disabled during OOBE when it is
 // already enrolled, even if the device is marked as disabled.
 TEST_F(DeviceDisablingManagerOOBETest, NotDisabledWhenEnterpriseOwned) {
-  UpdateInstallAttributes(kEnrollmentDomain,
-                          kTestUser,
-                          policy::DEVICE_MODE_ENTERPRISE);
+  SetEnterpriseOwned();
   SetDeviceDisabled(true);
   CheckWhetherDeviceDisabledDuringOOBE();
   EXPECT_FALSE(device_disabled());
@@ -227,9 +234,7 @@
 // Verifies that the device is not considered disabled during OOBE when it is
 // already owned by a consumer, even if the device is marked as disabled.
 TEST_F(DeviceDisablingManagerOOBETest, NotDisabledWhenConsumerOwned) {
-  UpdateInstallAttributes(std::string() /* enrollment_domain */,
-                          std::string() /* registration_user */,
-                          policy::DEVICE_MODE_CONSUMER);
+  SetConsumerOwned();
   SetDeviceDisabled(true);
   CheckWhetherDeviceDisabledDuringOOBE();
   EXPECT_FALSE(device_disabled());
@@ -262,9 +267,6 @@
   // DeviceDisablingManager::Observer:
   MOCK_METHOD1(OnDisabledMessageChanged, void(const std::string&));
 
-  void SetUnowned();
-  void SetEnterpriseOwned();
-  void SetConsumerOwned();
   void MakeCrosSettingsTrusted();
 
   void SetDeviceDisabled(bool disabled);
@@ -299,24 +301,6 @@
   DeviceDisablingManagerTestBase::DestroyDeviceDisablingManager();
 }
 
-void DeviceDisablingManagerTest::SetUnowned() {
-  UpdateInstallAttributes(std::string() /* enrollment_domain */,
-                          std::string() /* registration_user */,
-                          policy::DEVICE_MODE_NOT_SET);
-}
-
-void DeviceDisablingManagerTest::SetEnterpriseOwned() {
-  UpdateInstallAttributes(kEnrollmentDomain,
-                          kTestUser,
-                          policy::DEVICE_MODE_ENTERPRISE);
-}
-
-void DeviceDisablingManagerTest::SetConsumerOwned() {
-  UpdateInstallAttributes(std::string() /* enrollment_domain */,
-                          std::string() /* registration_user */,
-                          policy::DEVICE_MODE_CONSUMER);
-}
-
 void DeviceDisablingManagerTest::MakeCrosSettingsTrusted() {
   scoped_refptr<ownership::MockOwnerKeyUtil> owner_key_util(
       new ownership::MockOwnerKeyUtil);
diff --git a/chrome/browser/chromeos/ui/focus_ring_layer.cc b/chrome/browser/chromeos/ui/focus_ring_layer.cc
index 81b4c675..39de53d 100644
--- a/chrome/browser/chromeos/ui/focus_ring_layer.cc
+++ b/chrome/browser/chromeos/ui/focus_ring_layer.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/chromeos/ui/focus_ring_layer.h"
 
-#include "base/bind.h"
 #include "ui/aura/window.h"
 #include "ui/compositor/compositor_animation_observer.h"
 #include "ui/compositor/layer.h"
@@ -117,10 +116,6 @@
     delegate_->OnDeviceScaleFactorChanged();
 }
 
-base::Closure FocusRingLayer::PrepareForLayerBoundsChange() {
-  return base::Bind(&base::DoNothing);
-}
-
 void FocusRingLayer::OnAnimationStep(base::TimeTicks timestamp) {
   delegate_->OnAnimationStep(timestamp);
 }
diff --git a/chrome/browser/chromeos/ui/focus_ring_layer.h b/chrome/browser/chromeos/ui/focus_ring_layer.h
index ea6d3def..0b17813 100644
--- a/chrome/browser/chromeos/ui/focus_ring_layer.h
+++ b/chrome/browser/chromeos/ui/focus_ring_layer.h
@@ -68,7 +68,6 @@
   void OnPaintLayer(const ui::PaintContext& context) override;
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
   void OnDeviceScaleFactorChanged(float device_scale_factor) override;
-  base::Closure PrepareForLayerBoundsChange() override;
 
   // CompositorAnimationObserver overrides:
   void OnAnimationStep(base::TimeTicks timestamp) override;
diff --git a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
index 329d1cc..626984f2 100644
--- a/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
+++ b/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc
@@ -100,7 +100,7 @@
     std::unique_ptr<chromeos::StubInstallAttributes> attributes =
         base::MakeUnique<chromeos::StubInstallAttributes>();
 
-    attributes->SetRegistrationUser(affiliated_account_id_.GetUserEmail());
+    attributes->SetEnterprise("fake-domain", "fake-id");
     policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
         attributes.release());
 
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc
index 01e84795..4a71583 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc
@@ -161,11 +161,7 @@
     ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
         .WillByDefault(Invoke(GetCertificateCallbackTrue));
 
-    // Set the Enterprise install attributes.
-    stub_install_attributes_.SetDomain("google.com");
-    stub_install_attributes_.SetRegistrationUser(kUserEmail);
-    stub_install_attributes_.SetDeviceId("device_id");
-    stub_install_attributes_.SetMode(policy::DEVICE_MODE_ENTERPRISE);
+    stub_install_attributes_.SetEnterprise("google.com", "device_id");
 
     settings_helper_.ReplaceProvider(chromeos::kDeviceAttestationEnabled);
     settings_helper_.SetBoolean(chromeos::kDeviceAttestationEnabled, true);
@@ -277,7 +273,7 @@
 };
 
 TEST_F(EPKChallengeMachineKeyTest, NonEnterpriseDevice) {
-  stub_install_attributes_.SetRegistrationUser("");
+  stub_install_attributes_.SetConsumer();
 
   EXPECT_EQ(EPKPChallengeMachineKey::kNonEnterpriseDeviceError,
             RunFunctionAndReturnError(func_.get(), CreateArgs(), browser()));
@@ -496,7 +492,7 @@
 }
 
 TEST_F(EPKChallengeUserKeyTest, PersonalDevice) {
-  stub_install_attributes_.SetRegistrationUser("");
+  stub_install_attributes_.SetConsumer();
 
   // Currently personal devices are not supported.
   EXPECT_EQ(GetCertificateError(kUserRejected),
diff --git a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
index b3c78fbe..6d9e269 100644
--- a/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc
@@ -170,11 +170,7 @@
     ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _))
         .WillByDefault(Invoke(GetCertificateCallbackTrue));
 
-    // Set the Enterprise install attributes.
-    stub_install_attributes_.SetDomain("google.com");
-    stub_install_attributes_.SetRegistrationUser(kUserEmail);
-    stub_install_attributes_.SetDeviceId("device_id");
-    stub_install_attributes_.SetMode(policy::DEVICE_MODE_ENTERPRISE);
+    stub_install_attributes_.SetEnterprise("google.com", "device_id");
 
     settings_helper_.ReplaceProvider(chromeos::kDeviceAttestationEnabled);
     settings_helper_.SetBoolean(chromeos::kDeviceAttestationEnabled, true);
@@ -262,7 +258,7 @@
 }
 
 TEST_F(EPKPChallengeMachineKeyTest, NonEnterpriseDevice) {
-  stub_install_attributes_.SetRegistrationUser("");
+  stub_install_attributes_.SetConsumer();
 
   EXPECT_EQ(EPKPChallengeMachineKey::kNonEnterpriseDeviceError,
             utils::RunFunctionAndReturnError(func_.get(), kArgs, browser()));
@@ -477,7 +473,7 @@
 }
 
 TEST_F(EPKPChallengeUserKeyTest, PersonalDevice) {
-  stub_install_attributes_.SetRegistrationUser("");
+  stub_install_attributes_.SetConsumer();
 
   // Currently personal devices are not supported.
   EXPECT_EQ(GetCertificateError(kUserRejected),
diff --git a/chrome/browser/extensions/api/identity/identity_apitest.cc b/chrome/browser/extensions/api/identity/identity_apitest.cc
index 06d8037..22f056d 100644
--- a/chrome/browser/extensions/api/identity/identity_apitest.cc
+++ b/chrome/browser/extensions/api/identity/identity_apitest.cc
@@ -1597,8 +1597,7 @@
     // enterprise-managed.
      std::unique_ptr<chromeos::StubInstallAttributes> attributes
          = base::MakeUnique<chromeos::StubInstallAttributes>();
-     attributes->SetDomain("example.com");
-     attributes->SetRegistrationUser("user@example.com");
+     attributes->SetEnterprise("example.com", "fake-id");
      policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
          attributes.release());
   }
diff --git a/chrome/browser/extensions/extension_commands_global_registry.cc b/chrome/browser/extensions/extension_commands_global_registry.cc
index c98051c4..f43caa1d 100644
--- a/chrome/browser/extensions/extension_commands_global_registry.cc
+++ b/chrome/browser/extensions/extension_commands_global_registry.cc
@@ -83,10 +83,6 @@
       continue;
     const ui::Accelerator& accelerator = iter->second.accelerator();
 
-    VLOG(0) << "Adding global keybinding for " << extension->name().c_str()
-            << " " << command_name.c_str()
-            << " key: " << accelerator.GetShortcutText();
-
     if (!IsAcceleratorRegistered(accelerator)) {
       if (!GlobalShortcutListener::GetInstance()->RegisterAccelerator(
               accelerator, this))
@@ -100,8 +96,6 @@
 void ExtensionCommandsGlobalRegistry::RemoveExtensionKeybindingImpl(
     const ui::Accelerator& accelerator,
     const std::string& command_name) {
-  VLOG(0) << "Removing keybinding for " << command_name.c_str();
-
   GlobalShortcutListener::GetInstance()->UnregisterAccelerator(
       accelerator, this);
 }
diff --git a/chrome/browser/net/errorpage_browsertest.cc b/chrome/browser/net/errorpage_browsertest.cc
index 6b20ce24..ed86cca 100644
--- a/chrome/browser/net/errorpage_browsertest.cc
+++ b/chrome/browser/net/errorpage_browsertest.cc
@@ -1301,8 +1301,7 @@
       // Set up fake install attributes.
       std::unique_ptr<chromeos::StubInstallAttributes> attributes =
           base::MakeUnique<chromeos::StubInstallAttributes>();
-      attributes->SetDomain("example.com");
-      attributes->SetRegistrationUser("user@example.com");
+      attributes->SetEnterprise("example.com", "fake-id");
       policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
           attributes.release());
     }
diff --git a/chrome/browser/notifications/native_notification_display_service.cc b/chrome/browser/notifications/native_notification_display_service.cc
index c09e118e..d7271b0 100644
--- a/chrome/browser/notifications/native_notification_display_service.cc
+++ b/chrome/browser/notifications/native_notification_display_service.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/notifications/native_notification_display_service.h"
 
 #include "base/memory/ptr_util.h"
+#include "base/strings/nullable_string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/notifications/non_persistent_notification_handler.h"
 #include "chrome/browser/notifications/notification.h"
@@ -84,7 +85,8 @@
   CHECK(handler);
   switch (operation) {
     case NotificationCommon::CLICK:
-      handler->OnClick(profile_, origin, notification_id, action_index);
+      handler->OnClick(profile_, origin, notification_id, action_index,
+                       base::NullableString16() /* reply */);
       break;
     case NotificationCommon::CLOSE:
       handler->OnClose(profile_, origin, notification_id, true /* by_user */);
diff --git a/chrome/browser/notifications/non_persistent_notification_handler.cc b/chrome/browser/notifications/non_persistent_notification_handler.cc
index 3e21f926..e2c5d87 100644
--- a/chrome/browser/notifications/non_persistent_notification_handler.cc
+++ b/chrome/browser/notifications/non_persistent_notification_handler.cc
@@ -25,9 +25,12 @@
     Profile* profile,
     const std::string& origin,
     const std::string& notification_id,
-    int action_index) {
-  // Buttons not supported for non persistent notifications.
+    int action_index,
+    const base::NullableString16& reply) {
+  // Buttons and replies not supported for non persistent notifications.
   DCHECK_EQ(action_index, -1);
+  DCHECK(reply.is_null());
+
   if (notifications_.find(notification_id) != notifications_.end()) {
     notifications_[notification_id]->Click();
   }
diff --git a/chrome/browser/notifications/non_persistent_notification_handler.h b/chrome/browser/notifications/non_persistent_notification_handler.h
index 51b8d36..78ad623 100644
--- a/chrome/browser/notifications/non_persistent_notification_handler.h
+++ b/chrome/browser/notifications/non_persistent_notification_handler.h
@@ -28,7 +28,8 @@
   void OnClick(Profile* profile,
                const std::string& origin,
                const std::string& notification_id,
-               int action_index) override;
+               int action_index,
+               const base::NullableString16& reply) override;
 
   void OpenSettings(Profile* profile) override;
 
diff --git a/chrome/browser/notifications/notification_handler.h b/chrome/browser/notifications/notification_handler.h
index b410d49..851e76b 100644
--- a/chrome/browser/notifications/notification_handler.h
+++ b/chrome/browser/notifications/notification_handler.h
@@ -8,6 +8,10 @@
 #include <memory>
 #include <string>
 
+namespace base {
+class NullableString16;
+}
+
 class NotificationDelegate;
 class Profile;
 
@@ -28,7 +32,8 @@
   virtual void OnClick(Profile* profile,
                        const std::string& origin,
                        const std::string& notification_id,
-                       int action_index) = 0;
+                       int action_index,
+                       const base::NullableString16& reply) = 0;
 
   // Open notification settings.
   virtual void OpenSettings(Profile* profile) = 0;
diff --git a/chrome/browser/notifications/persistent_notification_delegate.cc b/chrome/browser/notifications/persistent_notification_delegate.cc
index 1e05cbf..b38f3c1 100644
--- a/chrome/browser/notifications/persistent_notification_delegate.cc
+++ b/chrome/browser/notifications/persistent_notification_delegate.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/notifications/persistent_notification_delegate.h"
 
+#include "base/strings/nullable_string16.h"
 #include "chrome/browser/notifications/platform_notification_service_impl.h"
 #include "url/gurl.h"
 
@@ -26,7 +27,8 @@
 
 void PersistentNotificationDelegate::Click() {
   PlatformNotificationServiceImpl::GetInstance()->OnPersistentNotificationClick(
-      browser_context(), id(), origin(), -1 /* action_index */);
+      browser_context(), id(), origin(), -1 /* action_index */,
+      base::NullableString16() /* reply */);
 }
 
 void PersistentNotificationDelegate::ButtonClick(int button_index) {
@@ -37,5 +39,16 @@
   }
 
   PlatformNotificationServiceImpl::GetInstance()->OnPersistentNotificationClick(
-      browser_context(), id(), origin(), button_index);
+      browser_context(), id(), origin(), button_index,
+      base::NullableString16() /* reply */);
+}
+
+void PersistentNotificationDelegate::ButtonClickWithReply(
+    int button_index,
+    const base::string16& reply) {
+  DCHECK_GE(button_index, 0);
+  DCHECK_NE(button_index, notification_settings_index_);
+  PlatformNotificationServiceImpl::GetInstance()->OnPersistentNotificationClick(
+      browser_context(), id(), origin(), button_index,
+      base::NullableString16(reply, false /* is_null */));
 }
diff --git a/chrome/browser/notifications/persistent_notification_delegate.h b/chrome/browser/notifications/persistent_notification_delegate.h
index 932dc5f..ace6d1b 100644
--- a/chrome/browser/notifications/persistent_notification_delegate.h
+++ b/chrome/browser/notifications/persistent_notification_delegate.h
@@ -31,6 +31,8 @@
   void Close(bool by_user) override;
   void Click() override;
   void ButtonClick(int button_index) override;
+  void ButtonClickWithReply(int button_index,
+                            const base::string16& reply) override;
 
  protected:
   ~PersistentNotificationDelegate() override;
diff --git a/chrome/browser/notifications/persistent_notification_handler.cc b/chrome/browser/notifications/persistent_notification_handler.cc
index 810b0f1..16b62654d 100644
--- a/chrome/browser/notifications/persistent_notification_handler.cc
+++ b/chrome/browser/notifications/persistent_notification_handler.cc
@@ -25,15 +25,17 @@
       profile, notification_id, notification_origin, by_user);
 }
 
-void PersistentNotificationHandler::OnClick(Profile* profile,
-                                            const std::string& origin,
-                                            const std::string& notification_id,
-                                            int action_index) {
+void PersistentNotificationHandler::OnClick(
+    Profile* profile,
+    const std::string& origin,
+    const std::string& notification_id,
+    int action_index,
+    const base::NullableString16& reply) {
   const GURL notification_origin(origin);
   DCHECK(notification_origin.is_valid());
 
   PlatformNotificationServiceImpl::GetInstance()->OnPersistentNotificationClick(
-      profile, notification_id, notification_origin, action_index);
+      profile, notification_id, notification_origin, action_index, reply);
 }
 
 void PersistentNotificationHandler::OpenSettings(Profile* profile) {
diff --git a/chrome/browser/notifications/persistent_notification_handler.h b/chrome/browser/notifications/persistent_notification_handler.h
index c251a0e..577f8ba4 100644
--- a/chrome/browser/notifications/persistent_notification_handler.h
+++ b/chrome/browser/notifications/persistent_notification_handler.h
@@ -25,7 +25,8 @@
   void OnClick(Profile* profile,
                const std::string& origin,
                const std::string& notification_id,
-               int action_index) override;
+               int action_index,
+               const base::NullableString16& reply) override;
   void OpenSettings(Profile* profile) override;
   void RegisterNotification(const std::string& notification_id,
                             NotificationDelegate* delegate) override;
diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc
index 13d772a..aa0683af 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.cc
+++ b/chrome/browser/notifications/platform_notification_service_impl.cc
@@ -107,7 +107,8 @@
     BrowserContext* browser_context,
     const std::string& notification_id,
     const GURL& origin,
-    int action_index) {
+    int action_index,
+    const base::NullableString16& reply) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   blink::mojom::PermissionStatus permission_status =
       CheckPermissionOnUIThread(browser_context, origin,
@@ -140,7 +141,7 @@
 
   content::NotificationEventDispatcher::GetInstance()
       ->DispatchNotificationClickEvent(
-          browser_context, notification_id, origin, action_index,
+          browser_context, notification_id, origin, action_index, reply,
           base::Bind(
               &PlatformNotificationServiceImpl::OnClickEventDispatchComplete,
               base::Unretained(this)));
diff --git a/chrome/browser/notifications/platform_notification_service_impl.h b/chrome/browser/notifications/platform_notification_service_impl.h
index 88642b37..31482d9 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.h
+++ b/chrome/browser/notifications/platform_notification_service_impl.h
@@ -29,6 +29,10 @@
 class NotificationDisplayService;
 class ScopedKeepAlive;
 
+namespace base {
+class NullableString16;
+}
+
 namespace content {
 class BrowserContext;
 struct NotificationResources;
@@ -53,7 +57,8 @@
   void OnPersistentNotificationClick(content::BrowserContext* browser_context,
                                      const std::string& notification_id,
                                      const GURL& origin,
-                                     int action_index);
+                                     int action_index,
+                                     const base::NullableString16& reply);
 
   // To be called when a persistent notification has been closed. The data
   // associated with the notification has to be pruned from the database in this
diff --git a/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc b/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc
index b967394..f88f16f 100644
--- a/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc
+++ b/chrome/browser/notifications/platform_notification_service_interactive_uitest.cc
@@ -557,6 +557,25 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceBrowserTest,
+                       DisplayPersistentNotificationWithReplyButton) {
+  ASSERT_NO_FATAL_FAILURE(GrantNotificationPermissionForTest());
+
+  std::string script_result;
+  ASSERT_TRUE(RunScript("DisplayPersistentNotificationWithReplyButton()",
+                        &script_result));
+  EXPECT_EQ("ok", script_result);
+  ASSERT_EQ(1u, ui_manager()->GetNotificationCount());
+
+  const Notification& notification = ui_manager()->GetNotificationAt(0);
+  ASSERT_EQ(1u, notification.buttons().size());
+  EXPECT_EQ("actionTitle1", base::UTF16ToUTF8(notification.buttons()[0].title));
+
+  notification.delegate()->ButtonClickWithReply(0, base::ASCIIToUTF16("hello"));
+  ASSERT_TRUE(RunScript("GetMessageFromWorker()", &script_result));
+  EXPECT_EQ("action_button_click actionId1 hello", script_result);
+}
+
+IN_PROC_BROWSER_TEST_F(PlatformNotificationServiceBrowserTest,
                        TestShouldDisplayNormal) {
   ASSERT_NO_FATAL_FAILURE(GrantNotificationPermissionForTest());
   EnableFullscreenNotifications();
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index 48b7d03b..53b2055 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -336,7 +336,7 @@
       browser()->tab_strip_model()->GetActiveWebContents(), url);
 
   chrome::Navigate(&params);
-  EXPECT_TRUE(manager.WaitForWillStartRequest());
+  EXPECT_TRUE(manager.WaitForRequestStart());
 
   GURL url2(embedded_test_server()->GetURL("/title2.html"));
   chrome::NavigateParams params2(browser(), url2,
@@ -359,7 +359,7 @@
       browser()->tab_strip_model()->GetActiveWebContents(), url);
 
   chrome::Navigate(&params);
-  EXPECT_TRUE(manager.WaitForWillStartRequest());
+  EXPECT_TRUE(manager.WaitForRequestStart());
 
   chrome::NavigateParams params2(browser(), url, ui::PAGE_TRANSITION_RELOAD);
   content::TestNavigationManager manager2(
@@ -380,7 +380,7 @@
       browser()->tab_strip_model()->GetActiveWebContents(), url);
 
   chrome::Navigate(&params);
-  EXPECT_TRUE(manager.WaitForWillStartRequest());
+  EXPECT_TRUE(manager.WaitForRequestStart());
 
   browser()->tab_strip_model()->GetActiveWebContents()->Close();
 
@@ -399,7 +399,7 @@
       browser()->tab_strip_model()->GetActiveWebContents(), url);
 
   chrome::Navigate(&params);
-  EXPECT_TRUE(manager.WaitForWillStartRequest());
+  EXPECT_TRUE(manager.WaitForRequestStart());
 
   GURL url2(embedded_test_server()->GetURL("/title2.html"));
   chrome::NavigateParams params2(browser(), url2, ui::PAGE_TRANSITION_TYPED);
@@ -407,7 +407,7 @@
       browser()->tab_strip_model()->GetActiveWebContents(), url2);
   chrome::Navigate(&params2);
 
-  EXPECT_TRUE(manager2.WaitForWillStartRequest());
+  EXPECT_TRUE(manager2.WaitForRequestStart());
   manager.WaitForNavigationFinished();
 
   GURL url3(embedded_test_server()->GetURL("/title3.html"));
@@ -416,7 +416,7 @@
       browser()->tab_strip_model()->GetActiveWebContents(), url3);
   chrome::Navigate(&params3);
 
-  EXPECT_TRUE(manager3.WaitForWillStartRequest());
+  EXPECT_TRUE(manager3.WaitForRequestStart());
   manager2.WaitForNavigationFinished();
 
   manager3.WaitForNavigationFinished();
@@ -437,7 +437,7 @@
   content::TestNavigationManager manager(
       browser()->tab_strip_model()->GetActiveWebContents(), second_url);
   chrome::Navigate(&params);
-  EXPECT_TRUE(manager.WaitForWillStartRequest());
+  EXPECT_TRUE(manager.WaitForRequestStart());
 
   {
     content::TestNavigationManager reload_manager(
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index b5c1210..c0b7e83 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -539,6 +539,9 @@
   { key::kArcBackupRestoreEnabled,
     prefs::kArcBackupRestoreEnabled,
     base::Value::TYPE_BOOLEAN },
+  { key::kReportArcStatus,
+    prefs::kReportArcStatus,
+    base::Value::TYPE_BOOLEAN },
 #endif  // defined(OS_CHROMEOS)
 
 // Metrics reporting is controlled by a platform specific policy for ChromeOS
diff --git a/chrome/browser/resources/inline_login/inline_login.js b/chrome/browser/resources/inline_login/inline_login.js
index 7e67cbc0..17f1c43 100644
--- a/chrome/browser/resources/inline_login/inline_login.js
+++ b/chrome/browser/resources/inline_login/inline_login.js
@@ -20,6 +20,11 @@
    */
   var authReadyFired;
 
+  /**
+  * Whether the login UI is loaded for signing in primary account.
+  */
+  var isLoginPrimaryAccount;
+
   function onResize(e) {
     chrome.send('switchToFullTab', [e.detail]);
   }
@@ -27,7 +32,8 @@
   function onAuthReady(e) {
     $('contents').classList.toggle('loading', false);
     authReadyFired = true;
-    chrome.send('metricsHandler:recordAction', ['Signin_SigninPage_Shown']);
+    if (isLoginPrimaryAccount)
+      chrome.send('metricsHandler:recordAction', ['Signin_SigninPage_Shown']);
   }
 
   function onDropLink(e) {
@@ -74,6 +80,7 @@
     $('contents').classList.toggle('loading',
         data.authMode != cr.login.GaiaAuthHost.AuthMode.DESKTOP ||
         data.constrained == '1');
+    isLoginPrimaryAccount = data.isLoginPrimaryAccount;
   }
 
   /**
diff --git a/chrome/browser/resources/translate_internals/translate_internals.css b/chrome/browser/resources/translate_internals/translate_internals.css
index 11626b4..9d9a7f9 100644
--- a/chrome/browser/resources/translate_internals/translate_internals.css
+++ b/chrome/browser/resources/translate_internals/translate_internals.css
@@ -138,3 +138,7 @@
 .prefs-setting-disabled {
   display: none;
 }
+
+#country-override input {
+ margin-bottom: 1px;
+}
diff --git a/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc b/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc
index 64a9b83d..2b2cff2 100644
--- a/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc
+++ b/chrome/browser/ssl/chrome_security_state_model_client_browser_tests.cc
@@ -966,13 +966,9 @@
 
 // Tests that when an invisible password field is present on an HTTP page
 // load, and when the command-line flag is set, the security level is
-// downgraded to HTTP_SHOW_WARNING.
-//
-// TODO(estark): this will eventually be refined so that the warning
-// will not show up for invisible password
-// inputs. https://codereview.chromium.org/2378503002/
+// *not* downgraded to HTTP_SHOW_WARNING.
 IN_PROC_BROWSER_TEST_F(ChromeSecurityStateModelClientTestWithPasswordCcSwitch,
-                       PasswordSecurityLevelDowngradedForInvisibleInput) {
+                       PasswordSecurityLevelNotDowngradedForInvisibleInput) {
   content::WebContents* contents =
       browser()->tab_strip_model()->GetActiveWebContents();
   ASSERT_TRUE(contents);
@@ -987,13 +983,13 @@
                                  "/password/invisible_password.html"));
   security_state::SecurityStateModel::SecurityInfo security_info;
   model_client->GetSecurityInfo(&security_info);
-  EXPECT_EQ(security_state::SecurityStateModel::HTTP_SHOW_WARNING,
+  EXPECT_EQ(security_state::SecurityStateModel::NONE,
             security_info.security_level);
 
   content::NavigationEntry* entry = contents->GetController().GetVisibleEntry();
   ASSERT_TRUE(entry);
-  EXPECT_TRUE(entry->GetSSL().content_status &
-              content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP);
+  EXPECT_FALSE(entry->GetSSL().content_status &
+               content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP);
 }
 
 // Tests that when a visible password field is detected inside an iframe
diff --git a/chrome/browser/task_manager/task_manager_interface.cc b/chrome/browser/task_manager/task_manager_interface.cc
index 624f241..9cdecf1e 100644
--- a/chrome/browser/task_manager/task_manager_interface.cc
+++ b/chrome/browser/task_manager/task_manager_interface.cc
@@ -76,12 +76,11 @@
   // Recalculate the minimum refresh rate and the enabled resource flags.
   int64_t flags = 0;
   base::TimeDelta min_time = base::TimeDelta::Max();
-  base::ObserverList<TaskManagerObserver>::Iterator itr(&observers_);
-  while (TaskManagerObserver* obs = itr.GetNext()) {
-    if (obs->desired_refresh_time() < min_time)
-      min_time = obs->desired_refresh_time();
+  for (auto& observer : observers_) {
+    if (observer.desired_refresh_time() < min_time)
+      min_time = observer.desired_refresh_time();
 
-    flags |= obs->desired_resources_flags();
+    flags |= observer.desired_resources_flags();
   }
 
   if (min_time == base::TimeDelta::Max()) {
@@ -97,9 +96,8 @@
 
 void TaskManagerInterface::RecalculateRefreshFlags() {
   int64_t flags = 0;
-  base::ObserverList<TaskManagerObserver>::Iterator itr(&observers_);
-  while (TaskManagerObserver* obs = itr.GetNext())
-    flags |= obs->desired_resources_flags();
+  for (auto& observer : observers_)
+    flags |= observer.desired_resources_flags();
 
   SetEnabledResourceFlags(flags);
 }
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 6d6262c..abc8082 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -10,8 +10,8 @@
 #include <string>
 
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
-#include "base/stl_util.h"
 #include "chrome/app/chrome_command_ids.h"
 #include "chrome/browser/browser_shutdown.h"
 #include "chrome/browser/defaults.h"
@@ -109,7 +109,7 @@
 
 WebContents* CloseTracker::Next() {
   if (observers_.empty())
-    return NULL;
+    return nullptr;
 
   DeletionObserver* observer = observers_[0];
   WebContents* web_contents = observer->web_contents();
@@ -210,8 +210,8 @@
     : content::WebContentsObserver(contents),
       contents_(contents),
       tab_strip_model_(tab_strip_model),
-      group_(NULL),
-      opener_(NULL),
+      group_(nullptr),
+      opener_(nullptr),
       reset_group_on_select_(false),
       pinned_(false),
       blocked_(false) {}
@@ -245,7 +245,7 @@
 }
 
 TabStripModel::~TabStripModel() {
-  base::STLDeleteElements(&contents_data_);
+  contents_data_.clear();
   order_controller_.reset();
 }
 
@@ -287,7 +287,8 @@
   // otherwise we run into problems when we try to change the active contents
   // since the old contents and the new contents will be the same...
   WebContents* active_contents = GetActiveWebContents();
-  WebContentsData* data = new WebContentsData(this, contents);
+  std::unique_ptr<WebContentsData> data =
+      base::MakeUnique<WebContentsData>(this, contents);
   data->set_pinned(pin);
   if ((add_types & ADD_INHERIT_GROUP) && active_contents) {
     if (active) {
@@ -315,12 +316,13 @@
   if (manager)
     data->set_blocked(manager->IsDialogActive());
 
-  contents_data_.insert(contents_data_.begin() + index, data);
+  contents_data_.insert(contents_data_.begin() + index, std::move(data));
 
   selection_model_.IncrementFrom(index);
 
-  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                    TabInsertedAt(this, contents, index, active));
+  for (auto& observer : observers_)
+    observer.TabInsertedAt(this, contents, index, active);
+
   if (active) {
     ui::ListSelectionModel new_model;
     new_model.Copy(selection_model_);
@@ -340,20 +342,16 @@
 
   contents_data_[index]->SetWebContents(new_contents);
 
-  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                    TabReplacedAt(this, old_contents, new_contents, index));
+  for (auto& observer : observers_)
+    observer.TabReplacedAt(this, old_contents, new_contents, index);
 
   // When the active WebContents is replaced send out a selection notification
   // too. We do this as nearly all observers need to treat a replacement of the
   // selected contents as the selection changing.
   if (active_index() == index) {
-    FOR_EACH_OBSERVER(
-        TabStripModelObserver,
-        observers_,
-        ActiveTabChanged(old_contents,
-                         new_contents,
-                         active_index(),
-                         TabStripModelObserver::CHANGE_REASON_REPLACED));
+    for (auto& observer : observers_)
+      observer.ActiveTabChanged(old_contents, new_contents, active_index(),
+                                TabStripModelObserver::CHANGE_REASON_REPLACED);
   }
   return old_contents;
 }
@@ -361,7 +359,7 @@
 WebContents* TabStripModel::DetachWebContentsAt(int index) {
   CHECK(!in_notify_);
   if (contents_data_.empty())
-    return NULL;
+    return nullptr;
   DCHECK(ContainsIndex(index));
 
   FixOpenersAndGroupsReferencing(index);
@@ -369,17 +367,17 @@
   WebContents* removed_contents = GetWebContentsAtImpl(index);
   bool was_selected = IsTabSelected(index);
   int next_selected_index = order_controller_->DetermineNewSelectedIndex(index);
-  delete contents_data_[index];
   contents_data_.erase(contents_data_.begin() + index);
   if (empty())
     closing_all_ = true;
-  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                    TabDetachedAt(removed_contents, index));
+  for (auto& observer : observers_)
+    observer.TabDetachedAt(removed_contents, index);
   if (empty()) {
     selection_model_.Clear();
     // TabDetachedAt() might unregister observers, so send |TabStripEmpty()| in
     // a second pass.
-    FOR_EACH_OBSERVER(TabStripModelObserver, observers_, TabStripEmpty());
+    for (auto& observer : observers_)
+      observer.TabStripEmpty();
   } else {
     int old_active = active_index();
     selection_model_.DecrementFrom(index);
@@ -405,8 +403,8 @@
     // notification is sent even though the tab selection has changed because
     // |old_model| is stored after calling DecrementFrom().
     if (was_selected) {
-      FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                        TabSelectionChanged(this, old_model));
+      for (auto& observer : observers_)
+        observer.TabSelectionChanged(this, old_model);
     }
   }
   return removed_contents;
@@ -486,7 +484,7 @@
 WebContents* TabStripModel::GetWebContentsAt(int index) const {
   if (ContainsIndex(index))
     return GetWebContentsAtImpl(index);
-  return NULL;
+  return nullptr;
 }
 
 int TabStripModel::GetIndexOfWebContents(const WebContents* contents) const {
@@ -501,8 +499,8 @@
     TabStripModelObserver::TabChangeType change_type) {
   DCHECK(ContainsIndex(index));
 
-  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-      TabChangedAt(GetWebContentsAtImpl(index), index, change_type));
+  for (auto& observer : observers_)
+    observer.TabChangedAt(GetWebContentsAtImpl(index), index, change_type);
 }
 
 void TabStripModel::CloseAllTabs() {
@@ -524,11 +522,11 @@
 }
 
 bool TabStripModel::TabsAreLoading() const {
-  for (WebContentsDataVector::const_iterator iter = contents_data_.begin();
-       iter != contents_data_.end(); ++iter) {
-    if ((*iter)->web_contents()->IsLoading())
+  for (const auto& data : contents_data_) {
+    if (data->web_contents()->IsLoading())
       return true;
   }
+
   return false;
 }
 
@@ -612,16 +610,15 @@
 void TabStripModel::ForgetAllOpeners() {
   // Forget all opener memories so we don't do anything weird with tab
   // re-selection ordering.
-  for (WebContentsDataVector::const_iterator iter = contents_data_.begin();
-       iter != contents_data_.end(); ++iter)
-    (*iter)->set_opener(NULL);
+  for (const auto& data : contents_data_)
+    data->set_opener(nullptr);
 }
 
 void TabStripModel::ForgetGroup(WebContents* contents) {
   int index = GetIndexOfWebContents(contents);
   DCHECK(ContainsIndex(index));
-  contents_data_[index]->set_group(NULL);
-  contents_data_[index]->set_opener(NULL);
+  contents_data_[index]->set_group(nullptr);
+  contents_data_[index]->set_opener(nullptr);
 }
 
 bool TabStripModel::ShouldResetGroupOnSelect(WebContents* contents) const {
@@ -635,10 +632,9 @@
   if (contents_data_[index]->blocked() == blocked)
     return;
   contents_data_[index]->set_blocked(blocked);
-  FOR_EACH_OBSERVER(
-      TabStripModelObserver, observers_,
-      TabBlockedStateChanged(contents_data_[index]->web_contents(),
-                             index));
+  for (auto& observer : observers_)
+    observer.TabBlockedStateChanged(contents_data_[index]->web_contents(),
+                                    index);
 }
 
 void TabStripModel::SetTabPinned(int index, bool pinned) {
@@ -657,9 +653,9 @@
     index = non_pinned_tab_index - 1;
   }
 
-  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                    TabPinnedStateChanged(
-                        this, contents_data_[index]->web_contents(), index));
+  for (auto& observer : observers_)
+    observer.TabPinnedStateChanged(this, contents_data_[index]->web_contents(),
+                                   index);
 }
 
 bool TabStripModel::IsTabPinned(int index) const {
@@ -1154,7 +1150,8 @@
   base::WeakPtr<TabStripModel> ref(weak_factory_.GetWeakPtr());
   const bool closing_all = indices.size() == contents_data_.size();
   if (closing_all)
-    FOR_EACH_OBSERVER(TabStripModelObserver, observers_, WillCloseAllTabs());
+    for (auto& observer : observers_)
+      observer.WillCloseAllTabs();
 
   // We only try the fast shutdown path if the whole browser process is *not*
   // shutting down. Fast shutdown during browser termination is handled in
@@ -1210,10 +1207,9 @@
                      (close_types & CLOSE_CREATE_HISTORICAL_TAB) != 0);
   }
 
-  if (ref && closing_all && !retval) {
-    FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                      CloseAllTabsCanceled());
-  }
+  if (ref && closing_all && !retval)
+    for (auto& observer : observers_)
+      observer.CloseAllTabsCanceled();
 
   return retval;
 }
@@ -1221,8 +1217,8 @@
 void TabStripModel::InternalCloseTab(WebContents* contents,
                                      int index,
                                      bool create_historical_tabs) {
-  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                    TabClosingAt(this, contents, index));
+  for (auto& observer : observers_)
+    observer.TabClosingAt(this, contents, index);
 
   // Ask the delegate to save an entry for this tab in the historical tab
   // database if applicable.
@@ -1242,8 +1238,8 @@
 
 void TabStripModel::NotifyIfTabDeactivated(WebContents* contents) {
   if (contents) {
-    FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                      TabDeactivated(contents));
+    for (auto& observer : observers_)
+      observer.TabDeactivated(contents);
   }
 }
 
@@ -1256,11 +1252,9 @@
                  : TabStripModelObserver::CHANGE_REASON_NONE;
     CHECK(!in_notify_);
     in_notify_ = true;
-    FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-        ActiveTabChanged(old_contents,
-                         new_contents,
-                         active_index(),
-                         reason));
+    for (auto& observer : observers_)
+      observer.ActiveTabChanged(old_contents, new_contents, active_index(),
+                                reason);
     in_notify_ = false;
   }
 }
@@ -1272,8 +1266,8 @@
   NotifyIfActiveTabChanged(old_contents, notify_types);
 
   if (!selection_model().Equals(old_model)) {
-    FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                      TabSelectionChanged(this, old_model));
+    for (auto& observer : observers_)
+      observer.TabSelectionChanged(this, old_model);
   }
 }
 
@@ -1306,9 +1300,12 @@
                                           bool select_after_move) {
   FixOpenersAndGroupsReferencing(index);
 
-  WebContentsData* moved_data = contents_data_[index];
+  std::unique_ptr<WebContentsData> moved_data =
+      std::move(contents_data_[index]);
+  WebContents* web_contents = moved_data->web_contents();
   contents_data_.erase(contents_data_.begin() + index);
-  contents_data_.insert(contents_data_.begin() + to_position, moved_data);
+  contents_data_.insert(contents_data_.begin() + to_position,
+                        std::move(moved_data));
 
   selection_model_.Move(index, to_position);
   if (!selection_model_.IsSelected(to_position) && select_after_move) {
@@ -1316,8 +1313,8 @@
     selection_model_.SetSelectedIndex(to_position);
   }
 
-  FOR_EACH_OBSERVER(TabStripModelObserver, observers_,
-                    TabMoved(moved_data->web_contents(), index, to_position));
+  for (auto& observer : observers_)
+    observer.TabMoved(web_contents, index, to_position);
 }
 
 void TabStripModel::MoveSelectedTabsToImpl(int index,
@@ -1357,7 +1354,7 @@
 }
 
 // static
-bool TabStripModel::OpenerMatches(const WebContentsData* data,
+bool TabStripModel::OpenerMatches(const std::unique_ptr<WebContentsData>& data,
                                   const WebContents* opener,
                                   bool use_group) {
   return data->opener() == opener || (use_group && data->group() == opener);
@@ -1365,7 +1362,7 @@
 
 void TabStripModel::FixOpenersAndGroupsReferencing(int index) {
   WebContents* old_contents = GetWebContentsAtImpl(index);
-  for (WebContentsData* data : contents_data_) {
+  for (auto& data : contents_data_) {
     if (data->group() == old_contents)
       data->set_group(contents_data_[index]->group());
     if (data->opener() == old_contents)
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index fd49bdb0..703850fa 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -518,7 +518,7 @@
   // Returns true if the tab represented by the specified data has an opener
   // that matches the specified one. If |use_group| is true, then this will
   // fall back to check the group relationship as well.
-  static bool OpenerMatches(const WebContentsData* data,
+  static bool OpenerMatches(const std::unique_ptr<WebContentsData>& data,
                             const content::WebContents* opener,
                             bool use_group);
 
@@ -530,8 +530,7 @@
   TabStripModelDelegate* delegate_;
 
   // The WebContents data currently hosted within this TabStripModel.
-  typedef std::vector<WebContentsData*> WebContentsDataVector;
-  WebContentsDataVector contents_data_;
+  std::vector<std::unique_ptr<WebContentsData>> contents_data_;
 
   // A profile associated with this TabStripModel.
   Profile* profile_;
@@ -544,8 +543,7 @@
   std::unique_ptr<TabStripModelOrderController> order_controller_;
 
   // Our observers.
-  typedef base::ObserverList<TabStripModelObserver> TabStripModelObservers;
-  TabStripModelObservers observers_;
+  base::ObserverList<TabStripModelObserver> observers_;
 
   ui::ListSelectionModel selection_model_;
 
diff --git a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
index 66aa2136..d5bd241 100644
--- a/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
+++ b/chrome/browser/ui/views/desktop_capture/desktop_media_picker_views.cc
@@ -290,7 +290,7 @@
 bool DesktopMediaPickerDialogView::IsDialogButtonEnabled(
     ui::DialogButton button) const {
   if (button == ui::DIALOG_BUTTON_OK)
-    return list_views_[pane_->selected_tab_index()]->GetSelection() != nullptr;
+    return list_views_[pane_->GetSelectedTabIndex()]->GetSelection() != nullptr;
   return true;
 }
 
@@ -315,7 +315,7 @@
 
 bool DesktopMediaPickerDialogView::Accept() {
   DesktopMediaSourceView* selection =
-      list_views_[pane_->selected_tab_index()]->GetSelection();
+      list_views_[pane_->GetSelectedTabIndex()]->GetSelection();
 
   // Ok button should only be enabled when a source is selected.
   DCHECK(selection);
@@ -373,16 +373,16 @@
 
 DesktopMediaListView* DesktopMediaPickerDialogView::GetMediaListViewForTesting()
     const {
-  return list_views_[pane_->selected_tab_index()];
+  return list_views_[pane_->GetSelectedTabIndex()];
 }
 
 DesktopMediaSourceView*
 DesktopMediaPickerDialogView::GetMediaSourceViewForTesting(int index) const {
-  if (list_views_[pane_->selected_tab_index()]->child_count() <= index)
+  if (list_views_[pane_->GetSelectedTabIndex()]->child_count() <= index)
     return nullptr;
 
   return reinterpret_cast<DesktopMediaSourceView*>(
-      list_views_[pane_->selected_tab_index()]->child_at(index));
+      list_views_[pane_->GetSelectedTabIndex()]->child_at(index));
 }
 
 views::Checkbox* DesktopMediaPickerDialogView::GetCheckboxForTesting() const {
diff --git a/chrome/browser/ui/webui/options/preferences_browsertest.cc b/chrome/browser/ui/webui/options/preferences_browsertest.cc
index 444c9db..8883127 100644
--- a/chrome/browser/ui/webui/options/preferences_browsertest.cc
+++ b/chrome/browser/ui/webui/options/preferences_browsertest.cc
@@ -725,8 +725,7 @@
     // Set up fake install attributes.
     std::unique_ptr<chromeos::StubInstallAttributes> attributes =
         base::MakeUnique<chromeos::StubInstallAttributes>();
-    attributes->SetDomain("example.com");
-    attributes->SetRegistrationUser("user@example.com");
+    attributes->SetEnterprise("example.com", "fake-id");
     policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting(
         attributes.release());
 
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler.cc b/chrome/browser/ui/webui/signin/inline_login_handler.cc
index 3f7b633e..e9a1901 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler.cc
@@ -198,13 +198,14 @@
   signin_metrics::Reason reason =
       signin::GetSigninReasonForPromoURL(current_url);
 
-  if (reason != signin_metrics::Reason::REASON_REAUTHENTICATION ||
-      reason != signin_metrics::Reason::REASON_UNLOCK ||
+  if (reason != signin_metrics::Reason::REASON_REAUTHENTICATION &&
+      reason != signin_metrics::Reason::REASON_UNLOCK &&
       reason != signin_metrics::Reason::REASON_ADD_SECONDARY_ACCOUNT) {
     signin_metrics::LogSigninAccessPointStarted(access_point);
+    RecordSigninUserActionForAccessPoint(access_point);
+    content::RecordAction(base::UserMetricsAction("Signin_SigninPage_Loading"));
+    params.SetBoolean("isLoginPrimaryAccount", true);
   }
-  RecordSigninUserActionForAccessPoint(access_point);
-  content::RecordAction(base::UserMetricsAction("Signin_SigninPage_Loading"));
 
   params.SetString("continueUrl", signin::GetLandingURL(access_point).spec());
 
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index c1302453b..ecb95d0 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1856,6 +1856,9 @@
 // be an Android app).
 const char kIsBootstrappingSlave[] = "is_oobe_bootstrapping_slave";
 
+// A preference that controlles Android status reporting.
+const char kReportArcStatus[] = "arc.status_reporting";
+
 #endif  // defined(OS_CHROMEOS)
 
 // Whether there is a Flash version installed that supports clearing LSO data.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index e9467454..e7f91db 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -650,6 +650,7 @@
 extern const char kLogoutStartedLast[];
 extern const char kConsumerManagementStage[];
 extern const char kIsBootstrappingSlave[];
+extern const char kReportArcStatus[];
 #endif  // defined(OS_CHROMEOS)
 
 extern const char kClearPluginLSODataEnabled[];
diff --git a/chrome/test/data/notifications/platform_notification_service.html b/chrome/test/data/notifications/platform_notification_service.html
index 60e4763..88b2ac3 100644
--- a/chrome/test/data/notifications/platform_notification_service.html
+++ b/chrome/test/data/notifications/platform_notification_service.html
@@ -116,6 +116,17 @@
         });
       }
 
+      // Displays a persistent notification with a reply button.
+      function DisplayPersistentNotificationWithReplyButton() {
+        DisplayPersistentNotification('action_button_click', {
+          body: 'Contents',
+          actions: [
+            { action: 'actionId1', title: 'actionTitle1', icon: 'icon.png',
+              type: 'text' }
+          ]
+        });
+      }
+
       // Returns the latest received message from the worker. If no message has
       // been received, nothing will be done. For successfully registered
       // Service Workers this is OK, however, since the "message" event handler
diff --git a/chrome/test/data/notifications/platform_notification_service.js b/chrome/test/data/notifications/platform_notification_service.js
index e7a3bf2..07a15b1 100644
--- a/chrome/test/data/notifications/platform_notification_service.js
+++ b/chrome/test/data/notifications/platform_notification_service.js
@@ -21,7 +21,8 @@
 
   if (message == 'action_button_click')
     message += ' ' + event.action;
-
+  if (event.reply)
+    message += ' ' + event.reply;
   messagePort.postMessage(message);
 });
 
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index a886d4a..1c8acf6 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -2613,6 +2613,16 @@
     ]
   },
 
+  "ReportArcStatus": {
+    "os": ["chromeos"],
+    "can_be_recommended": false,
+    "test_policy": { "ReportArcStatus": false },
+    "pref_mappings": [
+      { "pref": "arc.status_reporting",
+        "local_state": true }
+    ]
+  },
+
   "----- Chrome OS device policies ---------------------------------------": {},
 
   "DevicePolicyRefreshRate": {
diff --git a/chromecast/browser/cast_media_blocker.cc b/chromecast/browser/cast_media_blocker.cc
index dfc371e..935dec5 100644
--- a/chromecast/browser/cast_media_blocker.cc
+++ b/chromecast/browser/cast_media_blocker.cc
@@ -47,10 +47,8 @@
   }
 }
 
-void CastMediaBlocker::MediaSessionStateChanged(
-    bool is_controllable,
-    bool is_suspended,
-    const base::Optional<content::MediaMetadata>& metadata) {
+void CastMediaBlocker::MediaSessionStateChanged(bool is_controllable,
+                                                bool is_suspended) {
   controllable_ = is_controllable;
   suspended_ = is_suspended;
   UpdateMediaBlockedState();
diff --git a/chromecast/browser/cast_media_blocker.h b/chromecast/browser/cast_media_blocker.h
index 2bb9ab8..042742b 100644
--- a/chromecast/browser/cast_media_blocker.h
+++ b/chromecast/browser/cast_media_blocker.h
@@ -41,10 +41,8 @@
   };
 
   // content::WebContentsObserver implementation:
-  void MediaSessionStateChanged(
-      bool is_controllable,
-      bool is_suspended,
-      const base::Optional<content::MediaMetadata>& metadata) override;
+  void MediaSessionStateChanged(bool is_controllable,
+                                bool is_suspended) override;
 
   // Whether or not media in the app can be controlled and if media is currently
   // suspended. These variables cache arguments from MediaSessionStateChanged().
diff --git a/chromecast/public/avsettings.h b/chromecast/public/avsettings.h
index 4bd29c7..53d012b 100644
--- a/chromecast/public/avsettings.h
+++ b/chromecast/public/avsettings.h
@@ -295,18 +295,32 @@
   // Sets the HDMI video mode according to the given parameters:
   // |allow_4k|: if false, the resolution set will not be a 4K resolution.
   // |optimize_for_fps|: *Attempts* to pick a refresh rate optimal for the
-  // given content frame rate. |optimize_for_fps| is expressed as framerate
+  // given content frame rate.  |optimize_for_fps| is expressed as framerate
   // * 100. I.e. 24hz -> 2400, 23.98hz -> 2398, etc.  Values <= 0 are ignored.
+  // |output_type|: if set to HDR_OUTPUT_DOLBYVISION, the video mode set will
+  // be a DV supported resolution. If set to HDR_OUTPUT_HDR, the video mode set
+  // will be a 10-bit or greater video mode.
   //
   // Returns:
   // - true if HDMI video mode change is beginning.  Caller should wait for
   //   SCREEN_INFO_CHANGED event for mode change to complete.
   // - false if no HDMI video mode change has begun.  This could be because
   // HDMI is disconnected, or the current resolution is already good for the
-  // given parameters.
+  // given parameters, or no valid resolution with the given parameters is
+  // found (ie. setting require_dolby_vision/require_hdr to true when the
+  // sink doesn't support those features).
   //
   // Non-HDMI devices should return false.
-  virtual bool SetHdmiVideoMode(bool allow_4k, int optimize_for_fps) = 0;
+  virtual bool SetHdmiVideoMode(bool allow_4k,
+                                int optimize_for_fps,
+                                HdrOutputType output_type) = 0;
+
+  // Returns true if the HDMI sink supports the specified HDR output type in
+  // the current HDMI mode.  Returns false otherwise.
+  //
+  // Non-HDMI devices should return false.
+  virtual bool IsHdrOutputSupportedByCurrentHdmiVideoMode(
+      HdrOutputType output_type) = 0;
 };
 
 }  // namespace chromecast
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc
index 317807f..d41ac97f 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -13,9 +13,12 @@
 #include "base/lazy_instance.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/stl_util.h"
+#include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/autofill/content/renderer/form_autofill_util.h"
+#include "components/autofill/core/common/autofill_util.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/autofill/core/common/password_form_field_prediction_map.h"
 #include "google_apis/gaia/gaia_urls.h"
@@ -702,9 +705,11 @@
 
 bool HasAutocompleteAttributeValue(const blink::WebInputElement& element,
                                    const char* value_in_lowercase) {
-  return base::LowerCaseEqualsASCII(
-      base::StringPiece16(element.getAttribute("autocomplete")),
-      value_in_lowercase);
+  base::string16 autocomplete_attribute(element.getAttribute("autocomplete"));
+  std::vector<std::string> tokens = LowercaseAndTokenizeAttributeString(
+      base::UTF16ToUTF8(autocomplete_attribute));
+
+  return base::ContainsValue(tokens, value_in_lowercase);
 }
 
 }  // namespace autofill
diff --git a/components/autofill/core/browser/form_structure.cc b/components/autofill/core/browser/form_structure.cc
index fb0c4954..3b2d93a 100644
--- a/components/autofill/core/browser/form_structure.cc
+++ b/components/autofill/core/browser/form_structure.cc
@@ -897,17 +897,14 @@
     // section names.
     field->set_section(kDefaultSection);
 
-    // Canonicalize the attribute value by trimming whitespace, collapsing
-    // non-space characters (e.g. tab) to spaces, and converting to lowercase.
-    std::string autocomplete_attribute =
-        base::CollapseWhitespaceASCII(field->autocomplete_attribute, false);
-    autocomplete_attribute = base::ToLowerASCII(autocomplete_attribute);
+    std::vector<std::string> tokens =
+        LowercaseAndTokenizeAttributeString(field->autocomplete_attribute);
 
     // The autocomplete attribute is overloaded: it can specify either a field
     // type hint or whether autocomplete should be enabled at all.  Ignore the
     // latter type of attribute value.
-    if (autocomplete_attribute.empty() || autocomplete_attribute == "on" ||
-        autocomplete_attribute == "off") {
+    if (tokens.empty() ||
+        (tokens.size() == 1 && (tokens[0] == "on" || tokens[0] == "off"))) {
       continue;
     }
 
@@ -917,15 +914,11 @@
     // the form.
     has_author_specified_types_ = true;
 
-    // Tokenize the attribute value.  Per the spec, the tokens are parsed in
-    // reverse order.
-    std::vector<std::string> tokens =
-        base::SplitString(autocomplete_attribute, " ", base::KEEP_WHITESPACE,
-                          base::SPLIT_WANT_NONEMPTY);
-
     // The final token must be the field type.
     // If it is not one of the known types, abort.
     DCHECK(!tokens.empty());
+
+    // Per the spec, the tokens are parsed in reverse order.
     std::string field_type_token = tokens.back();
     tokens.pop_back();
     HtmlFieldType field_type =
diff --git a/components/autofill/core/common/autofill_util.cc b/components/autofill/core/common/autofill_util.cc
index faf019e8..bc458a96 100644
--- a/components/autofill/core/common/autofill_util.cc
+++ b/components/autofill/core/common/autofill_util.cc
@@ -5,7 +5,6 @@
 #include "components/autofill/core/common/autofill_util.h"
 
 #include <algorithm>
-#include <vector>
 
 #include "base/command_line.h"
 #include "base/i18n/case_conversion.h"
@@ -132,4 +131,11 @@
   }
 }
 
+std::vector<std::string> LowercaseAndTokenizeAttributeString(
+    const std::string& attribute) {
+  return base::SplitString(base::ToLowerASCII(attribute),
+                           base::kWhitespaceASCII, base::TRIM_WHITESPACE,
+                           base::SPLIT_WANT_NONEMPTY);
+}
+
 }  // namespace autofill
diff --git a/components/autofill/core/common/autofill_util.h b/components/autofill/core/common/autofill_util.h
index 519b3cbe..fccd473a 100644
--- a/components/autofill/core/common/autofill_util.h
+++ b/components/autofill/core/common/autofill_util.h
@@ -7,6 +7,9 @@
 
 #include <stddef.h>
 
+#include <string>
+#include <vector>
+
 #include "base/strings/string16.h"
 #include "components/autofill/core/common/form_field_data.h"
 
@@ -51,6 +54,12 @@
                     bool isCheckable,
                     bool isChecked);
 
+// Lowercases and tokenizes a given |attribute| string.
+// Considers any ASCII whitespace character as a possible separator.
+// Also ignores empty tokens, resulting in a collapsing of whitespace.
+std::vector<std::string> LowercaseAndTokenizeAttributeString(
+    const std::string& attribute);
+
 }  // namespace autofill
 
 #endif  // COMPONENTS_AUTOFILL_CORE_COMMON_AUTOFILL_UTIL_H_
diff --git a/components/autofill/core/common/autofill_util_unittest.cc b/components/autofill/core/common/autofill_util_unittest.cc
index 823be3d4..60c5010 100644
--- a/components/autofill/core/common/autofill_util_unittest.cc
+++ b/components/autofill/core/common/autofill_util_unittest.cc
@@ -99,4 +99,33 @@
   }
 }
 
+// Tests for LowercaseAndTokenizeAttributeString
+TEST(AutofillUtilTest, LowercaseAndTokenizeAttributeString) {
+  const struct {
+    const char* const attribute;
+    std::vector<std::string> tokens;
+  } kTestCases[] = {
+      // Test leading and trailing whitespace, test tabs and newlines
+      {"foo bar baz", {"foo", "bar", "baz"}},
+      {" foo bar baz ", {"foo", "bar", "baz"}},
+      {"foo\tbar baz ", {"foo", "bar", "baz"}},
+      {"foo\nbar baz ", {"foo", "bar", "baz"}},
+
+      // Test different forms of capitalization
+      {"FOO BAR BAZ", {"foo", "bar", "baz"}},
+      {"foO baR bAz", {"foo", "bar", "baz"}},
+
+      // Test collapsing of multiple whitespace characters in a row
+      {"  \t\t\n\n   ", std::vector<std::string>()},
+      {"foO    baR bAz", {"foo", "bar", "baz"}},
+  };
+
+  for (size_t i = 0; i < arraysize(kTestCases); ++i) {
+    SCOPED_TRACE(testing::Message() << "attribute = "
+                                    << kTestCases[i].attribute);
+
+    EXPECT_EQ(kTestCases[i].tokens,
+              LowercaseAndTokenizeAttributeString(kTestCases[i].attribute));
+  }
+}
 }  // namespace autofill
diff --git a/components/nacl/browser/nacl_broker_host_win.cc b/components/nacl/browser/nacl_broker_host_win.cc
index 21bd188a..501ba6c6 100644
--- a/components/nacl/browser/nacl_broker_host_win.cc
+++ b/components/nacl/browser/nacl_broker_host_win.cc
@@ -73,9 +73,8 @@
   if (NaClBrowser::GetDelegate()->DialogsAreSuppressed())
     cmd_line->AppendSwitch(switches::kNoErrorDialogs);
 
-  process_->Launch(new NaClBrokerSandboxedProcessLauncherDelegate,
-                   cmd_line,
-                   true);
+  process_->Launch(new NaClBrokerSandboxedProcessLauncherDelegate, cmd_line,
+                   nullptr, true);
   return true;
 }
 
diff --git a/components/nacl/browser/nacl_process_host.cc b/components/nacl/browser/nacl_process_host.cc
index 7f23abe..ecd66b01 100644
--- a/components/nacl/browser/nacl_process_host.cc
+++ b/components/nacl/browser/nacl_process_host.cc
@@ -668,8 +668,7 @@
 #endif
   process_->Launch(
       new NaClSandboxedProcessLauncherDelegate(process_->GetHost()),
-      cmd_line.release(),
-      true);
+      cmd_line.release(), nullptr, true);
   return true;
 }
 
diff --git a/components/offline_pages/background/request_coordinator.cc b/components/offline_pages/background/request_coordinator.cc
index c4d602e..087be6f 100644
--- a/components/offline_pages/background/request_coordinator.cc
+++ b/components/offline_pages/background/request_coordinator.cc
@@ -638,12 +638,22 @@
 }
 
 void RequestCoordinator::EnableForOffliner(int64_t request_id) {
-    disabled_requests_.erase(request_id);
-    // If we are not busy, start processing right away.
-    StartProcessingIfConnected();
+  // Since the recent tab helper might call multiple times, ignore subsequent
+  // calls for a particular request_id.
+  if (disabled_requests_.find(request_id) == disabled_requests_.end())
+    return;
+  disabled_requests_.erase(request_id);
+  // If we are not busy, start processing right away.
+  StartProcessingIfConnected();
 }
 
 void RequestCoordinator::MarkRequestCompleted(int64_t request_id) {
+  // Since the recent tab helper might call multiple times, ignore subsequent
+  // calls for a particular request_id.
+  if (disabled_requests_.find(request_id) == disabled_requests_.end())
+    return;
+  disabled_requests_.erase(request_id);
+
   // Remove the request, but send out SUCCEEDED instead of removed.
   std::vector<int64_t> request_ids { request_id };
     queue_->RemoveRequests(
diff --git a/components/offline_pages/background/request_coordinator_unittest.cc b/components/offline_pages/background/request_coordinator_unittest.cc
index 18b0e675..06614b0d 100644
--- a/components/offline_pages/background/request_coordinator_unittest.cc
+++ b/components/offline_pages/background/request_coordinator_unittest.cc
@@ -948,10 +948,11 @@
   // Add a request to the queue.
   offline_pages::SavePageRequest request1(kRequestId1, kUrl1, kClientId1,
                                           base::Time::Now(), kUserRequested);
-  coordinator()->queue()->AddRequest(
-      request1, base::Bind(&RequestCoordinatorTest::AddRequestDone,
-                           base::Unretained(this)));
+  int64_t request_id = coordinator()->SavePageLater(
+      kUrl1, kClientId1, kUserRequested,
+      RequestCoordinator::RequestAvailability::DISABLED_FOR_OFFLINER);
   PumpLoop();
+  EXPECT_NE(request_id, 0l);
 
   // Ensure the start processing request stops before the completion callback.
   EnableOfflinerCallback(false);
@@ -963,7 +964,7 @@
   EXPECT_TRUE(coordinator()->StartProcessing(device_conditions, callback));
 
   // Call the method under test, making sure we send SUCCESS to the observer.
-  coordinator()->MarkRequestCompleted(kRequestId1);
+  coordinator()->MarkRequestCompleted(request_id);
   PumpLoop();
 
   // Our observer should have seen SUCCESS instead of REMOVED.
diff --git a/components/offline_pages/background/request_queue_in_memory_store.cc b/components/offline_pages/background/request_queue_in_memory_store.cc
index e2d79ed2..f46f9a10 100644
--- a/components/offline_pages/background/request_queue_in_memory_store.cc
+++ b/components/offline_pages/background/request_queue_in_memory_store.cc
@@ -4,6 +4,8 @@
 
 #include "components/offline_pages/background/request_queue_in_memory_store.h"
 
+#include <unordered_set>
+
 #include "base/bind.h"
 #include "base/location.h"
 #include "base/threading/thread_task_runner_handle.h"
@@ -28,6 +30,33 @@
       base::Bind(callback, true, base::Passed(std::move(result_requests))));
 }
 
+void RequestQueueInMemoryStore::GetRequestsByIds(
+    const std::vector<int64_t>& request_ids,
+    const UpdateCallback& callback) {
+  std::unique_ptr<UpdateRequestsResult> result(
+      new UpdateRequestsResult(state()));
+
+  ItemActionStatus status;
+  // Make sure not to include the same request multiple times, while preserving
+  // the order of non-duplicated IDs in the result.
+  std::unordered_set<int64_t> processed_ids;
+  for (const auto& request_id : request_ids) {
+    if (!processed_ids.insert(request_id).second)
+      continue;
+    RequestsMap::iterator iter = requests_.find(request_id);
+    if (iter != requests_.end()) {
+      status = ItemActionStatus::SUCCESS;
+      result->updated_items.push_back(iter->second);
+    } else {
+      status = ItemActionStatus::NOT_FOUND;
+    }
+    result->item_statuses.push_back(std::make_pair(request_id, status));
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback, base::Passed(&result)));
+}
+
 void RequestQueueInMemoryStore::AddRequest(const SavePageRequest& request,
                                            const AddCallback& callback) {
   RequestsMap::iterator iter = requests_.find(request.request_id());
diff --git a/components/offline_pages/background/request_queue_in_memory_store.h b/components/offline_pages/background/request_queue_in_memory_store.h
index 7c8b138..63b18e3d 100644
--- a/components/offline_pages/background/request_queue_in_memory_store.h
+++ b/components/offline_pages/background/request_queue_in_memory_store.h
@@ -23,6 +23,8 @@
 
   // RequestQueueStore implementaiton.
   void GetRequests(const GetRequestsCallback& callback) override;
+  void GetRequestsByIds(const std::vector<int64_t>& request_ids,
+                        const UpdateCallback& callback) override;
   void AddRequest(const SavePageRequest& offline_page,
                   const AddCallback& callback) override;
   void UpdateRequests(const std::vector<SavePageRequest>& requests,
diff --git a/components/offline_pages/background/request_queue_store.h b/components/offline_pages/background/request_queue_store.h
index b661ea0..bb2e5966 100644
--- a/components/offline_pages/background/request_queue_store.h
+++ b/components/offline_pages/background/request_queue_store.h
@@ -38,6 +38,11 @@
   // Gets all of the requests from the store.
   virtual void GetRequests(const GetRequestsCallback& callback) = 0;
 
+  // Gets requests with specified IDs from the store. UpdateCallback is used
+  // instead of GetRequestsCallback to indicate which requests where not found.
+  virtual void GetRequestsByIds(const std::vector<int64_t>& request_ids,
+                                const UpdateCallback& callback) = 0;
+
   // Asynchronously adds request in store. Fails if request with the same
   // offline ID already exists.
   virtual void AddRequest(const SavePageRequest& offline_page,
diff --git a/components/offline_pages/background/request_queue_store_sql.cc b/components/offline_pages/background/request_queue_store_sql.cc
index f88872be..b008ed3 100644
--- a/components/offline_pages/background/request_queue_store_sql.cc
+++ b/components/offline_pages/background/request_queue_store_sql.cc
@@ -4,6 +4,8 @@
 
 #include "components/offline_pages/background/request_queue_store_sql.h"
 
+#include <unordered_set>
+
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
@@ -22,7 +24,6 @@
 
 namespace {
 
-using UpdateStatus = RequestQueueStore::UpdateStatus;
 using StoreStateCallback = base::Callback<void(StoreState)>;
 
 // This is a macro instead of a const so that
@@ -109,8 +110,9 @@
   sql::Statement statement(db->GetCachedStatement(SQL_FROM_HERE, kSql));
   statement.BindInt64(0, request_id);
 
-  statement.Run();
-  return MakeSavePageRequest(statement);
+  if (statement.Step())
+    return MakeSavePageRequest(statement);
+  return std::unique_ptr<SavePageRequest>(nullptr);
 }
 
 ItemActionStatus DeleteRequestById(sql::Connection* db, int64_t request_id) {
@@ -247,6 +249,44 @@
                                          base::Passed(&requests)));
 }
 
+void GetRequestsByIdsSync(sql::Connection* db,
+                          scoped_refptr<base::SingleThreadTaskRunner> runner,
+                          const std::vector<int64_t>& request_ids,
+                          const RequestQueueStore::UpdateCallback& callback) {
+  // TODO(fgorski): Perhaps add metrics here.
+  std::unique_ptr<UpdateRequestsResult> result(
+      new UpdateRequestsResult(StoreState::LOADED));
+
+  // If you create a transaction but don't Commit() it is automatically
+  // rolled back by its destructor when it falls out of scope.
+  sql::Transaction transaction(db);
+  if (!transaction.Begin()) {
+    PostStoreErrorForAllIds(runner, request_ids, callback);
+    return;
+  }
+
+  // Make sure not to include the same request multiple times, preserving the
+  // order of non-duplicated IDs in the result.
+  std::unordered_set<int64_t> processed_ids;
+  for (int64_t request_id : request_ids) {
+    if (!processed_ids.insert(request_id).second)
+      continue;
+    std::unique_ptr<SavePageRequest> request = GetOneRequest(db, request_id);
+    if (request.get())
+      result->updated_items.push_back(*request);
+    ItemActionStatus status =
+        request.get() ? ItemActionStatus::SUCCESS : ItemActionStatus::NOT_FOUND;
+    result->item_statuses.push_back(std::make_pair(request_id, status));
+  }
+
+  if (!transaction.Commit()) {
+    PostStoreErrorForAllIds(runner, request_ids, callback);
+    return;
+  }
+
+  runner->PostTask(FROM_HERE, base::Bind(callback, base::Passed(&result)));
+}
+
 void AddRequestSync(sql::Connection* db,
                     scoped_refptr<base::SingleThreadTaskRunner> runner,
                     const SavePageRequest& request,
@@ -385,6 +425,21 @@
                             base::ThreadTaskRunnerHandle::Get(), callback));
 }
 
+void RequestQueueStoreSQL::GetRequestsByIds(
+    const std::vector<int64_t>& request_ids,
+    const UpdateCallback& callback) {
+  if (!db_.get()) {
+    PostStoreErrorForAllIds(base::ThreadTaskRunnerHandle::Get(), request_ids,
+                            callback);
+    return;
+  }
+
+  background_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&GetRequestsByIdsSync, db_.get(),
+                 base::ThreadTaskRunnerHandle::Get(), request_ids, callback));
+}
+
 void RequestQueueStoreSQL::AddRequest(const SavePageRequest& request,
                                       const AddCallback& callback) {
   if (!CheckDb(base::Bind(callback, ItemActionStatus::STORE_ERROR)))
diff --git a/components/offline_pages/background/request_queue_store_sql.h b/components/offline_pages/background/request_queue_store_sql.h
index d67d14f..0be2eb5 100644
--- a/components/offline_pages/background/request_queue_store_sql.h
+++ b/components/offline_pages/background/request_queue_store_sql.h
@@ -33,6 +33,11 @@
 
   // RequestQueueStore implementation.
   void GetRequests(const GetRequestsCallback& callback) override;
+  // Note: current implementation of this method makes a SQL query per ID. This
+  // is OK as long as number of IDs stays low, which is a typical case.
+  // Implementation should be revisited in case that presumption changes.
+  void GetRequestsByIds(const std::vector<int64_t>& request_ids,
+                        const UpdateCallback& callback) override;
   void AddRequest(const SavePageRequest& offline_page,
                   const AddCallback& callback) override;
   void UpdateRequests(const std::vector<SavePageRequest>& requests,
diff --git a/components/offline_pages/background/request_queue_store_unittest.cc b/components/offline_pages/background/request_queue_store_unittest.cc
index 0a20dfb4..c4264c4 100644
--- a/components/offline_pages/background/request_queue_store_unittest.cc
+++ b/components/offline_pages/background/request_queue_store_unittest.cc
@@ -24,6 +24,7 @@
 namespace {
 const int64_t kRequestId = 42;
 const int64_t kRequestId2 = 44;
+const int64_t kRequestId3 = 47;
 const GURL kUrl("http://example.com");
 const GURL kUrl2("http://another-example.com");
 const ClientId kClientId("bookmark", "1234");
@@ -198,6 +199,65 @@
   ASSERT_TRUE(this->last_requests().empty());
 }
 
+TYPED_TEST(RequestQueueStoreTest, GetRequestsByIds) {
+  std::unique_ptr<RequestQueueStore> store(this->BuildStore());
+  base::Time creation_time = base::Time::Now();
+  SavePageRequest request1(kRequestId, kUrl, kClientId, creation_time,
+                           kUserRequested);
+  store->AddRequest(request1,
+                    base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
+                               base::Unretained(this)));
+  SavePageRequest request2(kRequestId2, kUrl2, kClientId2, creation_time,
+                           kUserRequested);
+  store->AddRequest(request2,
+                    base::Bind(&RequestQueueStoreTestBase::AddRequestDone,
+                               base::Unretained(this)));
+  this->PumpLoop();
+  this->ClearResults();
+
+  std::vector<int64_t> request_ids{kRequestId, kRequestId2};
+  store->GetRequestsByIds(
+      request_ids, base::Bind(&RequestQueueStoreTestBase::UpdateRequestDone,
+                              base::Unretained(this)));
+
+  ASSERT_FALSE(this->last_update_result());
+  this->PumpLoop();
+  ASSERT_TRUE(this->last_update_result());
+  EXPECT_EQ(2UL, this->last_update_result()->item_statuses.size());
+  EXPECT_EQ(kRequestId, this->last_update_result()->item_statuses[0].first);
+  EXPECT_EQ(ItemActionStatus::SUCCESS,
+            this->last_update_result()->item_statuses[0].second);
+  EXPECT_EQ(kRequestId2, this->last_update_result()->item_statuses[1].first);
+  EXPECT_EQ(ItemActionStatus::SUCCESS,
+            this->last_update_result()->item_statuses[1].second);
+  EXPECT_EQ(2UL, this->last_update_result()->updated_items.size());
+  EXPECT_EQ(request1, this->last_update_result()->updated_items.at(0));
+  EXPECT_EQ(request2, this->last_update_result()->updated_items.at(1));
+  this->ClearResults();
+
+  request_ids.clear();
+  request_ids.push_back(kRequestId);
+  request_ids.push_back(kRequestId3);
+  request_ids.push_back(kRequestId);
+
+  store->GetRequestsByIds(
+      request_ids, base::Bind(&RequestQueueStoreTestBase::UpdateRequestDone,
+                              base::Unretained(this)));
+
+  ASSERT_FALSE(this->last_update_result());
+  this->PumpLoop();
+  ASSERT_TRUE(this->last_update_result());
+  EXPECT_EQ(2UL, this->last_update_result()->item_statuses.size());
+  EXPECT_EQ(kRequestId, this->last_update_result()->item_statuses[0].first);
+  EXPECT_EQ(ItemActionStatus::SUCCESS,
+            this->last_update_result()->item_statuses[0].second);
+  EXPECT_EQ(kRequestId3, this->last_update_result()->item_statuses[1].first);
+  EXPECT_EQ(ItemActionStatus::NOT_FOUND,
+            this->last_update_result()->item_statuses[1].second);
+  EXPECT_EQ(1UL, this->last_update_result()->updated_items.size());
+  EXPECT_EQ(request1, this->last_update_result()->updated_items.at(0));
+}
+
 TYPED_TEST(RequestQueueStoreTest, AddRequest) {
   std::unique_ptr<RequestQueueStore> store(this->BuildStore());
   base::Time creation_time = base::Time::Now();
diff --git a/components/offline_pages/offline_page_model.h b/components/offline_pages/offline_page_model.h
index c1036b7..cf6ef74 100644
--- a/components/offline_pages/offline_page_model.h
+++ b/components/offline_pages/offline_page_model.h
@@ -81,10 +81,13 @@
   virtual void AddObserver(Observer* observer) = 0;
   virtual void RemoveObserver(Observer* observer) = 0;
 
+  static const int64_t kInvalidOfflineId = 0;
+
   // Attempts to save a page addressed by |url| offline. Requires that the model
   // is loaded.  Generates a new offline id and returns
   // it. |proposed_offline_id| is used for the offline_id for the saved file if
-  // it is non-zero.  If it is zero, a new, random ID will be generated.
+  // it is non-zero.  If it is kInvalidOfflineId, a new, random ID will be
+  // generated.
   virtual void SavePage(const GURL& url,
                         const ClientId& client_id,
                         int64_t proposed_offline_id,
diff --git a/components/offline_pages/offline_page_model_impl.cc b/components/offline_pages/offline_page_model_impl.cc
index e16d547..0a5094fb 100644
--- a/components/offline_pages/offline_page_model_impl.cc
+++ b/components/offline_pages/offline_page_model_impl.cc
@@ -357,7 +357,7 @@
   }
 
   // If we already have an offline id, use it.  If not, generate one.
-  if (proposed_offline_id == 0l)
+  if (proposed_offline_id == kInvalidOfflineId)
     proposed_offline_id = GenerateOfflineId();
 
   archiver->CreateArchive(
diff --git a/components/offline_pages/offline_page_model_impl.h b/components/offline_pages/offline_page_model_impl.h
index 194fa206..a805f1b 100644
--- a/components/offline_pages/offline_page_model_impl.h
+++ b/components/offline_pages/offline_page_model_impl.h
@@ -44,8 +44,6 @@
 
 namespace offline_pages {
 
-static const int64_t kInvalidOfflineId = 0;
-
 struct ClientId;
 struct OfflinePageItem;
 
diff --git a/components/password_manager/content/browser/content_password_manager_driver.cc b/components/password_manager/content/browser/content_password_manager_driver.cc
index c9854058..b658e0bd 100644
--- a/components/password_manager/content/browser/content_password_manager_driver.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver.cc
@@ -174,7 +174,6 @@
 
 void ContentPasswordManagerDriver::OnPasswordFormsParsedNoRenderCheck(
     const std::vector<autofill::PasswordForm>& forms) {
-  MaybeNotifyPasswordInputShownOnHttp(render_frame_host_);
   GetPasswordManager()->OnPasswordFormsParsed(this, forms);
   GetPasswordGenerationManager()->CheckIfFormClassifierShouldRun();
 }
@@ -209,9 +208,7 @@
 }
 
 void ContentPasswordManagerDriver::PasswordFieldVisibleInInsecureContext() {
-  // TODO(estark): notify the WebContents that a password field was
-  // shown, which will downgrade the security UI
-  // appropriately. https://crbug.com/647560
+  MaybeNotifyPasswordInputShownOnHttp(render_frame_host_);
 }
 
 void ContentPasswordManagerDriver::DidNavigateFrame(
diff --git a/components/password_manager/content/browser/content_password_manager_driver_unittest.cc b/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
index 06e21b3..7bdd57d4 100644
--- a/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver_unittest.cc
@@ -10,6 +10,8 @@
 #include "components/autofill/core/browser/test_autofill_client.h"
 #include "components/password_manager/core/browser/stub_log_manager.h"
 #include "components/password_manager/core/browser/stub_password_manager_client.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/ssl_status.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/test_renderer_host.h"
 #include "mojo/public/cpp/bindings/binding.h"
@@ -167,6 +169,35 @@
   EXPECT_EQ(should_allow_logging, logging_activated);
 }
 
+// Tests that password visibility notifications are forwarded to the
+// WebContents.
+TEST_P(ContentPasswordManagerDriverTest, PasswordVisibility) {
+  std::unique_ptr<ContentPasswordManagerDriver> driver(
+      new ContentPasswordManagerDriver(main_rfh(), &password_manager_client_,
+                                       &autofill_client_));
+
+  // Do a mock navigation so that there is a navigation entry on which
+  // password visibility gets recorded.
+  GURL url("http://example.test");
+  NavigateAndCommit(url);
+  content::NavigationEntry* entry =
+      web_contents()->GetController().GetVisibleEntry();
+  ASSERT_TRUE(entry);
+  EXPECT_EQ(url, entry->GetURL());
+  EXPECT_FALSE(!!(entry->GetSSL().content_status &
+                  content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
+
+  driver->PasswordFieldVisibleInInsecureContext();
+
+  // Check that the password visibility notification was passed on to
+  // the WebContents (and from there to the SSLStatus).
+  entry = web_contents()->GetController().GetVisibleEntry();
+  ASSERT_TRUE(entry);
+  EXPECT_EQ(url, entry->GetURL());
+  EXPECT_TRUE(!!(entry->GetSSL().content_status &
+                 content::SSLStatus::DISPLAYED_PASSWORD_FIELD_ON_HTTP));
+}
+
 INSTANTIATE_TEST_CASE_P(,
                         ContentPasswordManagerDriverTest,
                         testing::Values(true, false));
diff --git a/components/password_manager/content/browser/credential_manager_impl_unittest.cc b/components/password_manager/content/browser/credential_manager_impl_unittest.cc
index a4492d3..a03315ec 100644
--- a/components/password_manager/content/browser/credential_manager_impl_unittest.cc
+++ b/components/password_manager/content/browser/credential_manager_impl_unittest.cc
@@ -40,6 +40,7 @@
 using content::WebContents;
 
 using testing::_;
+using testing::ElementsAre;
 using testing::Pointee;
 using testing::UnorderedElementsAre;
 
@@ -450,6 +451,41 @@
   EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, new_form.scheme);
 }
 
+TEST_F(CredentialManagerImplTest, StoreFederatedAfterPassword) {
+  // Populate the PasswordStore with a form.
+  store_->AddLogin(form_);
+
+  autofill::PasswordForm federated = form_;
+  federated.password_value.clear();
+  federated.type = autofill::PasswordForm::TYPE_API;
+  federated.preferred = true;
+  federated.federation_origin = url::Origin(GURL("https://google.com/"));
+  federated.signon_realm = "federation://example.com/google.com";
+  CredentialInfo info(federated, CredentialType::CREDENTIAL_TYPE_FEDERATED);
+  EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
+                            _, CredentialSourceType::CREDENTIAL_SOURCE_API));
+  EXPECT_CALL(*client_, NotifyStorePasswordCalled());
+
+  bool called = false;
+  CallStore(info, base::Bind(&RespondCallback, &called));
+
+  // Allow the PasswordFormManager to talk to the password store, determine
+  // that the form is new, and set it as pending.
+  RunAllPendingTasks();
+
+  EXPECT_TRUE(called);
+  EXPECT_TRUE(client_->pending_manager()->HasCompletedMatching());
+  client_->pending_manager()->Save();
+
+  RunAllPendingTasks();
+  TestPasswordStore::PasswordMap passwords = store_->stored_passwords();
+  EXPECT_THAT(passwords["https://example.com/"], ElementsAre(form_));
+  federated.date_created =
+      passwords["federation://example.com/google.com"][0].date_created;
+  EXPECT_THAT(passwords["federation://example.com/google.com"],
+              ElementsAre(federated));
+}
+
 TEST_F(CredentialManagerImplTest, CredentialManagerStoreOverwrite) {
   // Populate the PasswordStore with a form.
   store_->AddLogin(form_);
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 59d9c0a..919f1713 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -1218,6 +1218,8 @@
 
 const PasswordForm* PasswordFormManager::FindBestSavedMatch(
     const PasswordForm* form) const {
+  if (!form->federation_origin.unique())
+    return nullptr;
   auto it = best_matches_.find(form->username_value);
   if (it != best_matches_.end())
     return it->second;
diff --git a/components/policy/core/browser/configuration_policy_handler_list.cc b/components/policy/core/browser/configuration_policy_handler_list.cc
index 8fb0ed5..9cdfc2aa 100644
--- a/components/policy/core/browser/configuration_policy_handler_list.cc
+++ b/components/policy/core/browser/configuration_policy_handler_list.cc
@@ -32,6 +32,10 @@
     const PolicyMap& policies,
     PrefValueMap* prefs,
     PolicyErrorMap* errors) const {
+  // This function is used both to apply the policy settings, and to check them
+  // and list errors. As such it must get all the errors even if it isn't
+  // applying the policies.
+  // TODO (aberent) split into two functions.
   PolicyErrorMap scoped_errors;
   if (!errors)
     errors = &scoped_errors;
@@ -39,13 +43,11 @@
   policy::PolicyHandlerParameters parameters;
   parameters_callback_.Run(&parameters);
 
-  if (prefs) {
-    std::vector<ConfigurationPolicyHandler*>::const_iterator handler;
-    for (handler = handlers_.begin(); handler != handlers_.end(); ++handler) {
-      if ((*handler)->CheckPolicySettings(policies, errors)) {
-        (*handler)
-            ->ApplyPolicySettingsWithParameters(policies, parameters, prefs);
-      }
+  std::vector<ConfigurationPolicyHandler*>::const_iterator handler;
+  for (handler = handlers_.begin(); handler != handlers_.end(); ++handler) {
+    if ((*handler)->CheckPolicySettings(policies, errors) && prefs) {
+      (*handler)
+          ->ApplyPolicySettingsWithParameters(policies, parameters, prefs);
     }
   }
 
diff --git a/components/policy/core/common/cloud/cloud_policy_client.cc b/components/policy/core/common/cloud/cloud_policy_client.cc
index 1b68c94..ea5ba54e 100644
--- a/components/policy/core/common/cloud/cloud_policy_client.cc
+++ b/components/policy/core/common/cloud/cloud_policy_client.cc
@@ -32,6 +32,8 @@
       return DEVICE_MODE_ENTERPRISE;
     case em::DeviceRegisterResponse::RETAIL:
       return DEVICE_MODE_LEGACY_RETAIL_MODE;
+    case em::DeviceRegisterResponse::CHROME_AD:
+      return DEVICE_MODE_ENTERPRISE_AD;
   }
   LOG(ERROR) << "Unknown enrollment mode in registration response: " << mode;
   return DEVICE_MODE_NOT_SET;
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.cc b/components/policy/core/common/cloud/cloud_policy_constants.cc
index 380ec12..0dd4e7df 100644
--- a/components/policy/core/common/cloud/cloud_policy_constants.cc
+++ b/components/policy/core/common/cloud/cloud_policy_constants.cc
@@ -24,9 +24,11 @@
 const char kParamAppType[] = "apptype";
 const char kParamDeviceID[] = "deviceid";
 const char kParamDeviceType[] = "devicetype";
+const char kParamLastError[] = "lasterror";
 const char kParamOAuthToken[] = "oauth_token";
 const char kParamPlatform[] = "platform";
 const char kParamRequest[] = "request";
+const char kParamRetry[] = "retry";
 
 // String constants for the device and app type we report to the server.
 const char kValueAppType[] = "Chrome";
diff --git a/components/policy/core/common/cloud/cloud_policy_constants.h b/components/policy/core/common/cloud/cloud_policy_constants.h
index b960620..b767bf3c 100644
--- a/components/policy/core/common/cloud/cloud_policy_constants.h
+++ b/components/policy/core/common/cloud/cloud_policy_constants.h
@@ -23,9 +23,11 @@
 POLICY_EXPORT extern const char kParamAppType[];
 POLICY_EXPORT extern const char kParamDeviceID[];
 POLICY_EXPORT extern const char kParamDeviceType[];
+POLICY_EXPORT extern const char kParamLastError[];
 POLICY_EXPORT extern const char kParamOAuthToken[];
 POLICY_EXPORT extern const char kParamPlatform[];
 POLICY_EXPORT extern const char kParamRequest[];
+POLICY_EXPORT extern const char kParamRetry[];
 
 // String extern constants for the device and app type we report to the server.
 POLICY_EXPORT extern const char kValueAppType[];
@@ -117,6 +119,7 @@
                                    // device.
   DEVICE_MODE_ENTERPRISE,          // The device is enrolled as an enterprise
                                    // device.
+  DEVICE_MODE_ENTERPRISE_AD,       // The device has joined AD.
   DEVICE_MODE_LEGACY_RETAIL_MODE,  // The device is enrolled as a retail kiosk
                                    // device. Even though retail mode is
                                    // deprecated, we still check for this device
diff --git a/components/policy/core/common/cloud/device_management_service.cc b/components/policy/core/common/cloud/device_management_service.cc
index c2790e83..b84cfcf5 100644
--- a/components/policy/core/common/cloud/device_management_service.cc
+++ b/components/policy/core/common/cloud/device_management_service.cc
@@ -220,6 +220,9 @@
   // Number of times that this job has been retried due to connection errors.
   int retries_count_;
 
+  // The last error why we had to retry.
+  int last_error_ = 0;
+
   // The request context to use for this job.
   scoped_refptr<net::URLRequestContextGetter> request_context_;
 
@@ -328,10 +331,20 @@
     const std::string& server_url) {
   std::string result(server_url);
   result += '?';
-  for (ParameterMap::const_iterator entry(query_params_.begin());
-       entry != query_params_.end();
-       ++entry) {
-    if (entry != query_params_.begin())
+  ParameterMap current_query_params(query_params_);
+  if (last_error_ == 0) {
+    // Not a retry.
+    current_query_params.push_back(
+        std::make_pair(dm_protocol::kParamRetry, "false"));
+  } else {
+    current_query_params.push_back(
+        std::make_pair(dm_protocol::kParamRetry, "true"));
+    current_query_params.push_back(std::make_pair(dm_protocol::kParamLastError,
+                                                  std::to_string(last_error_)));
+  }
+  for (ParameterMap::const_iterator entry(current_query_params.begin());
+       entry != current_query_params.end(); ++entry) {
+    if (entry != current_query_params.begin())
       result += '&';
     result += net::EscapeQueryParamValue(entry->first, true);
     result += '=';
@@ -362,6 +375,7 @@
 
 DeviceManagementRequestJobImpl::RetryMethod
 DeviceManagementRequestJobImpl::ShouldRetry(const net::URLFetcher* fetcher) {
+  last_error_ = fetcher->GetStatus().error();
   if (FailedWithProxy(fetcher) && !bypass_proxy_) {
     // Retry the job immediately if it failed due to a broken proxy, by
     // bypassing the proxy on the next try.
diff --git a/components/policy/core/common/cloud/device_management_service_unittest.cc b/components/policy/core/common/cloud/device_management_service_unittest.cc
index 075a978..5a0bb4e 100644
--- a/components/policy/core/common/cloud/device_management_service_unittest.cc
+++ b/components/policy/core/common/cloud/device_management_service_unittest.cc
@@ -402,7 +402,8 @@
  protected:
   void CheckURLAndQueryParams(const GURL& request_url,
                               const std::string& request_type,
-                              const std::string& device_id) {
+                              const std::string& device_id,
+                              const std::string& last_error) {
     const GURL service_url(kServiceUrl);
     EXPECT_EQ(service_url.scheme(), request_url.scheme());
     EXPECT_EQ(service_url.host(), request_url.host());
@@ -416,6 +417,12 @@
                                    dm_protocol::kValueDeviceType));
     EXPECT_TRUE(query_params.Check(dm_protocol::kParamAppType,
                                    dm_protocol::kValueAppType));
+    if (last_error == "") {
+      EXPECT_TRUE(query_params.Check(dm_protocol::kParamRetry, "false"));
+    } else {
+      EXPECT_TRUE(query_params.Check(dm_protocol::kParamRetry, "true"));
+      EXPECT_TRUE(query_params.Check(dm_protocol::kParamLastError, last_error));
+    }
   }
 };
 
@@ -440,8 +447,7 @@
   ASSERT_TRUE(fetcher);
 
   CheckURLAndQueryParams(fetcher->GetOriginalURL(),
-                         dm_protocol::kValueRequestRegister,
-                         kClientID);
+                         dm_protocol::kValueRequestRegister, kClientID, "");
 
   std::string expected_data;
   ASSERT_TRUE(request_job->GetRequest()->SerializeToString(&expected_data));
@@ -466,8 +472,8 @@
   ASSERT_TRUE(fetcher);
 
   CheckURLAndQueryParams(fetcher->GetOriginalURL(),
-                         dm_protocol::kValueRequestCertBasedRegister,
-                         kClientID);
+                         dm_protocol::kValueRequestCertBasedRegister, kClientID,
+                         "");
 
   std::string expected_data;
   ASSERT_TRUE(request_job->GetRequest()->SerializeToString(&expected_data));
@@ -492,8 +498,8 @@
   ASSERT_TRUE(fetcher);
 
   CheckURLAndQueryParams(fetcher->GetOriginalURL(),
-                         dm_protocol::kValueRequestApiAuthorization,
-                         kClientID);
+                         dm_protocol::kValueRequestApiAuthorization, kClientID,
+                         "");
 
   std::string expected_data;
   ASSERT_TRUE(request_job->GetRequest()->SerializeToString(&expected_data));
@@ -525,8 +531,7 @@
   EXPECT_EQ(service_url.path(), request_url.path());
 
   CheckURLAndQueryParams(fetcher->GetOriginalURL(),
-                         dm_protocol::kValueRequestUnregister,
-                         kClientID);
+                         dm_protocol::kValueRequestUnregister, kClientID, "");
 
   std::string expected_data;
   ASSERT_TRUE(request_job->GetRequest()->SerializeToString(&expected_data));
@@ -672,7 +677,9 @@
   net::TestURLFetcher* fetcher = GetFetcher();
   ASSERT_TRUE(fetcher);
   EXPECT_EQ(0, fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY);
-  const GURL original_url(fetcher->GetOriginalURL());
+  // Not a retry.
+  CheckURLAndQueryParams(fetcher->GetOriginalURL(),
+                         dm_protocol::kValueRequestRegister, kClientID, "");
   const std::string upload_data(fetcher->upload_data());
 
   // Generate a callback with a proxy failure.
@@ -683,8 +690,11 @@
   fetcher = GetFetcher();
   ASSERT_TRUE(fetcher);
   EXPECT_TRUE(fetcher->GetLoadFlags() & net::LOAD_BYPASS_PROXY);
-  EXPECT_EQ(original_url, fetcher->GetOriginalURL());
   EXPECT_EQ(upload_data, fetcher->upload_data());
+  // Retry with last error net::ERR_PROXY_CONNECTION_FAILED.
+  CheckURLAndQueryParams(fetcher->GetOriginalURL(),
+                         dm_protocol::kValueRequestRegister, kClientID,
+                         std::to_string(net::ERR_PROXY_CONNECTION_FAILED));
 }
 
 TEST_F(DeviceManagementServiceTest, RetryOnBadResponseFromProxy) {
@@ -727,7 +737,9 @@
       StartRegistrationJob());
   net::TestURLFetcher* fetcher = GetFetcher();
   ASSERT_TRUE(fetcher);
-  const GURL original_url(fetcher->GetOriginalURL());
+  // Not a retry.
+  CheckURLAndQueryParams(fetcher->GetOriginalURL(),
+                         dm_protocol::kValueRequestRegister, kClientID, "");
   const std::string original_upload_data(fetcher->upload_data());
 
   // Make it fail with ERR_NETWORK_CHANGED.
@@ -742,9 +754,12 @@
   Mock::VerifyAndClearExpectations(this);
   fetcher = GetFetcher();
   ASSERT_TRUE(fetcher);
-  EXPECT_EQ(original_url, fetcher->GetOriginalURL());
   EXPECT_EQ(original_upload_data, fetcher->upload_data());
   EXPECT_EQ(net::URLRequestStatus::SUCCESS, fetcher->GetStatus().status());
+  // Retry with last error net::ERR_NETWORK_CHANGED.
+  CheckURLAndQueryParams(fetcher->GetOriginalURL(),
+                         dm_protocol::kValueRequestRegister, kClientID,
+                         std::to_string(net::ERR_NETWORK_CHANGED));
 }
 
 TEST_F(DeviceManagementServiceTest, PolicyFetchRetryImmediately) {
@@ -759,7 +774,9 @@
       StartPolicyFetchJob());
   net::TestURLFetcher* fetcher = GetFetcher();
   ASSERT_TRUE(fetcher);
-  const GURL original_url(fetcher->GetOriginalURL());
+  // Not a retry.
+  CheckURLAndQueryParams(fetcher->GetOriginalURL(),
+                         dm_protocol::kValueRequestPolicy, kClientID, "");
   const std::string original_upload_data(fetcher->upload_data());
 
   // Make it fail with ERR_NETWORK_CHANGED.
@@ -774,9 +791,12 @@
   Mock::VerifyAndClearExpectations(this);
   fetcher = GetFetcher();
   ASSERT_TRUE(fetcher);
-  EXPECT_EQ(original_url, fetcher->GetOriginalURL());
   EXPECT_EQ(original_upload_data, fetcher->upload_data());
   EXPECT_EQ(net::URLRequestStatus::SUCCESS, fetcher->GetStatus().status());
+  // Retry with last error net::ERR_NETWORK_CHANGED.
+  CheckURLAndQueryParams(fetcher->GetOriginalURL(),
+                         dm_protocol::kValueRequestPolicy, kClientID,
+                         std::to_string(net::ERR_NETWORK_CHANGED));
 }
 
 TEST_F(DeviceManagementServiceTest, RetryLimit) {
@@ -793,6 +813,16 @@
     fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED,
                                               net::ERR_NETWORK_CHANGED));
     fetcher->set_url(GURL(kServiceUrl));
+    if (i == 0) {
+      // Not a retry.
+      CheckURLAndQueryParams(fetcher->GetOriginalURL(),
+                             dm_protocol::kValueRequestRegister, kClientID, "");
+    } else {
+      // Retry with last error net::ERR_NETWORK_CHANGED.
+      CheckURLAndQueryParams(fetcher->GetOriginalURL(),
+                             dm_protocol::kValueRequestRegister, kClientID,
+                             std::to_string(net::ERR_NETWORK_CHANGED));
+    }
     fetcher->delegate()->OnURLFetchComplete(fetcher);
     base::RunLoop().RunUntilIdle();
     Mock::VerifyAndClearExpectations(this);
diff --git a/components/policy/proto/device_management_backend.proto b/components/policy/proto/device_management_backend.proto
index 388e331..b70bacd 100644
--- a/components/policy/proto/device_management_backend.proto
+++ b/components/policy/proto/device_management_backend.proto
@@ -19,14 +19,14 @@
   optional int32 extra_data_bytes = 3;
 }
 
-// Request from device to server to register device.
+// Request from device to server to register a device, user or browser.
 message DeviceRegisterRequest {
   // Reregister device without erasing server state.  It can be used
   // to refresh dmtoken etc.  Client MUST set this value to true if it
   // reuses an existing device id.
   optional bool reregister = 1;
 
-  // Device register type.  This field does not exist for TT release.
+  // Register type.  This field does not exist for TT release.
   // When a client requests for policies, server should verify the
   // client has been registered properly.  For example, a client must
   // register with type DEVICE in order to retrieve device policies.
@@ -125,8 +125,16 @@
     // settings from the cloud, but additionally this mode enables the demo
     // account on the device.
     RETAIL = 1;
+    // Devices in CHROME_AD mode are in enterprises with AD.  Device settings
+    // are controlled through the AD policy infrastructure.
+    CHROME_AD = 2;
   }
   optional DeviceMode enrollment_type = 3 [default = ENTERPRISE];
+
+  // An opaque configuration string for devices that require it.  CHROME_AD
+  // devices, for example, may use this string for AD discovery.  Must be at
+  // most a few kBytes.
+  optional string configuration_seed = 4;
 }
 
 // Request from device to server to unregister device.
@@ -163,10 +171,6 @@
 message DeviceServiceApiAccessResponse {
   // The OAuth2 authorization code for the requested scope(s).
   // This can be exchanged for a refresh token.
-  //
-  // The server may send a successful response but not set this field or set an
-  // empty string to reject the auth code request and instruct the client to
-  // skip robot account auth setup.
   optional string auth_code = 1;
 }
 
@@ -235,6 +239,24 @@
   optional string verification_key_hash = 9;
 }
 
+// This message contains the information which is signed by the verification
+// key during policy key rotation.  It is included in serialized form in
+// PolicyFetchResponse below.  A signature of the serialized form is included
+// in the new_public_key_verification_data_signature field. For backward
+// compatibility reasons, a signature over just {new_public_key, domain} fields
+// is included in new_public_key_verification_signature_DEPRECATED field.
+message PublicKeyVerificationData {
+  // The new public policy key after a key rotation.
+  optional bytes new_public_key = 1;
+
+  // The domain of the device/user.
+  optional string domain = 2;
+
+  // The version number of the new_public_key. This must be monotonically
+  // increasing (within a domain).
+  optional int32 new_public_key_version = 3;
+}
+
 // This message customizes how the device behaves when it is disabled by its
 // owner. The message will be sent as part of the DeviceState fetched during
 // normal operation and as part of the DeviceStateRetrievalResponse fetched when
@@ -262,9 +284,8 @@
   optional DisabledState disabled_state = 2;
 }
 
-// This message is included in serialized form in PolicyFetchResponse
-// below.  It may also be signed, with the signature being created for
-// the serialized form.
+// This message is included in serialized form in PolicyFetchResponse below. It
+// may also be signed, with the signature being created for the serialized form.
 message PolicyData {
   // See PolicyFetchRequest.policy_type.
   optional string policy_type = 1;
@@ -349,7 +370,7 @@
 
   // Server-provided identifier of the fetched policy. This is to be used
   // by the client when requesting Policy Posture assertion through an API
-  // call or SAML flow.
+  // call or SAML flow. For details, see http://go/chrome-nac-server-design.
   optional string policy_token = 15;
 
   // Indicates the management mode of the device. Note that old policies do not
@@ -434,6 +455,34 @@
   optional bytes new_public_key = 5;
   optional bytes new_public_key_signature = 6;
 
+  // DEPRECATED ON THE SERVER: Exists only to support older clients.  This
+  // signature is similar to new_public_key_verification_data_signature, but is
+  // computed over PublicKeyVerificationData proto with version field unset.  In
+  // other words, we set the new public key value, and domain value and then
+  // produce this signature.
+  optional bytes new_public_key_verification_signature = 7;
+
+  // This is a serialized |PublicKeyVerificationData| protobuf
+  // (defined above). See comments for |new_public_key_verification_signature|
+  // field for details on how this data is signed.
+  // Please note that |new_public_key| is also included inside this data
+  // field. Thus we have new public key signed with old version of private key
+  // (if client indicated to us that it has old key version), and
+  // new public key data signed by master verification key (if client told
+  // us that it has public verification key - see |verification_key_id| field
+  // of |PolicyFetchRequest|). In most cases, both signatures will be provided.
+  // However, client might not have old policy signing key - for example, when
+  // new profile is being set up. In this case, only verification signature
+  // is supplied.
+  // Or, client might not have verification public key (legacy Chrome build
+  // before verification key was introduced, or outdated build which has
+  // old/compromised verification key). In that case, verification signature
+  // cannot be provided.
+  // If client is missing both public keys (old signing key and verification
+  // key), then we are unable to produce any valid signature and client must
+  // drop such PolicyFetchResponse.
+  optional bytes new_public_key_verification_data = 8;
+
   // If new_public_key is specified, this field contains a signature
   // of a PolicyPublicKeyAndDomain protobuf, signed using a key only
   // available to DMServer. The public key portion of this well-known key is
@@ -448,10 +497,11 @@
   // and new_public_key_signature described above, Chrome also verifies
   // new_public_key with the embedded public key and
   // new_public_key_verification_signature.
-  optional bytes new_public_key_verification_signature = 7;
+  optional bytes new_public_key_verification_data_signature = 9;
 }
 
-// Protobuf used to generate the new_public_key_verification_signature field.
+// DEPRECATED ON THE SERVER: Protobuf used to generate the deprecated
+// new_public_key_verification_signature field.
 message PolicyPublicKeyAndDomain {
   // The public key to sign (taken from the |new_public_key| field in
   // PolicyFetchResponse).
@@ -1105,7 +1155,7 @@
 message CheckAndroidManagementResponse {}
 
 // Request to register a new device (authenticated by enterprise enrollment
-// certificate).
+// certificate). See http://go/zero-touch-chrome for details.
 // The response message will be the DeviceRegisterReponse.
 message CertificateBasedDeviceRegisterRequest {
   // Signed request to register with a certificate. The signed_request.data
@@ -1165,7 +1215,7 @@
 //   * devicetype: MUST BE "1" for Android or "2" for Chrome OS.
 //   * apptype: MUST BE Android or Chrome.
 //   * deviceid: MUST BE no more than 64-char in [\x21-\x7E].
-//   * agent: MUST BE a string of characters.
+//   * agent: MUST BE no more than 64-char long.
 // * HTTP Authorization header MUST be in the following formats:
 //   * For register, ping and check_android_management requests
 //     Authorization: GoogleLogin auth=<auth cookie for Mobile Sync>
@@ -1271,9 +1321,37 @@
 // 491 Request Pending: the request is pending approval.
 // 500 Internal Server Error: most likely a bug in DM server.
 // 503 Service Unavailable: most likely a backend error.
-// 901 Device Not Found: the device id is not found.
 // 902 Policy Not Found: the policy is not found.
 message DeviceManagementResponse {
+  // TODO(hong): move error handling to HTTP level.
+  // Error code to client.
+  enum ErrorCode {
+    SUCCESS = 0;
+    // Returned for register request when device management is not supported
+    // for the domain.
+    DEVICE_MANAGEMENT_NOT_SUPPORTED = 1;
+    // Returned when the device is not found.
+    DEVICE_NOT_FOUND  = 2;
+    // Returned when passed in device management token doesn't match the token
+    // on server side.
+    DEVICE_MANAGEMENT_TOKEN_INVALID  = 3;
+    // Returned when device registration is pending approval (if required).
+    ACTIVATION_PENDING = 4;
+    // Returned when the policy is not found.
+    POLICY_NOT_FOUND  = 5;
+  }
+
+  // Error code for this reponse.
+  //
+  // For responses to TT clients, this field MUST be set, since it WAS
+  // a required field.  For special error code listed above, we return
+  // 200 in HTTP Status Code and set the real error code here.
+  //
+  // For release clients, we plan to move all error code to HTTP
+  // Status Code, so it is much easier for log analysis.  If possible,
+  // we plan to remove this field once Chrome OS TT phase is over.
+  optional ErrorCode error = 1 [default = SUCCESS];
+
   // Error message.
   optional string error_message = 2;
 
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index ca1023a7..cf07596 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -120,6 +120,8 @@
 #   'can_be_recommended' can be set to True to include that policy in the
 #   recommended policies templates. This only affects the template generation;
 #   all policies can be at the recommended level. The default is False.
+#   'per_profile' controls whether a user policy applies to every user logging
+#   into the browser or only one profile.
 #
 #   The 'max_size' key is used to specify the maximal size of the external data
 #   that a policy can reference, in bytes. This annotation is compulsory for
@@ -137,7 +139,7 @@
 #   persistent IDs for all fields (but not for groups!) are needed. These are
 #   specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs,
 #   because doing so would break the deployed wire format!
-#   For your editing convenience: highest ID currently used: 348
+#   For your editing convenience: highest ID currently used: 349
 #
 # Placeholders:
 #   The following placeholder strings are automatically substituted:
@@ -4994,8 +4996,8 @@
       'desc': '''Report information about the active kiosk session, such as
       application ID and version.
 
-      If the policy is set to false, the session information will not be
-      reported. If set to true or left unset, session information will be
+      If the policy is set to false, the kiosk session information will not be
+      reported. If set to true or left unset, kiosk session information will be
       reported.''',
       'arc_support': 'This policy has no effect on the logging done by Android.',
     },
@@ -5019,6 +5021,27 @@
       'arc_support': 'This policy has no effect on the logging done by Android.',
     },
     {
+      'name': 'ReportArcStatus',
+      'type': 'main',
+      'schema': { 'type': 'boolean' },
+      'supported_on': ['chrome_os:55-'],
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': False,
+      },
+      'example_value': False,
+      'id': 349,
+      'caption': '''Report information about status of Android''',
+      'tags': ['admin-sharing'],
+      'desc': '''Report information about the status of Android is send back to
+      the server.
+
+      If the policy is set to false, the information will not be reported.
+      If set to true or left unset, the information will be reported.
+
+      This policy only applies if Android apps are enabled.''',
+    },
+    {
       'name': 'HeartbeatEnabled',
       'type': 'main',
       'schema': { 'type': 'boolean' },
diff --git a/components/search_engines/default_search_policy_handler.cc b/components/search_engines/default_search_policy_handler.cc
index a2837ee8..7c742da5 100644
--- a/components/search_engines/default_search_policy_handler.cc
+++ b/components/search_engines/default_search_policy_handler.cc
@@ -301,11 +301,13 @@
 bool DefaultSearchPolicyHandler::CheckIndividualPolicies(
     const PolicyMap& policies,
     PolicyErrorMap* errors) {
+  bool all_ok = true;
   for (const auto& handler : handlers_) {
-    if (!handler->CheckPolicySettings(policies, errors))
-      return false;
+    // It's important to call CheckPolicySettings() on all handlers and not just
+    // exit on the first error, so we report all policy errors.
+    all_ok &= handler->CheckPolicySettings(policies, errors);
   }
-  return true;
+  return all_ok;
 }
 
 bool DefaultSearchPolicyHandler::HasDefaultSearchPolicy(
diff --git a/components/spellcheck/browser/android/java/src/org/chromium/components/spellcheck/SpellCheckerSessionBridge.java b/components/spellcheck/browser/android/java/src/org/chromium/components/spellcheck/SpellCheckerSessionBridge.java
index 679b2111..0804e14 100644
--- a/components/spellcheck/browser/android/java/src/org/chromium/components/spellcheck/SpellCheckerSessionBridge.java
+++ b/components/spellcheck/browser/android/java/src/org/chromium/components/spellcheck/SpellCheckerSessionBridge.java
@@ -100,6 +100,12 @@
         ArrayList<Integer> lengths = new ArrayList<Integer>();
 
         for (SentenceSuggestionsInfo result : results) {
+            if (result == null) {
+                // In some cases null can be returned by the selected spellchecking service,
+                // see crbug.com/651458. In this case skip to next result to avoid a
+                // NullPointerException later on.
+                continue;
+            }
             for (int i = 0; i < result.getSuggestionsCount(); i++) {
                 // If a word looks like a typo, record its offset and length.
                 if ((result.getSuggestionsInfoAt(i).getSuggestionsAttributes()
diff --git a/components/sync/engine_impl/syncer.cc b/components/sync/engine_impl/syncer.cc
index 3b783c2a..76b7da3 100644
--- a/components/sync/engine_impl/syncer.cc
+++ b/components/sync/engine_impl/syncer.cc
@@ -7,30 +7,22 @@
 #include <memory>
 
 #include "base/auto_reset.h"
-#include "base/location.h"
 #include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "components/sync/base/cancelation_signal.h"
-#include "components/sync/base/syncer_error.h"
-#include "components/sync/base/unique_position.h"
 #include "components/sync/engine_impl/apply_control_data_updates.h"
 #include "components/sync/engine_impl/clear_server_data.h"
 #include "components/sync/engine_impl/commit.h"
 #include "components/sync/engine_impl/commit_processor.h"
 #include "components/sync/engine_impl/cycle/nudge_tracker.h"
+#include "components/sync/engine_impl/cycle/sync_cycle.h"
 #include "components/sync/engine_impl/get_updates_delegate.h"
 #include "components/sync/engine_impl/get_updates_processor.h"
 #include "components/sync/engine_impl/net/server_connection_manager.h"
 #include "components/sync/syncable/directory.h"
 #include "components/sync/syncable/mutable_entry.h"
 
-using base::Time;
-using base::TimeDelta;
-using sync_pb::ClientCommand;
-
 namespace syncer {
 
 // TODO(akalin): We may want to propagate this switch up
@@ -145,7 +137,7 @@
   return !ExitRequested();
 }
 
-SyncerError Syncer::BuildAndPostCommits(ModelTypeSet requested_types,
+SyncerError Syncer::BuildAndPostCommits(ModelTypeSet request_types,
                                         NudgeTracker* nudge_tracker,
                                         SyncCycle* cycle,
                                         CommitProcessor* commit_processor) {
@@ -154,7 +146,7 @@
   // However, it doesn't hurt to check it anyway.
   while (!ExitRequested()) {
     std::unique_ptr<Commit> commit(
-        Commit::Init(requested_types, cycle->context()->GetEnabledTypes(),
+        Commit::Init(request_types, cycle->context()->GetEnabledTypes(),
                      cycle->context()->max_commit_batch_size(),
                      cycle->context()->account_name(),
                      cycle->context()->directory()->cache_guid(),
diff --git a/components/sync/engine_impl/syncer.h b/components/sync/engine_impl/syncer.h
index 1d40991..dcea8f7 100644
--- a/components/sync/engine_impl/syncer.h
+++ b/components/sync/engine_impl/syncer.h
@@ -7,24 +7,21 @@
 
 #include <stdint.h>
 
-#include <utility>
 #include <vector>
 
-#include "base/callback.h"
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/synchronization/lock.h"
-#include "components/sync/base/extensions_activity.h"
 #include "components/sync/base/model_type.h"
-#include "components/sync/engine_impl/conflict_resolver.h"
-#include "components/sync/engine_impl/cycle/sync_cycle.h"
-#include "components/sync/engine_impl/syncer_types.h"
+#include "components/sync/base/syncer_error.h"
+#include "components/sync/protocol/sync.pb.h"
 
 namespace syncer {
 
 class CancelationSignal;
 class CommitProcessor;
 class GetUpdatesProcessor;
+class NudgeTracker;
+class SyncCycle;
 
 // A Syncer provides a control interface for driving the sync cycle.  These
 // cycles consist of downloading updates, parsing the response (aka. process
diff --git a/components/sync/engine_impl/syncer_unittest.cc b/components/sync/engine_impl/syncer_unittest.cc
index 34b2564..2acd8e0c 100644
--- a/components/sync/engine_impl/syncer_unittest.cc
+++ b/components/sync/engine_impl/syncer_unittest.cc
@@ -28,6 +28,7 @@
 #include "build/build_config.h"
 #include "components/sync/base/cancelation_signal.h"
 #include "components/sync/base/cryptographer.h"
+#include "components/sync/base/extensions_activity.h"
 #include "components/sync/base/fake_encryptor.h"
 #include "components/sync/base/time.h"
 #include "components/sync/engine/cycle/commit_counters.h"
@@ -44,7 +45,6 @@
 #include "components/sync/protocol/bookmark_specifics.pb.h"
 #include "components/sync/protocol/nigori_specifics.pb.h"
 #include "components/sync/protocol/preference_specifics.pb.h"
-#include "components/sync/protocol/sync.pb.h"
 #include "components/sync/syncable/mutable_entry.h"
 #include "components/sync/syncable/nigori_util.h"
 #include "components/sync/syncable/syncable_delete_journal.h"
@@ -302,7 +302,7 @@
         syncer_));
 
     syncable::ReadTransaction trans(FROM_HERE, directory());
-    syncable::Directory::Metahandles children;
+    Directory::Metahandles children;
     directory()->GetChildHandlesById(&trans, trans.root_id(), &children);
     ASSERT_EQ(0u, children.size());
     root_id_ = TestIdFactory::root();
@@ -529,7 +529,7 @@
     mock_server_->ExpectGetUpdatesRequestTypes(enabled_datatypes_);
   }
 
-  Cryptographer* GetCryptographer(syncable::BaseTransaction* trans) {
+  Cryptographer* GetCryptographer(BaseTransaction* trans) {
     return directory()->GetCryptographer(trans);
   }
 
@@ -629,7 +629,7 @@
   {
     // Nothing should have been committed as bookmarks is throttled.
     syncable::ReadTransaction rtrans(FROM_HERE, directory());
-    Entry entryA(&rtrans, syncable::GET_BY_ID, ids_.FromNumber(1));
+    Entry entryA(&rtrans, GET_BY_ID, ids_.FromNumber(1));
     ASSERT_TRUE(entryA.good());
     EXPECT_TRUE(entryA.GetIsUnsynced());
   }
@@ -640,7 +640,7 @@
   {
     // It should have been committed.
     syncable::ReadTransaction rtrans(FROM_HERE, directory());
-    Entry entryA(&rtrans, syncable::GET_BY_ID, ids_.FromNumber(1));
+    Entry entryA(&rtrans, GET_BY_ID, ids_.FromNumber(1));
     ASSERT_TRUE(entryA.good());
     EXPECT_FALSE(entryA.GetIsUnsynced());
   }
@@ -759,7 +759,7 @@
 #define VERIFY_ENTRY(id, is_unapplied, is_unsynced, prev_initialized,         \
                      parent_id, version, server_version, id_fac, rtrans)      \
   do {                                                                        \
-    Entry entryA(rtrans, syncable::GET_BY_ID, id_fac.FromNumber(id));         \
+    Entry entryA(rtrans, GET_BY_ID, id_fac.FromNumber(id));                   \
     ASSERT_TRUE(entryA.good());                                               \
     /* We don't use EXPECT_EQ here because if the left side param is false,*/ \
     /* gcc 4.6 warns converting 'false' to pointer type for argument 1.*/     \
@@ -1005,7 +1005,7 @@
 
   {
     // Run GetCommitIds, the function being tested.
-    syncable::Directory::Metahandles result_handles;
+    Directory::Metahandles result_handles;
     syncable::ReadTransaction trans(FROM_HERE, directory());
     GetCommitIdsForType(&trans, BOOKMARKS, 100, &result_handles);
 
@@ -1051,7 +1051,7 @@
 
   {
     // Run GetCommitIds with a limit of 2 entries to commit.
-    syncable::Directory::Metahandles result_handles;
+    Directory::Metahandles result_handles;
     syncable::ReadTransaction trans(FROM_HERE, directory());
     GetCommitIdsForType(&trans, BOOKMARKS, 2, &result_handles);
 
@@ -1118,13 +1118,13 @@
     VERIFY_ENTRY(3, false, false, false, 1, 10, 10, ids_, &rtrans);
     VERIFY_ENTRY(4, false, false, false, 0, 10, 10, ids_, &rtrans);
 
-    Entry entry1(&rtrans, syncable::GET_BY_ID, ids_.FromNumber(1));
+    Entry entry1(&rtrans, GET_BY_ID, ids_.FromNumber(1));
     ASSERT_TRUE(
         entry1.GetUniquePosition().Equals(entry1.GetServerUniquePosition()));
     pos1 = entry1.GetUniquePosition();
-    Entry entry2(&rtrans, syncable::GET_BY_ID, ids_.FromNumber(2));
+    Entry entry2(&rtrans, GET_BY_ID, ids_.FromNumber(2));
     pos2 = entry2.GetUniquePosition();
-    Entry entry3(&rtrans, syncable::GET_BY_ID, ids_.FromNumber(3));
+    Entry entry3(&rtrans, GET_BY_ID, ids_.FromNumber(3));
     pos3 = entry3.GetUniquePosition();
   }
 
@@ -1292,7 +1292,7 @@
   EXPECT_EQ(child_id_, mock_server_->committed_ids()[1]);
   {
     syncable::ReadTransaction rt(FROM_HERE, directory());
-    Entry entry(&rt, syncable::GET_BY_ID, child_id_);
+    Entry entry(&rt, GET_BY_ID, child_id_);
     ASSERT_TRUE(entry.good());
     VerifyTestDataInEntry(&rt, &entry);
   }
@@ -1339,14 +1339,14 @@
   EXPECT_EQ(child_id_, mock_server_->committed_ids()[1]);
   {
     syncable::ReadTransaction rt(FROM_HERE, directory());
-    Entry entry(&rt, syncable::GET_BY_ID, child_id_);
+    Entry entry(&rt, GET_BY_ID, child_id_);
     ASSERT_TRUE(entry.good());
     VerifyTestDataInEntry(&rt, &entry);
   }
   directory()->SaveChanges();
   {
     syncable::ReadTransaction rt(FROM_HERE, directory());
-    Entry entry(&rt, syncable::GET_BY_ID, pref_node_id);
+    Entry entry(&rt, GET_BY_ID, pref_node_id);
     ASSERT_FALSE(entry.good());
   }
 }
@@ -1373,7 +1373,7 @@
   directory()->SaveChanges();
   {
     syncable::ReadTransaction rt(FROM_HERE, directory());
-    Entry entry(&rt, syncable::GET_BY_ID, parent_id_);
+    Entry entry(&rt, GET_BY_ID, parent_id_);
     ASSERT_FALSE(entry.good());
   }
 }
@@ -1866,13 +1866,13 @@
   {
     syncable::ReadTransaction rtrans(FROM_HERE, directory());
     // Check that things committed correctly.
-    Entry entry_1(&rtrans, syncable::GET_BY_ID, parent_id_);
+    Entry entry_1(&rtrans, GET_BY_ID, parent_id_);
     EXPECT_EQ(parent1_name, entry_1.GetNonUniqueName());
     // Check that parent2 is a subfolder of parent1.
     EXPECT_EQ(1, CountEntriesWithName(&rtrans, parent_id_, parent2_name));
 
     // Parent2 was a local ID and thus should have changed on commit!
-    Entry pre_commit_entry_parent2(&rtrans, syncable::GET_BY_ID, parent2_id);
+    Entry pre_commit_entry_parent2(&rtrans, GET_BY_ID, parent2_id);
     ASSERT_FALSE(pre_commit_entry_parent2.good());
 
     // Look up the new ID.
@@ -1880,7 +1880,7 @@
         GetOnlyEntryWithName(&rtrans, parent_id_, parent2_name);
     EXPECT_TRUE(parent2_committed_id.ServerKnows());
 
-    Entry child(&rtrans, syncable::GET_BY_ID, child_id);
+    Entry child(&rtrans, GET_BY_ID, child_id);
     EXPECT_EQ(parent2_committed_id, child.GetParentId());
   }
 }
@@ -1933,22 +1933,21 @@
   {
     syncable::ReadTransaction rtrans(FROM_HERE, directory());
 
-    Entry parent(&rtrans, syncable::GET_BY_ID,
+    Entry parent(&rtrans, GET_BY_ID,
                  GetOnlyEntryWithName(&rtrans, rtrans.root_id(), parent_name));
     ASSERT_TRUE(parent.good());
     EXPECT_TRUE(parent.GetId().ServerKnows());
 
-    Entry parent2(&rtrans, syncable::GET_BY_ID,
+    Entry parent2(&rtrans, GET_BY_ID,
                   GetOnlyEntryWithName(&rtrans, parent.GetId(), parent2_name));
     ASSERT_TRUE(parent2.good());
     EXPECT_TRUE(parent2.GetId().ServerKnows());
 
     // Id changed on commit, so this should fail.
-    Entry local_parent2_id_entry(&rtrans, syncable::GET_BY_ID,
-                                 parent2_local_id);
+    Entry local_parent2_id_entry(&rtrans, GET_BY_ID, parent2_local_id);
     ASSERT_FALSE(local_parent2_id_entry.good());
 
-    Entry entry_b(&rtrans, syncable::GET_BY_HANDLE, meta_handle_b);
+    Entry entry_b(&rtrans, GET_BY_HANDLE, meta_handle_b);
     EXPECT_TRUE(entry_b.GetId().ServerKnows());
     EXPECT_TRUE(parent2.GetId() == entry_b.GetParentId());
   }
@@ -2181,7 +2180,7 @@
   syncable::Id entry_id;
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
-    Entry entry(&trans, syncable::GET_BY_HANDLE, metahandle_entry);
+    Entry entry(&trans, GET_BY_HANDLE, metahandle_entry);
     ASSERT_TRUE(entry.good());
     EXPECT_EQ(folder_id, entry.GetParentId());
     EXPECT_EQ("new_entry", entry.GetNonUniqueName());
@@ -2223,7 +2222,7 @@
     EXPECT_FALSE(old_dead_folder.good());
 
     // The child's parent should have changed.
-    Entry entry(&trans, syncable::GET_BY_HANDLE, metahandle_entry);
+    Entry entry(&trans, GET_BY_HANDLE, metahandle_entry);
     ASSERT_TRUE(entry.good());
     EXPECT_EQ("new_entry", entry.GetNonUniqueName());
     EXPECT_EQ(new_folder_id, entry.GetParentId());
@@ -2454,7 +2453,7 @@
   void CreateFolderInBob() {
     WriteTransaction trans(FROM_HERE, UNITTEST, directory());
     MutableEntry bob(
-        &trans, syncable::GET_BY_ID,
+        &trans, GET_BY_ID,
         GetOnlyEntryWithName(&trans, TestIdFactory::root(), "bob"));
     ASSERT_TRUE(bob.good());
 
@@ -2484,12 +2483,12 @@
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
     Entry parent_entry(
-        &trans, syncable::GET_BY_ID,
+        &trans, GET_BY_ID,
         GetOnlyEntryWithName(&trans, TestIdFactory::root(), "bob"));
     ASSERT_TRUE(parent_entry.good());
 
     Id child_id = GetOnlyEntryWithName(&trans, parent_entry.GetId(), "bob");
-    Entry child(&trans, syncable::GET_BY_ID, child_id);
+    Entry child(&trans, GET_BY_ID, child_id);
     ASSERT_TRUE(child.good());
     EXPECT_EQ(parent_entry.GetId(), child.GetParentId());
   }
@@ -2564,12 +2563,12 @@
                                   local_cache_guid(), local_id.GetServerId());
   mock_server_->set_conflict_all_commits(true);
   EXPECT_FALSE(SyncShareNudge());
-  syncable::Directory::Metahandles children;
+  Directory::Metahandles children;
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
     directory()->GetChildHandlesById(&trans, parent_id_, &children);
     // We expect the conflict resolver to preserve the local entry.
-    Entry child(&trans, syncable::GET_BY_ID, child_id_);
+    Entry child(&trans, GET_BY_ID, child_id_);
     ASSERT_TRUE(child.good());
     EXPECT_TRUE(child.GetIsUnsynced());
     EXPECT_FALSE(child.GetIsUnappliedUpdate());
@@ -2605,7 +2604,7 @@
   int64_t version;
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
-    Entry entry(&trans, syncable::GET_BY_HANDLE, entry_metahandle);
+    Entry entry(&trans, GET_BY_HANDLE, entry_metahandle);
     ASSERT_TRUE(entry.good());
     id = entry.GetId();
     EXPECT_TRUE(id.ServerKnows());
@@ -2621,7 +2620,7 @@
   EXPECT_TRUE(SyncShareNudge());
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
-    Entry entry(&trans, syncable::GET_BY_ID, id);
+    Entry entry(&trans, GET_BY_ID, id);
     ASSERT_TRUE(entry.good());
     EXPECT_EQ(test_time, entry.GetMtime());
   }
@@ -2679,7 +2678,7 @@
     std::vector<int64_t> unapplied;
     directory()->GetUnappliedUpdateMetaHandles(&trans, all_types, &unapplied);
     EXPECT_EQ(0u, unapplied.size());
-    syncable::Directory::Metahandles unsynced;
+    Directory::Metahandles unsynced;
     directory()->GetUnsyncedMetaHandles(&trans, &unsynced);
     EXPECT_EQ(0u, unsynced.size());
   }
@@ -3004,7 +3003,7 @@
   SyncShareConfigure();
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
-    Entry entry(&trans, syncable::GET_BY_HANDLE, newfolder_metahandle);
+    Entry entry(&trans, GET_BY_HANDLE, newfolder_metahandle);
     ASSERT_TRUE(entry.good());
   }
 }
@@ -4000,10 +3999,10 @@
   EXPECT_TRUE(SyncShareNudge());
   {
     syncable::ReadTransaction rtrans(FROM_HERE, directory());
-    Entry good_entry(&rtrans, syncable::GET_BY_ID, ids_.FromNumber(1));
+    Entry good_entry(&rtrans, GET_BY_ID, ids_.FromNumber(1));
     ASSERT_TRUE(good_entry.good());
     EXPECT_FALSE(good_entry.GetIsUnappliedUpdate());
-    Entry bad_parent(&rtrans, syncable::GET_BY_ID, ids_.FromNumber(2));
+    Entry bad_parent(&rtrans, GET_BY_ID, ids_.FromNumber(2));
     ASSERT_TRUE(bad_parent.good());
     EXPECT_TRUE(bad_parent.GetIsUnappliedUpdate());
   }
@@ -4212,7 +4211,7 @@
   }
   // Now read it back out and make sure the value is max int64_t.
   syncable::ReadTransaction rtrans(FROM_HERE, directory());
-  Entry entry(&rtrans, syncable::GET_BY_HANDLE, item_metahandle);
+  Entry entry(&rtrans, GET_BY_HANDLE, item_metahandle);
   ASSERT_TRUE(entry.good());
   EXPECT_EQ(really_big_int, entry.GetBaseVersion());
 }
@@ -4560,7 +4559,7 @@
     Entry pref_root(&trans, GET_TYPE_ROOT, PREFERENCES);
     ASSERT_TRUE(pref_root.good());
 
-    syncable::Directory::Metahandles children;
+    Directory::Metahandles children;
     directory()->GetChildHandlesById(&trans, pref_root.GetId(), &children);
     ASSERT_EQ(2U, children.size());
   }
@@ -4604,7 +4603,7 @@
     Entry pref_root(&trans, GET_TYPE_ROOT, PREFERENCES);
     ASSERT_TRUE(pref_root.good());
 
-    syncable::Directory::Metahandles children;
+    Directory::Metahandles children;
     directory()->GetChildHandlesById(&trans, pref_root.GetId(), &children);
     ASSERT_EQ(2U, children.size());
   }
@@ -4689,7 +4688,7 @@
     ASSERT_TRUE(pref_root.good());
 
     // Verify that we have exactly 3 tagged nodes under the type root.
-    syncable::Directory::Metahandles children;
+    Directory::Metahandles children;
     directory()->GetChildHandlesById(&trans, pref_root.GetId(), &children);
     ASSERT_EQ(3U, children.size());
   }
@@ -4749,7 +4748,7 @@
     ASSERT_TRUE(pref_entry.GetParentId().IsNull());
 
     // Verify that there is still one node under the type root.
-    syncable::Directory::Metahandles children;
+    Directory::Metahandles children;
     directory()->GetChildHandlesById(&trans, pref_root_id, &children);
     ASSERT_EQ(1U, children.size());
   }
@@ -5011,7 +5010,7 @@
 
   {
     syncable::ReadTransaction trans(FROM_HERE, directory());
-    syncable::Entry root(&trans, syncable::GET_TYPE_ROOT, PREFERENCES);
+    Entry root(&trans, GET_TYPE_ROOT, PREFERENCES);
     EXPECT_TRUE(root.good());
   }
 
diff --git a/components/sync/engine_impl/syncer_util_unittest.cc b/components/sync/engine_impl/syncer_util_unittest.cc
index 1ceeb1b0..89148c1d0 100644
--- a/components/sync/engine_impl/syncer_util_unittest.cc
+++ b/components/sync/engine_impl/syncer_util_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/message_loop/message_loop.h"
 #include "base/rand_util.h"
 #include "components/sync/base/unique_position.h"
 #include "components/sync/core/test/test_entry_factory.h"
diff --git a/content/app/content_main_runner.cc b/content/app/content_main_runner.cc
index a8e8660..d46acd2 100644
--- a/content/app/content_main_runner.cc
+++ b/content/app/content_main_runner.cc
@@ -32,6 +32,7 @@
 #include "base/path_service.h"
 #include "base/process/launch.h"
 #include "base/process/memory.h"
+#include "base/process/process.h"
 #include "base/process/process_handle.h"
 #include "base/profiler/scoped_tracker.h"
 #include "base/strings/string_number_conversions.h"
@@ -142,12 +143,8 @@
 
   // Ensure any field trials in browser are reflected into the child
   // process.
-  if (command_line.HasSwitch(switches::kForceFieldTrials)) {
-    bool result = base::FieldTrialList::CreateTrialsFromString(
-        command_line.GetSwitchValueASCII(switches::kForceFieldTrials),
-        std::set<std::string>());
-    DCHECK(result);
-  }
+  base::FieldTrialList::CreateTrialsFromCommandLine(
+      command_line, switches::kFieldTrialHandle);
 
   std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
   feature_list->InitializeFromCommandLine(
diff --git a/content/browser/DEPS b/content/browser/DEPS
index ce4c81d..64329ac 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -59,12 +59,14 @@
   "+third_party/WebKit/public/platform/WebFocusType.h",
   "+third_party/WebKit/public/platform/WebGamepad.h",
   "+third_party/WebKit/public/platform/WebGamepads.h",
+  "+third_party/WebKit/public/platform/WebInputEvent.h",
   "+third_party/WebKit/public/platform/WebInsecureRequestPolicy.h",
   "+third_party/WebKit/public/platform/WebNavigationHintType.h",
   "+third_party/WebKit/public/platform/WebReferrerPolicy.h",
   "+third_party/WebKit/public/platform/WebScreenInfo.h",
   "+third_party/WebKit/public/platform/WebSecurityStyle.h",
   "+third_party/WebKit/public/platform/WebString.h",
+  "+third_party/WebKit/public/platform/WebTextInputType.h",
   "+third_party/WebKit/public/platform/mime_registry.mojom.h",
   "+third_party/WebKit/public/platform/modules/background_sync/background_sync.mojom.h",
   "+third_party/WebKit/public/platform/modules/broadcastchannel/broadcast_channel.mojom.h",
@@ -108,7 +110,6 @@
   "+third_party/WebKit/public/web/WebSharedWorkerCreationContextType.h",
   "+third_party/WebKit/public/web/WebSharedWorkerCreationErrors.h",
   "+third_party/WebKit/public/web/WebTextDirection.h",
-  "+third_party/WebKit/public/web/WebTextInputType.h",
   "+third_party/WebKit/public/web/WebTreeScopeType.h",
   "+third_party/WebKit/public/web/mac/WebScrollbarTheme.h",
 
diff --git a/content/browser/android/web_contents_observer_proxy.cc b/content/browser/android/web_contents_observer_proxy.cc
index b9e23ac..ca274f8 100644
--- a/content/browser/android/web_contents_observer_proxy.cc
+++ b/content/browser/android/web_contents_observer_proxy.cc
@@ -306,9 +306,17 @@
                                                                  jstring_url);
 }
 
-void WebContentsObserverProxy::MediaSessionStateChanged(
-    bool is_controllable,
-    bool is_suspended,
+void WebContentsObserverProxy::MediaSessionStateChanged(bool is_controllable,
+                                                        bool is_suspended) {
+  JNIEnv* env = AttachCurrentThread();
+
+  ScopedJavaLocalRef<jobject> obj(java_observer_);
+
+  Java_WebContentsObserverProxy_mediaSessionStateChanged(
+      env, obj, is_controllable, is_suspended);
+}
+
+void WebContentsObserverProxy::MediaSessionMetadataChanged(
     const base::Optional<MediaMetadata>& metadata) {
   JNIEnv* env = AttachCurrentThread();
 
@@ -318,8 +326,8 @@
   if (metadata.has_value())
     j_metadata = MediaMetadataAndroid::CreateJavaObject(env, metadata.value());
 
-  Java_WebContentsObserverProxy_mediaSessionStateChanged(
-      env, obj, is_controllable, is_suspended, j_metadata);
+  Java_WebContentsObserverProxy_mediaSessionMetadataChanged(env, obj,
+                                                            j_metadata);
 }
 
 void WebContentsObserverProxy::SetToBaseURLForDataURLIfNeeded(
diff --git a/content/browser/android/web_contents_observer_proxy.h b/content/browser/android/web_contents_observer_proxy.h
index f6d546c6..0829acc 100644
--- a/content/browser/android/web_contents_observer_proxy.h
+++ b/content/browser/android/web_contents_observer_proxy.h
@@ -72,9 +72,9 @@
   void DidStartNavigationToPendingEntry(
       const GURL& url,
       ReloadType reload_type) override;
-  void MediaSessionStateChanged(
-      bool is_controllable,
-      bool is_suspended,
+  void MediaSessionStateChanged(bool is_controllable,
+                                bool is_suspended) override;
+  void MediaSessionMetadataChanged(
       const base::Optional<MediaMetadata>& metadata) override;
   void SetToBaseURLForDataURLIfNeeded(std::string* url);
 
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index a8d19b0..bb6a646 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -38,6 +38,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/child_process_data.h"
 #include "content/public/browser/content_browser_client.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/mojo_channel_switches.h"
 #include "content/public/common/process_type.h"
@@ -207,7 +208,8 @@
 }
 
 // static
-void BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(
+std::unique_ptr<base::SharedMemory>
+BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(
     base::CommandLine* cmd_line) {
   std::string enabled_features;
   std::string disabled_features;
@@ -220,17 +222,14 @@
 
   // If we run base::FieldTrials, we want to pass to their state to the
   // child process so that it can act in accordance with each state.
-  std::string field_trial_states;
-  base::FieldTrialList::AllStatesToString(&field_trial_states);
-  if (!field_trial_states.empty()) {
-    cmd_line->AppendSwitchASCII(switches::kForceFieldTrials,
-                                field_trial_states);
-  }
+  return base::FieldTrialList::CopyFieldTrialStateToFlags(
+      switches::kFieldTrialHandle, cmd_line);
 }
 
 void BrowserChildProcessHostImpl::Launch(
     SandboxedProcessLauncherDelegate* delegate,
     base::CommandLine* cmd_line,
+    const base::SharedMemory* field_trial_state,
     bool terminate_on_shutdown) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
@@ -258,11 +257,7 @@
 
   notify_child_disconnected_ = true;
   child_process_.reset(new ChildProcessLauncher(
-      delegate,
-      cmd_line,
-      data_.id,
-      this,
-      child_token_,
+      delegate, cmd_line, data_.id, this, field_trial_state, child_token_,
       base::Bind(&BrowserChildProcessHostImpl::OnMojoError,
                  weak_factory_.GetWeakPtr(),
                  base::ThreadTaskRunnerHandle::Get()),
diff --git a/content/browser/browser_child_process_host_impl.h b/content/browser/browser_child_process_host_impl.h
index c10b9adf..c88ec6e 100644
--- a/content/browser/browser_child_process_host_impl.h
+++ b/content/browser/browser_child_process_host_impl.h
@@ -12,6 +12,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
 #include "base/memory/weak_ptr.h"
 #include "base/process/process.h"
 #include "base/single_thread_task_runner.h"
@@ -65,12 +66,14 @@
   // Copies kEnableFeatures and kDisableFeatures to the command line. Generates
   // them from the FeatureList override state, to take into account overrides
   // from FieldTrials.
-  static void CopyFeatureAndFieldTrialFlags(base::CommandLine* cmd_line);
+  static std::unique_ptr<base::SharedMemory> CopyFeatureAndFieldTrialFlags(
+      base::CommandLine* cmd_line);
 
   // BrowserChildProcessHost implementation:
   bool Send(IPC::Message* message) override;
   void Launch(SandboxedProcessLauncherDelegate* delegate,
               base::CommandLine* cmd_line,
+              const base::SharedMemory* field_trial_state,
               bool terminate_on_shutdown) override;
   const ChildProcessData& GetData() const override;
   ChildProcessHost* GetHost() const override;
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc
index 0d640fa..82d6744b 100644
--- a/content/browser/child_process_launcher.cc
+++ b/content/browser/child_process_launcher.cc
@@ -121,6 +121,7 @@
 #if defined(OS_ANDROID)
                             base::ScopedFD ipcfd,
 #endif
+                            const base::SharedMemory* field_trial_state,
                             mojo::edk::ScopedPlatformHandle client_handle,
                             base::CommandLine* cmd_line) {
   DCHECK_CURRENTLY_ON(BrowserThread::PROCESS_LAUNCHER);
@@ -152,6 +153,8 @@
   } else {
     base::HandlesToInheritVector handles;
     handles.push_back(client_handle.get().handle);
+    if (field_trial_state)
+      handles.push_back(field_trial_state->handle().GetHandle());
     cmd_line->AppendSwitchASCII(
         mojo::edk::PlatformChannelPair::kMojoPlatformChannelHandleSwitch,
         base::UintToString(base::win::HandleToUint32(handles[0])));
@@ -397,6 +400,7 @@
     base::CommandLine* cmd_line,
     int child_process_id,
     Client* client,
+    const base::SharedMemory* field_trial_state,
     const std::string& mojo_child_token,
     const mojo::edk::ProcessErrorCallback& process_error_callback,
     bool terminate_on_shutdown)
@@ -417,7 +421,7 @@
       weak_factory_(this) {
   DCHECK(CalledOnValidThread());
   CHECK(BrowserThread::GetCurrentThreadIdentifier(&client_thread_id_));
-  Launch(delegate, cmd_line, child_process_id);
+  Launch(delegate, cmd_line, child_process_id, field_trial_state);
 }
 
 ChildProcessLauncher::~ChildProcessLauncher() {
@@ -431,10 +435,10 @@
   }
 }
 
-void ChildProcessLauncher::Launch(
-    SandboxedProcessLauncherDelegate* delegate,
-    base::CommandLine* cmd_line,
-    int child_process_id) {
+void ChildProcessLauncher::Launch(SandboxedProcessLauncherDelegate* delegate,
+                                  base::CommandLine* cmd_line,
+                                  int child_process_id,
+                                  const base::SharedMemory* field_trial_state) {
   DCHECK(CalledOnValidThread());
 
 #if defined(OS_ANDROID)
@@ -483,7 +487,7 @@
 #if defined(OS_ANDROID)
                  base::Passed(&ipcfd),
 #endif
-                 base::Passed(&client_handle), cmd_line));
+                 field_trial_state, base::Passed(&client_handle), cmd_line));
 }
 
 void ChildProcessLauncher::UpdateTerminationStatus(bool known_dead) {
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h
index b0cf02ca..943aba2e 100644
--- a/content/browser/child_process_launcher.h
+++ b/content/browser/child_process_launcher.h
@@ -7,6 +7,7 @@
 
 #include "base/files/scoped_file.h"
 #include "base/macros.h"
+#include "base/memory/shared_memory.h"
 #include "base/memory/weak_ptr.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
@@ -79,6 +80,7 @@
       base::CommandLine* cmd_line,
       int child_process_id,
       Client* client,
+      const base::SharedMemory* field_trial_state,
       const std::string& mojo_child_token,
       const mojo::edk::ProcessErrorCallback& process_error_callback,
       bool terminate_on_shutdown = true);
@@ -116,7 +118,8 @@
   // Posts a task to the launcher thread to do the actual work.
   void Launch(SandboxedProcessLauncherDelegate* delegate,
               base::CommandLine* cmd_line,
-              int child_process_id);
+              int child_process_id,
+              const base::SharedMemory* field_trial_state);
 
   void UpdateTerminationStatus(bool known_dead);
 
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 4ccab78..7259036a 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -1898,7 +1898,7 @@
                          "document.body.appendChild(iframe);";
     EXPECT_TRUE(ExecuteScript(root, script));
   }
-  EXPECT_TRUE(subframe_delayer.WaitForWillStartRequest());
+  EXPECT_TRUE(subframe_delayer.WaitForRequestStart());
 
   // Stop the request so that we can wait for load stop below, without ending up
   // with a commit for this frame.
@@ -4568,7 +4568,7 @@
   // second page, though, causes it to do a replaceState().
   TestNavigationManager manager(shell()->web_contents(), start_url);
   controller.GoBack();
-  EXPECT_TRUE(manager.WaitForWillStartRequest());
+  EXPECT_TRUE(manager.WaitForRequestStart());
 
   // The navigation that just happened was the replaceState(), which should not
   // have changed the position into the navigation entry list. Make sure that
@@ -5491,9 +5491,9 @@
       frame_url_a2);
   TestNavigationManager mainframe_delayer(shell()->web_contents(), url_b);
   controller.GoForward();
-  EXPECT_TRUE(subframe_delayer.WaitForWillStartRequest());
+  EXPECT_TRUE(subframe_delayer.WaitForRequestStart());
   controller.GoForward();
-  EXPECT_TRUE(mainframe_delayer.WaitForWillStartRequest());
+  EXPECT_TRUE(mainframe_delayer.WaitForRequestStart());
   EXPECT_EQ(2, controller.GetPendingEntryIndex());
 
   // Let the subframe commit.
@@ -5543,7 +5543,7 @@
   TestNavigationManager delayer(shell()->web_contents(),
                                 embedded_test_server()->GetURL("/title3.html"));
   shell()->LoadURL(embedded_test_server()->GetURL("/title3.html"));
-  EXPECT_TRUE(delayer.WaitForWillStartRequest());
+  EXPECT_TRUE(delayer.WaitForRequestStart());
 
   NavigationController& controller = shell()->web_contents()->GetController();
 
diff --git a/content/browser/frame_host/navigation_handle_impl_browsertest.cc b/content/browser/frame_host/navigation_handle_impl_browsertest.cc
index 37bfde7..ff6e2d5 100644
--- a/content/browser/frame_host/navigation_handle_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_handle_impl_browsertest.cc
@@ -695,7 +695,7 @@
 
   // Starts and verifies the main frame navigation.
   shell()->LoadURL(main_url);
-  EXPECT_TRUE(main_manager.WaitForWillStartRequest());
+  EXPECT_TRUE(main_manager.WaitForRequestStart());
   // The throttle should not be null.
   EXPECT_NE(previous_throttle, installer.navigation_throttle());
   // Checks the only URL recorded so far is the one expected for the main frame.
@@ -709,7 +709,7 @@
 
   // Ditto for frame b navigation.
   main_manager.WaitForNavigationFinished();
-  EXPECT_TRUE(b_manager.WaitForWillStartRequest());
+  EXPECT_TRUE(b_manager.WaitForRequestStart());
   EXPECT_NE(previous_throttle, installer.navigation_throttle());
   EXPECT_EQ(b_url, url_recorder.urls().back());
   EXPECT_EQ(2ul, url_recorder.urls().size());
@@ -719,7 +719,7 @@
 
   // Ditto for frame c navigation.
   b_manager.WaitForNavigationFinished();
-  EXPECT_TRUE(c_manager.WaitForWillStartRequest());
+  EXPECT_TRUE(c_manager.WaitForRequestStart());
   EXPECT_NE(previous_throttle, installer.navigation_throttle());
   EXPECT_EQ(c_url, url_recorder.urls().back());
   EXPECT_EQ(3ul, url_recorder.urls().size());
@@ -757,7 +757,7 @@
       shell(), "window.domAutomationController.send(clickSameSiteLink());",
       &success));
   EXPECT_TRUE(success);
-  EXPECT_TRUE(link_manager.WaitForWillStartRequest());
+  EXPECT_TRUE(link_manager.WaitForRequestStart());
   EXPECT_EQ(link_url, url_recorder.urls().back());
   EXPECT_EQ(2ul, url_recorder.urls().size());
   EXPECT_EQ(REQUEST_CONTEXT_TYPE_HYPERLINK,
@@ -790,7 +790,7 @@
   EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
   GURL submit_url("javascript:submitForm('isubmit')");
   shell()->LoadURL(submit_url);
-  EXPECT_TRUE(post_manager.WaitForWillStartRequest());
+  EXPECT_TRUE(post_manager.WaitForRequestStart());
   EXPECT_EQ(post_url, url_recorder.urls().back());
   EXPECT_EQ(2ul, url_recorder.urls().size());
   EXPECT_EQ(REQUEST_CONTEXT_TYPE_FORM,
@@ -823,7 +823,7 @@
     // iframe_secure_url never happened and the expected upgrade may not be
     // working.
     shell()->LoadURL(start_url);
-    EXPECT_TRUE(navigation_manager.WaitForWillStartRequest());
+    EXPECT_TRUE(navigation_manager.WaitForRequestStart());
 
     // The main frame should have finished navigating while the iframe should
     // have just started.
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 42307944..d444801 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -970,8 +970,11 @@
 
   base::CommandLine* cmd_line = new base::CommandLine(exe_path);
 #endif
+
   cmd_line->AppendSwitchASCII(switches::kProcessType, switches::kGpuProcess);
-  BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(cmd_line);
+
+  field_trial_state_ =
+      BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(cmd_line);
 
 #if defined(OS_WIN)
   cmd_line->AppendArg(switches::kPrefetchArgumentGpu);
@@ -1015,10 +1018,8 @@
     cmd_line->PrependWrapper(gpu_launcher);
 
   process_->Launch(
-      new GpuSandboxedProcessLauncherDelegate(cmd_line,
-                                              process_->GetHost()),
-      cmd_line,
-      true);
+      new GpuSandboxedProcessLauncherDelegate(cmd_line, process_->GetHost()),
+      cmd_line, field_trial_state_.get(), true);
   process_launched_ = true;
 
   UMA_HISTOGRAM_ENUMERATION("GPU.GPUProcessLifetimeEvents",
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index d42c354..c8e66825 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -292,6 +292,12 @@
 
   std::string shader_prefix_key_;
 
+  // Anonymous shared memory segment to share with subprocess containing list of
+  // field trials (represented as a string).
+  // TODO(crbug.com/653874): Eventually remove this and use single shared memory
+  // object across processes.
+  std::unique_ptr<base::SharedMemory> field_trial_state_;
+
   DISALLOW_COPY_AND_ASSIGN(GpuProcessHost);
 };
 
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 14bfe17..29092f2 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -1031,10 +1031,11 @@
     GlobalRequestID id(filter_->child_id(), request_id);
     DelegateMap::iterator it = delegate_map_.find(id);
     if (it != delegate_map_.end()) {
-      base::ObserverList<ResourceMessageDelegate>::Iterator del_it(it->second);
-      ResourceMessageDelegate* delegate;
-      while (!handled && (delegate = del_it.GetNext()) != NULL) {
-        handled = delegate->OnMessageReceived(message);
+      for (auto& delegate : *it->second) {
+        if (delegate.OnMessageReceived(message)) {
+          handled = true;
+          break;
+        }
       }
     }
 
@@ -1170,11 +1171,8 @@
     DelegateMap::iterator it = delegate_map_.find(old_request_id);
     if (it != delegate_map_.end()) {
       // Tell each delegate that the request ID has changed.
-      base::ObserverList<ResourceMessageDelegate>::Iterator del_it(it->second);
-      ResourceMessageDelegate* delegate;
-      while ((delegate = del_it.GetNext()) != NULL) {
-        delegate->set_request_id(new_request_id);
-      }
+      for (auto& delegate : *it->second)
+        delegate.set_request_id(new_request_id);
       // Now store the observer list under the new request ID.
       delegate_map_[new_request_id] = delegate_map_[old_request_id];
       delegate_map_.erase(old_request_id);
diff --git a/content/browser/media/encrypted_media_browsertest.cc b/content/browser/media/encrypted_media_browsertest.cc
index aec2165..019f3d2 100644
--- a/content/browser/media/encrypted_media_browsertest.cc
+++ b/content/browser/media/encrypted_media_browsertest.cc
@@ -206,7 +206,14 @@
   TestConfigChange();
 }
 
-IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, FrameSizeChangeVideo) {
+#if defined(OS_ANDROID)
+// Flaky on android: https://crbug.com/655630
+#define MAYBE_FrameSizeChangeVideo DISABLED_FrameSizeChangeVideo
+#else
+#define MAYBE_FrameSizeChangeVideo FrameSizeChangeVideo
+#endif
+
+IN_PROC_BROWSER_TEST_P(EncryptedMediaTest, MAYBE_FrameSizeChangeVideo) {
   TestFrameSizeChange();
 }
 #endif  // !defined(DISABLE_ENCRYPTED_MEDIA_PLAYBACK_TESTS)
diff --git a/content/browser/media/session/media_session.cc b/content/browser/media/session/media_session.cc
index 147b337..aa165b9 100644
--- a/content/browser/media/session/media_session.cc
+++ b/content/browser/media/session/media_session.cc
@@ -75,10 +75,8 @@
 
 void MediaSession::SetMetadata(const base::Optional<MediaMetadata>& metadata) {
   metadata_ = metadata;
-  // TODO(zqzhang): On Android, the metadata is sent though JNI everytime the
-  // media session play/pause state changes. Need to find a way to seprate the
-  // state change and Metadata update. See https://crbug.com/621855.
-  static_cast<WebContentsImpl*>(web_contents())->OnMediaSessionStateChanged();
+  static_cast<WebContentsImpl*>(web_contents())
+      ->OnMediaSessionMetadataChanged();
 }
 
 bool MediaSession::AddPlayer(MediaSessionObserver* observer,
diff --git a/content/browser/media/session/media_session_browsertest.cc b/content/browser/media/session/media_session_browsertest.cc
index 629c562..959bead1 100644
--- a/content/browser/media/session/media_session_browsertest.cc
+++ b/content/browser/media/session/media_session_browsertest.cc
@@ -52,9 +52,8 @@
   MockWebContentsObserver(WebContents* web_contents)
       : WebContentsObserver(web_contents) {}
 
-  MOCK_METHOD3(MediaSessionStateChanged,
-               void(bool is_controllable, bool is_suspended,
-                    const base::Optional<content::MediaMetadata>& metadata));
+  MOCK_METHOD2(MediaSessionStateChanged,
+               void(bool is_controllable, bool is_suspended));
 };
 
 }  // namespace
@@ -588,7 +587,7 @@
 
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsShowForContent) {
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(true, false, testing::_));
+              MediaSessionStateChanged(true, false));
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
       new MockMediaSessionObserver);
@@ -603,7 +602,7 @@
 
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsNoShowForTransient) {
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(false, false, testing::_));
+              MediaSessionStateChanged(false, false));
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
       new MockMediaSessionObserver);
@@ -618,9 +617,9 @@
 
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsHideWhenStopped) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(false, true, testing::_))
+              MediaSessionStateChanged(false, true))
       .After(showControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -637,7 +636,7 @@
 
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsShownAcceptTransient) {
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(true, false, testing::_));
+              MediaSessionStateChanged(true, false));
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
       new MockMediaSessionObserver);
@@ -655,10 +654,10 @@
 
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ControlsShownAfterContentAdded) {
-  Expectation dontShowControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(false, false, testing::_));
+  Expectation dontShowControls = EXPECT_CALL(
+      *mock_web_contents_observer(), MediaSessionStateChanged(false, false));
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(true, false, testing::_))
+              MediaSessionStateChanged(true, false))
       .After(dontShowControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -678,7 +677,7 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ControlsStayIfOnlyOnePlayerHasBeenPaused) {
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(true, false, testing::_));
+              MediaSessionStateChanged(true, false));
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
       new MockMediaSessionObserver);
@@ -699,9 +698,9 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ControlsHideWhenTheLastPlayerIsRemoved) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(false, true, testing::_))
+              MediaSessionStateChanged(false, true))
       .After(showControls);
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
       new MockMediaSessionObserver);
@@ -725,9 +724,9 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ControlsHideWhenAllThePlayersAreRemoved) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(false, true, testing::_))
+              MediaSessionStateChanged(false, true))
       .After(showControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -747,9 +746,9 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ControlsNotHideWhenTheLastPlayerIsPaused) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(true, true, testing::_))
+              MediaSessionStateChanged(true, true))
       .After(showControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -774,9 +773,9 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        SuspendTemporaryUpdatesControls) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(true, true, testing::_))
+              MediaSessionStateChanged(true, true))
       .After(showControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -793,11 +792,12 @@
 
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest, ControlsUpdatedWhenResumed) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, true, testing::_)).After(showControls);
+                                          MediaSessionStateChanged(true, true))
+                                  .After(showControls);
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(true, false, testing::_))
+              MediaSessionStateChanged(true, false))
       .After(pauseControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -815,9 +815,9 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ControlsHideWhenSessionSuspendedPermanently) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(false, true, testing::_))
+              MediaSessionStateChanged(false, true))
       .After(showControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -835,11 +835,12 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ConstrolsHideWhenSessionStops) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, true, testing::_)).After(showControls);
+                                          MediaSessionStateChanged(true, true))
+                                  .After(showControls);
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(false, true, testing::_))
+              MediaSessionStateChanged(false, true))
       .After(pauseControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -857,11 +858,12 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ControlsHideWhenSessionChangesFromContentToTransient) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, true, testing::_)).After(showControls);
+                                          MediaSessionStateChanged(true, true))
+                                  .After(showControls);
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(false, false, testing::_))
+              MediaSessionStateChanged(false, false))
       .After(pauseControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -883,11 +885,12 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ControlsUpdatedWhenNewPlayerResetsSession) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, true, testing::_)).After(showControls);
+                                          MediaSessionStateChanged(true, true))
+                                  .After(showControls);
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(true, false, testing::_))
+              MediaSessionStateChanged(true, false))
       .After(pauseControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -908,11 +911,12 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ControlsResumedWhenPlayerIsResumed) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, true, testing::_)).After(showControls);
+                                          MediaSessionStateChanged(true, true))
+                                  .After(showControls);
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(true, false, testing::_))
+              MediaSessionStateChanged(true, false))
       .After(pauseControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -933,9 +937,9 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ControlsUpdatedDueToResumeSessionAction) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(true, true, testing::_))
+              MediaSessionStateChanged(true, true))
       .After(showControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
@@ -952,11 +956,12 @@
 IN_PROC_BROWSER_TEST_F(MediaSessionBrowserTest,
                        ControlsUpdatedDueToSuspendSessionAction) {
   Expectation showControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, false, testing::_));
+                                         MediaSessionStateChanged(true, false));
   Expectation pauseControls = EXPECT_CALL(*mock_web_contents_observer(),
-      MediaSessionStateChanged(true, true, testing::_)).After(showControls);
+                                          MediaSessionStateChanged(true, true))
+                                  .After(showControls);
   EXPECT_CALL(*mock_web_contents_observer(),
-              MediaSessionStateChanged(true, false, testing::_))
+              MediaSessionStateChanged(true, false))
       .After(pauseControls);
 
   std::unique_ptr<MockMediaSessionObserver> media_session_observer(
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.cc b/content/browser/notifications/notification_event_dispatcher_impl.cc
index 9eb1ade..5f097bc0 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.cc
+++ b/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -203,6 +203,7 @@
     const scoped_refptr<ServiceWorkerVersion>& service_worker,
     const NotificationDatabaseData& notification_database_data,
     int action_index,
+    const base::NullableString16& reply,
     const ServiceWorkerVersion::StatusCallback& callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   int request_id = service_worker->StartRequest(
@@ -212,12 +213,13 @@
       request_id,
       ServiceWorkerMsg_NotificationClickEvent(
           request_id, notification_database_data.notification_id,
-          notification_database_data.notification_data, action_index));
+          notification_database_data.notification_data, action_index, reply));
 }
 
 // Dispatches the notification click event on the |service_worker_registration|.
 void DoDispatchNotificationClickEvent(
     int action_index,
+    const base::NullableString16& reply,
     const NotificationDispatchCompleteCallback& dispatch_complete_callback,
     const scoped_refptr<PlatformNotificationContext>& notification_context,
     const ServiceWorkerRegistration* service_worker_registration,
@@ -229,7 +231,7 @@
       base::Bind(
           &DispatchNotificationClickEventOnWorker,
           make_scoped_refptr(service_worker_registration->active_version()),
-          notification_database_data, action_index, status_callback),
+          notification_database_data, action_index, reply, status_callback),
       status_callback);
 }
 
@@ -360,10 +362,11 @@
     const std::string& notification_id,
     const GURL& origin,
     int action_index,
+    const base::NullableString16& reply,
     const NotificationDispatchCompleteCallback& dispatch_complete_callback) {
   DispatchNotificationEvent(
       browser_context, notification_id, origin,
-      base::Bind(&DoDispatchNotificationClickEvent, action_index,
+      base::Bind(&DoDispatchNotificationClickEvent, action_index, reply,
                  dispatch_complete_callback),
       dispatch_complete_callback);
 }
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.h b/content/browser/notifications/notification_event_dispatcher_impl.h
index 4c7f14d..a0b0399e 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.h
+++ b/content/browser/notifications/notification_event_dispatcher_impl.h
@@ -24,6 +24,7 @@
       const std::string& notification_id,
       const GURL& origin,
       int action_index,
+      const base::NullableString16& reply,
       const NotificationDispatchCompleteCallback& dispatch_complete_callback)
       override;
   void DispatchNotificationCloseEvent(
diff --git a/content/browser/ppapi_plugin_process_host.cc b/content/browser/ppapi_plugin_process_host.cc
index 1bdf4a96..b5e3335e 100644
--- a/content/browser/ppapi_plugin_process_host.cc
+++ b/content/browser/ppapi_plugin_process_host.cc
@@ -444,11 +444,9 @@
   // On posix, never use the zygote for the broker. Also, only use the zygote if
   // we are not using a plugin launcher - having a plugin launcher means we need
   // to use another process instead of just forking the zygote.
-  process_->Launch(
-      new PpapiPluginSandboxedProcessLauncherDelegate(is_broker_,
-                                                      process_->GetHost()),
-      cmd_line,
-      true);
+  process_->Launch(new PpapiPluginSandboxedProcessLauncherDelegate(
+                       is_broker_, process_->GetHost()),
+                   cmd_line, nullptr, true);
   return true;
 }
 
diff --git a/content/browser/renderer_host/ime_adapter_android.cc b/content/browser/renderer_host/ime_adapter_android.cc
index a49e2729..d441190 100644
--- a/content/browser/renderer_host/ime_adapter_android.cc
+++ b/content/browser/renderer_host/ime_adapter_android.cc
@@ -29,9 +29,9 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/content_features.h"
 #include "jni/ImeAdapter_jni.h"
+#include "third_party/WebKit/public/platform/WebInputEvent.h"
+#include "third_party/WebKit/public/platform/WebTextInputType.h"
 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "third_party/WebKit/public/web/WebTextInputType.h"
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF16;
diff --git a/content/browser/renderer_host/input/touch_action_browsertest.cc b/content/browser/renderer_host/input/touch_action_browsertest.cc
index 1c4a305e..33845ae9 100644
--- a/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -188,15 +188,11 @@
 // Mac doesn't yet have a gesture recognizer, so can't support turning touch
 // events into scroll gestures.
 // Will be fixed with http://crbug.com/337142
-#if defined(OS_MACOSX)
-#define MAYBE_DefaultAuto DISABLED_DefaultAuto
-#else
-#define MAYBE_DefaultAuto DefaultAuto
-#endif
+// Flaky on all platforms: https://crbug.com/376668
 //
 // Verify the test infrastructure works - we can touch-scroll the page and get a
 // touchcancel as expected.
-IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, MAYBE_DefaultAuto) {
+IN_PROC_BROWSER_TEST_F(TouchActionBrowserTest, DISABLED_DefaultAuto) {
   LoadURL();
 
   bool scrolled = DoTouchScroll(gfx::Point(50, 50), gfx::Vector2d(0, 45), true);
diff --git a/content/browser/renderer_host/media/video_capture_manager.cc b/content/browser/renderer_host/media/video_capture_manager.cc
index 28040d8c..b8aadb8 100644
--- a/content/browser/renderer_host/media/video_capture_manager.cc
+++ b/content/browser/renderer_host/media/video_capture_manager.cc
@@ -551,8 +551,9 @@
 
     auto request = photo_request_queue_.begin();
     while(request != photo_request_queue_.end()) {
-      if (GetDeviceEntryBySessionId(request->first)->video_capture_device()) {
-        request->second.Run(entry->video_capture_device());
+      DeviceEntry* maybe_entry = GetDeviceEntryBySessionId(request->first);
+      if (maybe_entry && maybe_entry->video_capture_device()) {
+        request->second.Run(maybe_entry->video_capture_device());
         photo_request_queue_.erase(request);
       }
       ++request;
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 3c9fe8a..459e933 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -966,7 +966,7 @@
     // at this stage.
     child_process_launcher_.reset(new ChildProcessLauncher(
         new RendererSandboxedProcessLauncherDelegate(channel_.get()), cmd_line,
-        GetID(), this, child_token_,
+        GetID(), this, field_trial_state_.get(), child_token_,
         base::Bind(&RenderProcessHostImpl::OnMojoError, id_)));
     channel_->Pause();
 
@@ -1579,7 +1579,7 @@
 }
 
 void RenderProcessHostImpl::AppendRendererCommandLine(
-    base::CommandLine* command_line) const {
+    base::CommandLine* command_line) {
   // Pass the process type first, so it shows first in process listings.
   command_line->AppendSwitchASCII(switches::kProcessType,
                                   switches::kRendererProcess);
@@ -1618,7 +1618,7 @@
 
 void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
     const base::CommandLine& browser_cmd,
-    base::CommandLine* renderer_cmd) const {
+    base::CommandLine* renderer_cmd) {
   // Propagate the following switches to the renderer command line (along
   // with any associated values) if present in the browser command line.
   static const char* const kSwitchNames[] = {
@@ -1828,7 +1828,8 @@
   renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
                                  arraysize(kSwitchNames));
 
-  BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(renderer_cmd);
+  field_trial_state_ =
+      BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(renderer_cmd);
 
   if (browser_cmd.HasSwitch(switches::kTraceStartup) &&
       BrowserMainLoop::GetInstance()->is_tracing_startup_for_duration()) {
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index f07c487e..f97cd70a 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -336,14 +336,14 @@
 
   // Generates a command line to be used to spawn a renderer and appends the
   // results to |*command_line|.
-  void AppendRendererCommandLine(base::CommandLine* command_line) const;
+  void AppendRendererCommandLine(base::CommandLine* command_line);
 
   // Copies applicable command line switches from the given |browser_cmd| line
   // flags to the output |renderer_cmd| line flags. Not all switches will be
   // copied over.
   void PropagateBrowserCommandLineToRenderer(
       const base::CommandLine& browser_cmd,
-      base::CommandLine* renderer_cmd) const;
+      base::CommandLine* renderer_cmd);
 
   // Inspects the current object state and sets/removes background priority if
   // appropriate. Should be called after any of the involved data members
@@ -558,6 +558,12 @@
   // The memory allocator, if any, in which the renderer will write its metrics.
   std::unique_ptr<base::SharedPersistentMemoryAllocator> metrics_allocator_;
 
+  // Anonymous shared memory segment to share with subprocess containing list of
+  // field trials (represented as a string).
+  // TODO(crbug.com/653874): Eventually remove this and use single shared memory
+  // object across processes.
+  std::unique_ptr<base::SharedMemory> field_trial_state_;
+
   bool channel_connected_;
   bool sent_render_process_ready_;
 
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 842a57a3..8e81ee9 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -775,9 +775,8 @@
 }
 
 bool EmbeddedWorkerInstance::OnMessageReceived(const IPC::Message& message) {
-  ListenerList::Iterator it(&listener_list_);
-  while (Listener* listener = it.GetNext()) {
-    if (listener->OnMessageReceived(message))
+  for (auto& listener : listener_list_) {
+    if (listener.OnMessageReceived(message))
       return true;
   }
   return false;
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 9c9c424..5d97b9da 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -7960,7 +7960,7 @@
   GURL stall_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
   TestNavigationManager delayer(shell()->web_contents(), stall_url);
   shell()->LoadURL(stall_url);
-  EXPECT_TRUE(delayer.WaitForWillStartRequest());
+  EXPECT_TRUE(delayer.WaitForRequestStart());
 
   // The pending RFH should be in the same process as the popup.
   RenderFrameHostImpl* pending_rfh =
@@ -8022,7 +8022,7 @@
   GURL stall_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
   TestNavigationManager delayer(shell()->web_contents(), stall_url);
   shell()->LoadURL(stall_url);
-  EXPECT_TRUE(delayer.WaitForWillStartRequest());
+  EXPECT_TRUE(delayer.WaitForRequestStart());
 
   // Kill the b.com process, currently in use by the pending RenderFrameHost
   // and the popup.
@@ -8329,7 +8329,7 @@
                                            cross_site_url_1);
   shell()->web_contents()->GetController().LoadURL(
       cross_site_url_1, Referrer(), ui::PAGE_TRANSITION_LINK, std::string());
-  EXPECT_TRUE(cross_site_manager.WaitForWillProcessResponse());
+  EXPECT_TRUE(cross_site_manager.WaitForResponse());
 
   // Start a renderer-initiated navigation to a cross-process url and make sure
   // the navigation will be blocked before being transferred.
@@ -8339,7 +8339,7 @@
                                          cross_site_url_2);
   EXPECT_TRUE(ExecuteScript(
       root, "location.href = '" + cross_site_url_2.spec() + "';"));
-  EXPECT_TRUE(transfer_manager.WaitForWillProcessResponse());
+  EXPECT_TRUE(transfer_manager.WaitForResponse());
 
   // Now have the cross-process navigation commit and mark the current RFH as
   // pending deletion.
diff --git a/content/browser/utility_process_host_impl.cc b/content/browser/utility_process_host_impl.cc
index 708a09d..8601a09c 100644
--- a/content/browser/utility_process_host_impl.cc
+++ b/content/browser/utility_process_host_impl.cc
@@ -340,13 +340,10 @@
       cmd_line->AppendSwitch(switches::kUtilityProcessRunningElevated);
 #endif
 
-    process_->Launch(
-        new UtilitySandboxedProcessLauncherDelegate(exposed_dir_,
-                                                    run_elevated_,
-                                                    no_sandbox_, env_,
-                                                    process_->GetHost()),
-        cmd_line,
-        true);
+    process_->Launch(new UtilitySandboxedProcessLauncherDelegate(
+                         exposed_dir_, run_elevated_, no_sandbox_, env_,
+                         process_->GetHost()),
+                     cmd_line, nullptr, true);
   }
 
   return true;
diff --git a/content/browser/web_contents/aura/gesture_nav_simple.cc b/content/browser/web_contents/aura/gesture_nav_simple.cc
index 4ff4abe5..b826800 100644
--- a/content/browser/web_contents/aura/gesture_nav_simple.cc
+++ b/content/browser/web_contents/aura/gesture_nav_simple.cc
@@ -110,10 +110,6 @@
 
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
 
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
-
   const gfx::Image& image_;
   const bool left_arrow_;
 
diff --git a/content/browser/web_contents/aura/shadow_layer_delegate.cc b/content/browser/web_contents/aura/shadow_layer_delegate.cc
index a4a1660..89ffa64 100644
--- a/content/browser/web_contents/aura/shadow_layer_delegate.cc
+++ b/content/browser/web_contents/aura/shadow_layer_delegate.cc
@@ -4,7 +4,6 @@
 
 #include "content/browser/web_contents/aura/shadow_layer_delegate.h"
 
-#include "base/bind.h"
 #include "base/macros.h"
 #include "third_party/skia/include/effects/SkGradientShader.h"
 #include "ui/aura/window.h"
@@ -59,8 +58,4 @@
 void ShadowLayerDelegate::OnDeviceScaleFactorChanged(float scale_factor) {
 }
 
-base::Closure ShadowLayerDelegate::PrepareForLayerBoundsChange() {
-  return base::Bind(&base::DoNothing);
-}
-
 }  // namespace content
diff --git a/content/browser/web_contents/aura/shadow_layer_delegate.h b/content/browser/web_contents/aura/shadow_layer_delegate.h
index 6c1729f..c3eab8e2 100644
--- a/content/browser/web_contents/aura/shadow_layer_delegate.h
+++ b/content/browser/web_contents/aura/shadow_layer_delegate.h
@@ -37,7 +37,6 @@
   void OnPaintLayer(const ui::PaintContext& context) override;
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
   void OnDeviceScaleFactorChanged(float device_scale_factor) override;
-  base::Closure PrepareForLayerBoundsChange() override;
 
   std::unique_ptr<ui::Layer> layer_;
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 6ceef42..9842629 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -675,16 +675,16 @@
     return true;
   }
 
-  base::ObserverListBase<WebContentsObserver>::Iterator it(&observers_);
-  WebContentsObserver* observer;
   if (render_frame_host) {
-    while ((observer = it.GetNext()) != NULL)
-      if (observer->OnMessageReceived(message, render_frame_host))
+    for (auto& observer : observers_) {
+      if (observer.OnMessageReceived(message, render_frame_host))
         return true;
+    }
   } else {
-    while ((observer = it.GetNext()) != NULL)
-      if (observer->OnMessageReceived(message))
+    for (auto& observer : observers_) {
+      if (observer.OnMessageReceived(message))
         return true;
+    }
   }
 
   // Message handlers should be aware of which
@@ -3818,10 +3818,17 @@
 
 void WebContentsImpl::OnMediaSessionStateChanged() {
   MediaSession* session = MediaSession::Get(this);
-  FOR_EACH_OBSERVER(WebContentsObserver, observers_,
-                    MediaSessionStateChanged(session->IsControllable(),
-                                             session->IsSuspended(),
-                                             session->metadata()));
+  for (auto& observer : observers_) {
+    observer.MediaSessionStateChanged(session->IsControllable(),
+                                       session->IsSuspended());
+  }
+}
+
+void WebContentsImpl::OnMediaSessionMetadataChanged() {
+  MediaSession* session = MediaSession::Get(this);
+  for (auto& observer : observers_) {
+    observer.MediaSessionMetadataChanged(session->metadata());
+  }
 }
 
 void WebContentsImpl::ResumeMediaSession() {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 68278ee1..e57408e 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -414,7 +414,6 @@
   void GetManifest(const GetManifestCallback& callback) override;
   void ExitFullscreen(bool will_cause_resize) override;
   void ResumeLoadingCreatedWebContents() override;
-  void OnMediaSessionStateChanged();
   void ResumeMediaSession() override;
   void SuspendMediaSession() override;
   void StopMediaSession() override;
@@ -432,6 +431,13 @@
   bool GetAllowOtherViews() override;
 #endif
 
+  // This method is called when the MediaSession state has changed, and will
+  // notify the WebContents observers.
+  void OnMediaSessionStateChanged();
+  // This method is called when the MediaSession metadata has changed, and will
+  // notify the WebContents observers.
+  void OnMediaSessionMetadataChanged();
+
   // Implementation of PageNavigator.
   WebContents* OpenURL(const OpenURLParams& params) override;
 
diff --git a/content/browser/web_contents/web_contents_impl_browsertest.cc b/content/browser/web_contents/web_contents_impl_browsertest.cc
index 436d71b..a0f0555 100644
--- a/content/browser/web_contents/web_contents_impl_browsertest.cc
+++ b/content/browser/web_contents/web_contents_impl_browsertest.cc
@@ -899,17 +899,11 @@
 
 // TODO(clamy): Make the test work on Windows and on Mac. On Mac and Windows,
 // there seem to be an issue with the ShellJavascriptDialogManager.
-#if defined(OS_WIN) || defined(OS_MACOSX)
-#define MAYBE_NoResetOnBeforeUnloadCanceledOnCommit \
-  DISABLED_NoResetOnBeforeUnloadCanceledOnCommit
-#else
-#define MAYBE_NoResetOnBeforeUnloadCanceledOnCommit \
-  NoResetOnBeforeUnloadCanceledOnCommit
-#endif
+// Flaky on all platforms: https://crbug.com/655628
 // Test that if a BeforeUnload dialog is destroyed due to the commit of a
 // cross-site navigation, it will not reset the loading state.
 IN_PROC_BROWSER_TEST_F(WebContentsImplBrowserTest,
-                       MAYBE_NoResetOnBeforeUnloadCanceledOnCommit) {
+                       DISABLED_NoResetOnBeforeUnloadCanceledOnCommit) {
   ASSERT_TRUE(embedded_test_server()->Start());
   const GURL kStartURL(
       embedded_test_server()->GetURL("/hang_before_unload.html"));
@@ -923,7 +917,7 @@
   TestNavigationManager cross_site_delayer(shell()->web_contents(),
                                            kCrossSiteURL);
   shell()->LoadURL(kCrossSiteURL);
-  EXPECT_TRUE(cross_site_delayer.WaitForWillStartRequest());
+  EXPECT_TRUE(cross_site_delayer.WaitForRequestStart());
 
   // Click on a link in the page. This will show the BeforeUnload dialog.
   // Ensure the dialog is not dismissed, which will cause it to still be
diff --git a/content/child/service_worker/web_service_worker_registration_impl.cc b/content/child/service_worker/web_service_worker_registration_impl.cc
index ae2705ee..f9e18f9 100644
--- a/content/child/service_worker/web_service_worker_registration_impl.cc
+++ b/content/child/service_worker/web_service_worker_registration_impl.cc
@@ -13,6 +13,7 @@
 #include "content/child/service_worker/web_service_worker_impl.h"
 #include "content/child/service_worker/web_service_worker_provider_impl.h"
 #include "content/common/service_worker/service_worker_types.h"
+#include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerError.h"
 #include "third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRegistrationProxy.h"
 
 namespace content {
@@ -145,6 +146,24 @@
                                       registration_id(), callbacks);
 }
 
+void WebServiceWorkerRegistrationImpl::enableNavigationPreload(
+    WebEnableNavigationPreloadCallbacks* callbacks) {
+  std::unique_ptr<WebEnableNavigationPreloadCallbacks> owned_callbacks(
+      callbacks);
+  // TODO(falken): Implement this.
+  owned_callbacks->onError(blink::WebServiceWorkerError(
+      blink::WebServiceWorkerError::ErrorTypeAbort, "Not implemented"));
+}
+
+void WebServiceWorkerRegistrationImpl::disableNavigationPreload(
+    WebDisableNavigationPreloadCallbacks* callbacks) {
+  std::unique_ptr<WebDisableNavigationPreloadCallbacks> owned_callbacks(
+      callbacks);
+  // TODO(falken): Implement this.
+  owned_callbacks->onError(blink::WebServiceWorkerError(
+      blink::WebServiceWorkerError::ErrorTypeAbort, "Not implemented"));
+}
+
 int64_t WebServiceWorkerRegistrationImpl::registration_id() const {
   return handle_ref_->registration_id();
 }
diff --git a/content/child/service_worker/web_service_worker_registration_impl.h b/content/child/service_worker/web_service_worker_registration_impl.h
index 49904748..7d6deade 100644
--- a/content/child/service_worker/web_service_worker_registration_impl.h
+++ b/content/child/service_worker/web_service_worker_registration_impl.h
@@ -55,6 +55,10 @@
               WebServiceWorkerUpdateCallbacks* callbacks) override;
   void unregister(blink::WebServiceWorkerProvider* provider,
                   WebServiceWorkerUnregistrationCallbacks* callbacks) override;
+  void enableNavigationPreload(
+      WebEnableNavigationPreloadCallbacks* callbacks) override;
+  void disableNavigationPreload(
+      WebDisableNavigationPreloadCallbacks* callbacks) override;
 
   int64_t registration_id() const;
 
diff --git a/content/common/service_worker/service_worker_messages.h b/content/common/service_worker/service_worker_messages.h
index 01ca941..37f2e18d 100644
--- a/content/common/service_worker/service_worker_messages.h
+++ b/content/common/service_worker/service_worker_messages.h
@@ -487,11 +487,12 @@
 IPC_MESSAGE_CONTROL2(ServiceWorkerMsg_ExtendableMessageEvent,
                      int /* request_id */,
                      ServiceWorkerMsg_ExtendableMessageEvent_Params)
-IPC_MESSAGE_CONTROL4(ServiceWorkerMsg_NotificationClickEvent,
+IPC_MESSAGE_CONTROL5(ServiceWorkerMsg_NotificationClickEvent,
                      int /* request_id */,
                      std::string /* notification_id */,
                      content::PlatformNotificationData /* notification_data */,
-                     int /* action_index */)
+                     int /* action_index */,
+                     base::NullableString16 /* notification reply */)
 IPC_MESSAGE_CONTROL3(ServiceWorkerMsg_NotificationCloseEvent,
                      int /* request_id */,
                      std::string /* notification_id */,
diff --git a/content/public/android/BUILD.gn b/content/public/android/BUILD.gn
index 682cc46..ee8ea271 100644
--- a/content/public/android/BUILD.gn
+++ b/content/public/android/BUILD.gn
@@ -56,10 +56,6 @@
     "//ui/android:ui_java",
   ]
 
-  if (enable_webvr) {
-    deps += [ "//device/vr:java" ]
-  }
-
   srcjar_deps = [
     ":common_aidl",
     ":content_public_android_java_enums_srcjar",
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java
index 2e9157f..f3e2c6a 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsObserverProxy.java
@@ -232,11 +232,17 @@
 
     @Override
     @CalledByNative
-    public void mediaSessionStateChanged(
-            boolean isControllable, boolean isSuspended, MediaMetadata metadata) {
+    public void mediaSessionStateChanged(boolean isControllable, boolean isSuspended) {
         for (mObserversIterator.rewind(); mObserversIterator.hasNext();) {
-            mObserversIterator.next().mediaSessionStateChanged(
-                    isControllable, isSuspended, metadata);
+            mObserversIterator.next().mediaSessionStateChanged(isControllable, isSuspended);
+        }
+    }
+
+    @Override
+    @CalledByNative
+    public void mediaSessionMetadataChanged(MediaMetadata metadata) {
+        for (mObserversIterator.rewind(); mObserversIterator.hasNext();) {
+            mObserversIterator.next().mediaSessionMetadataChanged(metadata);
         }
     }
 
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java
index 85c8819e..0a42bb0 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContentsObserver.java
@@ -166,10 +166,14 @@
      * Called when the media session state changed.
      * @param isControllable if the session can be resumed or suspended.
      * @param isSuspended if the session currently suspended or not.
-     * @param metadata of the media session.
      */
-    public void mediaSessionStateChanged(
-            boolean isControllable, boolean isSuspended, MediaMetadata metadata) {}
+    public void mediaSessionStateChanged(boolean isControllable, boolean isSuspended) {}
+
+    /**
+     * Called when the media session metadata changed.
+     * @param metadata the new MediaMetadata after change.
+     */
+    public void mediaSessionMetadataChanged(MediaMetadata metadata) {}
 
     /**
      * Stop observing the web contents and clean up associated references.
diff --git a/content/public/browser/browser_child_process_host.h b/content/public/browser/browser_child_process_host.h
index e0f2d49e..e8506d8 100644
--- a/content/public/browser/browser_child_process_host.h
+++ b/content/public/browser/browser_child_process_host.h
@@ -6,6 +6,7 @@
 #define CONTENT_PUBLIC_BROWSER_BROWSER_CHILD_PROCESS_HOST_H_
 
 #include "base/environment.h"
+#include "base/memory/shared_memory.h"
 #include "base/process/kill.h"
 #include "base/process/process_handle.h"
 #include "base/strings/string16.h"
@@ -62,11 +63,13 @@
   ~BrowserChildProcessHost() override {}
 
   // Derived classes call this to launch the child process asynchronously.
-  // Takes ownership of |cmd_line| and |delegate|.
-  virtual void Launch(
-      SandboxedProcessLauncherDelegate* delegate,
-      base::CommandLine* cmd_line,
-      bool terminate_on_shutdown) = 0;
+  // Takes ownership of |cmd_line| and |delegate|. Takes in |field_trial_state|
+  // to explicitly pass its handle to be inherited on Windows to the child
+  // process via the command line.
+  virtual void Launch(SandboxedProcessLauncherDelegate* delegate,
+                      base::CommandLine* cmd_line,
+                      const base::SharedMemory* field_trial_state,
+                      bool terminate_on_shutdown) = 0;
 
   virtual const ChildProcessData& GetData() const = 0;
 
diff --git a/content/public/browser/notification_event_dispatcher.h b/content/public/browser/notification_event_dispatcher.h
index 1c2289d..ce2261b3 100644
--- a/content/public/browser/notification_event_dispatcher.h
+++ b/content/public/browser/notification_event_dispatcher.h
@@ -13,6 +13,10 @@
 
 class GURL;
 
+namespace base {
+class NullableString16;
+}
+
 namespace content {
 
 class BrowserContext;
@@ -36,6 +40,7 @@
       const std::string& notification_id,
       const GURL& origin,
       int action_index,
+      const base::NullableString16& reply,
       const NotificationDispatchCompleteCallback&
           dispatch_complete_callback) = 0;
 
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h
index ea27d243..704c509c 100644
--- a/content/public/browser/web_contents_observer.h
+++ b/content/public/browser/web_contents_observer.h
@@ -469,9 +469,12 @@
   virtual void MediaStoppedPlaying(const MediaPlayerId& id) {}
 
   // Invoked when media session has changed its state.
-  virtual void MediaSessionStateChanged(
-      bool is_controllable,
-      bool is_suspended,
+  virtual void MediaSessionStateChanged(bool is_controllable,
+                                        bool is_suspended) {}
+
+  // Invoked when media session metadata has changed. When |metadata| is
+  // nullopt, it means the metadata is being unset.
+  virtual void MediaSessionMetadataChanged(
       const base::Optional<MediaMetadata>& metadata) {}
 
   // Invoked when the renderer process changes the page scale factor.
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index 41c636f0..95d7544 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -530,6 +530,12 @@
 // numbers.
 const char kExplicitlyAllowedPorts[]        = "explicitly-allowed-ports";
 
+// Handle to the shared memory segment containing field trial state that is to
+// be shared between processes. The argument to this switch is the handle id
+// (pointer on Windows) as a string, followed by a comma, then the size of the
+// shared memory segment as a string.
+const char kFieldTrialHandle[] = "field-trial-handle";
+
 // Always use the Skia GPU backend for drawing layer tiles. Only valid with GPU
 // accelerated compositing + impl-side painting. Overrides the
 // kEnableGpuRasterization flag.
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index dd1bc05..d6f16f47 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -162,6 +162,7 @@
 CONTENT_EXPORT extern const char kEnableWebVR[];
 CONTENT_EXPORT extern const char kEnableZeroCopy[];
 CONTENT_EXPORT extern const char kExplicitlyAllowedPorts[];
+CONTENT_EXPORT extern const char kFieldTrialHandle[];
 CONTENT_EXPORT extern const char kForceDisplayList2dCanvas[];
 CONTENT_EXPORT extern const char kForceGpuRasterization[];
 CONTENT_EXPORT extern const char kForceOverlayFullscreenVideo[];
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 5e8bcb3..06cd0b3f 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -1645,63 +1645,34 @@
                                              const GURL& url)
     : WebContentsObserver(web_contents),
       url_(url),
-      navigation_paused_in_will_start_(false),
-      navigation_paused_in_will_process_response_(false),
       handle_(nullptr),
-      handled_navigation_(false),
+      navigation_paused_(false),
+      current_state_(NavigationState::INITIAL),
+      desired_state_(NavigationState::STARTED),
       weak_factory_(this) {}
 
 TestNavigationManager::~TestNavigationManager() {
-  ResumeNavigation();
+  if (navigation_paused_)
+    handle_->Resume();
 }
 
-bool TestNavigationManager::WaitForWillStartRequest() {
-  DCHECK(!did_finish_loop_runner_);
-  if (!handle_ && handled_navigation_)
-    return true;
-  if (navigation_paused_in_will_start_)
-    return true;
-  DCHECK(!navigation_paused_in_will_process_response_);
-  will_start_loop_runner_ = new MessageLoopRunner();
-  will_start_loop_runner_->Run();
-  will_start_loop_runner_ = nullptr;
-
-  // This will only be false if DidFinishNavigation is called before
-  // OnWillStartRequest, which could occur if a throttle cancels the navigation
-  // before the TestNavigationManagerThrottle's method is called.
-  return !handled_navigation_;
+bool TestNavigationManager::WaitForRequestStart() {
+  // This is the default desired state. In PlzNavigate, a browser-initiated
+  // navigation can reach this state synchronously, so the TestNavigationManager
+  // is set to always pause navigations at WillStartRequest. This ensures the
+  // user can always call WaitForWillStartRequest.
+  DCHECK(desired_state_ == NavigationState::STARTED);
+  return WaitForDesiredState();
 }
 
-bool TestNavigationManager::WaitForWillProcessResponse() {
-  DCHECK(!did_finish_loop_runner_);
-  if (!handle_ && handled_navigation_)
-    return true;
-  if (navigation_paused_in_will_process_response_)
-    return true;
-  // Ensure the navigation is resumed if the manager paused it previously.
-  if (navigation_paused_in_will_start_)
-    ResumeNavigation();
-  will_process_response_loop_runner_ = new MessageLoopRunner();
-  will_process_response_loop_runner_->Run();
-  will_process_response_loop_runner_ = nullptr;
-
-  // This will only be false if DidFinishNavigation is called before
-  // OnWillProcessResponse.
-  return !handled_navigation_;
+bool TestNavigationManager::WaitForResponse() {
+  desired_state_ = NavigationState::RESPONSE;
+  return WaitForDesiredState();
 }
 
 void TestNavigationManager::WaitForNavigationFinished() {
-  DCHECK(!will_start_loop_runner_);
-  if (!handle_ && handled_navigation_)
-    return;
-  // Ensure the navigation is resumed if the manager paused it previously.
-  if (navigation_paused_in_will_start_ ||
-      navigation_paused_in_will_process_response_) {
-    ResumeNavigation();
-  }
-  did_finish_loop_runner_ = new MessageLoopRunner();
-  did_finish_loop_runner_->Run();
-  did_finish_loop_runner_ = nullptr;
+  desired_state_ = NavigationState::FINISHED;
+  WaitForDesiredState();
 }
 
 void TestNavigationManager::DidStartNavigation(NavigationHandle* handle) {
@@ -1721,58 +1692,64 @@
 void TestNavigationManager::DidFinishNavigation(NavigationHandle* handle) {
   if (handle != handle_)
     return;
+  current_state_ = NavigationState::FINISHED;
+  navigation_paused_ = false;
   handle_ = nullptr;
-  handled_navigation_ = true;
-  navigation_paused_in_will_start_ = false;
-  navigation_paused_in_will_process_response_ = false;
-
-  // Resume any clients that are waiting for the end of the navigation. Note
-  // that |will_start_loop_runner_| can be running if the navigation was
-  // cancelled while it was deferred.
-  if (did_finish_loop_runner_)
-    did_finish_loop_runner_->Quit();
-  if (will_start_loop_runner_)
-    will_start_loop_runner_->Quit();
-  if (will_process_response_loop_runner_)
-    will_process_response_loop_runner_->Quit();
+  OnNavigationStateChanged();
 }
 
 void TestNavigationManager::OnWillStartRequest() {
-  navigation_paused_in_will_start_ = true;
-  if (will_start_loop_runner_)
-    will_start_loop_runner_->Quit();
-
-  // If waiting for further events in the navigation, resume the navigation.
-  if (did_finish_loop_runner_ || will_process_response_loop_runner_)
-    ResumeNavigation();
+  current_state_ = NavigationState::STARTED;
+  navigation_paused_ = true;
+  OnNavigationStateChanged();
 }
 
 void TestNavigationManager::OnWillProcessResponse() {
-  navigation_paused_in_will_process_response_ = true;
-  DCHECK(!will_start_loop_runner_);
-  if (will_process_response_loop_runner_)
-    will_process_response_loop_runner_->Quit();
-
-  // If waiting for further events in the navigation, resume the navigation.
-  if (did_finish_loop_runner_)
-    ResumeNavigation();
+  current_state_ = NavigationState::RESPONSE;
+  navigation_paused_ = true;
+  OnNavigationStateChanged();
 }
 
-void TestNavigationManager::ResumeNavigation() {
-  if (!(navigation_paused_in_will_start_ ||
-        navigation_paused_in_will_process_response_) ||
-      !handle_) {
+bool TestNavigationManager::WaitForDesiredState() {
+  // If the desired state has laready been reached, just return.
+  if (current_state_ == desired_state_)
+    return true;
+
+  // Resume the navigation if it was paused.
+  if (navigation_paused_)
+     handle_->Resume();
+
+  // Wait for the desired state if needed.
+  if (current_state_ < desired_state_) {
+    DCHECK(!loop_runner_);
+    loop_runner_ = new MessageLoopRunner();
+    loop_runner_->Run();
+    loop_runner_ = nullptr;
+  }
+
+  // Return false if the navigation did not reach the state specified by the
+  // user.
+  return current_state_ == desired_state_;
+}
+
+void TestNavigationManager::OnNavigationStateChanged() {
+  // If the state the user was waiting for has been reached, exit the message
+  // loop.
+  if (current_state_ >= desired_state_) {
+    if (loop_runner_)
+      loop_runner_->Quit();
     return;
   }
-  navigation_paused_in_will_start_ = false;
-  navigation_paused_in_will_process_response_ = false;
-  handle_->Resume();
+
+  // Otherwise, the navigation should be resumed if it was previously paused.
+  if (navigation_paused_)
+    handle_->Resume();
 }
 
 bool TestNavigationManager::ShouldMonitorNavigation(NavigationHandle* handle) {
   if (handle_ || handle->GetURL() != url_)
     return false;
-  if (handled_navigation_)
+  if (current_state_ != NavigationState::INITIAL)
     return false;
   return true;
 }
diff --git a/content/public/test/browser_test_utils.h b/content/public/test/browser_test_utils.h
index 4d02c44c..0429a1be 100644
--- a/content/public/test/browser_test_utils.h
+++ b/content/public/test/browser_test_utils.h
@@ -612,11 +612,11 @@
 
   // Waits until the navigation request is ready to be sent to the network
   // stack. Returns false if the request was aborted before starting.
-  WARN_UNUSED_RESULT bool WaitForWillStartRequest();
+  WARN_UNUSED_RESULT bool WaitForRequestStart();
 
   // Waits until the navigation response has been sent received. Returns false
   // if the request was aborted before getting a response.
-  WARN_UNUSED_RESULT bool WaitForWillProcessResponse();
+  WARN_UNUSED_RESULT bool WaitForResponse();
 
   // Waits until the navigation has been finished. Will automatically resume
   // navigations paused before this point.
@@ -628,6 +628,13 @@
   virtual bool ShouldMonitorNavigation(NavigationHandle* handle);
 
  private:
+  enum class NavigationState {
+    INITIAL = 0,
+    STARTED = 1,
+    RESPONSE = 2,
+    FINISHED = 3,
+  };
+
   // WebContentsObserver:
   void DidStartNavigation(NavigationHandle* handle) override;
   void DidFinishNavigation(NavigationHandle* handle) override;
@@ -640,17 +647,21 @@
   // WillProcessResponse.
   void OnWillProcessResponse();
 
-  // Resumes the navigation.
-  void ResumeNavigation();
+  // Waits for the desired state. Returns false if the desired state cannot be
+  // reached (eg the navigation finishes before reaching this state).
+  bool WaitForDesiredState();
+
+  // Called when the state of the navigation has changed. This will either stop
+  // the message loop if the state specified by the user has been reached, or
+  // resume the navigation if it hasn't been reached yet.
+  void OnNavigationStateChanged();
 
   const GURL url_;
-  bool navigation_paused_in_will_start_;
-  bool navigation_paused_in_will_process_response_;
   NavigationHandle* handle_;
-  bool handled_navigation_;
-  scoped_refptr<MessageLoopRunner> will_start_loop_runner_;
-  scoped_refptr<MessageLoopRunner> will_process_response_loop_runner_;
-  scoped_refptr<MessageLoopRunner> did_finish_loop_runner_;
+  bool navigation_paused_;
+  NavigationState current_state_;
+  NavigationState desired_state_;
+  scoped_refptr<MessageLoopRunner> loop_runner_;
 
   base::WeakPtrFactory<TestNavigationManager> weak_factory_;
 
diff --git a/content/public/test/mock_render_thread.cc b/content/public/test/mock_render_thread.cc
index f28f88f..e93d645fb 100644
--- a/content/public/test/mock_render_thread.cc
+++ b/content/public/test/mock_render_thread.cc
@@ -269,10 +269,8 @@
 }
 
 bool MockRenderThread::OnControlMessageReceived(const IPC::Message& msg) {
-  base::ObserverListBase<RenderThreadObserver>::Iterator it(&observers_);
-  RenderThreadObserver* observer;
-  while ((observer = it.GetNext()) != NULL) {
-    if (observer->OnControlMessageReceived(msg))
+  for (auto& observer : observers_) {
+    if (observer.OnControlMessageReceived(msg))
       return true;
   }
   return OnMessageReceived(msg);
diff --git a/content/renderer/pepper/event_conversion.cc b/content/renderer/pepper/event_conversion.cc
index 14cd388..d21f0cf 100644
--- a/content/renderer/pepper/event_conversion.cc
+++ b/content/renderer/pepper/event_conversion.cc
@@ -99,18 +99,18 @@
 
 PP_InputEvent_Type ConvertEventTypes(const WebInputEvent& event) {
   if (IsStylusEvent(event)) {
+    const WebMouseEvent& mouse_event = static_cast<const WebMouseEvent&>(event);
+    if (mouse_event.button != blink::WebMouseEvent::Button::Left &&
+        !(mouse_event.modifiers & blink::WebInputEvent::LeftButtonDown))
+      return PP_INPUTEVENT_TYPE_UNDEFINED;
+
     switch (event.type) {
       case WebInputEvent::MouseDown:
         return PP_INPUTEVENT_TYPE_TOUCHSTART;
       case WebInputEvent::MouseUp:
         return PP_INPUTEVENT_TYPE_TOUCHEND;
-      case WebInputEvent::MouseMove: {
-        const WebMouseEvent& mouse_event =
-            static_cast<const WebMouseEvent&>(event);
-        return (mouse_event.modifiers & blink::WebInputEvent::LeftButtonDown)
-                   ? PP_INPUTEVENT_TYPE_TOUCHMOVE
-                   : PP_INPUTEVENT_TYPE_UNDEFINED;
-      }
+      case WebInputEvent::MouseMove:
+        return PP_INPUTEVENT_TYPE_TOUCHMOVE;
       default:
         return PP_INPUTEVENT_TYPE_UNDEFINED;
     }
@@ -225,23 +225,21 @@
 
   InputEventData result = GetEventWithCommonFieldsAndType(event);
   result.event_modifiers = ConvertEventModifiers(event.modifiers);
+  if (result.event_type == PP_INPUTEVENT_TYPE_UNDEFINED)
+    return;
 
-  if (mouse_event.modifiers & blink::WebInputEvent::LeftButtonDown &&
-      (mouse_event.type == WebInputEvent::MouseDown ||
-       mouse_event.type == WebInputEvent::MouseMove)) {
-    PP_TouchPoint touch_point;
-    touch_point.id = 0;
-    touch_point.position.x = mouse_event.x;
-    touch_point.position.y = mouse_event.y;
-    touch_point.pressure = mouse_event.force;
+  PP_TouchPoint touch_point;
+  touch_point.id = 0;
+  touch_point.position.x = mouse_event.x;
+  touch_point.position.y = mouse_event.y;
+  touch_point.pressure = mouse_event.force;
 
+  result.changed_touches.push_back(touch_point);
+  result.target_touches.push_back(touch_point);
+  if (result.event_type != PP_INPUTEVENT_TYPE_TOUCHEND)
     result.touches.push_back(touch_point);
-    result.changed_touches.push_back(touch_point);
-    result.target_touches.push_back(touch_point);
-  }
 
-  if (result.event_type != PP_INPUTEVENT_TYPE_UNDEFINED)
-    result_events->push_back(result);
+  result_events->push_back(result);
 }
 
 void AppendMouseEvent(const WebInputEvent& event,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index b13d2ca..348f57d 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -1506,10 +1506,8 @@
   if (!frame_->document().isNull())
     GetContentClient()->SetActiveURL(frame_->document().url());
 
-  base::ObserverListBase<RenderFrameObserver>::Iterator it(&observers_);
-  RenderFrameObserver* observer;
-  while ((observer = it.GetNext()) != NULL) {
-    if (observer->OnMessageReceived(msg))
+  for (auto& observer : observers_) {
+    if (observer.OnMessageReceived(msg))
       return true;
   }
 
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 2a737e2..9e7bf65 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1719,10 +1719,8 @@
 }
 
 bool RenderThreadImpl::OnControlMessageReceived(const IPC::Message& msg) {
-  base::ObserverListBase<RenderThreadObserver>::Iterator it(&observers_);
-  RenderThreadObserver* observer;
-  while ((observer = it.GetNext()) != nullptr) {
-    if (observer->OnControlMessageReceived(msg))
+  for (auto& observer : observers_) {
+    if (observer.OnControlMessageReceived(msg))
       return true;
   }
 
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index 26b6bc91..2cd7b96 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1304,11 +1304,10 @@
   if (is_swapped_out_ && IPC_MESSAGE_ID_CLASS(message.type()) == InputMsgStart)
     return false;
 
-  base::ObserverListBase<RenderViewObserver>::Iterator it(&observers_);
-  RenderViewObserver* observer;
-  while ((observer = it.GetNext()) != NULL)
-    if (observer->OnMessageReceived(message))
+  for (auto& observer : observers_) {
+    if (observer.OnMessageReceived(message))
       return true;
+  }
 
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(RenderViewImpl, message)
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index bcbdffbd..0a9e9d1 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -35,12 +35,12 @@
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
 #include "third_party/WebKit/public/platform/WebDisplayMode.h"
+#include "third_party/WebKit/public/platform/WebInputEvent.h"
 #include "third_party/WebKit/public/platform/WebRect.h"
+#include "third_party/WebKit/public/platform/WebTextInputInfo.h"
 #include "third_party/WebKit/public/web/WebCompositionUnderline.h"
-#include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "third_party/WebKit/public/web/WebPopupType.h"
 #include "third_party/WebKit/public/web/WebTextDirection.h"
-#include "third_party/WebKit/public/web/WebTextInputInfo.h"
 #include "third_party/WebKit/public/web/WebTouchAction.h"
 #include "third_party/WebKit/public/web/WebWidget.h"
 #include "third_party/WebKit/public/web/WebWidgetClient.h"
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 210bd3e..c840404 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -914,12 +914,14 @@
     int request_id,
     const std::string& notification_id,
     const PlatformNotificationData& notification_data,
-    int action_index) {
+    int action_index,
+    const base::NullableString16& reply) {
   TRACE_EVENT0("ServiceWorker",
                "ServiceWorkerContextClient::OnNotificationClickEvent");
   proxy_->dispatchNotificationClickEvent(
       request_id, blink::WebString::fromUTF8(notification_id),
-      ToWebNotificationData(notification_data), action_index);
+      ToWebNotificationData(notification_data), action_index,
+      blink::WebString(reply));
 }
 
 void ServiceWorkerContextClient::OnNotificationCloseEvent(
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index dee3309..b425843 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -225,7 +225,8 @@
       int request_id,
       const std::string& notification_id,
       const PlatformNotificationData& notification_data,
-      int action_index);
+      int action_index,
+      const base::NullableString16& reply);
   void OnPushEvent(int request_id, const PushEventPayload& payload);
   void OnNotificationCloseEvent(
       int request_id,
diff --git a/content/shell/browser/layout_test/layout_test_notification_manager.cc b/content/shell/browser/layout_test/layout_test_notification_manager.cc
index 1fd856e1..81ec335 100644
--- a/content/shell/browser/layout_test/layout_test_notification_manager.cc
+++ b/content/shell/browser/layout_test/layout_test_notification_manager.cc
@@ -5,6 +5,7 @@
 #include "content/shell/browser/layout_test/layout_test_notification_manager.h"
 
 #include "base/guid.h"
+#include "base/strings/nullable_string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/desktop_notification_delegate.h"
@@ -111,9 +112,10 @@
 
     const PersistentNotification& notification = persistent_iter->second;
     content::NotificationEventDispatcher::GetInstance()
-        ->DispatchNotificationClickEvent(
-            notification.browser_context, notification_id, notification.origin,
-            action_index, base::Bind(&OnEventDispatchComplete));
+        ->DispatchNotificationClickEvent(notification.browser_context,
+                                         notification_id, notification.origin,
+                                         action_index, base::NullableString16(),
+                                         base::Bind(&OnEventDispatchComplete));
   } else if (non_persistent_iter != non_persistent_notifications_.end()) {
     DCHECK_EQ(action_index, -1) << "Action buttons are only supported for "
                                    "persistent notifications";
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn
index 860b4881..317c898 100644
--- a/device/vr/BUILD.gn
+++ b/device/vr/BUILD.gn
@@ -45,7 +45,6 @@
     ]
 
     deps += [
-      ":jni_headers",
       "//device/gamepad",
       "//third_party/WebKit/public:blink_headers",
       "//third_party/gvr-android-sdk:libgvr",
@@ -79,22 +78,3 @@
 
   use_new_wrapper_types = false
 }
-
-if (is_android) {
-  java_sources_needing_jni =
-      [ "android/java/src/org/chromium/device/vr/GvrDeviceProvider.java" ]
-
-  generate_jni("jni_headers") {
-    sources = java_sources_needing_jni
-    jni_package = "vr"
-  }
-
-  android_library("java") {
-    java_files = java_sources_needing_jni
-    deps = [
-      "//base:base_java",
-      "//third_party/android_protobuf:protobuf_nano_javalib",
-      "//third_party/gvr-android-sdk:gvr_common_java",
-    ]
-  }
-}
diff --git a/device/vr/android/gvr/gvr_delegate.h b/device/vr/android/gvr/gvr_delegate.h
index 18be9b8..d7b4297 100644
--- a/device/vr/android/gvr/gvr_delegate.h
+++ b/device/vr/android/gvr/gvr_delegate.h
@@ -15,18 +15,6 @@
 
 namespace device {
 
-class DEVICE_VR_EXPORT GvrDelegateProvider {
- public:
-  static void SetInstance(GvrDelegateProvider* delegate_provider);
-  static GvrDelegateProvider* GetInstance();
-
-  virtual bool RequestWebVRPresent(GvrDeviceProvider* device_provider) = 0;
-  virtual void ExitWebVRPresent() = 0;
-
- private:
-  static GvrDelegateProvider* delegate_provider_;
-};
-
 class DEVICE_VR_EXPORT GvrDelegate {
  public:
   virtual void SetWebVRSecureOrigin(bool secure_origin) = 0;
@@ -41,6 +29,20 @@
   virtual gvr::GvrApi* gvr_api() = 0;
 };
 
+class DEVICE_VR_EXPORT GvrDelegateProvider {
+ public:
+  static void SetInstance(GvrDelegateProvider* delegate_provider);
+  static GvrDelegateProvider* GetInstance();
+
+  virtual bool RequestWebVRPresent(GvrDeviceProvider* device_provider) = 0;
+  virtual void ExitWebVRPresent() = 0;
+  virtual GvrDelegate* GetNonPresentingDelegate() = 0;
+  virtual void DestroyNonPresentingDelegate() = 0;
+
+ private:
+  static GvrDelegateProvider* delegate_provider_;
+};
+
 }  // namespace device
 
 #endif  // DEVICE_VR_ANDROID_GVR_DELEGATE_H
diff --git a/device/vr/android/gvr/gvr_device_provider.cc b/device/vr/android/gvr/gvr_device_provider.cc
index 1025ca4..252aa117 100644
--- a/device/vr/android/gvr/gvr_device_provider.cc
+++ b/device/vr/android/gvr/gvr_device_provider.cc
@@ -14,7 +14,6 @@
 #include "device/vr/android/gvr/gvr_device.h"
 #include "device/vr/android/gvr/gvr_gamepad_data_fetcher.h"
 #include "device/vr/vr_device_manager.h"
-#include "jni/GvrDeviceProvider_jni.h"
 #include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr.h"
 #include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_controller.h"
 #include "third_party/gvr-android-sdk/src/ndk/include/vr/gvr/capi/include/gvr_types.h"
@@ -24,62 +23,16 @@
 
 namespace device {
 
-// A temporary delegate till a VrShell instance becomes available.
-class GvrNonPresentingDelegate : public GvrDelegate {
- public:
-  GvrNonPresentingDelegate() { Initialize(); }
-
-  virtual ~GvrNonPresentingDelegate() { Shutdown(); }
-
-  void Initialize() {
-    if (j_device_.is_null()) {
-      JNIEnv* env = AttachCurrentThread();
-
-      j_device_.Reset(
-          Java_GvrDeviceProvider_create(env, GetApplicationContext()));
-      jlong context =
-          Java_GvrDeviceProvider_getNativeContext(env, j_device_.obj());
-
-      if (!context)
-        return;
-
-      gvr_api_ =
-          gvr::GvrApi::WrapNonOwned(reinterpret_cast<gvr_context*>(context));
-    }
-  }
-
-  void Shutdown() {
-    if (!j_device_.is_null()) {
-      gvr_api_ = nullptr;
-      JNIEnv* env = AttachCurrentThread();
-      Java_GvrDeviceProvider_shutdown(env, j_device_.obj());
-      j_device_ = nullptr;
-    }
-  }
-
-  // GvrDelegate implementation
-  void SetWebVRSecureOrigin(bool secure_origin) override {}
-  void SubmitWebVRFrame() override {}
-  void UpdateWebVRTextureBounds(int eye,
-                                float left,
-                                float top,
-                                float width,
-                                float height) override {}
-  void SetGvrPoseForWebVr(const gvr::Mat4f& pose,
-                          uint32_t pose_index) override {}
-
-  gvr::GvrApi* gvr_api() override { return gvr_api_.get(); }
-
- private:
-  base::android::ScopedJavaGlobalRef<jobject> j_device_;
-  std::unique_ptr<gvr::GvrApi> gvr_api_;
-};
-
 GvrDeviceProvider::GvrDeviceProvider()
     : VRDeviceProvider(),
       main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
 
 GvrDeviceProvider::~GvrDeviceProvider() {
+  device::GvrDelegateProvider* delegate_provider =
+      device::GvrDelegateProvider::GetInstance();
+  if (delegate_provider)
+    delegate_provider->DestroyNonPresentingDelegate();
+
   ExitPresent();
 }
 
@@ -96,17 +49,25 @@
 }
 
 void GvrDeviceProvider::Initialize() {
+  device::GvrDelegateProvider* delegate_provider =
+      device::GvrDelegateProvider::GetInstance();
+  if (!delegate_provider)
+    return;
+
   if (!vr_device_) {
-    vr_device_.reset(new GvrDevice(this, nullptr));
+    vr_device_.reset(
+        new GvrDevice(this, delegate_provider->GetNonPresentingDelegate()));
     client_->OnDeviceConnectionStatusChanged(vr_device_.get(), true);
   }
 }
 
 bool GvrDeviceProvider::RequestPresent() {
-  GvrDelegateProvider* delegate_provider = GvrDelegateProvider::GetInstance();
+  device::GvrDelegateProvider* delegate_provider =
+      device::GvrDelegateProvider::GetInstance();
   if (!delegate_provider)
     return false;
 
+  // RequestWebVRPresent is async as a render thread may be created.
   return delegate_provider->RequestWebVRPresent(this);
 }
 
@@ -116,14 +77,17 @@
   if (!vr_device_)
     return;
 
-  vr_device_->SetDelegate(nullptr);
+  device::GvrDelegateProvider* delegate_provider =
+      device::GvrDelegateProvider::GetInstance();
+  if (!delegate_provider)
+    return;
+
+  vr_device_->SetDelegate(delegate_provider->GetNonPresentingDelegate());
 
   GamepadDataFetcherManager::GetInstance()->RemoveSourceFactory(
       GAMEPAD_SOURCE_GVR);
 
-  GvrDelegateProvider* delegate_provider = GvrDelegateProvider::GetInstance();
-  if (delegate_provider)
-    delegate_provider->ExitWebVRPresent();
+  delegate_provider->ExitWebVRPresent();
 
   if (client_)
     client_->OnPresentEnded(vr_device_.get());
@@ -137,12 +101,10 @@
 }
 
 void GvrDeviceProvider::OnGvrDelegateRemoved() {
+  DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
   if (!vr_device_)
     return;
-
-  main_thread_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&GvrDeviceProvider::ExitPresent, base::Unretained(this)));
+  ExitPresent();
 }
 
 void GvrDeviceProvider::GvrDelegateReady(GvrDelegate* delegate) {
diff --git a/device/vr/android/gvr/gvr_device_provider.h b/device/vr/android/gvr/gvr_device_provider.h
index bb64966..23f8cb0 100644
--- a/device/vr/android/gvr/gvr_device_provider.h
+++ b/device/vr/android/gvr/gvr_device_provider.h
@@ -18,7 +18,6 @@
 
 class GvrDelegate;
 class GvrDevice;
-class GvrNonPresentingDelegate;
 
 class DEVICE_VR_EXPORT GvrDeviceProvider : public VRDeviceProvider {
  public:
diff --git a/device/vr/android/java/src/org/chromium/device/vr/GvrDeviceProvider.java b/device/vr/android/java/src/org/chromium/device/vr/GvrDeviceProvider.java
deleted file mode 100644
index ba4f44c..0000000
--- a/device/vr/android/java/src/org/chromium/device/vr/GvrDeviceProvider.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.device.vr;
-
-import android.content.Context;
-import android.os.StrictMode;
-
-import com.google.vr.ndk.base.GvrLayout;
-
-import org.chromium.base.Log;
-import org.chromium.base.annotations.CalledByNative;
-import org.chromium.base.annotations.JNINamespace;
-
-/**
- * This is the implementation of the C++ counterpart GvrDeviceProvider.
- */
-@JNINamespace("device")
-class GvrDeviceProvider {
-    private static final String TAG = "GvrDeviceProvider";
-    private final GvrLayout mLayout;
-
-    private GvrDeviceProvider(Context context) {
-        mLayout = new GvrLayout(context);
-    }
-
-    @CalledByNative
-    private static GvrDeviceProvider create(Context context) {
-        return new GvrDeviceProvider(context);
-    }
-
-    @CalledByNative
-    private long getNativeContext() {
-        long nativeGvrContext = 0;
-
-        StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
-
-        try {
-            nativeGvrContext = mLayout.getGvrApi().getNativeGvrContext();
-        } catch (Exception ex) {
-            Log.e(TAG, "Unable to instantiate GvrApi", ex);
-            return 0;
-        } finally {
-            StrictMode.setThreadPolicy(oldPolicy);
-        }
-
-        return nativeGvrContext;
-    }
-
-    @CalledByNative
-    private void shutdown() {
-        mLayout.shutdown();
-    }
-}
diff --git a/extensions/browser/extension_navigation_throttle.cc b/extensions/browser/extension_navigation_throttle.cc
index 4e511a5f..68c0a92 100644
--- a/extensions/browser/extension_navigation_throttle.cc
+++ b/extensions/browser/extension_navigation_throttle.cc
@@ -4,18 +4,24 @@
 
 #include "extensions/browser/extension_navigation_throttle.h"
 
+#include "components/guest_view/browser/guest_view_base.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/common/browser_side_navigation_policy.h"
 #include "content/public/common/url_constants.h"
 #include "extensions/browser/extension_registry.h"
+#include "extensions/browser/guest_view/web_view/web_view_guest.h"
+#include "extensions/browser/url_request_util.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/extension_set.h"
 #include "extensions/common/manifest_handlers/web_accessible_resources_info.h"
+#include "extensions/common/manifest_handlers/webview_info.h"
 #include "extensions/common/permissions/api_permission.h"
 #include "extensions/common/permissions/permissions_data.h"
+#include "ui/base/page_transition_types.h"
 
 namespace extensions {
 
@@ -29,8 +35,9 @@
 ExtensionNavigationThrottle::WillStartRequest() {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   GURL url(navigation_handle()->GetURL());
-  ExtensionRegistry* registry = ExtensionRegistry::Get(
-      navigation_handle()->GetWebContents()->GetBrowserContext());
+  content::WebContents* web_contents = navigation_handle()->GetWebContents();
+  ExtensionRegistry* registry =
+      ExtensionRegistry::Get(web_contents->GetBrowserContext());
 
   if (navigation_handle()->IsInMainFrame()) {
     // Block top-level navigations to blob: or filesystem: URLs with extension
@@ -57,6 +64,36 @@
         return content::NavigationThrottle::CANCEL;
     }
 
+    if (content::IsBrowserSideNavigationEnabled() &&
+        url.scheme() == extensions::kExtensionScheme) {
+      // This logic is performed for PlzNavigate sub-resources and for
+      // non-PlzNavigate in
+      // extensions::url_request_util::AllowCrossRendererResourceLoad.
+      const Extension* extension =
+          registry->enabled_extensions().GetExtensionOrAppByURL(url);
+      guest_view::GuestViewBase* guest =
+          guest_view::GuestViewBase::FromWebContents(web_contents);
+      if (guest) {
+        std::string owner_extension_id = guest->owner_host();
+        const Extension* owner_extension =
+            registry->enabled_extensions().GetByID(owner_extension_id);
+
+        std::string partition_domain, partition_id;
+        bool in_memory;
+        std::string resource_path = url.path();
+        bool is_guest = WebViewGuest::GetGuestPartitionConfigForSite(
+            navigation_handle()->GetStartingSiteInstance()->GetSiteURL(),
+            &partition_domain, &partition_id, &in_memory);
+
+        bool allowed = true;
+        url_request_util::AllowCrossRendererResourceLoadHelper(
+            is_guest, extension, owner_extension, partition_id, resource_path,
+            navigation_handle()->GetPageTransition(), &allowed);
+        if (!allowed)
+          return content::NavigationThrottle::CANCEL;
+      }
+    }
+
     return content::NavigationThrottle::PROCEED;
   }
 
@@ -76,7 +113,7 @@
   // the ancestor chain, so find the current RenderFrameHost and use it to
   // traverse up to the main frame.
   content::RenderFrameHost* navigating_frame = nullptr;
-  for (auto* frame : navigation_handle()->GetWebContents()->GetAllFrames()) {
+  for (auto* frame : web_contents->GetAllFrames()) {
     if (frame->GetFrameTreeNodeId() ==
         navigation_handle()->GetFrameTreeNodeId()) {
       navigating_frame = frame;
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.cc b/extensions/browser/guest_view/web_view/web_view_guest.cc
index 692e490..645d9af 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.cc
+++ b/extensions/browser/guest_view/web_view/web_view_guest.cc
@@ -23,6 +23,7 @@
 #include "content/public/browser/child_process_security_policy.h"
 #include "content/public/browser/native_web_keyboard_event.h"
 #include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/notification_details.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/notification_source.h"
@@ -600,13 +601,12 @@
 
 void WebViewGuest::LoadAbort(bool is_top_level,
                              const GURL& url,
-                             int error_code,
-                             const std::string& error_type) {
+                             int error_code) {
   std::unique_ptr<base::DictionaryValue> args(new base::DictionaryValue());
   args->SetBoolean(guest_view::kIsTopLevel, is_top_level);
   args->SetString(guest_view::kUrl, url.possibly_invalid_spec());
   args->SetInteger(guest_view::kCode, error_code);
-  args->SetString(guest_view::kReason, error_type);
+  args->SetString(guest_view::kReason, net::ErrorToShortString(error_code));
   DispatchEventToView(base::MakeUnique<GuestViewEvent>(webview::kEventLoadAbort,
                                                        std::move(args)));
 }
@@ -806,11 +806,26 @@
 WebViewGuest::~WebViewGuest() {
 }
 
-void WebViewGuest::DidCommitProvisionalLoadForFrame(
-    content::RenderFrameHost* render_frame_host,
-    const GURL& url,
-    ui::PageTransition transition_type) {
-  if (!render_frame_host->GetParent()) {
+void WebViewGuest::DidFinishNavigation(
+    content::NavigationHandle* navigation_handle) {
+  if (navigation_handle->IsErrorPage() || !navigation_handle->HasCommitted()) {
+    // Suppress loadabort for "mailto" URLs.
+    // Also during destruction, owner_web_contents() is null so there's no point
+    // trying to send the event.
+    if (!navigation_handle->GetURL().SchemeIs(url::kMailToScheme) &&
+        owner_web_contents()) {
+      // If it's not an error page, the request was blocked by the webrequest
+      // API.
+      int error_code = navigation_handle->IsErrorPage()
+                           ? navigation_handle->GetNetErrorCode()
+                           : net::ERR_BLOCKED_BY_CLIENT;
+      LoadAbort(navigation_handle->IsInMainFrame(), navigation_handle->GetURL(),
+                error_code);
+    }
+    return;
+  }
+
+  if (navigation_handle->IsInMainFrame()) {
     // For LoadDataWithBaseURL loads, |url| contains the data URL, but the
     // virtual URL is needed in that case. So use WebContents::GetURL instead.
     src_ = web_contents()->GetURL();
@@ -822,7 +837,7 @@
   }
   std::unique_ptr<base::DictionaryValue> args(new base::DictionaryValue());
   args->SetString(guest_view::kUrl, src_.spec());
-  args->SetBoolean(guest_view::kIsTopLevel, !render_frame_host->GetParent());
+  args->SetBoolean(guest_view::kIsTopLevel, navigation_handle->IsInMainFrame());
   args->SetString(webview::kInternalBaseURLForDataURL,
                   web_contents()
                       ->GetController()
@@ -841,28 +856,11 @@
   find_helper_.CancelAllFindSessions();
 }
 
-void WebViewGuest::DidFailProvisionalLoad(
-    content::RenderFrameHost* render_frame_host,
-    const GURL& validated_url,
-    int error_code,
-    const base::string16& error_description,
-    bool was_ignored_by_handler) {
-  // Suppress loadabort for "mailto" URLs.
-  if (validated_url.SchemeIs(url::kMailToScheme))
-    return;
-
-  LoadAbort(!render_frame_host->GetParent(), validated_url, error_code,
-            net::ErrorToShortString(error_code));
-}
-
-void WebViewGuest::DidStartProvisionalLoadForFrame(
-    content::RenderFrameHost* render_frame_host,
-    const GURL& validated_url,
-    bool is_error_page,
-    bool is_iframe_srcdoc) {
+void WebViewGuest::DidStartNavigation(
+    content::NavigationHandle* navigation_handle) {
   std::unique_ptr<base::DictionaryValue> args(new base::DictionaryValue());
-  args->SetString(guest_view::kUrl, validated_url.spec());
-  args->SetBoolean(guest_view::kIsTopLevel, !render_frame_host->GetParent());
+  args->SetString(guest_view::kUrl, navigation_handle->GetURL().spec());
+  args->SetBoolean(guest_view::kIsTopLevel, navigation_handle->IsInMainFrame());
   DispatchEventToView(base::MakeUnique<GuestViewEvent>(webview::kEventLoadStart,
                                                        std::move(args)));
 }
@@ -1381,8 +1379,7 @@
     ui::PageTransition transition_type,
     bool force_navigation) {
   if (!url.is_valid()) {
-    LoadAbort(true /* is_top_level */, url, net::ERR_INVALID_URL,
-              net::ErrorToShortString(net::ERR_INVALID_URL));
+    LoadAbort(true /* is_top_level */, url, net::ERR_INVALID_URL);
     NavigateGuest(url::kAboutBlankURL, false /* force_navigation */);
     return;
   }
@@ -1397,8 +1394,7 @@
   // This will block the embedder trying to load unwanted schemes, e.g.
   // chrome://.
   if (scheme_is_blocked) {
-    LoadAbort(true /* is_top_level */, url, net::ERR_DISALLOWED_URL_SCHEME,
-              net::ErrorToShortString(net::ERR_DISALLOWED_URL_SCHEME));
+    LoadAbort(true /* is_top_level */, url, net::ERR_DISALLOWED_URL_SCHEME);
     NavigateGuest(url::kAboutBlankURL, false /* force_navigation */);
     return;
   }
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.h b/extensions/browser/guest_view/web_view/web_view_guest.h
index 9ae9a4c..9ed2fbb 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.h
+++ b/extensions/browser/guest_view/web_view/web_view_guest.h
@@ -255,20 +255,8 @@
       const content::WebContents* web_contents) const final;
 
   // WebContentsObserver implementation.
-  void DidCommitProvisionalLoadForFrame(
-      content::RenderFrameHost* render_frame_host,
-      const GURL& url,
-      ui::PageTransition transition_type) final;
-  void DidFailProvisionalLoad(content::RenderFrameHost* render_frame_host,
-                              const GURL& validated_url,
-                              int error_code,
-                              const base::string16& error_description,
-                              bool was_ignored_by_handler) final;
-  void DidStartProvisionalLoadForFrame(
-      content::RenderFrameHost* render_frame_host,
-      const GURL& validated_url,
-      bool is_error_page,
-      bool is_iframe_srcdoc) final;
+  void DidStartNavigation(content::NavigationHandle* navigation_handle) final;
+  void DidFinishNavigation(content::NavigationHandle* navigation_handle) final;
   void RenderProcessGone(base::TerminationStatus status) final;
   void UserAgentOverrideSet(const std::string& user_agent) final;
   void FrameNameChanged(content::RenderFrameHost* render_frame_host,
@@ -308,10 +296,7 @@
 
   // Notification that a load in the guest resulted in abort. Note that |url|
   // may be invalid.
-  void LoadAbort(bool is_top_level,
-                 const GURL& url,
-                 int error_code,
-                 const std::string& error_type);
+  void LoadAbort(bool is_top_level, const GURL& url, int error_code);
 
   // Creates a new guest window owned by this WebViewGuest.
   void CreateNewGuestWebViewWindow(const content::OpenURLParams& params);
diff --git a/extensions/browser/url_request_util.cc b/extensions/browser/url_request_util.cc
index 1e44115b..126f694 100644
--- a/extensions/browser/url_request_util.cc
+++ b/extensions/browser/url_request_util.cc
@@ -7,6 +7,7 @@
 #include <string>
 
 #include "content/public/browser/resource_request_info.h"
+#include "content/public/common/browser_side_navigation_policy.h"
 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h"
 #include "extensions/browser/info_map.h"
 #include "extensions/common/extension.h"
@@ -25,34 +26,31 @@
                                     bool* allowed) {
   const content::ResourceRequestInfo* info =
       content::ResourceRequestInfo::ForRequest(request);
-
-  // Extensions with webview: allow loading certain resources by guest renderers
-  // with privileged partition IDs as specified in owner's extension the
-  // manifest file.
-  std::string owner_extension_id;
-  int owner_process_id;
-  WebViewRendererState::GetInstance()->GetOwnerInfo(
-      info->GetChildID(), &owner_process_id, &owner_extension_id);
-  const Extension* owner_extension =
-      extension_info_map->extensions().GetByID(owner_extension_id);
-  std::string partition_id;
-  bool is_guest = WebViewRendererState::GetInstance()->GetPartitionID(
-      info->GetChildID(), &partition_id);
   std::string resource_path = request->url().path();
 
-  // |owner_extension == extension| needs to be checked because extension
-  // resources should only be accessible to WebViews owned by that extension.
-  if (is_guest && owner_extension == extension &&
-      WebviewInfo::IsResourceWebviewAccessible(extension, partition_id,
-                                               resource_path)) {
-    *allowed = true;
-    return true;
-  }
+  // PlzNavigate: this logic is performed for main frame requests in
+  // ExtensionNavigationThrottle::WillStartRequest.
+  if (info->GetChildID() != -1 ||
+      info->GetResourceType() != content::RESOURCE_TYPE_MAIN_FRAME ||
+      !content::IsBrowserSideNavigationEnabled()) {
+    // Extensions with webview: allow loading certain resources by guest
+    // renderers with privileged partition IDs as specified in owner's extension
+    // the manifest file.
+    std::string owner_extension_id;
+    int owner_process_id;
+    WebViewRendererState::GetInstance()->GetOwnerInfo(
+        info->GetChildID(), &owner_process_id, &owner_extension_id);
+    const Extension* owner_extension =
+        extension_info_map->extensions().GetByID(owner_extension_id);
+    std::string partition_id;
+    bool is_guest = WebViewRendererState::GetInstance()->GetPartitionID(
+        info->GetChildID(), &partition_id);
 
-  if (is_guest &&
-      !ui::PageTransitionIsWebTriggerable(info->GetPageTransition())) {
-    *allowed = false;
-    return true;
+    if (AllowCrossRendererResourceLoadHelper(
+            is_guest, extension, owner_extension, partition_id, resource_path,
+            info->GetPageTransition(), allowed)) {
+      return true;
+    }
   }
 
   // The following checks require that we have an actual extension object. If we
@@ -137,5 +135,29 @@
   return WebViewRendererState::GetInstance()->IsGuest(info->GetChildID());
 }
 
+bool AllowCrossRendererResourceLoadHelper(bool is_guest,
+                                          const Extension* extension,
+                                          const Extension* owner_extension,
+                                          const std::string& partition_id,
+                                          const std::string& resource_path,
+                                          ui::PageTransition page_transition,
+                                          bool* allowed) {
+  // |owner_extension == extension| needs to be checked because extension
+  // resources should only be accessible to WebViews owned by that extension.
+  if (is_guest && owner_extension == extension &&
+      WebviewInfo::IsResourceWebviewAccessible(extension, partition_id,
+                                               resource_path)) {
+    *allowed = true;
+    return true;
+  }
+
+  if (is_guest && !ui::PageTransitionIsWebTriggerable(page_transition)) {
+    *allowed = false;
+    return true;
+  }
+
+  return false;
+}
+
 }  // namespace url_request_util
 }  // namespace extensions
diff --git a/extensions/browser/url_request_util.h b/extensions/browser/url_request_util.h
index afa0edb..e39fd87 100644
--- a/extensions/browser/url_request_util.h
+++ b/extensions/browser/url_request_util.h
@@ -5,6 +5,10 @@
 #ifndef EXTENSIONS_BROWSER_URL_REQUEST_UTIL_H_
 #define EXTENSIONS_BROWSER_URL_REQUEST_UTIL_H_
 
+#include <string>
+
+#include "ui/base/page_transition_types.h"
+
 namespace net {
 class URLRequest;
 }
@@ -30,6 +34,19 @@
 // <webview>.
 bool IsWebViewRequest(const net::URLRequest* request);
 
+// Helper method that is called by both AllowCrossRendererResourceLoad and
+// ExtensionNavigationThrottle to share logic.
+// Sets allowed=true to allow a chrome-extension:// resource request coming from
+// renderer A to access a resource in an extension running in renderer B.
+// Returns false when it couldn't determine if the resource is allowed or not
+bool AllowCrossRendererResourceLoadHelper(bool is_guest,
+                                          const Extension* extension,
+                                          const Extension* owner_extension,
+                                          const std::string& partition_id,
+                                          const std::string& resource_path,
+                                          ui::PageTransition page_transition,
+                                          bool* allowed);
+
 }  // namespace url_request_util
 }  // namespace extensions
 
diff --git a/media/gpu/generic_v4l2_device.cc b/media/gpu/generic_v4l2_device.cc
index e98ea72ed..830d004 100644
--- a/media/gpu/generic_v4l2_device.cc
+++ b/media/gpu/generic_v4l2_device.cc
@@ -434,7 +434,7 @@
       break;
     case Type::kJpegDecoder:
       device_pattern = kJpegDecoderDevicePattern;
-      buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+      buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
       break;
   }
 
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index fd48067..47ba91e 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -3630,6 +3630,9 @@
         "test": "unit_tests"
       },
       {
+        "override_compile_targets": [
+          "android_webview_test_apk"
+        ],
         "override_isolate_target": "android_webview_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -3697,6 +3700,9 @@
         "test": "blimp_test_apk"
       },
       {
+        "override_compile_targets": [
+          "chrome_public_test_apk"
+        ],
         "override_isolate_target": "chrome_public_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -3729,6 +3735,9 @@
         "test": "chrome_public_test_apk"
       },
       {
+        "override_compile_targets": [
+          "chrome_sync_shell_test_apk"
+        ],
         "override_isolate_target": "chrome_sync_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
@@ -3761,6 +3770,9 @@
         "test": "chrome_sync_shell_test_apk"
       },
       {
+        "override_compile_targets": [
+          "content_shell_test_apk"
+        ],
         "override_isolate_target": "content_shell_test_apk",
         "swarming": {
           "can_use_on_swarming_builders": true,
diff --git a/testing/buildbot/chromium.perf.fyi.json b/testing/buildbot/chromium.perf.fyi.json
index 17b5648..a1e14c59 100644
--- a/testing/buildbot/chromium.perf.fyi.json
+++ b/testing/buildbot/chromium.perf.fyi.json
@@ -38,10 +38,16 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "id": "build187-b4"
+              "gpu": "8086:22b1",
+              "id": "build187-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             },
             {
-              "id": "build171-b4"
+              "gpu": "1002:9874",
+              "id": "build171-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             }
           ],
           "expiration": 14400
@@ -65,10 +71,16 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "id": "build187-b4"
+              "gpu": "8086:22b1",
+              "id": "build187-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             },
             {
-              "id": "build171-b4"
+              "gpu": "1002:9874",
+              "id": "build171-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             }
           ],
           "expiration": 14400
@@ -91,10 +103,16 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "id": "build187-b4"
+              "gpu": "8086:22b1",
+              "id": "build187-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             },
             {
-              "id": "build171-b4"
+              "gpu": "1002:9874",
+              "id": "build171-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             }
           ],
           "expiration": 14400
@@ -118,10 +136,16 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "id": "build187-b4"
+              "gpu": "8086:22b1",
+              "id": "build187-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             },
             {
-              "id": "build171-b4"
+              "gpu": "1002:9874",
+              "id": "build171-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             }
           ],
           "expiration": 14400
@@ -144,10 +168,16 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "id": "build187-b4"
+              "gpu": "8086:22b1",
+              "id": "build187-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             },
             {
-              "id": "build186-b4"
+              "gpu": "1002:9874",
+              "id": "build171-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             }
           ],
           "expiration": 14400
@@ -171,10 +201,16 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "id": "build187-b4"
+              "gpu": "8086:22b1",
+              "id": "build187-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             },
             {
-              "id": "build186-b4"
+              "gpu": "1002:9874",
+              "id": "build186-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             }
           ],
           "expiration": 14400
@@ -197,10 +233,16 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "id": "build187-b4"
+              "gpu": "8086:22b1",
+              "id": "build187-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             },
             {
-              "id": "build186-b4"
+              "gpu": "1002:9874",
+              "id": "build186-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             }
           ],
           "expiration": 14400
@@ -224,10 +266,16 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "id": "build187-b4"
+              "gpu": "8086:22b1",
+              "id": "build187-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             },
             {
-              "id": "build186-b4"
+              "gpu": "1002:9874",
+              "id": "build186-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             }
           ],
           "expiration": 14400
@@ -250,10 +298,16 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "id": "build187-b4"
+              "gpu": "8086:22b1",
+              "id": "build187-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             },
             {
-              "id": "build171-b4"
+              "gpu": "1002:9874",
+              "id": "build186-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             }
           ],
           "expiration": 14400
@@ -277,10 +331,16 @@
           "can_use_on_swarming_builders": true,
           "dimension_sets": [
             {
-              "id": "build187-b4"
+              "gpu": "8086:22b1",
+              "id": "build187-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             },
             {
-              "id": "build171-b4"
+              "gpu": "1002:9874",
+              "id": "build186-b4",
+              "os": "Windows-10-10586",
+              "pool": "Chrome-perf"
             }
           ],
           "expiration": 14400
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
index 5439906..96f7ed13 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -127,7 +127,7 @@
 crbug.com/648600 fast/overflow/overflow-height-float-not-removed-crash.html [ Failure ]
 crbug.com/648600 virtual/spv2/fast/overflow/overflow-height-float-not-removed-crash.html [ Failure ]
 
-# https://crbug.com/648608: Send the right cookies when loading a popup
+# https://crbug.com/648608: Properly set the initator of the navigation.
 crbug.com/648608 http/tests/cookies/same-site/popup-same-site-post.html [ Failure ]
 crbug.com/648608 http/tests/cookies/same-site/popup-same-site.html [ Failure ]
 
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index f4a6a8a..57605949 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1278,3 +1278,6 @@
 crbug.com/655458 imported/wpt/workers/semantics/structured-clone/shared.html [ Crash Timeout ]
 
 crbug.com/652187 [ Win7 Debug ] http/tests/inspector/network/network-disable-cache-preloads.php [ Failure ]
+
+crbug.com/653424 inspector/console/console-format.html [ NeedsManualRebaseline ]
+crbug.com/653424 inspector/console/console-log-side-effects.html [ NeedsManualRebaseline ]
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations
index cc61764b..edea6c0 100644
--- a/third_party/WebKit/LayoutTests/W3CImportExpectations
+++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -325,7 +325,7 @@
 # imported/wpt/webstorage [ Pass ]
 imported/wpt/webvtt [ Skip ]
 ## Owners: nhiroki@chromium.org
-# imported/wpt/workers [ Pass ]
+# imported/wpt/workers [ Skip ]
 
 # Exceptions for individual files that fail due to bugs in the
 # upstream tests that we shouldn't bother importing until they are
diff --git a/third_party/WebKit/LayoutTests/fast/events/popup-allowed-from-pointerup-exactly-once.html b/third_party/WebKit/LayoutTests/fast/events/popup-allowed-from-pointerup-exactly-once.html
new file mode 100644
index 0000000..07db5fe
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/events/popup-allowed-from-pointerup-exactly-once.html
@@ -0,0 +1,29 @@
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<p>
+    Test that only a single popup is allowed in response to a single
+    pointer up user action. The test passes if only one popup is created.
+</p>
+<button id="button">Tap Here</button>
+<div id="console"></div>
+<script>
+    document.getElementById('button').addEventListener('pointerup', pointer_popup);
+    function pointer_popup() {
+        assert_not_equals(window.open("about:blank", "window1"), null, "Popup didn't open in pointerup handler.");
+        assert_equals(window.open("about:blank", "window2"), null, "Popup should open only once in pointerup handler.");
+        done();
+    }
+
+    if (window.testRunner) {
+        testRunner.setPopupBlockingEnabled(true);
+        testRunner.setCloseRemainingWindowsWhenComplete(true);
+
+        if (window.eventSender) {
+            var button = document.getElementById("button");
+            eventSender.addTouchPoint(button.offsetLeft + button.offsetWidth / 2, button.offsetTop + button.offsetHeight / 2);
+            eventSender.touchStart();
+            eventSender.releaseTouchPoint(0);
+            eventSender.touchEnd();
+        }
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/layout/scroll-anchoring/anchor-inside-iframe.html b/third_party/WebKit/LayoutTests/fast/layout/scroll-anchoring/anchor-inside-iframe.html
new file mode 100644
index 0000000..9407562
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/layout/scroll-anchoring/anchor-inside-iframe.html
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<script src="../../../resources/run-after-layout-and-paint.js"></script>
+<script src="../../../resources/testharness.js"></script>
+<script src="../../../resources/testharnessreport.js"></script>
+<iframe width="700" height="500" srcdoc="
+  <!DOCTYPE html>
+  <style> body { height: 1000px } div { height: 100px } </style>
+  <div id='block1'>abc</div>
+  <div id='block2'>def</div>
+"></iframe>
+<script>
+  async_test((t) => {
+    var iframeWindow = document.querySelector("iframe").contentWindow;
+    iframeWindow.addEventListener("load", () => {
+      var block1 = iframeWindow.document.querySelector("#block1");
+      iframeWindow.scrollTo(0, 150);
+
+      runAfterLayoutAndPaint(() => {
+        block1.style.height = "200px";
+        assert_equals(iframeWindow.scrollY, 250);
+        t.done();
+      });
+    });
+  }, "Scroll anchoring in an iframe.");
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/webfont/crbug-655076-expected.txt b/third_party/WebKit/LayoutTests/http/tests/webfont/crbug-655076-expected.txt
new file mode 100644
index 0000000..5b3b4a79
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/webfont/crbug-655076-expected.txt
@@ -0,0 +1 @@
+testtest
diff --git a/third_party/WebKit/LayoutTests/http/tests/webfont/crbug-655076.html b/third_party/WebKit/LayoutTests/http/tests/webfont/crbug-655076.html
new file mode 100644
index 0000000..94fef68e3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/webfont/crbug-655076.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<style></style>
+<div id="container"></div>
+<script>
+// Regression test for https://crbug.com/655076. Test passes by not crashing in
+// debug build.
+
+if (window.testRunner) {
+  testRunner.dumpAsText();
+  testRunner.waitUntilDone();
+}
+
+let container = document.getElementById('container');
+let font = 'slow-ahem-loading.cgi?delay=5000';
+
+function makeSpan(family) {
+  document.styleSheets[0].insertRule(
+      '@font-face { font-family: ' + family + '; src: url(' + font + '); }', 0);
+  let span = document.createElement('span');
+  span.style.fontFamily = family;
+  span.textContent = 'test';
+  container.appendChild(span);
+}
+
+window.onload = () => {
+  makeSpan('ahem-1');
+  setTimeout(() => {
+    makeSpan('ahem-2');
+    testRunner.notifyDone();
+  }, 4000);
+};
+</script>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames-expected.txt
new file mode 100644
index 0000000..664dc9e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames-expected.txt
@@ -0,0 +1,125 @@
+
+{
+    "method": "DOM.setChildNodes",
+    "params": {
+        "parentId": 13,
+        "nodes": [
+            {
+                "nodeId": 14,
+                "nodeType": 1,
+                "nodeName": "DIV",
+                "localName": "div",
+                "nodeValue": "",
+                "childNodeCount": 1,
+                "children": [
+                    {
+                        "nodeId": 15,
+                        "nodeType": 1,
+                        "nodeName": "DIV",
+                        "localName": "div",
+                        "nodeValue": "",
+                        "childNodeCount": 1,
+                        "children": [
+                            {
+                                "nodeId": 16,
+                                "nodeType": 1,
+                                "nodeName": "DIV",
+                                "localName": "div",
+                                "nodeValue": "",
+                                "childNodeCount": 1,
+                                "children": [
+                                    {
+                                        "nodeId": 17,
+                                        "nodeType": 1,
+                                        "nodeName": "IFRAME",
+                                        "localName": "iframe",
+                                        "nodeValue": "",
+                                        "childNodeCount": 0,
+                                        "children": [],
+                                        "attributes": [
+                                            "src",
+                                            "resources/iframe.html"
+                                        ],
+                                        "frameId": "???",
+                                        "contentDocument": {
+                                            "nodeId": 18,
+                                            "nodeType": 9,
+                                            "nodeName": "#document",
+                                            "localName": "",
+                                            "nodeValue": "",
+                                            "childNodeCount": 1,
+                                            "children": [
+                                                {
+                                                    "nodeId": 19,
+                                                    "nodeType": 1,
+                                                    "nodeName": "HTML",
+                                                    "localName": "html",
+                                                    "nodeValue": "",
+                                                    "childNodeCount": 2,
+                                                    "children": [
+                                                        {
+                                                            "nodeId": 20,
+                                                            "nodeType": 1,
+                                                            "nodeName": "HEAD",
+                                                            "localName": "head",
+                                                            "nodeValue": "",
+                                                            "childNodeCount": 0,
+                                                            "children": [],
+                                                            "attributes": []
+                                                        },
+                                                        {
+                                                            "nodeId": 21,
+                                                            "nodeType": 1,
+                                                            "nodeName": "BODY",
+                                                            "localName": "body",
+                                                            "nodeValue": "",
+                                                            "childNodeCount": 1,
+                                                            "children": [
+                                                                {
+                                                                    "nodeId": 22,
+                                                                    "nodeType": 1,
+                                                                    "nodeName": "DIV",
+                                                                    "localName": "div",
+                                                                    "nodeValue": "",
+                                                                    "childNodeCount": 0,
+                                                                    "children": [],
+                                                                    "attributes": [
+                                                                        "id",
+                                                                        "element_in_an_iframe"
+                                                                    ]
+                                                                }
+                                                            ],
+                                                            "attributes": []
+                                                        }
+                                                    ],
+                                                    "attributes": [],
+                                                    "frameId": "???"
+                                                }
+                                            ],
+                                            "documentURL": "???",
+                                            "baseURL": "???",
+                                            "xmlVersion": ""
+                                        }
+                                    }
+                                ],
+                                "attributes": [
+                                    "id",
+                                    "depth-3"
+                                ]
+                            }
+                        ],
+                        "attributes": [
+                            "id",
+                            "depth-2"
+                        ]
+                    }
+                ],
+                "attributes": [
+                    "id",
+                    "depth-1"
+                ]
+            }
+        ]
+    }
+}
+
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames.html b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames.html
new file mode 100644
index 0000000..e35f992
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-child-nodes-traverse-frames.html
@@ -0,0 +1,101 @@
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+<script type="text/javascript">
+
+function test()
+{
+    getDocument();
+
+    function getDocument()
+    {
+        InspectorTest.sendCommand("DOM.getDocument", {}, function(messageObject) {
+            if (messageObject.hasOwnProperty("error"))
+                InspectorTest.log("Backend error: " + messageObject.error.message + " (" + messageObject.error.code + ")\n");
+
+            var bodyId = messageObject.result.root.children[0].children[1].nodeId;
+            requestChildNodes(bodyId);
+        });
+    };
+
+    function requestChildNodes(bodyId)
+    {
+        InspectorTest.sendCommand("DOM.requestChildNodes", {"nodeId": bodyId, "depth": -1}, function(messageObject) {
+            if (messageObject.hasOwnProperty("error"))
+                InspectorTest.log("Backend error: " + messageObject.error.message + " (" + messageObject.error.code + ")\n");
+        });
+
+        InspectorTest.eventHandler["DOM.setChildNodes"] = function(messageObject)
+        {
+            var iframeContentDocument = messageObject.params.nodes[0].children[0].children[0].children[0].contentDocument;
+            if (iframeContentDocument.children) {
+                InspectorTest.log("Error IFrame node should not include children: " + JSON.stringify(iframeContentDocument, null, "    "));
+                InspectorTest.completeTest();
+            } else {
+                getDocumentIncludingIframe();
+            }
+        };
+    };
+
+    function getDocumentIncludingIframe()
+    {
+        InspectorTest.sendCommand("DOM.getDocument", {"traverseFrames": true}, function(messageObject) {
+            if (messageObject.hasOwnProperty("error"))
+                InspectorTest.log("Backend error: " + messageObject.error.message + " (" + messageObject.error.code + ")\n");
+
+            var bodyId = messageObject.result.root.children[0].children[1].nodeId;
+            requestAllChildNodesIncludingIframe(bodyId);
+        });
+    };
+
+    function replacePropertyRecursive(object, propertyNameToReplace)
+    {
+        for (var propertyName in object) {
+            if (!object.hasOwnProperty(propertyName))
+                continue;
+            if (propertyName === propertyNameToReplace) {
+                object[propertyName] = "???";
+            } else if (typeof object[propertyName] === "object") {
+                replacePropertyRecursive(object[propertyName], propertyNameToReplace);
+            }
+        }
+    }
+
+    function requestAllChildNodesIncludingIframe(bodyId)
+    {
+        InspectorTest.sendCommand("DOM.requestChildNodes", {"nodeId": bodyId, "depth": -1, "traverseFrames": true}, function(messageObject) {
+            if (messageObject.hasOwnProperty("error"))
+                InspectorTest.log("Backend error: " + messageObject.error.message + " (" + messageObject.error.code + ")\n");
+        });
+
+        InspectorTest.eventHandler["DOM.setChildNodes"] = function(messageObject)
+        {
+            // Replace properties that tend to change every run.
+            replacePropertyRecursive(messageObject, "frameId");
+            replacePropertyRecursive(messageObject, "documentURL");
+            replacePropertyRecursive(messageObject, "baseURL");
+
+            InspectorTest.log(JSON.stringify(messageObject, null, "    "));
+            InspectorTest.completeTest();
+        };
+    };
+};
+
+window.addEventListener("DOMContentLoaded", function () {
+    runTest();
+}, false);
+
+</script>
+</head>
+<body>
+
+<div id="depth-1">
+    <div id="depth-2">
+        <div id="depth-3">
+            <iframe src="resources/iframe.html"></iframe>
+        </div>
+    </div>
+</div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes-expected.txt
new file mode 100644
index 0000000..97b1fba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes-expected.txt
@@ -0,0 +1,128 @@
+
+{
+    "nodeId": 19,
+    "nodeType": 1,
+    "nodeName": "BODY",
+    "localName": "body",
+    "nodeValue": "",
+    "childNodeCount": 1,
+    "children": [
+        {
+            "nodeId": 20,
+            "nodeType": 1,
+            "nodeName": "DIV",
+            "localName": "div",
+            "nodeValue": "",
+            "childNodeCount": 1,
+            "children": [
+                {
+                    "nodeId": 21,
+                    "nodeType": 1,
+                    "nodeName": "DIV",
+                    "localName": "div",
+                    "nodeValue": "",
+                    "childNodeCount": 1,
+                    "children": [
+                        {
+                            "nodeId": 22,
+                            "nodeType": 1,
+                            "nodeName": "DIV",
+                            "localName": "div",
+                            "nodeValue": "",
+                            "childNodeCount": 1,
+                            "children": [
+                                {
+                                    "nodeId": 23,
+                                    "nodeType": 1,
+                                    "nodeName": "IFRAME",
+                                    "localName": "iframe",
+                                    "nodeValue": "",
+                                    "childNodeCount": 0,
+                                    "children": [],
+                                    "attributes": [
+                                        "src",
+                                        "resources/iframe.html"
+                                    ],
+                                    "frameId": "???",
+                                    "contentDocument": {
+                                        "nodeId": 24,
+                                        "nodeType": 9,
+                                        "nodeName": "#document",
+                                        "localName": "",
+                                        "nodeValue": "",
+                                        "childNodeCount": 1,
+                                        "children": [
+                                            {
+                                                "nodeId": 25,
+                                                "nodeType": 1,
+                                                "nodeName": "HTML",
+                                                "localName": "html",
+                                                "nodeValue": "",
+                                                "childNodeCount": 2,
+                                                "children": [
+                                                    {
+                                                        "nodeId": 26,
+                                                        "nodeType": 1,
+                                                        "nodeName": "HEAD",
+                                                        "localName": "head",
+                                                        "nodeValue": "",
+                                                        "childNodeCount": 0,
+                                                        "children": [],
+                                                        "attributes": []
+                                                    },
+                                                    {
+                                                        "nodeId": 27,
+                                                        "nodeType": 1,
+                                                        "nodeName": "BODY",
+                                                        "localName": "body",
+                                                        "nodeValue": "",
+                                                        "childNodeCount": 1,
+                                                        "children": [
+                                                            {
+                                                                "nodeId": 28,
+                                                                "nodeType": 1,
+                                                                "nodeName": "DIV",
+                                                                "localName": "div",
+                                                                "nodeValue": "",
+                                                                "childNodeCount": 0,
+                                                                "children": [],
+                                                                "attributes": [
+                                                                    "id",
+                                                                    "element_in_an_iframe"
+                                                                ]
+                                                            }
+                                                        ],
+                                                        "attributes": []
+                                                    }
+                                                ],
+                                                "attributes": [],
+                                                "frameId": "???"
+                                            }
+                                        ],
+                                        "documentURL": "???",
+                                        "baseURL": "???",
+                                        "xmlVersion": ""
+                                    }
+                                }
+                            ],
+                            "attributes": [
+                                "id",
+                                "depth-3"
+                            ]
+                        }
+                    ],
+                    "attributes": [
+                        "id",
+                        "depth-2"
+                    ]
+                }
+            ],
+            "attributes": [
+                "id",
+                "depth-1"
+            ]
+        }
+    ],
+    "attributes": []
+}
+
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes.html b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes.html
new file mode 100644
index 0000000..cf603ab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/dom-request-document-with-child-nodes.html
@@ -0,0 +1,76 @@
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+<script type="text/javascript">
+
+function test()
+{
+    getDocument();
+
+    function getDocument()
+    {
+        InspectorTest.sendCommand("DOM.getDocument", {"depth": -1}, function(messageObject) {
+            if (messageObject.hasOwnProperty("error"))
+                InspectorTest.log("Backend error: " + messageObject.error.message + " (" + messageObject.error.code + ")\n");
+
+            var iframeOwner = messageObject.result.root.children[0].children[1].children[0].children[0].children[0].children[0];
+            if (iframeOwner.contentDocument.children) {
+                InspectorTest.log("Error IFrame node should not include children: " + JSON.stringify(iframeOwner, null, "    "));
+                InspectorTest.completeTest();
+            } else {
+                getDocumentPlusIframe();
+            }
+        });
+    };
+
+    function replacePropertyRecursive(object, propertyNameToReplace)
+    {
+        for (var propertyName in object) {
+            if (!object.hasOwnProperty(propertyName))
+                continue;
+            if (propertyName === propertyNameToReplace) {
+                object[propertyName] = "???";
+            } else if (typeof object[propertyName] === "object") {
+                replacePropertyRecursive(object[propertyName], propertyNameToReplace);
+            }
+        }
+    }
+
+    function getDocumentPlusIframe()
+    {
+        InspectorTest.sendCommand("DOM.getDocument", {"depth": -1, "traverseFrames": true}, function(messageObject) {
+            if (messageObject.hasOwnProperty("error"))
+                InspectorTest.log("Backend error: " + messageObject.error.message + " (" + messageObject.error.code + ")\n");
+
+            var iframeOwner = messageObject.result.root.children[0].children[1].children[0].children[0].children[0].children[0];
+
+            // Replace properties that tend to change every run.
+            replacePropertyRecursive(messageObject, "frameId");
+            replacePropertyRecursive(messageObject, "documentURL");
+            replacePropertyRecursive(messageObject, "baseURL");
+
+            var bodyId = messageObject.result.root.children[0].children[1];
+            InspectorTest.log(JSON.stringify(bodyId, null, "    "));
+            InspectorTest.completeTest();
+        });
+    };
+};
+
+window.addEventListener("DOMContentLoaded", function () {
+    runTest();
+}, false);
+
+</script>
+</head>
+<body>
+
+<div id="depth-1">
+    <div id="depth-2">
+        <div id="depth-3">
+            <iframe src="resources/iframe.html"></iframe>
+        </div>
+    </div>
+</div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/dom/resources/iframe.html b/third_party/WebKit/LayoutTests/inspector-protocol/dom/resources/iframe.html
new file mode 100644
index 0000000..f416eb0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/dom/resources/iframe.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+<div id="element_in_an_iframe"></div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 7030880..ce591860 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -4822,12 +4822,16 @@
     method constructor
 interface RemotePlayback : EventTarget
     attribute @@toStringTag
-    getter onstatechange
+    getter onconnect
+    getter onconnecting
+    getter ondisconnect
     getter state
     method constructor
     method getAvailability
     method prompt
-    setter onstatechange
+    setter onconnect
+    setter onconnecting
+    setter ondisconnect
 interface RemotePlaybackAvailability : EventTarget
     attribute @@toStringTag
     getter onchange
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h
index ea17b88..1b7688e 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitor.h
@@ -256,5 +256,68 @@
      */
   v8::EmbedderReachableReferenceReporter* m_reporter = nullptr;
 };
+
+/**
+ * TraceWrapperMember is used for Member fields that should participate in
+ * wrapper tracing, i.e., strongly hold a ScriptWrappable alive. All
+ * TraceWrapperMember fields must be traced in the class' traceWrappers method.
+ */
+template <class T>
+class TraceWrapperMember : public Member<T> {
+  DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
+
+ public:
+  TraceWrapperMember(void* parent, T* raw) : Member<T>(raw), m_parent(parent) {
+#if DCHECK_IS_ON()
+    DCHECK(!m_parent || HeapObjectHeader::fromPayload(m_parent)->checkHeader());
+#endif
+    ScriptWrappableVisitor::writeBarrier(m_parent, raw);
+  }
+  TraceWrapperMember(WTF::HashTableDeletedValueType x)
+      : Member<T>(x), m_parent(nullptr) {}
+
+  /**
+   * Copying a TraceWrapperMember means that its backpointer will also be
+   * copied.
+   */
+  TraceWrapperMember(const TraceWrapperMember& other) { *this = other; }
+
+  template <typename U>
+  TraceWrapperMember& operator=(const TraceWrapperMember<U>& other) {
+    DCHECK(other.m_parent);
+    m_parent = other.m_parent;
+    Member<T>::operator=(other);
+    ScriptWrappableVisitor::writeBarrier(m_parent, other);
+    return *this;
+  }
+
+  template <typename U>
+  TraceWrapperMember& operator=(const Member<U>& other) {
+    DCHECK(m_parent);
+    Member<T>::operator=(other);
+    ScriptWrappableVisitor::writeBarrier(m_parent, other);
+    return *this;
+  }
+
+  template <typename U>
+  TraceWrapperMember& operator=(U* other) {
+    DCHECK(m_parent);
+    Member<T>::operator=(other);
+    ScriptWrappableVisitor::writeBarrier(m_parent, other);
+    return *this;
+  }
+
+  TraceWrapperMember& operator=(std::nullptr_t) {
+    // No need for a write barrier when assigning nullptr.
+    Member<T>::operator=(nullptr);
+    return *this;
+  }
+
+ private:
+  /**
+   * The parent object holding strongly onto the actual Member.
+   */
+  void* m_parent;
+};
 }
 #endif
diff --git a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
index 4e934d0..090e36c 100644
--- a/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/ScriptWrappableVisitorTest.cpp
@@ -29,6 +29,15 @@
   V8GCController::collectGarbage(isolate, false);
 }
 
+static bool DequeContains(const WTF::Deque<WrapperMarkingData>& deque,
+                          DeathAwareScriptWrappable* needle) {
+  for (auto item : deque) {
+    if (item.rawObjectPointer() == needle)
+      return true;
+  }
+  return false;
+}
+
 TEST(ScriptWrappableVisitorTest, ScriptWrappableVisitorTracesWrappers) {
   V8TestingScope scope;
   if (!RuntimeEnabledFeatures::traceWrappablesEnabled()) {
@@ -40,7 +49,7 @@
 
   DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::create();
   DeathAwareScriptWrappable* dependency = DeathAwareScriptWrappable::create();
-  target->setDependency(dependency);
+  target->setRawDependency(dependency);
 
   HeapObjectHeader* targetHeader = HeapObjectHeader::fromPayload(target);
   HeapObjectHeader* dependencyHeader =
@@ -209,7 +218,7 @@
 
   EXPECT_TRUE(visitor->getMarkingDeque()->isEmpty());
 
-  target->setDependency(dependency);
+  target->setRawDependency(dependency);
 
   EXPECT_TRUE(visitor->getMarkingDeque()->isEmpty());
 }
@@ -225,14 +234,22 @@
       V8PerIsolateData::from(scope.isolate())->scriptWrappableVisitor();
 
   DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::create();
-  DeathAwareScriptWrappable* dependency = DeathAwareScriptWrappable::create();
+  DeathAwareScriptWrappable* dependencies[] = {
+      DeathAwareScriptWrappable::create(), DeathAwareScriptWrappable::create(),
+      DeathAwareScriptWrappable::create(), DeathAwareScriptWrappable::create(),
+      DeathAwareScriptWrappable::create()};
 
   HeapObjectHeader::fromPayload(target)->markWrapperHeader();
-  HeapObjectHeader::fromPayload(dependency)->markWrapperHeader();
+  for (int i = 0; i < 5; i++) {
+    HeapObjectHeader::fromPayload(dependencies[i])->markWrapperHeader();
+  }
 
   EXPECT_TRUE(visitor->getMarkingDeque()->isEmpty());
 
-  target->setDependency(dependency);
+  target->setRawDependency(dependencies[0]);
+  target->setWrappedDependency(dependencies[1]);
+  target->addWrappedVectorDependency(dependencies[2]);
+  target->addWrappedHashMapDependency(dependencies[3], dependencies[4]);
 
   EXPECT_TRUE(visitor->getMarkingDeque()->isEmpty());
 }
@@ -248,15 +265,23 @@
       V8PerIsolateData::from(scope.isolate())->scriptWrappableVisitor();
 
   DeathAwareScriptWrappable* target = DeathAwareScriptWrappable::create();
-  DeathAwareScriptWrappable* dependency = DeathAwareScriptWrappable::create();
+  DeathAwareScriptWrappable* dependencies[] = {
+      DeathAwareScriptWrappable::create(), DeathAwareScriptWrappable::create(),
+      DeathAwareScriptWrappable::create(), DeathAwareScriptWrappable::create(),
+      DeathAwareScriptWrappable::create()};
 
   HeapObjectHeader::fromPayload(target)->markWrapperHeader();
 
   EXPECT_TRUE(visitor->getMarkingDeque()->isEmpty());
 
-  target->setDependency(dependency);
+  target->setRawDependency(dependencies[0]);
+  target->setWrappedDependency(dependencies[1]);
+  target->addWrappedVectorDependency(dependencies[2]);
+  target->addWrappedHashMapDependency(dependencies[3], dependencies[4]);
 
-  EXPECT_EQ(visitor->getMarkingDeque()->first().rawObjectPointer(), dependency);
+  for (int i = 0; i < 5; i++) {
+    EXPECT_TRUE(DequeContains(*visitor->getMarkingDeque(), dependencies[i]));
+  }
 
   visitor->getMarkingDeque()->clear();
   visitor->getVerifierDeque()->clear();
diff --git a/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp b/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp
index 57e48b3..9c3f564 100644
--- a/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp
+++ b/third_party/WebKit/Source/core/css/RemoteFontFaceSource.cpp
@@ -231,9 +231,10 @@
 void RemoteFontFaceSource::beginLoadIfNeeded() {
   if (m_fontSelector->document() && m_font->stillNeedsLoad()) {
     m_fontSelector->document()->fetcher()->startLoad(m_font);
+    if (!m_font->isLoaded())
+      m_font->startLoadLimitTimers();
     m_histograms.loadStarted();
   }
-  m_font->startLoadLimitTimersIfNeeded();
 
   if (m_face)
     m_face->didBeginLoad();
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index f1292c44..e7766f1 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -1816,7 +1816,7 @@
     EventHandlerRegistry::didMoveBetweenFrameHosts(
         *this, oldDocument.frameHost(), document().frameHost());
 
-  if (HeapVector<Member<MutationObserverRegistration>>* registry =
+  if (HeapVector<TraceWrapperMember<MutationObserverRegistration>>* registry =
           mutationObserverRegistry()) {
     for (size_t i = 0; i < registry->size(); ++i) {
       document().addMutationObserverTypes(registry->at(i)->mutationTypes());
@@ -1889,7 +1889,7 @@
   return *data;
 }
 
-HeapVector<Member<MutationObserverRegistration>>*
+HeapVector<TraceWrapperMember<MutationObserverRegistration>>*
 Node::mutationObserverRegistry() {
   if (!hasRareData())
     return nullptr;
@@ -1961,7 +1961,7 @@
     MutationObserverOptions options,
     const HashSet<AtomicString>& attributeFilter) {
   MutationObserverRegistration* registration = nullptr;
-  HeapVector<Member<MutationObserverRegistration>>& registry =
+  HeapVector<TraceWrapperMember<MutationObserverRegistration>>& registry =
       ensureRareData().ensureMutationObserverData().registry;
   for (size_t i = 0; i < registry.size(); ++i) {
     if (&registry[i]->observer() == &observer) {
@@ -1971,10 +1971,10 @@
   }
 
   if (!registration) {
-    registry.append(MutationObserverRegistration::create(
-        observer, this, options, attributeFilter));
-    registration = registry.last().get();
-    ScriptWrappableVisitor::writeBarrier(this, registration);
+    registration = MutationObserverRegistration::create(observer, this, options,
+                                                        attributeFilter);
+    registry.append(
+        TraceWrapperMember<MutationObserverRegistration>(this, registration));
   }
 
   document().addMutationObserverTypes(registration->mutationTypes());
@@ -1982,7 +1982,7 @@
 
 void Node::unregisterMutationObserver(
     MutationObserverRegistration* registration) {
-  HeapVector<Member<MutationObserverRegistration>>* registry =
+  HeapVector<TraceWrapperMember<MutationObserverRegistration>>* registry =
       mutationObserverRegistry();
   DCHECK(registry);
   if (!registry)
@@ -2024,7 +2024,7 @@
 
   ScriptForbiddenScope forbidScriptDuringRawIteration;
   for (Node* node = parentNode(); node; node = node->parentNode()) {
-    if (HeapVector<Member<MutationObserverRegistration>>* registry =
+    if (HeapVector<TraceWrapperMember<MutationObserverRegistration>>* registry =
             node->mutationObserverRegistry()) {
       const size_t size = registry->size();
       for (size_t i = 0; i < size; ++i)
diff --git a/third_party/WebKit/Source/core/dom/Node.h b/third_party/WebKit/Source/core/dom/Node.h
index bca9099..d058ecf6 100644
--- a/third_party/WebKit/Source/core/dom/Node.h
+++ b/third_party/WebKit/Source/core/dom/Node.h
@@ -935,7 +935,8 @@
 
   void trackForDebugging();
 
-  HeapVector<Member<MutationObserverRegistration>>* mutationObserverRegistry();
+  HeapVector<TraceWrapperMember<MutationObserverRegistration>>*
+  mutationObserverRegistry();
   HeapHashSet<Member<MutationObserverRegistration>>*
   transientMutationObserverRegistry();
 
diff --git a/third_party/WebKit/Source/core/dom/NodeIntersectionObserverData.cpp b/third_party/WebKit/Source/core/dom/NodeIntersectionObserverData.cpp
index 3041915..7a3fc71f 100644
--- a/third_party/WebKit/Source/core/dom/NodeIntersectionObserverData.cpp
+++ b/third_party/WebKit/Source/core/dom/NodeIntersectionObserverData.cpp
@@ -4,7 +4,6 @@
 
 #include "core/dom/NodeIntersectionObserverData.h"
 
-#include "bindings/core/v8/ScriptWrappableVisitor.h"
 #include "core/dom/Document.h"
 #include "core/dom/IntersectionObservation.h"
 #include "core/dom/IntersectionObserver.h"
@@ -24,8 +23,9 @@
 
 void NodeIntersectionObserverData::addObservation(
     IntersectionObservation& observation) {
-  m_intersectionObservations.add(&observation.observer(), &observation);
-  ScriptWrappableVisitor::writeBarrier(this, &observation.observer());
+  m_intersectionObservations.add(
+      TraceWrapperMember<IntersectionObserver>(this, &observation.observer()),
+      &observation);
 }
 
 void NodeIntersectionObserverData::removeObservation(
diff --git a/third_party/WebKit/Source/core/dom/NodeIntersectionObserverData.h b/third_party/WebKit/Source/core/dom/NodeIntersectionObserverData.h
index 997d577..72b56bf3 100644
--- a/third_party/WebKit/Source/core/dom/NodeIntersectionObserverData.h
+++ b/third_party/WebKit/Source/core/dom/NodeIntersectionObserverData.h
@@ -5,6 +5,7 @@
 #ifndef NodeIntersectionObserverData_h
 #define NodeIntersectionObserverData_h
 
+#include "bindings/core/v8/ScriptWrappableVisitor.h"
 #include "platform/heap/Handle.h"
 
 namespace blink {
@@ -32,7 +33,8 @@
   // IntersectionObservers for which the Node owning this data is root.
   HeapHashSet<WeakMember<IntersectionObserver>> m_intersectionObservers;
   // IntersectionObservations for which the Node owning this data is target.
-  HeapHashMap<Member<IntersectionObserver>, Member<IntersectionObservation>>
+  HeapHashMap<TraceWrapperMember<IntersectionObserver>,
+              Member<IntersectionObservation>>
       m_intersectionObservations;
 };
 
diff --git a/third_party/WebKit/Source/core/dom/NodeRareData.h b/third_party/WebKit/Source/core/dom/NodeRareData.h
index 2e2de6c..cf78936 100644
--- a/third_party/WebKit/Source/core/dom/NodeRareData.h
+++ b/third_party/WebKit/Source/core/dom/NodeRareData.h
@@ -35,7 +35,7 @@
   WTF_MAKE_NONCOPYABLE(NodeMutationObserverData);
 
  public:
-  HeapVector<Member<MutationObserverRegistration>> registry;
+  HeapVector<TraceWrapperMember<MutationObserverRegistration>> registry;
   HeapHashSet<Member<MutationObserverRegistration>> transientRegistry;
 
   static NodeMutationObserverData* create() {
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
index 04d893e..0eee09a 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/VisibleSelection.cpp
@@ -52,33 +52,35 @@
 
 template <typename Strategy>
 VisibleSelectionTemplate<Strategy>::VisibleSelectionTemplate(
-    const PositionTemplate<Strategy>& base,
-    const PositionTemplate<Strategy>& extent,
-    TextAffinity affinity,
-    bool isDirectional)
-    : m_base(base),
-      m_extent(extent),
-      m_affinity(affinity),
-      m_isDirectional(isDirectional),
-      m_granularity(CharacterGranularity),
-      m_hasTrailingWhitespace(false) {
+    const SelectionTemplate<Strategy>& selection)
+    : m_base(selection.base()),
+      m_extent(selection.extent()),
+      m_affinity(selection.affinity()),
+      m_isDirectional(selection.isDirectional()),
+      m_granularity(selection.granularity()),
+      m_hasTrailingWhitespace(selection.hasTrailingWhitespace()) {
   validate();
 }
 
 template <typename Strategy>
 VisibleSelectionTemplate<Strategy> VisibleSelectionTemplate<Strategy>::create(
-    const PositionTemplate<Strategy>& base,
-    const PositionTemplate<Strategy>& extent,
-    TextAffinity affinity,
-    bool isDirectional) {
-  return VisibleSelectionTemplate(base, extent, affinity, isDirectional);
+    const SelectionTemplate<Strategy>& selection) {
+  return VisibleSelectionTemplate(selection);
+}
+
+VisibleSelection createVisibleSelection(const SelectionInDOMTree& selection) {
+  return VisibleSelection::create(selection);
 }
 
 VisibleSelection createVisibleSelection(const Position& pos,
                                         TextAffinity affinity,
                                         bool isDirectional) {
   DCHECK(!needsLayoutTreeUpdate(pos));
-  return VisibleSelection::create(pos, pos, affinity, isDirectional);
+  SelectionInDOMTree::Builder builder;
+  builder.setAffinity(affinity).setIsDirectional(isDirectional);
+  if (pos.isNotNull())
+    builder.collapse(pos);
+  return createVisibleSelection(builder.build());
 }
 
 VisibleSelection createVisibleSelection(const Position& base,
@@ -87,23 +89,24 @@
                                         bool isDirectional) {
   DCHECK(!needsLayoutTreeUpdate(base));
   DCHECK(!needsLayoutTreeUpdate(extent));
-  // TODO(xiaochengh): We should check |base.isNotNull() || extent.isNull()|
-  // after all call sites have ensured that.
-  return VisibleSelection::create(base, extent, affinity, isDirectional);
+  // TODO(yosin): We should use |Builder::setBaseAndExtent()| once we get rid
+  // of callers passing |base.istNull()| but |extent.isNotNull()|.
+  SelectionInDOMTree::Builder builder;
+  builder.setBaseAndExtentDeprecated(base, extent)
+      .setAffinity(affinity)
+      .setIsDirectional(isDirectional);
+  return createVisibleSelection(builder.build());
 }
 
 VisibleSelection createVisibleSelection(const PositionWithAffinity& pos,
                                         bool isDirectional) {
-  DCHECK(!needsLayoutTreeUpdate(pos.position()));
-  return VisibleSelection::create(pos.position(), pos.position(),
-                                  pos.affinity(), isDirectional);
+  return createVisibleSelection(pos.position(), pos.affinity(), isDirectional);
 }
 
 VisibleSelection createVisibleSelection(const VisiblePosition& pos,
                                         bool isDirectional) {
-  DCHECK(pos.isValid());
-  return VisibleSelection::create(pos.deepEquivalent(), pos.deepEquivalent(),
-                                  pos.affinity(), isDirectional);
+  return createVisibleSelection(pos.deepEquivalent(), pos.affinity(),
+                                isDirectional);
 }
 
 VisibleSelection createVisibleSelection(const VisiblePosition& base,
@@ -111,11 +114,8 @@
                                         bool isDirectional) {
   DCHECK(base.isValid());
   DCHECK(extent.isValid());
-  // TODO(xiaochengh): We should check |base.isNotNull() || extent.isNull()|
-  // after all call sites have ensured that.
-  return VisibleSelection::create(base.deepEquivalent(),
-                                  extent.deepEquivalent(), base.affinity(),
-                                  isDirectional);
+  return createVisibleSelection(base.deepEquivalent(), extent.deepEquivalent(),
+                                base.affinity(), isDirectional);
 }
 
 VisibleSelection createVisibleSelection(const EphemeralRange& range,
@@ -123,15 +123,26 @@
                                         bool isDirectional) {
   DCHECK(!needsLayoutTreeUpdate(range.startPosition()));
   DCHECK(!needsLayoutTreeUpdate(range.endPosition()));
-  return VisibleSelection::create(range.startPosition(), range.endPosition(),
-                                  affinity, isDirectional);
+  SelectionInDOMTree::Builder builder;
+  builder.setBaseAndExtent(range).setAffinity(affinity).setIsDirectional(
+      isDirectional);
+  return createVisibleSelection(builder.build());
+}
+
+VisibleSelectionInFlatTree createVisibleSelection(
+    const SelectionInFlatTree& selection) {
+  return VisibleSelectionInFlatTree::create(selection);
 }
 
 VisibleSelectionInFlatTree createVisibleSelection(const PositionInFlatTree& pos,
                                                   TextAffinity affinity,
                                                   bool isDirectional) {
   DCHECK(!needsLayoutTreeUpdate(pos));
-  return VisibleSelectionInFlatTree::create(pos, pos, affinity, isDirectional);
+  SelectionInFlatTree::Builder builder;
+  builder.setAffinity(affinity).setIsDirectional(isDirectional);
+  if (pos.isNotNull())
+    builder.collapse(pos);
+  return createVisibleSelection(builder.build());
 }
 
 VisibleSelectionInFlatTree createVisibleSelection(
@@ -141,27 +152,27 @@
     bool isDirectional) {
   DCHECK(!needsLayoutTreeUpdate(base));
   DCHECK(!needsLayoutTreeUpdate(extent));
-  // TODO(xiaochengh): We should check |base.isNotNull() || extent.isNull()|
-  // after all call sites have ensured that.
-  return VisibleSelectionInFlatTree::create(base, extent, affinity,
-                                            isDirectional);
+  // TODO(yosin): We should use |Builder::setBaseAndExtent()| once we get rid
+  // of callers passing |base.istNull()| but |extent.isNotNull()|.
+  SelectionInFlatTree::Builder builder;
+  builder.setBaseAndExtentDeprecated(base, extent)
+      .setAffinity(affinity)
+      .setIsDirectional(isDirectional);
+  return createVisibleSelection(builder.build());
 }
 
 VisibleSelectionInFlatTree createVisibleSelection(
     const PositionInFlatTreeWithAffinity& pos,
     bool isDirectional) {
-  DCHECK(!needsLayoutTreeUpdate(pos.position()));
-  return VisibleSelectionInFlatTree::create(pos.position(), pos.position(),
-                                            pos.affinity(), isDirectional);
+  return createVisibleSelection(pos.position(), pos.affinity(), isDirectional);
 }
 
 VisibleSelectionInFlatTree createVisibleSelection(
     const VisiblePositionInFlatTree& pos,
     bool isDirectional) {
   DCHECK(pos.isValid());
-  return VisibleSelectionInFlatTree::create(pos.deepEquivalent(),
-                                            pos.deepEquivalent(),
-                                            pos.affinity(), isDirectional);
+  return createVisibleSelection(pos.deepEquivalent(), pos.affinity(),
+                                isDirectional);
 }
 
 VisibleSelectionInFlatTree createVisibleSelection(
@@ -172,9 +183,8 @@
   DCHECK(extent.isValid());
   // TODO(xiaochengh): We should check |base.isNotNull() || extent.isNull()|
   // after all call sites have ensured that.
-  return VisibleSelectionInFlatTree::create(base.deepEquivalent(),
-                                            extent.deepEquivalent(),
-                                            base.affinity(), isDirectional);
+  return createVisibleSelection(base.deepEquivalent(), extent.deepEquivalent(),
+                                base.affinity(), isDirectional);
 }
 
 VisibleSelectionInFlatTree createVisibleSelection(
@@ -183,8 +193,10 @@
     bool isDirectional) {
   DCHECK(!needsLayoutTreeUpdate(range.startPosition()));
   DCHECK(!needsLayoutTreeUpdate(range.endPosition()));
-  return VisibleSelectionInFlatTree::create(
-      range.startPosition(), range.endPosition(), affinity, isDirectional);
+  SelectionInFlatTree::Builder builder;
+  builder.setBaseAndExtent(range).setAffinity(affinity).setIsDirectional(
+      isDirectional);
+  return createVisibleSelection(builder.build());
 }
 
 template <typename Strategy>
@@ -246,10 +258,10 @@
   // needs to be audited. see http://crbug.com/590369 for more details.
   node->document().updateStyleAndLayoutIgnorePendingStylesheets();
 
-  return VisibleSelectionTemplate::create(
-      PositionTemplate<Strategy>::firstPositionInNode(node),
-      PositionTemplate<Strategy>::lastPositionInNode(node), SelDefaultAffinity,
-      false);
+  typename SelectionTemplate<Strategy>::Builder builder;
+  builder.collapse(PositionTemplate<Strategy>::firstPositionInNode(node))
+      .extend(PositionTemplate<Strategy>::lastPositionInNode(node));
+  return VisibleSelectionTemplate::create(builder.build());
 }
 
 template <typename Strategy>
diff --git a/third_party/WebKit/Source/core/editing/VisibleSelection.h b/third_party/WebKit/Source/core/editing/VisibleSelection.h
index 4c68c5a3..68e7010 100644
--- a/third_party/WebKit/Source/core/editing/VisibleSelection.h
+++ b/third_party/WebKit/Source/core/editing/VisibleSelection.h
@@ -29,6 +29,7 @@
 #include "core/CoreExport.h"
 #include "core/editing/EditingStrategy.h"
 #include "core/editing/EphemeralRange.h"
+#include "core/editing/SelectionTemplate.h"
 #include "core/editing/SelectionType.h"
 #include "core/editing/TextAffinity.h"
 #include "core/editing/TextGranularity.h"
@@ -60,12 +61,7 @@
 
   // Note: |create()| should be used only by |createVisibleSelection| and
   // |selectionFromContentsOfNode|.
-  // TODO(xiaochengh): Use enum class instead of boolean parameter.
-  static VisibleSelectionTemplate create(
-      const PositionTemplate<Strategy>& base,
-      const PositionTemplate<Strategy>& extent,
-      TextAffinity,
-      bool isDirectional);
+  static VisibleSelectionTemplate create(const SelectionTemplate<Strategy>&);
 
   static VisibleSelectionTemplate selectionFromContentsOfNode(Node*);
 
@@ -74,6 +70,9 @@
   void setAffinity(TextAffinity affinity) { m_affinity = affinity; }
   TextAffinity affinity() const { return m_affinity; }
 
+  // TODO(yosin): To make |VisibleSelection| as immutable object, we should
+  // get rid of |setBase()| and |setExtent()| by replacing them with
+  // |createVisibleSelection()|.
   void setBase(const PositionTemplate<Strategy>&);
   void setBase(const VisiblePositionTemplate<Strategy>&);
   void setExtent(const PositionTemplate<Strategy>&);
@@ -161,10 +160,7 @@
  private:
   friend class SelectionAdjuster;
 
-  VisibleSelectionTemplate(const PositionTemplate<Strategy>& base,
-                           const PositionTemplate<Strategy>& extent,
-                           TextAffinity,
-                           bool isDirectional);
+  VisibleSelectionTemplate(const SelectionTemplate<Strategy>&);
 
   void validate(TextGranularity = CharacterGranularity);
 
@@ -214,7 +210,9 @@
 using VisibleSelectionInFlatTree =
     VisibleSelectionTemplate<EditingInFlatTreeStrategy>;
 
-// TODO(xiaochengh): Introduce builder class to get rid of these overloads.
+// TODO(yosin): We should get rid of |createVisibleSelection()| overloads
+// except for taking |SelectionInDOMTree| and |SelectionInFlatTree|.
+CORE_EXPORT VisibleSelection createVisibleSelection(const SelectionInDOMTree&);
 CORE_EXPORT VisibleSelection createVisibleSelection(const Position&,
                                                     TextAffinity,
                                                     bool isDirectional = false);
@@ -236,6 +234,8 @@
                                                     bool isDirectional = false);
 
 CORE_EXPORT VisibleSelectionInFlatTree
+createVisibleSelection(const SelectionInFlatTree&);
+CORE_EXPORT VisibleSelectionInFlatTree
 createVisibleSelection(const PositionInFlatTree&,
                        TextAffinity,
                        bool isDirectional = false);
diff --git a/third_party/WebKit/Source/core/fetch/FontResource.cpp b/third_party/WebKit/Source/core/fetch/FontResource.cpp
index a5314e8..2de0a24 100644
--- a/third_party/WebKit/Source/core/fetch/FontResource.cpp
+++ b/third_party/WebKit/Source/core/fetch/FontResource.cpp
@@ -83,7 +83,7 @@
 FontResource::FontResource(const ResourceRequest& resourceRequest,
                            const ResourceLoaderOptions& options)
     : Resource(resourceRequest, Font, options),
-      m_loadLimitState(UnderLimit),
+      m_loadLimitState(LoadNotStarted),
       m_corsFailed(false),
       m_fontLoadShortLimitTimer(this,
                                 &FontResource::fontLoadShortLimitCallback),
@@ -105,15 +105,14 @@
 void FontResource::setRevalidatingRequest(const ResourceRequest& request) {
   // Reload will use the same object, and needs to reset |m_loadLimitState|
   // before any didAddClient() is called again.
-  m_loadLimitState = UnderLimit;
+  m_loadLimitState = LoadNotStarted;
   Resource::setRevalidatingRequest(request);
 }
 
-void FontResource::startLoadLimitTimersIfNeeded() {
-  DCHECK(!stillNeedsLoad());
-  if (isLoaded() || m_fontLoadLongLimitTimer.isActive())
-    return;
-  DCHECK_EQ(m_loadLimitState, UnderLimit);
+void FontResource::startLoadLimitTimers() {
+  DCHECK(isLoading());
+  DCHECK_EQ(m_loadLimitState, LoadNotStarted);
+  m_loadLimitState = UnderLimit;
   m_fontLoadShortLimitTimer.startOneShot(fontLoadWaitShortLimitSec,
                                          BLINK_FROM_HERE);
   m_fontLoadLongLimitTimer.startOneShot(fontLoadWaitLongLimitSec,
diff --git a/third_party/WebKit/Source/core/fetch/FontResource.h b/third_party/WebKit/Source/core/fetch/FontResource.h
index 97ea91f2e..e83ab31 100644
--- a/third_party/WebKit/Source/core/fetch/FontResource.h
+++ b/third_party/WebKit/Source/core/fetch/FontResource.h
@@ -54,7 +54,7 @@
   void setRevalidatingRequest(const ResourceRequest&) override;
 
   void allClientsAndObserversRemoved() override;
-  void startLoadLimitTimersIfNeeded();
+  void startLoadLimitTimers();
 
   void setCORSFailed() override { m_corsFailed = true; }
   bool isCORSFailed() const { return m_corsFailed; }
@@ -84,7 +84,12 @@
   void fontLoadShortLimitCallback(TimerBase*);
   void fontLoadLongLimitCallback(TimerBase*);
 
-  enum LoadLimitState { UnderLimit, ShortLimitExceeded, LongLimitExceeded };
+  enum LoadLimitState {
+    LoadNotStarted,
+    UnderLimit,
+    ShortLimitExceeded,
+    LongLimitExceeded
+  };
 
   std::unique_ptr<FontCustomPlatformData> m_fontData;
   String m_otsParsingMessage;
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index 099ed908..2ac47d8 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -699,6 +699,30 @@
 
   String encodingMimeType = toEncodingMimeType(mimeType, EncodeReasonToDataURL);
 
+  Optional<ScopedUsHistogramTimer> timer;
+  if (encodingMimeType == "image/png") {
+    DEFINE_THREAD_SAFE_STATIC_LOCAL(
+        CustomCountHistogram, scopedUsCounterPNG,
+        new CustomCountHistogram("Blink.Canvas.ToDataURL.PNG", 0, 10000000,
+                                 50));
+    timer.emplace(scopedUsCounterPNG);
+  } else if (encodingMimeType == "image/jpeg") {
+    DEFINE_THREAD_SAFE_STATIC_LOCAL(
+        CustomCountHistogram, scopedUsCounterJPEG,
+        new CustomCountHistogram("Blink.Canvas.ToDataURL.JPEG", 0, 10000000,
+                                 50));
+    timer.emplace(scopedUsCounterJPEG);
+  } else if (encodingMimeType == "image/webp") {
+    DEFINE_THREAD_SAFE_STATIC_LOCAL(
+        CustomCountHistogram, scopedUsCounterWEBP,
+        new CustomCountHistogram("Blink.Canvas.ToDataURL.WEBP", 0, 10000000,
+                                 50));
+    timer.emplace(scopedUsCounterWEBP);
+  } else {
+    // Currently we only support three encoding types.
+    NOTREACHED();
+  }
+
   ImageData* imageData = toImageData(sourceBuffer, SnapshotReasonToDataURL);
 
   if (!imageData)  // allocation failure
@@ -722,61 +746,6 @@
     exceptionState.throwSecurityError("Tainted canvases may not be exported.");
     return String();
   }
-  Optional<ScopedUsHistogramTimer> timer;
-  String lowercaseMimeType = mimeType.lower();
-  if (mimeType.isNull())
-    lowercaseMimeType = DefaultMimeType;
-  if (lowercaseMimeType == "image/png") {
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        CustomCountHistogram, scopedUsCounterPNG,
-        new CustomCountHistogram("Blink.Canvas.ToDataURL.PNG", 0, 10000000,
-                                 50));
-    timer.emplace(scopedUsCounterPNG);
-  } else if (lowercaseMimeType == "image/jpeg") {
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        CustomCountHistogram, scopedUsCounterJPEG,
-        new CustomCountHistogram("Blink.Canvas.ToDataURL.JPEG", 0, 10000000,
-                                 50));
-    timer.emplace(scopedUsCounterJPEG);
-  } else if (lowercaseMimeType == "image/webp") {
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        CustomCountHistogram, scopedUsCounterWEBP,
-        new CustomCountHistogram("Blink.Canvas.ToDataURL.WEBP", 0, 10000000,
-                                 50));
-    timer.emplace(scopedUsCounterWEBP);
-  } else if (lowercaseMimeType == "image/gif") {
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        CustomCountHistogram, scopedUsCounterGIF,
-        new CustomCountHistogram("Blink.Canvas.ToDataURL.GIF", 0, 10000000,
-                                 50));
-    timer.emplace(scopedUsCounterGIF);
-  } else if (lowercaseMimeType == "image/bmp" ||
-             lowercaseMimeType == "image/x-windows-bmp") {
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        CustomCountHistogram, scopedUsCounterBMP,
-        new CustomCountHistogram("Blink.Canvas.ToDataURL.BMP", 0, 10000000,
-                                 50));
-    timer.emplace(scopedUsCounterBMP);
-  } else if (lowercaseMimeType == "image/x-icon") {
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        CustomCountHistogram, scopedUsCounterICON,
-        new CustomCountHistogram("Blink.Canvas.ToDataURL.ICON", 0, 10000000,
-                                 50));
-    timer.emplace(scopedUsCounterICON);
-  } else if (lowercaseMimeType == "image/tiff" ||
-             lowercaseMimeType == "image/x-tiff") {
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        CustomCountHistogram, scopedUsCounterTIFF,
-        new CustomCountHistogram("Blink.Canvas.ToDataURL.TIFF", 0, 10000000,
-                                 50));
-    timer.emplace(scopedUsCounterTIFF);
-  } else {
-    DEFINE_THREAD_SAFE_STATIC_LOCAL(
-        CustomCountHistogram, scopedUsCounterUnknown,
-        new CustomCountHistogram("Blink.Canvas.ToDataURL.Unknown", 0, 10000000,
-                                 50));
-    timer.emplace(scopedUsCounterUnknown);
-  }
 
   double quality = UndefinedQualityValue;
   if (!qualityArgument.isEmpty()) {
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp
index 7b9109c7..79583d0 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp
@@ -161,9 +161,7 @@
                                      const CharacterType* end,
                                      int& value) {
   // Step 3
-  // We do not do this step and do not have a local sign
-  // variable since due to a bug in charactersToIntStrict
-  // we have to add the sign to the digits string.
+  bool isNegative = false;
 
   // Step 4
   while (position < end) {
@@ -178,9 +176,8 @@
   ASSERT(position < end);
 
   // Step 6
-  StringBuilder digits;
   if (*position == '-') {
-    digits.append('-');
+    isNegative = true;
     ++position;
   } else if (*position == '+')
     ++position;
@@ -193,19 +190,22 @@
     return false;
 
   // Step 8
-  while (position < end) {
-    if (!isASCIIDigit(*position))
-      break;
-    digits.append(*position++);
-  }
+  static const int intMax = std::numeric_limits<int>::max();
+  const int base = 10;
+  const int maxMultiplier = intMax / base;
 
+  unsigned temp = 0;
+  do {
+    int digitValue = *position - '0';
+    if (temp > maxMultiplier ||
+        (temp == maxMultiplier && digitValue > (intMax % base) + isNegative))
+      return false;
+    temp = temp * base + digitValue;
+    ++position;
+  } while (position < end && isASCIIDigit(*position));
   // Step 9
-  bool ok;
-  if (digits.is8Bit())
-    value = charactersToIntStrict(digits.characters8(), digits.length(), &ok);
-  else
-    value = charactersToIntStrict(digits.characters16(), digits.length(), &ok);
-  return ok;
+  value = isNegative ? (0 - temp) : temp;
+  return true;
 }
 
 // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.h b/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.h
index f10637e8..61f96ff 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.h
+++ b/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.h
@@ -58,7 +58,7 @@
     double fallbackValue = std::numeric_limits<double>::quiet_NaN());
 
 // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers
-bool parseHTMLInteger(const String&, int&);
+CORE_EXPORT bool parseHTMLInteger(const String&, int&);
 
 // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers
 CORE_EXPORT bool parseHTMLNonNegativeInteger(const String&, unsigned&);
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserIdiomsTest.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserIdiomsTest.cpp
index d9b4ade7..556058f 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLParserIdiomsTest.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLParserIdiomsTest.cpp
@@ -10,6 +10,26 @@
 
 namespace {
 
+TEST(HTMLParserIdiomsTest, ParseHTMLInteger) {
+  int value = 0;
+
+  EXPECT_TRUE(parseHTMLInteger("2147483646", value));
+  EXPECT_EQ(2147483646, value);
+  EXPECT_TRUE(parseHTMLInteger("2147483647", value));
+  EXPECT_EQ(2147483647, value);
+  value = 12345;
+  EXPECT_FALSE(parseHTMLInteger("2147483648", value));
+  EXPECT_EQ(12345, value);
+
+  EXPECT_TRUE(parseHTMLInteger("-2147483647", value));
+  EXPECT_EQ(-2147483647, value);
+  EXPECT_TRUE(parseHTMLInteger("-2147483648", value));
+  EXPECT_EQ(0 - 2147483648, value);
+  value = 12345;
+  EXPECT_FALSE(parseHTMLInteger("-2147483649", value));
+  EXPECT_EQ(12345, value);
+}
+
 TEST(HTMLParserIdiomsTest, ParseHTMLNonNegativeInteger) {
   unsigned value = 0;
 
diff --git a/third_party/WebKit/Source/core/html/track/TextTrack.cpp b/third_party/WebKit/Source/core/html/track/TextTrack.cpp
index 392d67f8..70caa74 100644
--- a/third_party/WebKit/Source/core/html/track/TextTrack.cpp
+++ b/third_party/WebKit/Source/core/html/track/TextTrack.cpp
@@ -33,7 +33,6 @@
 
 #include "bindings/core/v8/ExceptionState.h"
 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
-#include "bindings/core/v8/ScriptWrappableVisitor.h"
 #include "core/dom/ExceptionCode.h"
 #include "core/html/HTMLMediaElement.h"
 #include "core/html/track/CueTimeline.h"
@@ -94,6 +93,7 @@
                      TextTrackType type)
     : TrackBase(WebMediaPlayer::TextTrack, kind, label, language, id),
       m_cues(nullptr),
+      m_activeCues(this, nullptr),
       m_regions(nullptr),
       m_trackList(nullptr),
       m_mode(disabledKeyword()),
@@ -209,7 +209,6 @@
 
   if (!m_activeCues) {
     m_activeCues = TextTrackCueList::create();
-    ScriptWrappableVisitor::writeBarrier(this, m_activeCues);
   }
 
   m_cues->collectActiveCues(*m_activeCues);
diff --git a/third_party/WebKit/Source/core/html/track/TextTrack.h b/third_party/WebKit/Source/core/html/track/TextTrack.h
index 45dbbef..68359273 100644
--- a/third_party/WebKit/Source/core/html/track/TextTrack.h
+++ b/third_party/WebKit/Source/core/html/track/TextTrack.h
@@ -27,6 +27,7 @@
 #ifndef TextTrack_h
 #define TextTrack_h
 
+#include "bindings/core/v8/ScriptWrappableVisitor.h"
 #include "core/CoreExport.h"
 #include "core/events/EventTarget.h"
 #include "core/html/track/TrackBase.h"
@@ -148,7 +149,7 @@
 
   TextTrackCueList* ensureTextTrackCueList();
   Member<TextTrackCueList> m_cues;
-  Member<TextTrackCueList> m_activeCues;
+  TraceWrapperMember<TextTrackCueList> m_activeCues;
 
   VTTRegionList* ensureVTTRegionList();
   Member<VTTRegionList> m_regions;
diff --git a/third_party/WebKit/Source/core/html/track/TextTrackList.cpp b/third_party/WebKit/Source/core/html/track/TextTrackList.cpp
index 4991551..a5aa142 100644
--- a/third_party/WebKit/Source/core/html/track/TextTrackList.cpp
+++ b/third_party/WebKit/Source/core/html/track/TextTrackList.cpp
@@ -140,7 +140,7 @@
 }
 
 void TextTrackList::invalidateTrackIndexesAfterTrack(TextTrack* track) {
-  HeapVector<Member<TextTrack>>* tracks = nullptr;
+  HeapVector<TraceWrapperMember<TextTrack>>* tracks = nullptr;
 
   if (track->trackType() == TextTrack::TrackElement) {
     tracks = &m_elementTracks;
@@ -168,17 +168,16 @@
 
 void TextTrackList::append(TextTrack* track) {
   if (track->trackType() == TextTrack::AddTrack) {
-    m_addTrackTracks.append(track);
+    m_addTrackTracks.append(TraceWrapperMember<TextTrack>(this, track));
   } else if (track->trackType() == TextTrack::TrackElement) {
     // Insert tracks added for <track> element in tree order.
     size_t index = static_cast<LoadableTextTrack*>(track)->trackElementIndex();
-    m_elementTracks.insert(index, track);
+    m_elementTracks.insert(index, TraceWrapperMember<TextTrack>(this, track));
   } else if (track->trackType() == TextTrack::InBand) {
-    m_inbandTracks.append(track);
+    m_inbandTracks.append(TraceWrapperMember<TextTrack>(this, track));
   } else {
     NOTREACHED();
   }
-  ScriptWrappableVisitor::writeBarrier(this, track);
 
   invalidateTrackIndexesAfterTrack(track);
 
@@ -189,7 +188,7 @@
 }
 
 void TextTrackList::remove(TextTrack* track) {
-  HeapVector<Member<TextTrack>>* tracks = nullptr;
+  HeapVector<TraceWrapperMember<TextTrack>>* tracks = nullptr;
 
   if (track->trackType() == TextTrack::TrackElement) {
     tracks = &m_elementTracks;
@@ -223,7 +222,7 @@
 }
 
 bool TextTrackList::contains(TextTrack* track) const {
-  const HeapVector<Member<TextTrack>>* tracks = nullptr;
+  const HeapVector<TraceWrapperMember<TextTrack>>* tracks = nullptr;
 
   if (track->trackType() == TextTrack::TrackElement)
     tracks = &m_elementTracks;
diff --git a/third_party/WebKit/Source/core/html/track/TextTrackList.h b/third_party/WebKit/Source/core/html/track/TextTrackList.h
index 0f639d7..e893856 100644
--- a/third_party/WebKit/Source/core/html/track/TextTrackList.h
+++ b/third_party/WebKit/Source/core/html/track/TextTrackList.h
@@ -91,9 +91,9 @@
 
   Member<GenericEventQueue> m_asyncEventQueue;
 
-  HeapVector<Member<TextTrack>> m_addTrackTracks;
-  HeapVector<Member<TextTrack>> m_elementTracks;
-  HeapVector<Member<TextTrack>> m_inbandTracks;
+  HeapVector<TraceWrapperMember<TextTrack>> m_addTrackTracks;
+  HeapVector<TraceWrapperMember<TextTrack>> m_elementTracks;
+  HeapVector<TraceWrapperMember<TextTrack>> m_inbandTracks;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/html/track/TrackListBase.h b/third_party/WebKit/Source/core/html/track/TrackListBase.h
index ff785543..482a4e8 100644
--- a/third_party/WebKit/Source/core/html/track/TrackListBase.h
+++ b/third_party/WebKit/Source/core/html/track/TrackListBase.h
@@ -50,8 +50,7 @@
 
   void add(T* track) {
     track->setMediaElement(m_mediaElement);
-    m_tracks.append(track);
-    ScriptWrappableVisitor::writeBarrier(this, track);
+    m_tracks.append(TraceWrapperMember<T>(this, track));
     scheduleEvent(TrackEvent::create(EventTypeNames::addtrack, track));
   }
 
@@ -100,7 +99,7 @@
     m_mediaElement->scheduleEvent(event);
   }
 
-  HeapVector<Member<T>> m_tracks;
+  HeapVector<TraceWrapperMember<T>> m_tracks;
   Member<HTMLMediaElement> m_mediaElement;
 };
 
diff --git a/third_party/WebKit/Source/core/input/PointerEventManager.cpp b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
index 21ce995..5dae542 100644
--- a/third_party/WebKit/Source/core/input/PointerEventManager.cpp
+++ b/third_party/WebKit/Source/core/input/PointerEventManager.cpp
@@ -168,6 +168,13 @@
       UseCounter::count(m_frame->document(),
                         UseCounter::PointerEventDispatchPointerDown);
 
+    std::unique_ptr<UserGestureIndicator> gestureIndicator;
+    if (eventType == EventTypeNames::pointerup &&
+        pointerEvent->pointerType() == "touch") {
+      gestureIndicator =
+          wrapUnique(new UserGestureIndicator(UserGestureToken::create()));
+    }
+
     DispatchEventResult dispatchResult = target->dispatchEvent(pointerEvent);
     return EventHandlingUtil::toWebInputEventResult(dispatchResult);
   }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
index 54d1faa..becf36a 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.cpp
@@ -518,6 +518,8 @@
 
 void InspectorDOMAgent::getDocument(
     ErrorString* errorString,
+    const Maybe<int>& depth,
+    const Maybe<bool>& traverseFrames,
     std::unique_ptr<protocol::DOM::Node>* root) {
   // Backward compatibility. Mark agent as enabled when it requests document.
   if (!enabled())
@@ -530,7 +532,13 @@
 
   discardFrontendBindings();
 
-  *root = buildObjectForNode(m_document.get(), 2, m_documentNodeToIdMap.get());
+  int sanitizedDepth = depth.fromMaybe(2);
+  if (sanitizedDepth == -1)
+    sanitizedDepth = INT_MAX;
+
+  *root = buildObjectForNode(m_document.get(), sanitizedDepth,
+                             traverseFrames.fromMaybe(false),
+                             m_documentNodeToIdMap.get());
 }
 
 void InspectorDOMAgent::getLayoutTreeNodes(
@@ -604,7 +612,9 @@
   }
 }
 
-void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId, int depth) {
+void InspectorDOMAgent::pushChildNodesToFrontend(int nodeId,
+                                                 int depth,
+                                                 bool traverseFrames) {
   Node* node = nodeForId(nodeId);
   if (!node || (!node->isElementNode() && !node->isDocumentNode() &&
                 !node->isDocumentFragment()))
@@ -621,14 +631,14 @@
     for (node = innerFirstChild(node); node; node = innerNextSibling(node)) {
       int childNodeId = nodeMap->get(node);
       ASSERT(childNodeId);
-      pushChildNodesToFrontend(childNodeId, depth);
+      pushChildNodesToFrontend(childNodeId, depth, traverseFrames);
     }
 
     return;
   }
 
   std::unique_ptr<protocol::Array<protocol::DOM::Node>> children =
-      buildArrayForContainerChildren(node, depth, nodeMap);
+      buildArrayForContainerChildren(node, depth, traverseFrames, nodeMap);
   frontend()->setChildNodes(nodeId, std::move(children));
 }
 
@@ -685,9 +695,11 @@
     (*classNames)->addItem(className);
 }
 
-void InspectorDOMAgent::requestChildNodes(ErrorString* errorString,
-                                          int nodeId,
-                                          const Maybe<int>& depth) {
+void InspectorDOMAgent::requestChildNodes(
+    ErrorString* errorString,
+    int nodeId,
+    const Maybe<int>& depth,
+    const Maybe<bool>& maybeTaverseFrames) {
   int sanitizedDepth = depth.fromMaybe(1);
   if (sanitizedDepth == 0 || sanitizedDepth < -1) {
     *errorString =
@@ -697,7 +709,8 @@
   if (sanitizedDepth == -1)
     sanitizedDepth = INT_MAX;
 
-  pushChildNodesToFrontend(nodeId, sanitizedDepth);
+  pushChildNodesToFrontend(nodeId, sanitizedDepth,
+                           maybeTaverseFrames.fromMaybe(false));
 }
 
 void InspectorDOMAgent::querySelector(ErrorString* errorString,
@@ -797,7 +810,7 @@
   m_danglingNodeToIdMaps.append(newMap);
   std::unique_ptr<protocol::Array<protocol::DOM::Node>> children =
       protocol::Array<protocol::DOM::Node>::create();
-  children->addItem(buildObjectForNode(node, 0, danglingMap));
+  children->addItem(buildObjectForNode(node, 0, false, danglingMap));
   frontend()->setChildNodes(0, std::move(children));
 
   return pushNodePathToFrontend(nodeToPush, danglingMap);
@@ -1646,6 +1659,7 @@
 std::unique_ptr<protocol::DOM::Node> InspectorDOMAgent::buildObjectForNode(
     Node* node,
     int depth,
+    bool traverseFrames,
     NodeToIdMap* nodesMap) {
   int id = bind(node, nodesMap);
   String localName;
@@ -1690,8 +1704,10 @@
                                   ? toLocalFrame(frameOwner->contentFrame())
                                   : nullptr)
         value->setFrameId(IdentifiersFactory::frameId(frame));
-      if (Document* doc = frameOwner->contentDocument())
-        value->setContentDocument(buildObjectForNode(doc, 0, nodesMap));
+      if (Document* doc = frameOwner->contentDocument()) {
+        value->setContentDocument(buildObjectForNode(
+            doc, traverseFrames ? depth : 0, traverseFrames, nodesMap));
+      }
     }
 
     if (node->parentNode() && node->parentNode()->isDocumentNode()) {
@@ -1705,8 +1721,10 @@
       std::unique_ptr<protocol::Array<protocol::DOM::Node>> shadowRoots =
           protocol::Array<protocol::DOM::Node>::create();
       for (ShadowRoot* root = &shadow->youngestShadowRoot(); root;
-           root = root->olderShadowRoot())
-        shadowRoots->addItem(buildObjectForNode(root, 0, nodesMap));
+           root = root->olderShadowRoot()) {
+        shadowRoots->addItem(
+            buildObjectForNode(root, 0, traverseFrames, nodesMap));
+      }
       value->setShadowRoots(std::move(shadowRoots));
       forcePushChildren = true;
     }
@@ -1714,15 +1732,17 @@
     if (isHTMLLinkElement(*element)) {
       HTMLLinkElement& linkElement = toHTMLLinkElement(*element);
       if (linkElement.isImport() && linkElement.import() &&
-          innerParentNode(linkElement.import()) == linkElement)
-        value->setImportedDocument(
-            buildObjectForNode(linkElement.import(), 0, nodesMap));
+          innerParentNode(linkElement.import()) == linkElement) {
+        value->setImportedDocument(buildObjectForNode(
+            linkElement.import(), 0, traverseFrames, nodesMap));
+      }
       forcePushChildren = true;
     }
 
     if (isHTMLTemplateElement(*element)) {
-      value->setTemplateContent(buildObjectForNode(
-          toHTMLTemplateElement(*element).content(), 0, nodesMap));
+      value->setTemplateContent(
+          buildObjectForNode(toHTMLTemplateElement(*element).content(), 0,
+                             traverseFrames, nodesMap));
       forcePushChildren = true;
     }
 
@@ -1777,7 +1797,7 @@
     if (forcePushChildren && !depth)
       depth = 1;
     std::unique_ptr<protocol::Array<protocol::DOM::Node>> children =
-        buildArrayForContainerChildren(node, depth, nodesMap);
+        buildArrayForContainerChildren(node, depth, traverseFrames, nodesMap);
     if (children->length() > 0 ||
         depth)  // Push children along with shadow in any case.
       value->setChildren(std::move(children));
@@ -1803,6 +1823,7 @@
 std::unique_ptr<protocol::Array<protocol::DOM::Node>>
 InspectorDOMAgent::buildArrayForContainerChildren(Node* container,
                                                   int depth,
+                                                  bool traverseFrames,
                                                   NodeToIdMap* nodesMap) {
   std::unique_ptr<protocol::Array<protocol::DOM::Node>> children =
       protocol::Array<protocol::DOM::Node>::create();
@@ -1812,7 +1833,8 @@
     Node* firstChild = container->firstChild();
     if (firstChild && firstChild->getNodeType() == Node::kTextNode &&
         !firstChild->nextSibling()) {
-      children->addItem(buildObjectForNode(firstChild, 0, nodesMap));
+      children->addItem(
+          buildObjectForNode(firstChild, 0, traverseFrames, nodesMap));
       m_childrenRequested.add(bind(container, nodesMap));
     }
     return children;
@@ -1823,7 +1845,8 @@
   m_childrenRequested.add(bind(container, nodesMap));
 
   while (child) {
-    children->addItem(buildObjectForNode(child, depth, nodesMap));
+    children->addItem(
+        buildObjectForNode(child, depth, traverseFrames, nodesMap));
     child = innerNextSibling(child);
   }
   return children;
@@ -1838,12 +1861,14 @@
 
   std::unique_ptr<protocol::Array<protocol::DOM::Node>> pseudoElements =
       protocol::Array<protocol::DOM::Node>::create();
-  if (element->pseudoElement(PseudoIdBefore))
+  if (element->pseudoElement(PseudoIdBefore)) {
     pseudoElements->addItem(buildObjectForNode(
-        element->pseudoElement(PseudoIdBefore), 0, nodesMap));
-  if (element->pseudoElement(PseudoIdAfter))
-    pseudoElements->addItem(
-        buildObjectForNode(element->pseudoElement(PseudoIdAfter), 0, nodesMap));
+        element->pseudoElement(PseudoIdBefore), 0, false, nodesMap));
+  }
+  if (element->pseudoElement(PseudoIdAfter)) {
+    pseudoElements->addItem(buildObjectForNode(
+        element->pseudoElement(PseudoIdAfter), 0, false, nodesMap));
+  }
   return pseudoElements;
 }
 
@@ -1960,7 +1985,7 @@
   unbind(frameOwner, m_documentNodeToIdMap.get());
 
   std::unique_ptr<protocol::DOM::Node> value =
-      buildObjectForNode(frameOwner, 0, m_documentNodeToIdMap.get());
+      buildObjectForNode(frameOwner, 0, false, m_documentNodeToIdMap.get());
   Node* previousSibling = innerPreviousSibling(frameOwner);
   int prevId =
       previousSibling ? m_documentNodeToIdMap->get(previousSibling) : 0;
@@ -2002,7 +2027,7 @@
     Node* prevSibling = innerPreviousSibling(node);
     int prevId = prevSibling ? m_documentNodeToIdMap->get(prevSibling) : 0;
     std::unique_ptr<protocol::DOM::Node> value =
-        buildObjectForNode(node, 0, m_documentNodeToIdMap.get());
+        buildObjectForNode(node, 0, false, m_documentNodeToIdMap.get());
     frontend()->childNodeInserted(parentId, prevId, std::move(value));
   }
 }
@@ -2121,7 +2146,7 @@
 
   pushChildNodesToFrontend(hostId, 1);
   frontend()->shadowRootPushed(
-      hostId, buildObjectForNode(root, 0, m_documentNodeToIdMap.get()));
+      hostId, buildObjectForNode(root, 0, false, m_documentNodeToIdMap.get()));
 }
 
 void InspectorDOMAgent::willPopShadowRoot(Element* host, ShadowRoot* root) {
@@ -2186,7 +2211,7 @@
   pushChildNodesToFrontend(parentId, 1);
   frontend()->pseudoElementAdded(
       parentId,
-      buildObjectForNode(pseudoElement, 0, m_documentNodeToIdMap.get()));
+      buildObjectForNode(pseudoElement, 0, false, m_documentNodeToIdMap.get()));
 }
 
 void InspectorDOMAgent::pseudoElementDestroyed(PseudoElement* pseudoElement) {
@@ -2351,7 +2376,7 @@
     ErrorString* errorString) {
   if (!m_documentNodeToIdMap->contains(m_document)) {
     std::unique_ptr<protocol::DOM::Node> root;
-    getDocument(errorString, &root);
+    getDocument(errorString, Maybe<int>(), Maybe<bool>(), &root);
     return errorString->isEmpty();
   }
   return true;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h
index 32d10c0..3376c2e 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorDOMAgent.h
@@ -121,6 +121,8 @@
   void enable(ErrorString*) override;
   void disable(ErrorString*) override;
   void getDocument(ErrorString*,
+                   const Maybe<int>& depth,
+                   const Maybe<bool>& traverseFrames,
                    std::unique_ptr<protocol::DOM::Node>* root) override;
   void getLayoutTreeNodes(
       ErrorString*,
@@ -132,7 +134,8 @@
       std::unique_ptr<protocol::Array<String>>* classNames) override;
   void requestChildNodes(ErrorString*,
                          int nodeId,
-                         const Maybe<int>& depth) override;
+                         const Maybe<int>& depth,
+                         const Maybe<bool>& traverseFrames) override;
   void querySelector(ErrorString*,
                      int nodeId,
                      const String& selector,
@@ -322,18 +325,22 @@
   Element* assertEditableElement(ErrorString*, int nodeId);
 
   int pushNodePathToFrontend(Node*, NodeToIdMap* nodeMap);
-  void pushChildNodesToFrontend(int nodeId, int depth = 1);
+  void pushChildNodesToFrontend(int nodeId,
+                                int depth = 1,
+                                bool traverseFrames = false);
 
   void invalidateFrameOwnerElement(LocalFrame*);
 
   std::unique_ptr<protocol::DOM::Node> buildObjectForNode(Node*,
                                                           int depth,
+                                                          bool traverseFrames,
                                                           NodeToIdMap*);
   std::unique_ptr<protocol::Array<String>> buildArrayForElementAttributes(
       Element*);
   std::unique_ptr<protocol::Array<protocol::DOM::Node>>
   buildArrayForContainerChildren(Node* container,
                                  int depth,
+                                 bool traverseFrames,
                                  NodeToIdMap* nodesMap);
   std::unique_ptr<protocol::Array<protocol::DOM::Node>>
   buildArrayForPseudoElements(Element*, NodeToIdMap* nodesMap);
diff --git a/third_party/WebKit/Source/core/inspector/browser_protocol.json b/third_party/WebKit/Source/core/inspector/browser_protocol.json
index a469ff8..e8f88d9b 100644
--- a/third_party/WebKit/Source/core/inspector/browser_protocol.json
+++ b/third_party/WebKit/Source/core/inspector/browser_protocol.json
@@ -2183,10 +2183,14 @@
             },
             {
                 "name": "getDocument",
+                "parameters": [
+                    { "name": "depth", "type": "integer", "optional": true, "description": "The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.", "experimental": true },
+                    { "name": "traverseFrames", "type": "boolean", "optional": true, "description": "Whether or not iframes should be traversed when returning the subtree (default is false).", "experimental": true }
+                ],
                 "returns": [
                     { "name": "root", "$ref": "Node", "description": "Resulting node." }
                 ],
-                "description": "Returns the root DOM node to the caller."
+                "description": "Returns the root DOM node (and optionally the subtree) to the caller."
             },
             {
                 "name": "getLayoutTreeNodes",
@@ -2211,7 +2215,8 @@
                 "name": "requestChildNodes",
                 "parameters": [
                     { "name": "nodeId", "$ref": "NodeId", "description": "Id of the node to get children for." },
-                    { "name": "depth", "type": "integer", "optional": true, "description": "The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.", "experimental": true }
+                    { "name": "depth", "type": "integer", "optional": true, "description": "The maximum depth at which children should be retrieved, defaults to 1. Use -1 for the entire subtree or provide an integer larger than 0.", "experimental": true },
+                    { "name": "traverseFrames", "type": "boolean", "optional": true, "description": "Whether or not iframes should be traversed when returning the sub-tree (default is false).", "experimental": true }
                 ],
                 "description": "Requests that children of the node with given id are returned to the caller in form of <code>setChildNodes</code> events where not only immediate children are retrieved, but all children down to the specified depth."
             },
diff --git a/third_party/WebKit/Source/core/testing/DeathAwareScriptWrappable.h b/third_party/WebKit/Source/core/testing/DeathAwareScriptWrappable.h
index 3b965d2..386ff84 100644
--- a/third_party/WebKit/Source/core/testing/DeathAwareScriptWrappable.h
+++ b/third_party/WebKit/Source/core/testing/DeathAwareScriptWrappable.h
@@ -37,19 +37,51 @@
     s_instance = instance;
   }
 
-  DEFINE_INLINE_VIRTUAL_TRACE() { visitor->trace(m_dependency); }
-
-  DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() {
-    visitor->traceWrappers(m_dependency);
+  DEFINE_INLINE_VIRTUAL_TRACE() {
+    visitor->trace(m_rawDependency);
+    visitor->trace(m_wrappedDependency);
+    visitor->trace(m_wrappedVectorDependency);
+    visitor->trace(m_wrappedHashMapDependency);
   }
 
-  void setDependency(DeathAwareScriptWrappable* dependency) {
+  DEFINE_INLINE_VIRTUAL_TRACE_WRAPPERS() {
+    visitor->traceWrappers(m_rawDependency);
+    visitor->traceWrappers(m_wrappedDependency);
+    for (auto dep : m_wrappedVectorDependency) {
+      visitor->traceWrappers(dep);
+    }
+    for (auto pair : m_wrappedHashMapDependency) {
+      visitor->traceWrappers(pair.key);
+      visitor->traceWrappers(pair.value);
+    }
+  }
+
+  void setRawDependency(DeathAwareScriptWrappable* dependency) {
     ScriptWrappableVisitor::writeBarrier(this, dependency);
-    m_dependency = dependency;
+    m_rawDependency = dependency;
+  }
+
+  void setWrappedDependency(DeathAwareScriptWrappable* dependency) {
+    m_wrappedDependency = dependency;
+  }
+
+  void addWrappedVectorDependency(DeathAwareScriptWrappable* dependency) {
+    m_wrappedVectorDependency.append(Wrapper(this, dependency));
+  }
+
+  void addWrappedHashMapDependency(DeathAwareScriptWrappable* key,
+                                   DeathAwareScriptWrappable* value) {
+    m_wrappedHashMapDependency.add(Wrapper(this, key), Wrapper(this, value));
   }
 
  private:
-  Member<DeathAwareScriptWrappable> m_dependency;
+  typedef TraceWrapperMember<DeathAwareScriptWrappable> Wrapper;
+  DeathAwareScriptWrappable() : m_wrappedDependency(this, nullptr) {}
+
+  Member<DeathAwareScriptWrappable> m_rawDependency;
+  Wrapper m_wrappedDependency;
+  HeapVector<Wrapper> m_wrappedVectorDependency;
+  HeapHashMap<Wrapper, Wrapper> m_wrappedHashMapDependency;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
index c17d001..bddeb4b1 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.cpp
@@ -19,10 +19,13 @@
 namespace {
 
 const AtomicString& remotePlaybackStateToString(WebRemotePlaybackState state) {
+  DEFINE_STATIC_LOCAL(const AtomicString, connectingValue, ("connecting"));
   DEFINE_STATIC_LOCAL(const AtomicString, connectedValue, ("connected"));
   DEFINE_STATIC_LOCAL(const AtomicString, disconnectedValue, ("disconnected"));
 
   switch (state) {
+    case WebRemotePlaybackState::Connecting:
+      return connectingValue;
     case WebRemotePlaybackState::Connected:
       return connectedValue;
     case WebRemotePlaybackState::Disconnected:
@@ -146,7 +149,17 @@
     return;
 
   m_state = state;
-  dispatchEvent(Event::create(EventTypeNames::statechange));
+  switch (m_state) {
+    case WebRemotePlaybackState::Connecting:
+      dispatchEvent(Event::create(EventTypeNames::connecting));
+      break;
+    case WebRemotePlaybackState::Connected:
+      dispatchEvent(Event::create(EventTypeNames::connect));
+      break;
+    case WebRemotePlaybackState::Disconnected:
+      dispatchEvent(Event::create(EventTypeNames::disconnect));
+      break;
+  }
 }
 
 void RemotePlayback::availabilityChanged(bool available) {
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h
index cfab31c..a1b3e7db 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.h
@@ -46,7 +46,9 @@
   // ScriptWrappable implementation.
   bool hasPendingActivity() const final;
 
-  DEFINE_ATTRIBUTE_EVENT_LISTENER(statechange);
+  DEFINE_ATTRIBUTE_EVENT_LISTENER(connecting);
+  DEFINE_ATTRIBUTE_EVENT_LISTENER(connect);
+  DEFINE_ATTRIBUTE_EVENT_LISTENER(disconnect);
 
   DECLARE_VIRTUAL_TRACE();
 
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.idl b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.idl
index f4542ad..65539fb 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.idl
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlayback.idl
@@ -15,7 +15,9 @@
     RuntimeEnabled=RemotePlayback
 ] interface RemotePlayback : EventTarget {
     readonly attribute RemotePlaybackState state;
-    attribute EventHandler onstatechange;
+    attribute EventHandler onconnecting;
+    attribute EventHandler onconnect;
+    attribute EventHandler ondisconnect;
 
     [CallWith=ScriptState] Promise<RemotePlaybackAvailability> getAvailability();
     [CallWith=ScriptState] Promise<void> prompt();
diff --git a/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp b/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
index 87bfdf0..9f83a7e2 100644
--- a/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
+++ b/third_party/WebKit/Source/modules/remoteplayback/RemotePlaybackTest.cpp
@@ -10,6 +10,7 @@
 #include "core/html/HTMLVideoElement.h"
 #include "core/testing/DummyPageHolder.h"
 #include "platform/testing/UnitTestHelpers.h"
+#include "public/platform/modules/remoteplayback/WebRemotePlaybackState.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -30,11 +31,26 @@
       : ScriptFunction(scriptState) {}
 };
 
+class MockEventListener : public EventListener {
+ public:
+  MockEventListener() : EventListener(CPPEventListenerType) {}
+
+  bool operator==(const EventListener& other) const final {
+    return this == &other;
+  }
+
+  MOCK_METHOD2(handleEvent, void(ExecutionContext* executionContext, Event*));
+};
+
 class RemotePlaybackTest : public ::testing::Test {
  protected:
   void cancelPrompt(RemotePlayback* remotePlayback) {
     remotePlayback->promptCancelled();
   }
+
+  void setState(RemotePlayback* remotePlayback, WebRemotePlaybackState state) {
+    remotePlayback->stateChanged(state);
+  }
 };
 
 TEST_F(RemotePlaybackTest, PromptCancelledRejectsWithNotAllowedError) {
@@ -56,4 +72,37 @@
   cancelPrompt(remotePlayback);
 }
 
+TEST_F(RemotePlaybackTest, StateChangeEvents) {
+  V8TestingScope scope;
+
+  auto pageHolder = DummyPageHolder::create();
+
+  HTMLMediaElement* element = HTMLVideoElement::create(pageHolder->document());
+  RemotePlayback* remotePlayback = RemotePlayback::create(*element);
+
+  auto connectingHandler = new ::testing::StrictMock<MockEventListener>();
+  auto connectHandler = new ::testing::StrictMock<MockEventListener>();
+  auto disconnectHandler = new ::testing::StrictMock<MockEventListener>();
+
+  remotePlayback->addEventListener(EventTypeNames::connecting,
+                                   connectingHandler);
+  remotePlayback->addEventListener(EventTypeNames::connect, connectHandler);
+  remotePlayback->addEventListener(EventTypeNames::disconnect,
+                                   disconnectHandler);
+
+  EXPECT_CALL(*connectingHandler, handleEvent(::testing::_, ::testing::_))
+      .Times(1);
+  EXPECT_CALL(*connectHandler, handleEvent(::testing::_, ::testing::_))
+      .Times(1);
+  EXPECT_CALL(*disconnectHandler, handleEvent(::testing::_, ::testing::_))
+      .Times(1);
+
+  setState(remotePlayback, WebRemotePlaybackState::Connecting);
+  setState(remotePlayback, WebRemotePlaybackState::Connecting);
+  setState(remotePlayback, WebRemotePlaybackState::Connected);
+  setState(remotePlayback, WebRemotePlaybackState::Connected);
+  setState(remotePlayback, WebRemotePlaybackState::Disconnected);
+  setState(remotePlayback, WebRemotePlaybackState::Disconnected);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/serviceworkers/BUILD.gn b/third_party/WebKit/Source/modules/serviceworkers/BUILD.gn
index 6312cd9a..550563d 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/BUILD.gn
+++ b/third_party/WebKit/Source/modules/serviceworkers/BUILD.gn
@@ -18,6 +18,8 @@
     "ForeignFetchRespondWithObserver.h",
     "InstallEvent.cpp",
     "InstallEvent.h",
+    "NavigationPreloadCallbacks.cpp",
+    "NavigationPreloadCallbacks.h",
     "NavigationPreloadManager.cpp",
     "NavigationPreloadManager.h",
     "NavigatorServiceWorker.cpp",
diff --git a/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadCallbacks.cpp b/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadCallbacks.cpp
new file mode 100644
index 0000000..583bc9e7
--- /dev/null
+++ b/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadCallbacks.cpp
@@ -0,0 +1,59 @@
+// 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 "modules/serviceworkers/NavigationPreloadCallbacks.h"
+
+#include "bindings/core/v8/ScriptPromiseResolver.h"
+#include "core/dom/DOMException.h"
+#include "modules/serviceworkers/ServiceWorkerError.h"
+
+namespace blink {
+
+EnableNavigationPreloadCallbacks::EnableNavigationPreloadCallbacks(
+    ScriptPromiseResolver* resolver)
+    : m_resolver(resolver) {
+  DCHECK(m_resolver);
+}
+
+EnableNavigationPreloadCallbacks::~EnableNavigationPreloadCallbacks() {}
+
+void EnableNavigationPreloadCallbacks::onSuccess() {
+  if (!m_resolver->getExecutionContext() ||
+      m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
+    return;
+  m_resolver->resolve();
+}
+
+void EnableNavigationPreloadCallbacks::onError(
+    const WebServiceWorkerError& error) {
+  if (!m_resolver->getExecutionContext() ||
+      m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
+    return;
+  m_resolver->reject(ServiceWorkerError::take(m_resolver.get(), error));
+}
+
+DisableNavigationPreloadCallbacks::DisableNavigationPreloadCallbacks(
+    ScriptPromiseResolver* resolver)
+    : m_resolver(resolver) {
+  DCHECK(m_resolver);
+}
+
+DisableNavigationPreloadCallbacks::~DisableNavigationPreloadCallbacks() {}
+
+void DisableNavigationPreloadCallbacks::onSuccess() {
+  if (!m_resolver->getExecutionContext() ||
+      m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
+    return;
+  m_resolver->resolve();
+}
+
+void DisableNavigationPreloadCallbacks::onError(
+    const WebServiceWorkerError& error) {
+  if (!m_resolver->getExecutionContext() ||
+      m_resolver->getExecutionContext()->activeDOMObjectsAreStopped())
+    return;
+  m_resolver->reject(ServiceWorkerError::take(m_resolver.get(), error));
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadCallbacks.h b/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadCallbacks.h
new file mode 100644
index 0000000..497246fd
--- /dev/null
+++ b/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadCallbacks.h
@@ -0,0 +1,48 @@
+// 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 NavigationPreloadCallbacks_h
+#define NavigationPreloadCallbacks_h
+
+#include "public/platform/modules/serviceworker/WebServiceWorkerRegistration.h"
+
+namespace blink {
+
+class ScriptPromiseResolver;
+struct WebServiceWorkerError;
+
+class EnableNavigationPreloadCallbacks final
+    : public WebServiceWorkerRegistration::WebEnableNavigationPreloadCallbacks {
+ public:
+  EnableNavigationPreloadCallbacks(ScriptPromiseResolver*);
+  ~EnableNavigationPreloadCallbacks() override;
+
+  // WebEnableNavigationPreloadCallbacks interface.
+  void onSuccess() override;
+  void onError(const WebServiceWorkerError&) override;
+
+ private:
+  Persistent<ScriptPromiseResolver> m_resolver;
+  WTF_MAKE_NONCOPYABLE(EnableNavigationPreloadCallbacks);
+};
+
+class DisableNavigationPreloadCallbacks final
+    : public WebServiceWorkerRegistration::
+          WebDisableNavigationPreloadCallbacks {
+ public:
+  DisableNavigationPreloadCallbacks(ScriptPromiseResolver*);
+  ~DisableNavigationPreloadCallbacks() override;
+
+  // WebDisableNavigationPreloadCallbacks interface.
+  void onSuccess() override;
+  void onError(const WebServiceWorkerError&) override;
+
+ private:
+  Persistent<ScriptPromiseResolver> m_resolver;
+  WTF_MAKE_NONCOPYABLE(DisableNavigationPreloadCallbacks);
+};
+
+}  // namespace blink
+
+#endif  // NavigationPreloadCallbacks_h
diff --git a/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadManager.cpp b/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadManager.cpp
index d8487b7..1b03b42 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadManager.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadManager.cpp
@@ -4,16 +4,25 @@
 
 #include "modules/serviceworkers/NavigationPreloadManager.h"
 
+#include "modules/serviceworkers/NavigationPreloadCallbacks.h"
+#include "modules/serviceworkers/ServiceWorkerRegistration.h"
+
 namespace blink {
 
-ScriptPromise NavigationPreloadManager::enable(ScriptState*) {
-  NOTIMPLEMENTED();
-  return ScriptPromise();
+ScriptPromise NavigationPreloadManager::enable(ScriptState* scriptState) {
+  ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
+  ScriptPromise promise = resolver->promise();
+  m_registration->webRegistration()->enableNavigationPreload(
+      new EnableNavigationPreloadCallbacks(resolver));
+  return promise;
 }
 
-ScriptPromise NavigationPreloadManager::disable(ScriptState*) {
-  NOTIMPLEMENTED();
-  return ScriptPromise();
+ScriptPromise NavigationPreloadManager::disable(ScriptState* scriptState) {
+  ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
+  ScriptPromise promise = resolver->promise();
+  m_registration->webRegistration()->disableNavigationPreload(
+      new DisableNavigationPreloadCallbacks(resolver));
+  return promise;
 }
 
 ScriptPromise NavigationPreloadManager::setHeaderValue(ScriptState*,
@@ -27,6 +36,12 @@
   return ScriptPromise();
 }
 
-NavigationPreloadManager::NavigationPreloadManager() {}
+NavigationPreloadManager::NavigationPreloadManager(
+    ServiceWorkerRegistration* registration)
+    : m_registration(registration) {}
+
+DEFINE_TRACE(NavigationPreloadManager) {
+  visitor->trace(m_registration);
+}
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadManager.h b/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadManager.h
index 2c6512f..4f61c47c 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadManager.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/NavigationPreloadManager.h
@@ -11,14 +11,17 @@
 
 namespace blink {
 
+class ServiceWorkerRegistration;
+
 class NavigationPreloadManager final
     : public GarbageCollected<NavigationPreloadManager>,
       public ScriptWrappable {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
-  static NavigationPreloadManager* create() {
-    return new NavigationPreloadManager();
+  static NavigationPreloadManager* create(
+      ServiceWorkerRegistration* registration) {
+    return new NavigationPreloadManager(registration);
   }
 
   ScriptPromise enable(ScriptState*);
@@ -26,10 +29,12 @@
   ScriptPromise setHeaderValue(ScriptState*, const String& value);
   ScriptPromise getState(ScriptState*);
 
-  DEFINE_INLINE_TRACE() {}
+  DECLARE_TRACE();
 
  private:
-  NavigationPreloadManager();
+  explicit NavigationPreloadManager(ServiceWorkerRegistration*);
+
+  Member<ServiceWorkerRegistration> m_registration;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerRegistration.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerRegistration.cpp
index 5796077..516e59a 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerRegistration.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerRegistration.cpp
@@ -76,7 +76,7 @@
 
 NavigationPreloadManager* ServiceWorkerRegistration::navigationPreload() {
   if (!m_navigationPreload)
-    m_navigationPreload = NavigationPreloadManager::create();
+    m_navigationPreload = NavigationPreloadManager::create(this);
   return m_navigationPreload;
 }
 
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index f797e4ff..1fa21047 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -324,6 +324,7 @@
     "WebIconSizesParser.cpp",
     "WebScheduler.cpp",
     "WebTaskRunner.cpp",
+    "WebTextInputInfo.cpp",
     "WebThread.cpp",
     "WebThreadSupportingGC.cpp",
     "WebThreadSupportingGC.h",
diff --git a/third_party/WebKit/Source/web/WebTextInputInfo.cpp b/third_party/WebKit/Source/platform/WebTextInputInfo.cpp
similarity index 97%
rename from third_party/WebKit/Source/web/WebTextInputInfo.cpp
rename to third_party/WebKit/Source/platform/WebTextInputInfo.cpp
index 79e0e390..4886c74 100644
--- a/third_party/WebKit/Source/web/WebTextInputInfo.cpp
+++ b/third_party/WebKit/Source/platform/WebTextInputInfo.cpp
@@ -28,7 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "public/web/WebTextInputInfo.h"
+#include "public/platform/WebTextInputInfo.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
index cb2aae1..5c1a7e50 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzFace.cpp
@@ -84,6 +84,21 @@
   HarfBuzzFontData()
       : m_paint(), m_simpleFontData(nullptr), m_rangeSet(nullptr) {}
 
+  ~HarfBuzzFontData() {
+    if (m_simpleFontData)
+      FontCache::fontCache()->releaseFontData(m_simpleFontData);
+  }
+
+  void updateSimpleFontData(FontPlatformData* platformData) {
+    SimpleFontData* simpleFontData =
+        FontCache::fontCache()
+            ->fontDataFromFontPlatformData(platformData)
+            .get();
+    if (m_simpleFontData)
+      FontCache::fontCache()->releaseFontData(m_simpleFontData);
+    m_simpleFontData = simpleFontData;
+  }
+
   SkPaint m_paint;
   SimpleFontData* m_simpleFontData;
   RefPtr<UnicodeRangeSet> m_rangeSet;
@@ -370,10 +385,7 @@
   m_platformData->setupPaint(&m_harfBuzzFontData->m_paint);
   m_harfBuzzFontData->m_paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
   m_harfBuzzFontData->m_rangeSet = rangeSet;
-  m_harfBuzzFontData->m_simpleFontData =
-      FontCache::fontCache()
-          ->fontDataFromFontPlatformData(m_platformData)
-          .get();
+  m_harfBuzzFontData->updateSimpleFontData(m_platformData);
   ASSERT(m_harfBuzzFontData->m_simpleFontData);
   int scale = SkiaScalarToHarfBuzzPosition(m_platformData->size());
   hb_font_set_scale(m_unscaledFont, scale, scale);
diff --git a/third_party/WebKit/Source/platform/heap/HeapAllocator.h b/third_party/WebKit/Source/platform/heap/HeapAllocator.h
index d62e793..69ea46bf 100644
--- a/third_party/WebKit/Source/platform/heap/HeapAllocator.h
+++ b/third_party/WebKit/Source/platform/heap/HeapAllocator.h
@@ -463,6 +463,16 @@
 };
 
 template <typename T>
+struct VectorTraits<blink::TraceWrapperMember<T>>
+    : VectorTraitsBase<blink::TraceWrapperMember<T>> {
+  STATIC_ONLY(VectorTraits);
+  static const bool needsDestruction = false;
+  static const bool canInitializeWithMemset = true;
+  static const bool canClearUnusedSlotsWithMemset = true;
+  static const bool canMoveWithMemcpy = true;
+};
+
+template <typename T>
 struct VectorTraits<blink::WeakMember<T>>
     : VectorTraitsBase<blink::WeakMember<T>> {
   STATIC_ONLY(VectorTraits);
@@ -576,6 +586,45 @@
 };
 
 template <typename T>
+struct HashTraits<blink::TraceWrapperMember<T>>
+    : SimpleClassHashTraits<blink::TraceWrapperMember<T>> {
+  STATIC_ONLY(HashTraits);
+  // FIXME: The distinction between PeekInType and PassInType is there for
+  // the sake of the reference counting handles. When they are gone the two
+  // types can be merged into PassInType.
+  // FIXME: Implement proper const'ness for iterator types. Requires support
+  // in the marking Visitor.
+  using PeekInType = T*;
+  using PassInType = T*;
+  using IteratorGetType = blink::TraceWrapperMember<T>*;
+  using IteratorConstGetType = const blink::TraceWrapperMember<T>*;
+  using IteratorReferenceType = blink::TraceWrapperMember<T>&;
+  using IteratorConstReferenceType = const blink::TraceWrapperMember<T>&;
+  static IteratorReferenceType getToReferenceConversion(IteratorGetType x) {
+    return *x;
+  }
+  static IteratorConstReferenceType getToReferenceConstConversion(
+      IteratorConstGetType x) {
+    return *x;
+  }
+
+  using PeekOutType = T*;
+
+  template <typename U>
+  static void store(const U& value, blink::TraceWrapperMember<T>& storage) {
+    storage = value;
+  }
+
+  static PeekOutType peek(const blink::TraceWrapperMember<T>& value) {
+    return value;
+  }
+
+  static blink::TraceWrapperMember<T> emptyValue() {
+    return blink::TraceWrapperMember<T>(nullptr, nullptr);
+  }
+};
+
+template <typename T>
 struct HashTraits<blink::WeakMember<T>>
     : SimpleClassHashTraits<blink::WeakMember<T>> {
   STATIC_ONLY(HashTraits);
diff --git a/third_party/WebKit/Source/platform/heap/Member.h b/third_party/WebKit/Source/platform/heap/Member.h
index cb9dbd53..aec34ac 100644
--- a/third_party/WebKit/Source/platform/heap/Member.h
+++ b/third_party/WebKit/Source/platform/heap/Member.h
@@ -13,6 +13,8 @@
 
 template <typename T>
 class Persistent;
+template <typename T>
+class TraceWrapperMember;
 
 enum class TracenessMemberConfiguration {
   Traced,
@@ -401,6 +403,12 @@
 };
 
 template <typename T>
+struct DefaultHash<blink::TraceWrapperMember<T>> {
+  STATIC_ONLY(DefaultHash);
+  using Hash = MemberHash<T>;
+};
+
+template <typename T>
 struct IsTraceable<blink::Member<T>> {
   STATIC_ONLY(IsTraceable);
   static const bool value = true;
@@ -418,6 +426,12 @@
   static const bool value = true;
 };
 
+template <typename T>
+struct IsTraceable<blink::TraceWrapperMember<T>> {
+  STATIC_ONLY(IsTraceable);
+  static const bool value = true;
+};
+
 }  // namespace WTF
 
 #endif  // Member_h
diff --git a/third_party/WebKit/Source/platform/heap/ThreadingTraits.h b/third_party/WebKit/Source/platform/heap/ThreadingTraits.h
index 8aed039f9a..7dfffb55 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadingTraits.h
+++ b/third_party/WebKit/Source/platform/heap/ThreadingTraits.h
@@ -18,6 +18,9 @@
 
 namespace blink {
 
+template <typename T>
+class TraceWrapperMember;
+
 // ThreadAffinity indicates which threads objects can be used on. We
 // distinguish between objects that can be used on the main thread
 // only and objects that can be used on any thread.
@@ -80,6 +83,12 @@
 };
 
 template <typename T>
+struct ThreadingTrait<TraceWrapperMember<T>> {
+  STATIC_ONLY(ThreadingTrait);
+  static const ThreadAffinity Affinity = ThreadingTrait<T>::Affinity;
+};
+
+template <typename T>
 struct ThreadingTrait<WeakMember<T>> {
   STATIC_ONLY(ThreadingTrait);
   static const ThreadAffinity Affinity = ThreadingTrait<T>::Affinity;
diff --git a/third_party/WebKit/Source/platform/heap/TraceTraits.h b/third_party/WebKit/Source/platform/heap/TraceTraits.h
index e734a7f..a36afa751 100644
--- a/third_party/WebKit/Source/platform/heap/TraceTraits.h
+++ b/third_party/WebKit/Source/platform/heap/TraceTraits.h
@@ -346,6 +346,14 @@
 };
 
 template <typename T>
+class TraceEagerlyTrait<TraceWrapperMember<T>> {
+  STATIC_ONLY(TraceEagerlyTrait);
+
+ public:
+  static const bool value = TraceEagerlyTrait<T>::value;
+};
+
+template <typename T>
 class TraceEagerlyTrait<WeakMember<T>> {
   STATIC_ONLY(TraceEagerlyTrait);
 
diff --git a/third_party/WebKit/Source/platform/heap/Visitor.h b/third_party/WebKit/Source/platform/heap/Visitor.h
index eddab64..b9987e2 100644
--- a/third_party/WebKit/Source/platform/heap/Visitor.h
+++ b/third_party/WebKit/Source/platform/heap/Visitor.h
@@ -52,6 +52,8 @@
 class TraceEagerlyTrait;
 class ThreadState;
 class Visitor;
+template <typename T>
+class TraceWrapperMember;
 
 // The TraceMethodDelegate is used to convert a trace method for type T to a
 // TraceCallback.  This allows us to pass a type's trace method as a parameter
@@ -158,6 +160,11 @@
     mark(t.get());
   }
 
+  template <typename T>
+  void trace(const TraceWrapperMember<T>& t) {
+    trace(*(static_cast<const Member<T>*>(&t)));
+  }
+
   // Fallback method used only when we need to trace raw pointers of T.
   // This is the case when a member is a union where we do not support members.
   template <typename T>
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn
index 50336b16..df66130 100644
--- a/third_party/WebKit/Source/web/BUILD.gn
+++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -244,7 +244,6 @@
     "WebTextCheckingCompletionImpl.cpp",
     "WebTextCheckingCompletionImpl.h",
     "WebTextCheckingResult.cpp",
-    "WebTextInputInfo.cpp",
     "WebUserGestureIndicator.cpp",
     "WebUserGestureToken.cpp",
     "WebUserMediaRequest.cpp",
diff --git a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
index c522068..cefeb8b 100644
--- a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
+++ b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.cpp
@@ -244,7 +244,8 @@
     int eventID,
     const WebString& notificationID,
     const WebNotificationData& data,
-    int actionIndex) {
+    int actionIndex,
+    const WebString& reply) {
   WaitUntilObserver* observer = WaitUntilObserver::create(
       workerGlobalScope(), WaitUntilObserver::NotificationClick, eventID);
   NotificationEventInit eventInit;
@@ -252,6 +253,7 @@
       workerGlobalScope(), notificationID, data, true /* showing */));
   if (0 <= actionIndex && actionIndex < static_cast<int>(data.actions.size()))
     eventInit.setAction(data.actions[actionIndex].action);
+  eventInit.setReply(reply);
   Event* event = NotificationEvent::create(EventTypeNames::notificationclick,
                                            eventInit, observer);
   workerGlobalScope()->dispatchExtendableEvent(event, observer);
diff --git a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.h b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.h
index 5ce6d4da..a135654 100644
--- a/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.h
+++ b/third_party/WebKit/Source/web/ServiceWorkerGlobalScopeProxy.h
@@ -98,7 +98,8 @@
   void dispatchNotificationClickEvent(int,
                                       const WebString& notificationID,
                                       const WebNotificationData&,
-                                      int actionIndex) override;
+                                      int actionIndex,
+                                      const WebString& reply) override;
   void dispatchNotificationCloseEvent(int,
                                       const WebString& notificationID,
                                       const WebNotificationData&) override;
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index 59f134b..6dcc13d7 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -130,6 +130,7 @@
 #include "public/platform/WebImage.h"
 #include "public/platform/WebLayerTreeView.h"
 #include "public/platform/WebScheduler.h"
+#include "public/platform/WebTextInputInfo.h"
 #include "public/platform/WebURLRequest.h"
 #include "public/platform/WebVector.h"
 #include "public/platform/WebViewScheduler.h"
@@ -151,7 +152,6 @@
 #include "public/web/WebRange.h"
 #include "public/web/WebScopedUserGesture.h"
 #include "public/web/WebSelection.h"
-#include "public/web/WebTextInputInfo.h"
 #include "public/web/WebViewClient.h"
 #include "public/web/WebWindowFeatures.h"
 #include "web/CompositionUnderlineVectorBuilder.h"
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py
index a592ebc..861d0b0 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/servers/wptserve.py
@@ -42,7 +42,10 @@
         if self._port_obj.host.filesystem.exists(path_to_ws_handlers):
             start_cmd += ['--ws_doc_root', path_to_ws_handlers]
 
-        self._stdout = self._stderr = self._executive.DEVNULL
+        # TODO(tkent): Do not suppress console output on Windows until
+        # crbug.com/623613 is resolved.
+        if not self._platform.is_win():
+            self._stdout = self._stderr = self._executive.DEVNULL
         # TODO(burnik): We should stop setting the CWD once WPT can be run without it.
         self._cwd = path_to_wpt_root
         self._env = {'PYTHONPATH': path_to_thirdparty}
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index d1d51a63..44d66f9e 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -76,7 +76,7 @@
     sources = [
       "./platform/WebDisplayMode.h",
       "./platform/WebInputEvent.h",
-      "./web/WebTextInputType.h",
+      "./platform/WebTextInputType.h",
     ]
   }
 
@@ -295,6 +295,8 @@
     "platform/WebString.h",
     "platform/WebSuspendableTask.h",
     "platform/WebTaskRunner.h",
+    "platform/WebTextInputInfo.h",
+    "platform/WebTextInputType.h",
     "platform/WebTextRun.h",
     "platform/WebThemeEngine.h",
     "platform/WebThread.h",
@@ -553,8 +555,6 @@
     "web/WebTextCheckingResult.h",
     "web/WebTextDecorationType.h",
     "web/WebTextDirection.h",
-    "web/WebTextInputInfo.h",
-    "web/WebTextInputType.h",
     "web/WebTouchAction.h",
     "web/WebTreeScopeType.h",
     "web/WebURLLoaderOptions.h",
diff --git a/third_party/WebKit/public/web/WebTextInputInfo.h b/third_party/WebKit/public/platform/WebTextInputInfo.h
similarity index 95%
rename from third_party/WebKit/public/web/WebTextInputInfo.h
rename to third_party/WebKit/public/platform/WebTextInputInfo.h
index ca71b5d..61f8ecc 100644
--- a/third_party/WebKit/public/web/WebTextInputInfo.h
+++ b/third_party/WebKit/public/platform/WebTextInputInfo.h
@@ -26,7 +26,8 @@
 #ifndef WebTextInputInfo_h
 #define WebTextInputInfo_h
 
-#include "../platform/WebString.h"
+#include "WebCommon.h"
+#include "WebString.h"
 #include "WebTextInputType.h"
 
 namespace blink {
@@ -56,7 +57,7 @@
   // This string is lower-case.
   WebString inputMode;
 
-  BLINK_EXPORT bool equals(const WebTextInputInfo&) const;
+  BLINK_PLATFORM_EXPORT bool equals(const WebTextInputInfo&) const;
 
   WebTextInputInfo()
       : type(WebTextInputTypeNone),
diff --git a/third_party/WebKit/public/web/WebTextInputType.h b/third_party/WebKit/public/platform/WebTextInputType.h
similarity index 100%
rename from third_party/WebKit/public/web/WebTextInputType.h
rename to third_party/WebKit/public/platform/WebTextInputType.h
diff --git a/third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackState.h b/third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackState.h
index df1cdcc0..5697e35 100644
--- a/third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackState.h
+++ b/third_party/WebKit/public/platform/modules/remoteplayback/WebRemotePlaybackState.h
@@ -8,7 +8,8 @@
 namespace blink {
 
 enum class WebRemotePlaybackState {
-  Connected = 0,
+  Connecting = 0,
+  Connected,
   Disconnected,
 };
 
diff --git a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRegistration.h b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRegistration.h
index ac80115..c7a393d 100644
--- a/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRegistration.h
+++ b/third_party/WebKit/public/platform/modules/serviceworker/WebServiceWorkerRegistration.h
@@ -26,6 +26,10 @@
       WebCallbacks<void, const WebServiceWorkerError&>;
   using WebServiceWorkerUnregistrationCallbacks =
       WebCallbacks<bool, const WebServiceWorkerError&>;
+  using WebEnableNavigationPreloadCallbacks =
+      WebCallbacks<void, const WebServiceWorkerError&>;
+  using WebDisableNavigationPreloadCallbacks =
+      WebCallbacks<void, const WebServiceWorkerError&>;
 
   // The handle interface that retains a reference to the implementation of
   // WebServiceWorkerRegistration in the embedder and is owned by
@@ -46,6 +50,9 @@
                       WebServiceWorkerUpdateCallbacks*) {}
   virtual void unregister(WebServiceWorkerProvider*,
                           WebServiceWorkerUnregistrationCallbacks*) {}
+
+  virtual void enableNavigationPreload(WebEnableNavigationPreloadCallbacks*) {}
+  virtual void disableNavigationPreload(WebEnableNavigationPreloadCallbacks*) {}
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/public/web/WebWidget.h b/third_party/WebKit/public/web/WebWidget.h
index 9aaff922..b5b544c 100644
--- a/third_party/WebKit/public/web/WebWidget.h
+++ b/third_party/WebKit/public/web/WebWidget.h
@@ -38,11 +38,11 @@
 #include "../platform/WebPoint.h"
 #include "../platform/WebRect.h"
 #include "../platform/WebSize.h"
+#include "../platform/WebTextInputInfo.h"
 #include "../platform/WebTopControlsState.h"
 #include "WebCompositionUnderline.h"
 #include "WebRange.h"
 #include "WebTextDirection.h"
-#include "WebTextInputInfo.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h
index 4f262ec..e54f7c6 100644
--- a/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h
+++ b/third_party/WebKit/public/web/modules/serviceworker/WebServiceWorkerContextProxy.h
@@ -78,7 +78,8 @@
   virtual void dispatchNotificationClickEvent(int eventID,
                                               const WebString& notificationID,
                                               const WebNotificationData&,
-                                              int actionIndex) = 0;
+                                              int actionIndex,
+                                              const WebString& reply) = 0;
   virtual void dispatchNotificationCloseEvent(int eventID,
                                               const WebString& notificationID,
                                               const WebNotificationData&) = 0;
diff --git a/third_party/libwebp/README.chromium b/third_party/libwebp/README.chromium
index 4c69745..77ac2a9f 100644
--- a/third_party/libwebp/README.chromium
+++ b/third_party/libwebp/README.chromium
@@ -22,6 +22,8 @@
  * Merged COPYING/PATENTS to LICENSE
  * Disabled "-frename-registers" flag for ARM64 linux build as clang(3.9.0)
    build fails with error - unsupported flag.
+ * Disabled the SSE2 version of VerticalUnfilter due to a crash on android
+   (crbug.com/654974)
 Cherry-picks:
   Revert patch f7fc4bc: dec/webp.c: don't wait for data before reporting w/h
   Revert patch d1c359e: fix shared object build with -fvisibility=hidden
diff --git a/third_party/libwebp/dsp/filters_sse2.c b/third_party/libwebp/dsp/filters_sse2.c
index 67f7799..61bc6b5 100644
--- a/third_party/libwebp/dsp/filters_sse2.c
+++ b/third_party/libwebp/dsp/filters_sse2.c
@@ -315,7 +315,9 @@
 
 WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitSSE2(void) {
   WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter;
-  WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter;
+  // crbug.com/654974
+  // WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter;
+  (void)VerticalUnfilter;
   WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter;
 
   WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter;
diff --git a/tools/gn/bootstrap/bootstrap.py b/tools/gn/bootstrap/bootstrap.py
index 749ee36..5db0f3a1 100755
--- a/tools/gn/bootstrap/bootstrap.py
+++ b/tools/gn/bootstrap/bootstrap.py
@@ -498,6 +498,7 @@
       'base/trace_event/process_memory_totals.cc',
       'base/trace_event/trace_buffer.cc',
       'base/trace_event/trace_config.cc',
+      'base/trace_event/trace_event.cc',
       'base/trace_event/trace_event_argument.cc',
       'base/trace_event/trace_event_impl.cc',
       'base/trace_event/trace_event_memory_overhead.cc',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 0f9e7c8..c347a3d 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -5780,6 +5780,9 @@
 
 <histogram name="ChromeGeneratedCustomTab.IntentToFirstCommitNavigationTime"
     units="ms">
+  <obsolete>
+    Deprecated 10/2016 in favor of .IntentToFirstCommitNavigationTime2.*.
+  </obsolete>
   <owner>lizeb@chromium.org</owner>
   <summary>
     Time between the intent arrival in a Chrome generated CCT and the first
@@ -5788,11 +5791,22 @@
   </summary>
 </histogram>
 
+<histogram name="ChromeGeneratedCustomTab.IntentToFirstCommitNavigationTime2"
+    units="ms">
+  <owner>lizeb@chromium.org</owner>
+  <summary>
+    In &quot;Herb&quot; mode shows the time between the intent arrival in a
+    Chrome generated CCT and the first navigation commit, if the navigation is
+    successful. Similar in principle to Startup.FirstCommitNavigationTime.
+  </summary>
+</histogram>
+
 <histogram name="ChromeGeneratedCustomTab.IntentToPageLoadedTime" units="ms">
   <owner>lizeb@chromium.org</owner>
   <summary>
-    Time between the intent arrival in a Chrome generated CCT and the first
-    &quot;page loaded&quot; event, if the navigation is successful.
+    In &quot;Herb&quot; mode shows time between the intent arrival in a Chrome
+    generated CCT and the first &quot;page loaded&quot; event, if the navigation
+    is successful.
   </summary>
 </histogram>
 
@@ -7934,6 +7948,9 @@
 </histogram>
 
 <histogram name="CustomTabs.IntentToFirstCommitNavigationTime" units="ms">
+  <obsolete>
+    Deprecated 10/2016 in favor of .IntentToFirstCommitNavigationTime2.*.
+  </obsolete>
   <owner>lizeb@chromium.org</owner>
   <summary>
     Time between the intent arrival in Chrome and the first navigation commit,
@@ -7942,11 +7959,21 @@
   </summary>
 </histogram>
 
+<histogram name="CustomTabs.IntentToFirstCommitNavigationTime2" units="ms">
+  <owner>lizeb@chromium.org</owner>
+  <summary>
+    Time between the intent arrival to a Custom Tab and the first navigation
+    commit, if the navigation is successful. Similar in principle to
+    Startup.FirstCommitNavigationTime. Non-&quot;Herb&quot; mode.
+  </summary>
+</histogram>
+
 <histogram name="CustomTabs.IntentToPageLoadedTime" units="ms">
   <owner>lizeb@chromium.org</owner>
   <summary>
     Time between the intent arrival in Chrome and the first &quot;page
-    loaded&quot; event, if the navigation is successful.
+    loaded&quot; event, if the navigation is successful. Non-&quot;Herb&quot;
+    mode.
   </summary>
 </histogram>
 
@@ -14153,7 +14180,7 @@
   <owner>tdresser@chromium.org</owner>
   <owner>caseq@chromium.org</owner>
   <summary>
-    Whether the timestapms on input events produced by the windowing system
+    Whether the timestamps on input events produced by the windowing system
     appear to be sharing the same time base as TimeTicks, modulo possible
     roll-over.
   </summary>
@@ -59514,6 +59541,13 @@
   </summary>
 </histogram>
 
+<histogram name="SpecialLocale.PromotionDialog" enum="SpecialLocalePromoAction">
+  <owner>ianwen@chromium.org</owner>
+  <summary>
+    Records how users interact with the special locale promotion dialog.
+  </summary>
+</histogram>
+
 <histogram name="SpellCheck.SpellingService.Enabled" enum="BooleanEnabled">
   <owner>groby@chromium.org</owner>
   <owner>rlp@chromium.org</owner>
@@ -79579,6 +79613,7 @@
   <int value="346" label="Enables force sign in for browser."/>
   <int value="347" label="Always open PDF in external viewer."/>
   <int value="348" label="Force YouTube Restricted Mode"/>
+  <int value="349" label="Report information about the status of Android."/>
 </enum>
 
 <enum name="EnterprisePolicyInvalidations" type="int">
@@ -98649,6 +98684,13 @@
   <int value="1" label="sent"/>
 </enum>
 
+<enum name="SpecialLocalePromoAction" type="int">
+  <int value="0" label="Use Sogou"/>
+  <int value="1" label="Keep Google"/>
+  <int value="2" label="Settings"/>
+  <int value="3" label="Back key"/>
+</enum>
+
 <enum name="SpecialShFileOperationCodes" type="int">
   <summary>Legacy error codes still returned by |ShFileOperation()|</summary>
   <int value="5" label="Access denied (Win32)"/>
@@ -103424,13 +103466,33 @@
 </histogram_suffixes>
 
 <histogram_suffixes name="BlinkCanvasToDataURLTime" separator=".">
-  <suffix name="BMP"/>
-  <suffix name="GIF"/>
-  <suffix name="ICON"/>
+  <suffix name="BMP">
+    <obsolete>
+      Removed in Oct 2016
+    </obsolete>
+  </suffix>
+  <suffix name="GIF">
+    <obsolete>
+      Removed in Oct 2016
+    </obsolete>
+  </suffix>
+  <suffix name="ICON">
+    <obsolete>
+      Removed in Oct 2016
+    </obsolete>
+  </suffix>
   <suffix name="JPEG"/>
   <suffix name="PNG"/>
-  <suffix name="TIFF"/>
-  <suffix name="Unknown"/>
+  <suffix name="TIFF">
+    <obsolete>
+      Removed in Oct 2016
+    </obsolete>
+  </suffix>
+  <suffix name="Unknown">
+    <obsolete>
+      Removed in Oct 2016
+    </obsolete>
+  </suffix>
   <suffix name="WEBP"/>
   <affected-histogram name="Blink.Canvas.ToDataURL"/>
 </histogram_suffixes>
@@ -105565,6 +105627,17 @@
   <affected-histogram name="PLT.PT_StartToFinish"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="IntentToFirstCommitZoom" separator=".">
+  <owner>lizeb@chromium.org</owner>
+  <owner>pasko@chromium.org</owner>
+  <suffix name="ZoomedIn" label="Zoomed in view: shorter range, more buckets."/>
+  <suffix name="ZoomedOut"
+      label="Zoomed out view: longer time range, less buckets."/>
+  <affected-histogram
+      name="ChromeGeneratedCustomTab.IntentToFirstCommitNavigationTime2"/>
+  <affected-histogram name="CustomTabs.IntentToFirstCommitNavigationTime2"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="InterProcessTimeTicksConversionType">
   <owner>ppi@chromium.org</owner>
   <suffix name="BrowserToRenderer"/>
@@ -110060,6 +110133,12 @@
   <affected-histogram name="ThreadWatcher.UnresponsiveThreads"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="TimestampTimebaseProcess" separator=".">
+  <suffix name="Browser"/>
+  <suffix name="Renderer"/>
+  <affected-histogram name="Event.TimestampHasValidTimebase"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="TotalTimeToHttpsGoogle" separator=".">
   <suffix name="Quic">
     <obsolete>
diff --git a/tools/perf/benchmarks/system_health.py b/tools/perf/benchmarks/system_health.py
index c45a9de..4cbd8a9a 100644
--- a/tools/perf/benchmarks/system_health.py
+++ b/tools/perf/benchmarks/system_health.py
@@ -88,6 +88,7 @@
 
   https://goo.gl/Jek2NL.
   """
+  options = {'pageset_repeat': 3}
 
   def SetExtraBrowserOptions(self, options):
     options.AppendExtraBrowserArgs([
diff --git a/tools/perf/generate_perf_json.py b/tools/perf/generate_perf_json.py
index 076ed8e..97564be 100755
--- a/tools/perf/generate_perf_json.py
+++ b/tools/perf/generate_perf_json.py
@@ -235,9 +235,13 @@
     'win-low-end-2-core', 'win',
     swarming=[
       {
+       'gpu': '8086:22b1',
+       'os': 'Windows-10-10586',
        'device_ids': ['build187-b4']
       },
       {
+       'gpu': '1002:9874',
+       'os': 'Windows-10-10586',
        'device_ids': ['build171-b4', 'build186-b4']
       }
     ])
@@ -395,7 +399,10 @@
       # Id is unique within the swarming pool so it is the only needed
       # identifier for the bot to run the test on
       swarming_dimensions.append({
-        'id': device_id
+        'id': device_id,
+        'gpu': dimension['gpu'],
+        'os': dimension['os'],
+        'pool': 'Chrome-perf',
       })
 
     test = generate_telemetry_test(
diff --git a/ui/android/java/src/org/chromium/ui/base/Clipboard.java b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
index e02b588..4497c60 100644
--- a/ui/android/java/src/org/chromium/ui/base/Clipboard.java
+++ b/ui/android/java/src/org/chromium/ui/base/Clipboard.java
@@ -67,14 +67,16 @@
     @SuppressWarnings("javadoc")
     @CalledByNative
     private String getCoercedText() {
-        final ClipData clip = mClipboardManager.getPrimaryClip();
-        if (clip != null && clip.getItemCount() > 0) {
-            final CharSequence sequence = clip.getItemAt(0).coerceToText(mContext);
-            if (sequence != null) {
-                return sequence.toString();
-            }
+        // getPrimaryClip() has been observed to throw unexpected exceptions for some devices (see
+        // crbug.com/654802 and b/31501780)
+        try {
+            return mClipboardManager.getPrimaryClip()
+                    .getItemAt(0)
+                    .coerceToText(mContext)
+                    .toString();
+        } catch (Exception e) {
+            return null;
         }
-        return null;
     }
 
     /**
@@ -85,11 +87,13 @@
      */
     @CalledByNative
     private String getHTMLText() {
-        final ClipData clip = mClipboardManager.getPrimaryClip();
-        if (clip != null && clip.getItemCount() > 0) {
-            return clip.getItemAt(0).getHtmlText();
+        // getPrimaryClip() has been observed to throw unexpected exceptions for some devices (see
+        // crbug/654802 and b/31501780)
+        try {
+            return mClipboardManager.getPrimaryClip().getItemAt(0).getHtmlText();
+        } catch (Exception e) {
+            return null;
         }
-        return null;
     }
 
     /**
diff --git a/ui/aura/window.cc b/ui/aura/window.cc
index d920787..2d7a0487 100644
--- a/ui/aura/window.cc
+++ b/ui/aura/window.cc
@@ -719,7 +719,7 @@
   // changed notification from the layer (this typically happens after animating
   // hidden). We must notify ourselves.
   if (layer()->delegate() != this)
-    OnWindowBoundsChanged(old_bounds);
+    OnLayerBoundsChanged(old_bounds);
 }
 
 void Window::SetVisible(bool visible) {
@@ -1019,17 +1019,6 @@
   }
 }
 
-void Window::OnWindowBoundsChanged(const gfx::Rect& old_bounds) {
-  bounds_ = layer()->bounds();
-  if (layout_manager_)
-    layout_manager_->OnWindowResized();
-  if (delegate_)
-    delegate_->OnBoundsChanged(old_bounds, bounds());
-  FOR_EACH_OBSERVER(WindowObserver,
-                    observers_,
-                    OnWindowBoundsChanged(this, old_bounds, bounds()));
-}
-
 bool Window::CleanupGestureState() {
   bool state_modified = false;
   state_modified |= ui::GestureRecognizer::Get()->CancelActiveTouches(this);
@@ -1054,9 +1043,14 @@
                     OnDelegatedFrameDamage(this, damage_rect_in_dip));
 }
 
-base::Closure Window::PrepareForLayerBoundsChange() {
-  return base::Bind(&Window::OnWindowBoundsChanged, base::Unretained(this),
-                    bounds());
+void Window::OnLayerBoundsChanged(const gfx::Rect& old_bounds) {
+  bounds_ = layer()->bounds();
+  if (layout_manager_)
+    layout_manager_->OnWindowResized();
+  if (delegate_)
+    delegate_->OnBoundsChanged(old_bounds, bounds_);
+  for (auto& observer : observers_)
+    observer.OnWindowBoundsChanged(this, old_bounds, bounds_);
 }
 
 bool Window::CanAcceptEvent(const ui::Event& event) {
diff --git a/ui/aura/window.h b/ui/aura/window.h
index 946904b..f27c2be 100644
--- a/ui/aura/window.h
+++ b/ui/aura/window.h
@@ -444,15 +444,10 @@
   // |source|.
   void NotifyAncestorWindowTransformed(Window* source);
 
-  // Invoked when the bounds of the window changes. This may be invoked directly
-  // by us, or from the closure returned by PrepareForLayerBoundsChange() after
-  // the bounds of the layer has changed. |old_bounds| is the previous bounds.
-  void OnWindowBoundsChanged(const gfx::Rect& old_bounds);
-
   // Overridden from ui::LayerDelegate:
   void OnPaintLayer(const ui::PaintContext& context) override;
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
-  base::Closure PrepareForLayerBoundsChange() override;
+  void OnLayerBoundsChanged(const gfx::Rect& old_bounds) override;
 
   // Overridden from ui::EventTarget:
   bool CanAcceptEvent(const ui::Event& event) override;
diff --git a/ui/base/ime/text_input_flags.h b/ui/base/ime/text_input_flags.h
index 17fb9fb4..f2d7c49 100644
--- a/ui/base/ime/text_input_flags.h
+++ b/ui/base/ime/text_input_flags.h
@@ -8,7 +8,7 @@
 namespace ui {
 
 // Intentionally keep in sync with blink::WebTextInputFlags defined in:
-// third_party/WebKit/public/web/WebTextInputType.h
+// third_party/WebKit/public/platform/WebTextInputType.h
 enum TextInputFlags {
   TEXT_INPUT_FLAG_NONE = 0,
   TEXT_INPUT_FLAG_AUTOCOMPLETE_ON = 1 << 0,
diff --git a/ui/base/ime/text_input_type.h b/ui/base/ime/text_input_type.h
index 794f5c84..641cb7e 100644
--- a/ui/base/ime/text_input_type.h
+++ b/ui/base/ime/text_input_type.h
@@ -8,7 +8,7 @@
 namespace ui {
 
 // Intentionally keep sync with blink::WebTextInputType defined in:
-// third_party/WebKit/public/web/WebTextInputType.h
+// third_party/WebKit/public/platform/WebTextInputType.h
 //
 // A Java counterpart will be generated for this enum.
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.ui.base.ime
diff --git a/ui/compositor/BUILD.gn b/ui/compositor/BUILD.gn
index 44a2313..fc2c5a126 100644
--- a/ui/compositor/BUILD.gn
+++ b/ui/compositor/BUILD.gn
@@ -45,6 +45,7 @@
     "layer_animator.h",
     "layer_animator_collection.cc",
     "layer_animator_collection.h",
+    "layer_delegate.cc",
     "layer_delegate.h",
     "layer_observer.h",
     "layer_owner.cc",
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 67886fc..31c5da6 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -896,18 +896,16 @@
     return;
 
   base::Closure closure;
-  if (delegate_)
-    closure = delegate_->PrepareForLayerBoundsChange();
-  bool was_move = bounds_.size() == bounds.size();
+  const gfx::Rect old_bounds = bounds_;
   bounds_ = bounds;
 
   RecomputeDrawsContentAndUVRect();
   RecomputePosition();
 
-  if (!closure.is_null())
-    closure.Run();
+  if (delegate_)
+    delegate_->OnLayerBoundsChanged(old_bounds);
 
-  if (was_move) {
+  if (bounds.size() == old_bounds.size()) {
     // Don't schedule a draw if we're invisible. We'll schedule one
     // automatically when we get visible.
     if (IsDrawn())
diff --git a/ui/compositor/layer_delegate.cc b/ui/compositor/layer_delegate.cc
new file mode 100644
index 0000000..684bd2e
--- /dev/null
+++ b/ui/compositor/layer_delegate.cc
@@ -0,0 +1,11 @@
+// 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 "ui/compositor/layer_delegate.h"
+
+namespace ui {
+
+void LayerDelegate::OnLayerBoundsChanged(const gfx::Rect& old_bounds) {}
+
+}  // namespace ui
diff --git a/ui/compositor/layer_delegate.h b/ui/compositor/layer_delegate.h
index c3c4e39..55bc130 100644
--- a/ui/compositor/layer_delegate.h
+++ b/ui/compositor/layer_delegate.h
@@ -5,7 +5,6 @@
 #ifndef UI_COMPOSITOR_LAYER_DELEGATE_H_
 #define UI_COMPOSITOR_LAYER_DELEGATE_H_
 
-#include "base/callback_forward.h"
 #include "ui/compositor/compositor_export.h"
 
 namespace gfx {
@@ -29,9 +28,8 @@
   // Called when the layer's device scale factor has changed.
   virtual void OnDeviceScaleFactorChanged(float device_scale_factor) = 0;
 
-  // Invoked prior to the bounds changing. The returned closured is run after
-  // the bounds change.
-  virtual base::Closure PrepareForLayerBoundsChange() = 0;
+  // Invoked when the bounds have changed.
+  virtual void OnLayerBoundsChanged(const gfx::Rect& old_bounds);
 
  protected:
   virtual ~LayerDelegate() {}
diff --git a/ui/compositor/layer_unittest.cc b/ui/compositor/layer_unittest.cc
index d357c78a..0a58a64 100644
--- a/ui/compositor/layer_unittest.cc
+++ b/ui/compositor/layer_unittest.cc
@@ -87,10 +87,6 @@
 
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
 
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
-
  private:
   SkColor color_;
 };
@@ -147,10 +143,6 @@
 
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
 
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
-
  private:
   const SkColor background_color_;
   const SkColor halo_color_;
@@ -339,10 +331,6 @@
     device_scale_factor_ = device_scale_factor;
   }
 
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
-
   void reset() {
     color_index_ = 0;
     device_scale_factor_ = 0.0f;
@@ -379,9 +367,6 @@
   }
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
 
   bool painted_;
   const gfx::Rect layer_bounds_;
@@ -400,9 +385,6 @@
   void OnPaintLayer(const ui::PaintContext& context) override {}
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
 
   DISALLOW_COPY_AND_ASSIGN(NullLayerDelegate);
 };
@@ -1531,10 +1513,6 @@
 
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
 
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
-
   int paint_count_;
   Layer* layer_;
   gfx::Rect schedule_paint_rect_;
diff --git a/ui/events/android/motion_event_android.cc b/ui/events/android/motion_event_android.cc
index bf1fc53f..f7507bf9 100644
--- a/ui/events/android/motion_event_android.cc
+++ b/ui/events/android/motion_event_android.cc
@@ -12,6 +12,7 @@
 #include "jni/MotionEvent_jni.h"
 #include "ui/events/base_event_utils.h"
 #include "ui/events/event_constants.h"
+#include "ui/events/event_utils.h"
 
 using base::android::AttachCurrentThread;
 using namespace JNI_MotionEvent;
@@ -94,7 +95,10 @@
 }
 
 base::TimeTicks FromAndroidTime(int64_t time_ms) {
-  return base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms);
+  base::TimeTicks timestamp =
+      base::TimeTicks() + base::TimeDelta::FromMilliseconds(time_ms);
+  ValidateEventTimeClock(&timestamp);
+  return timestamp;
 }
 
 float ToValidFloat(float x) {
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index 81b1d09..01d2544 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -405,6 +405,11 @@
       input_handler_->MouseMoveAt(gfx::Point(mouse_event.x, mouse_event.y));
       return DID_NOT_HANDLE;
     }
+    case WebInputEvent::MouseLeave: {
+      CHECK(input_handler_);
+      input_handler_->MouseLeave();
+      return DID_NOT_HANDLE;
+    }
 
     default:
       if (WebInputEvent::isKeyboardEventType(event.type)) {
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 769eb99..889270c 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -151,6 +151,7 @@
 
   void MouseDown() override {}
   void MouseUp() override {}
+  void MouseLeave() override {}
 
   void MouseMoveAt(const gfx::Point& mouse_position) override {}
 
diff --git a/ui/events/blink/web_input_event.cc b/ui/events/blink/web_input_event.cc
index 705818f1..674f64f 100644
--- a/ui/events/blink/web_input_event.cc
+++ b/ui/events/blink/web_input_event.cc
@@ -399,8 +399,14 @@
       webkit_event.type = blink::WebInputEvent::MouseUp;
       webkit_event.clickCount = event.GetClickCount();
       break;
-    case ET_MOUSE_ENTERED:
     case ET_MOUSE_EXITED:
+// TODO(chaopeng) this fix only for chromeos now, should convert ET_MOUSE_EXITED
+// to MouseLeave when crbug.com/450631 fixed.
+#if defined(OS_CHROMEOS)
+      webkit_event.type = blink::WebInputEvent::MouseLeave;
+      break;
+#endif
+    case ET_MOUSE_ENTERED:
     case ET_MOUSE_MOVED:
     case ET_MOUSE_DRAGGED:
       webkit_event.type = blink::WebInputEvent::MouseMove;
diff --git a/ui/events/event_utils.cc b/ui/events/event_utils.cc
index 389edcad..dd0da342 100644
--- a/ui/events/event_utils.cc
+++ b/ui/events/event_utils.cc
@@ -62,25 +62,20 @@
 }
 
 void ValidateEventTimeClock(base::TimeTicks* timestamp) {
-// Restrict this validation to DCHECK builds except when using X11 which is
-// known to provide bogus timestamps that require correction (crbug.com/611950).
-#if defined(USE_X11) || DCHECK_IS_ON()
   if (base::debug::BeingDebugged())
     return;
 
   base::TimeTicks now = EventTimeForNow();
   int64_t delta = (now - *timestamp).InMilliseconds();
-  if (delta < 0 || delta > 60 * 1000) {
-    UMA_HISTOGRAM_BOOLEAN("Event.TimestampHasValidTimebase", false);
-#if defined(USE_X11)
-    *timestamp = now;
-#else
-    NOTREACHED() << "Unexpected event timestamp, now:" << now
-                 << " event timestamp:" << *timestamp;
-#endif
-  }
+  bool has_valid_timebase = delta >= 0 && delta <= 60 * 1000;
+  UMA_HISTOGRAM_BOOLEAN("Event.TimestampHasValidTimebase.Browser",
+                        has_valid_timebase);
 
-  UMA_HISTOGRAM_BOOLEAN("Event.TimestampHasValidTimebase", true);
+#if defined(USE_X11)
+  // Restrict this correction to X11 which is known to provide bogus timestamps
+  // that require correction (crbug.com/611950).
+  if (!has_valid_timebase)
+    *timestamp = now;
 #endif
 }
 
diff --git a/ui/events/ozone/evdev/event_converter_evdev.cc b/ui/events/ozone/evdev/event_converter_evdev.cc
index d0bf95b..42b48ea 100644
--- a/ui/events/ozone/evdev/event_converter_evdev.cc
+++ b/ui/events/ozone/evdev/event_converter_evdev.cc
@@ -154,7 +154,10 @@
 
 base::TimeTicks EventConverterEvdev::TimeTicksFromInputEvent(
     const input_event& event) {
-  return ui::EventTimeStampFromSeconds(event.time.tv_sec) +
+  base::TimeTicks timestamp =
+      ui::EventTimeStampFromSeconds(event.time.tv_sec) +
       base::TimeDelta::FromMicroseconds(event.time.tv_usec);
+  ValidateEventTimeClock(&timestamp);
+  return timestamp;
 }
 }  // namespace ui
diff --git a/ui/gfx/mojo/buffer_types.mojom b/ui/gfx/mojo/buffer_types.mojom
index aa5f3be5..8b8de3b8 100644
--- a/ui/gfx/mojo/buffer_types.mojom
+++ b/ui/gfx/mojo/buffer_types.mojom
@@ -70,7 +70,7 @@
 struct GpuMemoryBufferHandle {
   GpuMemoryBufferType type;
   GpuMemoryBufferId id;
-  handle shared_memory_handle;
+  handle? shared_memory_handle;
   uint32 offset;
   uint32 stride;
   NativePixmapHandle? native_pixmap_handle;
diff --git a/ui/gfx/mojo/buffer_types_traits.cc b/ui/gfx/mojo/buffer_types_traits.cc
index 71cef1b..122d844 100644
--- a/ui/gfx/mojo/buffer_types_traits.cc
+++ b/ui/gfx/mojo/buffer_types_traits.cc
@@ -72,6 +72,8 @@
   DCHECK(handle.handle.auto_close || handle.handle.fd == -1);
   platform_file = handle.handle.fd;
 #endif
+  if (platform_file == base::kInvalidPlatformFile)
+    return mojo::ScopedHandle();
   return mojo::WrapPlatformFile(platform_file);
 }
 
@@ -94,20 +96,25 @@
   if (!data.ReadType(&out->type) || !data.ReadId(&out->id))
     return false;
 
-  base::PlatformFile platform_file;
-  MojoResult unwrap_result = mojo::UnwrapPlatformFile(
-      data.TakeSharedMemoryHandle(), &platform_file);
-  if (unwrap_result != MOJO_RESULT_OK)
-    return false;
+  mojo::ScopedHandle handle = data.TakeSharedMemoryHandle();
+  if (handle.is_valid()) {
+    base::PlatformFile platform_file;
+    MojoResult unwrap_result = mojo::UnwrapPlatformFile(
+        std::move(handle), &platform_file);
+    if (unwrap_result != MOJO_RESULT_OK)
+      return false;
 #if defined(OS_WIN)
-  out->handle =
-      base::SharedMemoryHandle(platform_file, base::GetCurrentProcId());
+    out->handle =
+        base::SharedMemoryHandle(platform_file, base::GetCurrentProcId());
 #elif defined(OS_MACOSX) || defined(OS_IOS)
-  // TODO: Add support for mach_port on mac.
-  out->handle = base::SharedMemoryHandle();
+    // TODO: Add support for mach_port on mac.
+    out->handle = base::SharedMemoryHandle();
 #else
-  out->handle = base::SharedMemoryHandle(platform_file, true);
+    out->handle = base::SharedMemoryHandle(platform_file, true);
 #endif
+  } else {
+    out->handle = base::SharedMemoryHandle();
+  }
 
   out->offset = data.offset();
   out->stride = data.stride();
diff --git a/ui/gfx/mojo/struct_traits_unittest.cc b/ui/gfx/mojo/struct_traits_unittest.cc
index d837cd8..e7cb15f 100644
--- a/ui/gfx/mojo/struct_traits_unittest.cc
+++ b/ui/gfx/mojo/struct_traits_unittest.cc
@@ -185,4 +185,11 @@
 #endif
 }
 
+TEST_F(StructTraitsTest, NullGpuMemoryBufferHandle) {
+  mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
+  GpuMemoryBufferHandle output;
+  proxy->EchoGpuMemoryBufferHandle(GpuMemoryBufferHandle(), &output);
+  EXPECT_TRUE(output.is_null());
+}
+
 }  // namespace gfx
diff --git a/ui/message_center/cocoa/notification_controller.mm b/ui/message_center/cocoa/notification_controller.mm
index b14c26c..03ab334 100644
--- a/ui/message_center/cocoa/notification_controller.mm
+++ b/ui/message_center/cocoa/notification_controller.mm
@@ -690,6 +690,7 @@
 }
 
 - (void)settingsClicked:(id)sender {
+  [NSApp activateIgnoringOtherApps:YES];
   messageCenter_->ClickOnSettingsButton([self notificationID]);
 }
 
diff --git a/ui/message_center/notification_delegate.cc b/ui/message_center/notification_delegate.cc
index 405c703..70675233 100644
--- a/ui/message_center/notification_delegate.cc
+++ b/ui/message_center/notification_delegate.cc
@@ -4,6 +4,8 @@
 
 #include "ui/message_center/notification_delegate.h"
 
+#include "base/logging.h"
+
 namespace message_center {
 
 // NotificationDelegate:
@@ -18,6 +20,11 @@
 
 void NotificationDelegate::ButtonClick(int button_index) {}
 
+void NotificationDelegate::ButtonClickWithReply(int button_index,
+                                                const base::string16& reply) {
+  NOTIMPLEMENTED();
+}
+
 void NotificationDelegate::SettingsClick() {}
 
 bool NotificationDelegate::ShouldDisplaySettingsButton() {
diff --git a/ui/message_center/notification_delegate.h b/ui/message_center/notification_delegate.h
index 17b4e340..a493c18e 100644
--- a/ui/message_center/notification_delegate.h
+++ b/ui/message_center/notification_delegate.h
@@ -11,6 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
+#include "base/strings/string16.h"
 #include "ui/message_center/message_center_export.h"
 
 #if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
@@ -43,6 +44,12 @@
   // To be called when the user clicks a button in a notification.
   virtual void ButtonClick(int button_index);
 
+  // To be called when the user types a reply to a notification.
+  // TODO(crbug.com/599859) Support this feature in the message center -
+  // currently it is only supported on Android.
+  virtual void ButtonClickWithReply(int button_index,
+                                    const base::string16& reply);
+
   // To be called when the user clicks the settings button in a notification.
   virtual void SettingsClick();
 
diff --git a/ui/views/animation/ink_drop_painted_layer_delegates.cc b/ui/views/animation/ink_drop_painted_layer_delegates.cc
index 75609d7..eec57980 100644
--- a/ui/views/animation/ink_drop_painted_layer_delegates.cc
+++ b/ui/views/animation/ink_drop_painted_layer_delegates.cc
@@ -39,9 +39,6 @@
 void BasePaintedLayerDelegate::OnDeviceScaleFactorChanged(
     float device_scale_factor) {}
 
-base::Closure BasePaintedLayerDelegate::PrepareForLayerBoundsChange() {
-  return base::Closure();
-}
 
 ////////////////////////////////////////////////////////////////////////////////
 //
diff --git a/ui/views/animation/ink_drop_painted_layer_delegates.h b/ui/views/animation/ink_drop_painted_layer_delegates.h
index c4cab4f3..2103328 100644
--- a/ui/views/animation/ink_drop_painted_layer_delegates.h
+++ b/ui/views/animation/ink_drop_painted_layer_delegates.h
@@ -5,7 +5,6 @@
 #ifndef UI_VIEWS_ANIMATION_INK_DROP_PAINTED_LAYER_DELEGATES_H_
 #define UI_VIEWS_ANIMATION_INK_DROP_PAINTED_LAYER_DELEGATES_H_
 
-#include "base/callback.h"
 #include "base/macros.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/compositor/layer_delegate.h"
@@ -33,7 +32,6 @@
   // ui::LayerDelegate:
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
   void OnDeviceScaleFactorChanged(float device_scale_factor) override;
-  base::Closure PrepareForLayerBoundsChange() override;
 
  protected:
   explicit BasePaintedLayerDelegate(SkColor color);
diff --git a/ui/views/bubble/tray_bubble_view.cc b/ui/views/bubble/tray_bubble_view.cc
index 059458a0..fb21a45 100644
--- a/ui/views/bubble/tray_bubble_view.cc
+++ b/ui/views/bubble/tray_bubble_view.cc
@@ -187,7 +187,6 @@
   void OnPaintLayer(const ui::PaintContext& context) override;
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
   void OnDeviceScaleFactorChanged(float device_scale_factor) override;
-  base::Closure PrepareForLayerBoundsChange() override;
 
  private:
   ui::Layer layer_;
@@ -221,10 +220,6 @@
   // Redrawing will take care of scale factor change.
 }
 
-base::Closure TrayBubbleContentMask::PrepareForLayerBoundsChange() {
-  return base::Closure();
-}
-
 // Custom layout for the bubble-view. Does the default box-layout if there is
 // enough height. Otherwise, makes sure the bottom rows are visible.
 class BottomAlignedBoxLayout : public BoxLayout {
diff --git a/ui/views/cocoa/bridged_native_widget.h b/ui/views/cocoa/bridged_native_widget.h
index d1e2d08a..0bb5fd9 100644
--- a/ui/views/cocoa/bridged_native_widget.h
+++ b/ui/views/cocoa/bridged_native_widget.h
@@ -256,7 +256,6 @@
   void OnPaintLayer(const ui::PaintContext& context) override;
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
   void OnDeviceScaleFactorChanged(float device_scale_factor) override;
-  base::Closure PrepareForLayerBoundsChange() override;
 
   // Overridden from ui::AcceleratedWidgetMac:
   NSView* AcceleratedWidgetGetNSView() const override;
diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm
index 2dc4afd..8e47513 100644
--- a/ui/views/cocoa/bridged_native_widget.mm
+++ b/ui/views/cocoa/bridged_native_widget.mm
@@ -1108,10 +1108,6 @@
       device_scale_factor);
 }
 
-base::Closure BridgedNativeWidget::PrepareForLayerBoundsChange() {
-  return base::Closure();
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // BridgedNativeWidget, AcceleratedWidgetMac:
 
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.cc b/ui/views/controls/tabbed_pane/tabbed_pane.cc
index 1e9de95..56415db 100644
--- a/ui/views/controls/tabbed_pane/tabbed_pane.cc
+++ b/ui/views/controls/tabbed_pane/tabbed_pane.cc
@@ -20,6 +20,7 @@
 #include "ui/views/controls/label.h"
 #include "ui/views/controls/tabbed_pane/tabbed_pane_listener.h"
 #include "ui/views/layout/box_layout.h"
+#include "ui/views/layout/fill_layout.h"
 #include "ui/views/layout/layout_manager.h"
 #include "ui/views/widget/widget.h"
 
@@ -56,6 +57,7 @@
   void OnStateChanged() override;
 
   // Overridden from View:
+  gfx::Size GetPreferredSize() const override;
   void OnPaintBorder(gfx::Canvas* canvas) override;
 
  private:
@@ -68,18 +70,19 @@
   // Internal class name.
   static const char kViewClassName[];
 
-  explicit TabStrip(TabbedPane* tabbed_pane);
+  TabStrip();
   ~TabStrip() override;
 
   // Overridden from View:
-  gfx::Size GetPreferredSize() const override;
-  void Layout() override;
   const char* GetClassName() const override;
-  void OnPaint(gfx::Canvas* canvas) override;
+  void OnPaintBorder(gfx::Canvas* canvas) override;
+
+  Tab* GetSelectedTab() const;
+  Tab* GetTabAtDeltaFromSelected(int delta) const;
+  Tab* GetTabAtIndex(int index) const;
+  int GetSelectedTabIndex() const;
 
  private:
-  TabbedPane* tabbed_pane_;
-
   DISALLOW_COPY_AND_ASSIGN(TabStrip);
 };
 
@@ -87,13 +90,11 @@
 // class uses a BoxLayout to position tabs.
 class MdTabStrip : public TabStrip {
  public:
-  explicit MdTabStrip(TabbedPane* tabbed_pane);
+  MdTabStrip();
   ~MdTabStrip() override;
 
   // Overridden from View:
-  gfx::Size GetPreferredSize() const override;
-  void Layout() override;
-  void OnPaint(gfx::Canvas* canvas) override;
+  void OnPaintBorder(gfx::Canvas* canvas) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(MdTabStrip);
@@ -115,6 +116,13 @@
   // Calculate this now while the font list is guaranteed to be bold.
   preferred_title_size_ = title_->GetPreferredSize();
 
+  const int kTabVerticalPadding = 5;
+  const int kTabHorizontalPadding = 10;
+
+  SetBorder(Border::CreateEmptyBorder(
+      gfx::Insets(kTabVerticalPadding, kTabHorizontalPadding)));
+  SetLayoutManager(new FillLayout);
+
   SetState(TAB_INACTIVE);
   AddChildView(title_);
 }
@@ -187,20 +195,10 @@
 
 gfx::Size Tab::GetPreferredSize() const {
   gfx::Size size(preferred_title_size_);
-  size.Enlarge(21, 9);
-  const int kTabMinWidth = 54;
-  if (size.width() < kTabMinWidth)
-    size.set_width(kTabMinWidth);
+  size.Enlarge(GetInsets().width(), GetInsets().height());
   return size;
 }
 
-void Tab::Layout() {
-  gfx::Rect bounds = GetLocalBounds();
-  bounds.Inset(0, 1, 0, 0);
-  bounds.ClampToCenteredSize(preferred_title_size_);
-  title_->SetBoundsRect(bounds);
-}
-
 const char* Tab::GetClassName() const {
   return kViewClassName;
 }
@@ -213,10 +211,6 @@
   SchedulePaint();
 }
 
-bool Tab::ContainerHasFocus() {
-  return tabbed_pane_->HasFocus();
-}
-
 void Tab::OnFocus() {
   OnStateChanged();
   // When the tab gains focus, send an accessibility event indicating that the
@@ -302,49 +296,38 @@
       base_color);
 }
 
+gfx::Size MdTab::GetPreferredSize() const {
+  return gfx::Size(Tab::GetPreferredSize().width(), kHarmonyTabStripTabHeight);
+}
+
 // static
 const char TabStrip::kViewClassName[] = "TabStrip";
 
-TabStrip::TabStrip(TabbedPane* tabbed_pane) : tabbed_pane_(tabbed_pane) {}
+TabStrip::TabStrip() {
+  const int kTabStripLeadingEdgePadding = 9;
+  BoxLayout* layout =
+      new BoxLayout(BoxLayout::kHorizontal, kTabStripLeadingEdgePadding, 0, 0);
+  layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_START);
+  layout->set_cross_axis_alignment(BoxLayout::CROSS_AXIS_ALIGNMENT_END);
+  layout->SetDefaultFlex(0);
+  SetLayoutManager(layout);
+}
 
 TabStrip::~TabStrip() {}
 
-gfx::Size TabStrip::GetPreferredSize() const {
-  gfx::Size size;
-  for (int i = 0; i < child_count(); ++i) {
-    const gfx::Size child_size = child_at(i)->GetPreferredSize();
-    size.SetSize(size.width() + child_size.width(),
-                 std::max(size.height(), child_size.height()));
-  }
-  return size;
-}
-
-void TabStrip::Layout() {
-  const int kTabOffset = 9;
-  int x = kTabOffset;  // Layout tabs with an offset to the tabstrip border.
-  for (int i = 0; i < child_count(); ++i) {
-    gfx::Size ps = child_at(i)->GetPreferredSize();
-    child_at(i)->SetBounds(x, 0, ps.width(), ps.height());
-    x = child_at(i)->bounds().right();
-  }
-}
-
 const char* TabStrip::GetClassName() const {
   return kViewClassName;
 }
 
-void TabStrip::OnPaint(gfx::Canvas* canvas) {
-  OnPaintBackground(canvas);
-
-  // Draw the TabStrip border.
+void TabStrip::OnPaintBorder(gfx::Canvas* canvas) {
   SkPaint paint;
   paint.setColor(kTabBorderColor);
   paint.setStrokeWidth(kTabBorderThickness);
   SkScalar line_y = SkIntToScalar(height()) - (kTabBorderThickness / 2);
   SkScalar line_end = SkIntToScalar(width());
-  int selected_tab_index = tabbed_pane_->selected_tab_index();
+  int selected_tab_index = GetSelectedTabIndex();
   if (selected_tab_index >= 0) {
-    Tab* selected_tab = tabbed_pane_->GetTabAt(selected_tab_index);
+    Tab* selected_tab = GetTabAtIndex(selected_tab_index);
     SkPath path;
     SkScalar tab_height =
         SkIntToScalar(selected_tab->height()) - kTabBorderThickness;
@@ -368,7 +351,30 @@
   }
 }
 
-MdTabStrip::MdTabStrip(TabbedPane* tabbed_pane) : TabStrip(tabbed_pane) {
+Tab* TabStrip::GetTabAtIndex(int index) const {
+  return static_cast<Tab*>(const_cast<View*>(child_at(index)));
+}
+
+int TabStrip::GetSelectedTabIndex() const {
+  for (int i = 0; i < child_count(); ++i)
+    if (GetTabAtIndex(i)->selected())
+      return i;
+  return -1;
+}
+
+Tab* TabStrip::GetSelectedTab() const {
+  int index = GetSelectedTabIndex();
+  return index >= 0 ? GetTabAtIndex(index) : nullptr;
+}
+
+Tab* TabStrip::GetTabAtDeltaFromSelected(int delta) const {
+  int index = (GetSelectedTabIndex() + delta) % child_count();
+  if (index < 0)
+    index += child_count();
+  return GetTabAtIndex(index);
+}
+
+MdTabStrip::MdTabStrip() {
   BoxLayout* layout =
       new BoxLayout(BoxLayout::kHorizontal, 0, kHarmonyTabStripVerticalPad, 0);
   layout->set_main_axis_alignment(BoxLayout::MAIN_AXIS_ALIGNMENT_CENTER);
@@ -379,35 +385,25 @@
 
 MdTabStrip::~MdTabStrip() {}
 
-gfx::Size MdTabStrip::GetPreferredSize() const {
-  return gfx::Size(width(),
-                   kHarmonyTabStripVerticalPad * 2 + kHarmonyTabStripTabHeight);
-}
-
-// Let this class's LayoutManager handle the layout.
-void MdTabStrip::Layout() {
-  return View::Layout();
-}
-
-// The tab strip "border" is drawn as part of the tabs, so all this method needs
-// to do is paint the background.
-void MdTabStrip::OnPaint(gfx::Canvas* canvas) {
-  OnPaintBackground(canvas);
-}
+// The tab strip "border" is drawn as part of the tabs.
+void MdTabStrip::OnPaintBorder(gfx::Canvas* canvas) {}
 
 TabbedPane::TabbedPane()
     : listener_(NULL),
       tab_strip_(ui::MaterialDesignController::IsSecondaryUiMaterial()
-                     ? new MdTabStrip(this)
-                     : new TabStrip(this)),
-      contents_(new View()),
-      selected_tab_index_(-1) {
+                     ? new MdTabStrip
+                     : new TabStrip),
+      contents_(new View()) {
   AddChildView(tab_strip_);
   AddChildView(contents_);
 }
 
 TabbedPane::~TabbedPane() {}
 
+int TabbedPane::GetSelectedTabIndex() const {
+  return tab_strip_->GetSelectedTabIndex();
+}
+
 int TabbedPane::GetTabCount() {
   DCHECK_EQ(tab_strip_->child_count(), contents_->child_count());
   return contents_->child_count();
@@ -429,24 +425,18 @@
           : new Tab(this, title, contents),
       index);
   contents_->AddChildViewAt(contents, index);
-  // TODO(ellyjones): if index < selected_tab_index(), selected_tab_index() gets
-  // out of sync with which tab believes it is selected. This class should
-  // directly ask Tabs whether they are selected.
-  if (selected_tab_index() < 0)
+  if (!GetSelectedTab())
     SelectTabAt(index);
 
   PreferredSizeChanged();
 }
 
-void TabbedPane::SelectTabAt(int index) {
-  DCHECK(index >= 0 && index < GetTabCount());
-  if (index == selected_tab_index())
+void TabbedPane::SelectTab(Tab* new_selected_tab) {
+  Tab* old_selected_tab = tab_strip_->GetSelectedTab();
+  if (old_selected_tab == new_selected_tab)
     return;
 
-  Tab* old_selected_tab = GetSelectedTab();
-  Tab* new_selected_tab = GetTabAt(index);
   new_selected_tab->SetSelected(true);
-  selected_tab_index_ = index;
   if (old_selected_tab) {
     if (old_selected_tab->HasFocus())
       new_selected_tab->RequestFocus();
@@ -463,13 +453,13 @@
   }
 
   if (listener())
-    listener()->TabSelectedAt(index);
+    listener()->TabSelectedAt(tab_strip_->GetIndexOf(new_selected_tab));
 }
 
-void TabbedPane::SelectTab(Tab* tab) {
-  const int index = tab_strip_->GetIndexOf(tab);
-  if (index >= 0)
-    SelectTabAt(index);
+void TabbedPane::SelectTabAt(int index) {
+  Tab* tab = tab_strip_->GetTabAtIndex(index);
+  if (tab)
+    SelectTab(tab);
 }
 
 gfx::Size TabbedPane::GetPreferredSize() const {
@@ -480,22 +470,14 @@
   return size;
 }
 
-Tab* TabbedPane::GetTabAt(int index) {
-  return static_cast<Tab*>(tab_strip_->child_at(index));
-}
-
 Tab* TabbedPane::GetSelectedTab() {
-  return selected_tab_index() >= 0 ? GetTabAt(selected_tab_index()) : nullptr;
+  return tab_strip_->GetSelectedTab();
 }
 
 bool TabbedPane::MoveSelectionBy(int delta) {
-  const int tab_count = GetTabCount();
-  if (tab_count <= 1)
+  if (contents_->child_count() <= 1)
     return false;
-  int next_selected_index = (selected_tab_index() + delta) % tab_count;
-  if (next_selected_index < 0)
-    next_selected_index += tab_count;
-  SelectTabAt(next_selected_index);
+  SelectTab(tab_strip_->GetTabAtDeltaFromSelected(delta));
   return true;
 }
 
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane.h b/ui/views/controls/tabbed_pane/tabbed_pane.h
index 44c48bb..af41d969 100644
--- a/ui/views/controls/tabbed_pane/tabbed_pane.h
+++ b/ui/views/controls/tabbed_pane/tabbed_pane.h
@@ -30,7 +30,9 @@
   TabbedPaneListener* listener() const { return listener_; }
   void set_listener(TabbedPaneListener* listener) { listener_ = listener; }
 
-  int selected_tab_index() const { return selected_tab_index_; }
+  // Returns the index of the currently selected tab, or -1 if no tab is
+  // selected.
+  int GetSelectedTabIndex() const;
 
   // Returns the number of tabs.
   int GetTabCount();
@@ -118,7 +120,6 @@
   void OnMouseExited(const ui::MouseEvent& event) override;
   void OnGestureEvent(ui::GestureEvent* event) override;
   gfx::Size GetPreferredSize() const override;
-  void Layout() override;
   const char* GetClassName() const override;
   void OnFocus() override;
   void OnBlur() override;
@@ -130,9 +131,6 @@
   // Called whenever |tab_state_| changes.
   virtual void OnStateChanged();
 
-  // Returns whether the containing TabStrip has focus.
-  bool ContainerHasFocus();
-
  private:
   enum TabState {
     TAB_INACTIVE,
diff --git a/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc b/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
index 9b1fb8c..e02a252 100644
--- a/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
+++ b/ui/views/controls/tabbed_pane/tabbed_pane_unittest.cc
@@ -74,20 +74,20 @@
     View* tab = new View();
     tabbed_pane->AddTab(ASCIIToUTF16("tab"), tab);
     EXPECT_EQ(i + 1, tabbed_pane->GetTabCount());
-    EXPECT_EQ(0, tabbed_pane->selected_tab_index());
+    EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex());
   }
 
   // Select each tab.
   for (int i = 0; i < tabbed_pane->GetTabCount(); ++i) {
     tabbed_pane->SelectTabAt(i);
-    EXPECT_EQ(i, tabbed_pane->selected_tab_index());
+    EXPECT_EQ(i, tabbed_pane->GetSelectedTabIndex());
   }
 
   // Add a tab at index 0, it should not be selected automatically.
   View* tab0 = new View();
   tabbed_pane->AddTabAtIndex(0, ASCIIToUTF16("tab0"), tab0);
   EXPECT_NE(tab0, tabbed_pane->GetSelectedTabContentView());
-  EXPECT_NE(0, tabbed_pane->selected_tab_index());
+  EXPECT_NE(0, tabbed_pane->GetSelectedTabIndex());
 }
 
 ui::KeyEvent MakeKeyPressedEvent(ui::KeyboardCode keyboard_code, int flags) {
@@ -104,27 +104,27 @@
     EXPECT_EQ(i + 1, tabbed_pane->GetTabCount());
   }
 
-  EXPECT_EQ(0, tabbed_pane->selected_tab_index());
+  EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex());
 
   // Right arrow should select tab 1:
   tabbed_pane->GetSelectedTab()->OnKeyPressed(
       MakeKeyPressedEvent(ui::VKEY_RIGHT, 0));
-  EXPECT_EQ(1, tabbed_pane->selected_tab_index());
+  EXPECT_EQ(1, tabbed_pane->GetSelectedTabIndex());
 
   // Left arrow should select tab 0:
   tabbed_pane->GetSelectedTab()->OnKeyPressed(
       MakeKeyPressedEvent(ui::VKEY_LEFT, 0));
-  EXPECT_EQ(0, tabbed_pane->selected_tab_index());
+  EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex());
 
   // Left arrow again should wrap to tab 2:
   tabbed_pane->GetSelectedTab()->OnKeyPressed(
       MakeKeyPressedEvent(ui::VKEY_LEFT, 0));
-  EXPECT_EQ(2, tabbed_pane->selected_tab_index());
+  EXPECT_EQ(2, tabbed_pane->GetSelectedTabIndex());
 
   // Right arrow again should wrap to tab 0:
   tabbed_pane->GetSelectedTab()->OnKeyPressed(
       MakeKeyPressedEvent(ui::VKEY_RIGHT, 0));
-  EXPECT_EQ(0, tabbed_pane->selected_tab_index());
+  EXPECT_EQ(0, tabbed_pane->GetSelectedTabIndex());
 }
 
 }  // namespace views
diff --git a/ui/views/examples/tabbed_pane_example.cc b/ui/views/examples/tabbed_pane_example.cc
index 087c77bf..524fec6c9 100644
--- a/ui/views/examples/tabbed_pane_example.cc
+++ b/ui/views/examples/tabbed_pane_example.cc
@@ -40,6 +40,7 @@
   // Create a few tabs with a button first.
   AddButton("Tab 1");
   AddButton("Tab 2");
+  AddButton("Tab 3");
 
   // Add control buttons horizontally.
   const int button_column = 1;
@@ -76,7 +77,7 @@
 void TabbedPaneExample::PrintStatus() {
   ExampleBase::PrintStatus("Tab Count:%d, Selected Tab:%d",
                            tabbed_pane_->GetTabCount(),
-                           tabbed_pane_->selected_tab_index());
+                           tabbed_pane_->GetSelectedTabIndex());
 }
 
 void TabbedPaneExample::AddButton(const std::string& label) {
diff --git a/ui/views/view.cc b/ui/views/view.cc
index ca1913ed..3cb42dc 100644
--- a/ui/views/view.cc
+++ b/ui/views/view.cc
@@ -1527,10 +1527,6 @@
   // Repainting with new scale factor will paint the content at the right scale.
 }
 
-base::Closure View::PrepareForLayerBoundsChange() {
-  return base::Closure();
-}
-
 void View::ReorderLayers() {
   View* v = this;
   while (v && !v->layer())
diff --git a/ui/views/view.h b/ui/views/view.h
index 05f6da3..572d3a5 100644
--- a/ui/views/view.h
+++ b/ui/views/view.h
@@ -1123,7 +1123,6 @@
   void OnPaintLayer(const ui::PaintContext& context) override;
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
   void OnDeviceScaleFactorChanged(float device_scale_factor) override;
-  base::Closure PrepareForLayerBoundsChange() override;
 
   // Finds the layer that this view paints to (it may belong to an ancestor
   // view), then reorders the immediate children of that layer to match the
diff --git a/ui/wm/core/image_grid.cc b/ui/wm/core/image_grid.cc
index c4be0c3..527d6eb 100644
--- a/ui/wm/core/image_grid.cc
+++ b/ui/wm/core/image_grid.cc
@@ -286,10 +286,6 @@
   // Redrawing will take care of scale factor change.
 }
 
-base::Closure ImageGrid::ImagePainter::PrepareForLayerBoundsChange() {
-  return base::Closure();
-}
-
 void ImageGrid::SetImage(const gfx::Image* image,
                          std::unique_ptr<ui::Layer>* layer_ptr,
                          std::unique_ptr<ImagePainter>* painter_ptr,
diff --git a/ui/wm/core/image_grid.h b/ui/wm/core/image_grid.h
index eba2817..d171e9b 100644
--- a/ui/wm/core/image_grid.h
+++ b/ui/wm/core/image_grid.h
@@ -140,7 +140,6 @@
     void OnPaintLayer(const ui::PaintContext& context) override;
     void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override;
     void OnDeviceScaleFactorChanged(float device_scale_factor) override;
-    base::Closure PrepareForLayerBoundsChange() override;
 
    private:
     friend class TestAPI;
diff --git a/ui/wm/core/window_util_unittest.cc b/ui/wm/core/window_util_unittest.cc
index 8453e30..5cc2b38 100644
--- a/ui/wm/core/window_util_unittest.cc
+++ b/ui/wm/core/window_util_unittest.cc
@@ -28,9 +28,6 @@
   void OnPaintLayer(const ui::PaintContext& context) override {}
   void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
   void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
-  base::Closure PrepareForLayerBoundsChange() override {
-    return base::Closure();
-  }
 
   ui::Layer* original_layer() { return original_layer_; }