diff --git a/AUTHORS b/AUTHORS
index 498f6aec..2ac0c60 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -136,6 +136,7 @@
 David Leen <davileen@amazon.com>
 David McAllister <mcdavid@amazon.com>
 David Spellman <dspell@amazon.com>
+Dax Kelson <dkelson@gurulabs.com>
 Debashish Samantaray <d.samantaray@samsung.com>
 Deepak Dilip Borade <deepak.db@samsung.com>
 Deepak Mittal <deepak.m1@samsung.com>
diff --git a/BUILD.gn b/BUILD.gn
index d1791b0..4ee431b 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -653,7 +653,7 @@
     }
   }
 
-  if (is_android) {
+  if (is_android || is_linux || is_chromeos) {
     deps += [ "//blimp" ]
   }
 
diff --git a/DEPS b/DEPS
index 8f22ef7..5ebf3a0 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': 'fbd87d611a16d6e1397226d1c8418c810c76b598',
+  'skia_revision': '84a80652752976c9abe42d28e467c362baff3e39',
   # 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': '0a4246b40ef3c36b6980507ba0381cfef697100c',
+  'v8_revision': '12a032e6a657cbaba85b9df70bbea89dd561daf1',
   # 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.
diff --git a/cc/scheduler/compositor_timing_history.cc b/cc/scheduler/compositor_timing_history.cc
index 34726d5..8c1bbe3 100644
--- a/cc/scheduler/compositor_timing_history.cc
+++ b/cc/scheduler/compositor_timing_history.cc
@@ -17,6 +17,15 @@
   virtual void AddBeginMainFrameToCommitDuration(base::TimeDelta duration,
                                                  base::TimeDelta estimate,
                                                  bool affects_estimate) = 0;
+  virtual void AddBeginMainFrameQueueDurationCriticalDuration(
+      base::TimeDelta duration,
+      bool affects_estimate) = 0;
+  virtual void AddBeginMainFrameQueueDurationNotCriticalDuration(
+      base::TimeDelta duration,
+      bool affects_estimate) = 0;
+  virtual void AddBeginMainFrameStartToCommitDuration(
+      base::TimeDelta duration,
+      bool affects_estimate) = 0;
   virtual void AddCommitToReadyToActivateDuration(base::TimeDelta duration,
                                                   base::TimeDelta estimate,
                                                   bool affects_estimate) = 0;
@@ -39,6 +48,9 @@
 // TODO(brianderson): Fine tune the percentiles below.
 const size_t kDurationHistorySize = 60;
 const double kBeginMainFrameToCommitEstimationPercentile = 90.0;
+const double kBeginMainFrameQueueDurationCriticalEstimationPercentile = 90.0;
+const double kBeginMainFrameQueueDurationNotCriticalEstimationPercentile = 90.0;
+const double kBeginMainFrameStartToCommitEstimationPercentile = 90.0;
 const double kCommitToReadyToActivateEstimationPercentile = 90.0;
 const double kPrepareTilesEstimationPercentile = 90.0;
 const double kActivateEstimationPercentile = 90.0;
@@ -77,6 +89,7 @@
                               kUmaDurationMinMicros, kUmaDurationMaxMicros, \
                               kUmaDurationBucketCount);
 
+// Records over/under estimates.
 #define REPORT_COMPOSITOR_TIMING_HISTORY_UMA(category, subcategory)            \
   do {                                                                         \
     base::TimeDelta duration_overestimate;                                     \
@@ -100,6 +113,18 @@
     }                                                                          \
   } while (false)
 
+// Does not record over/under estimates.
+#define REPORT_COMPOSITOR_TIMING_HISTORY_UMA2(category, subcategory)           \
+  do {                                                                         \
+    UMA_HISTOGRAM_CUSTOM_TIMES_MICROS("Scheduling." category "." subcategory,  \
+                                      duration);                               \
+    if (!affects_estimate) {                                                   \
+      UMA_HISTOGRAM_CUSTOM_TIMES_MICROS("Scheduling." category "." subcategory \
+                                        ".NotUsedForEstimate",                 \
+                                        duration);                             \
+    }                                                                          \
+  } while (false)
+
 class RendererUMAReporter : public CompositorTimingHistory::UMAReporter {
  public:
   ~RendererUMAReporter() override {}
@@ -110,6 +135,26 @@
     REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Renderer", "BeginMainFrameToCommit");
   }
 
+  void AddBeginMainFrameQueueDurationCriticalDuration(
+      base::TimeDelta duration,
+      bool affects_estimate) override {
+    REPORT_COMPOSITOR_TIMING_HISTORY_UMA2(
+        "Renderer", "BeginMainFrameQueueDurationCritical");
+  }
+
+  void AddBeginMainFrameQueueDurationNotCriticalDuration(
+      base::TimeDelta duration,
+      bool affects_estimate) override {
+    REPORT_COMPOSITOR_TIMING_HISTORY_UMA2(
+        "Renderer", "BeginMainFrameQueueDurationNotCritical");
+  }
+
+  void AddBeginMainFrameStartToCommitDuration(base::TimeDelta duration,
+                                              bool affects_estimate) override {
+    REPORT_COMPOSITOR_TIMING_HISTORY_UMA2(
+        "Renderer", "BeginMainFrameStartToCommitDuration");
+  }
+
   void AddCommitToReadyToActivateDuration(base::TimeDelta duration,
                                           base::TimeDelta estimate,
                                           bool affects_estimate) override {
@@ -146,6 +191,26 @@
     REPORT_COMPOSITOR_TIMING_HISTORY_UMA("Browser", "BeginMainFrameToCommit");
   }
 
+  void AddBeginMainFrameQueueDurationCriticalDuration(
+      base::TimeDelta duration,
+      bool affects_estimate) override {
+    REPORT_COMPOSITOR_TIMING_HISTORY_UMA2(
+        "Browser", "BeginMainFrameQueueDurationCritical");
+  }
+
+  void AddBeginMainFrameQueueDurationNotCriticalDuration(
+      base::TimeDelta duration,
+      bool affects_estimate) override {
+    REPORT_COMPOSITOR_TIMING_HISTORY_UMA2(
+        "Browser", "BeginMainFrameQueueDurationNotCritical");
+  }
+
+  void AddBeginMainFrameStartToCommitDuration(base::TimeDelta duration,
+                                              bool affects_estimate) override {
+    REPORT_COMPOSITOR_TIMING_HISTORY_UMA2("Browser",
+                                          "BeginMainFrameStartToCommit");
+  }
+
   void AddCommitToReadyToActivateDuration(base::TimeDelta duration,
                                           base::TimeDelta estimate,
                                           bool affects_estimate) override {
@@ -175,15 +240,23 @@
 class NullUMAReporter : public CompositorTimingHistory::UMAReporter {
  public:
   ~NullUMAReporter() override {}
-  void AddPrepareTilesDuration(base::TimeDelta duration,
-                               base::TimeDelta estimate,
-                               bool affects_estimate) override {}
   void AddBeginMainFrameToCommitDuration(base::TimeDelta duration,
                                          base::TimeDelta estimate,
                                          bool affects_estimate) override {}
+  void AddBeginMainFrameQueueDurationCriticalDuration(
+      base::TimeDelta duration,
+      bool affects_estimate) override {}
+  void AddBeginMainFrameQueueDurationNotCriticalDuration(
+      base::TimeDelta duration,
+      bool affects_estimate) override {}
+  void AddBeginMainFrameStartToCommitDuration(base::TimeDelta duration,
+                                              bool affects_estimate) override {}
   void AddCommitToReadyToActivateDuration(base::TimeDelta duration,
                                           base::TimeDelta estimate,
                                           bool affects_estimate) override {}
+  void AddPrepareTilesDuration(base::TimeDelta duration,
+                               base::TimeDelta estimate,
+                               bool affects_estimate) override {}
   void AddActivateDuration(base::TimeDelta duration,
                            base::TimeDelta estimate,
                            bool affects_estimate) override {}
@@ -198,11 +271,16 @@
     UMACategory uma_category,
     RenderingStatsInstrumentation* rendering_stats_instrumentation)
     : enabled_(false),
-      begin_main_frame_to_commit_duration_history_(kDurationHistorySize),
+      begin_main_frame_sent_to_commit_duration_history_(kDurationHistorySize),
+      begin_main_frame_queue_duration_critical_history_(kDurationHistorySize),
+      begin_main_frame_queue_duration_not_critical_history_(
+          kDurationHistorySize),
+      begin_main_frame_start_to_commit_duration_history_(kDurationHistorySize),
       commit_to_ready_to_activate_duration_history_(kDurationHistorySize),
       prepare_tiles_duration_history_(kDurationHistorySize),
       activate_duration_history_(kDurationHistorySize),
       draw_duration_history_(kDurationHistorySize),
+      begin_main_frame_on_critical_path_(false),
       uma_reporter_(CreateUMAReporter(uma_category)),
       rendering_stats_instrumentation_(rendering_stats_instrumentation) {}
 
@@ -250,11 +328,30 @@
 
 base::TimeDelta
 CompositorTimingHistory::BeginMainFrameToCommitDurationEstimate() const {
-  return begin_main_frame_to_commit_duration_history_.Percentile(
+  return begin_main_frame_sent_to_commit_duration_history_.Percentile(
       kBeginMainFrameToCommitEstimationPercentile);
 }
 
 base::TimeDelta
+CompositorTimingHistory::BeginMainFrameQueueDurationCriticalEstimate() const {
+  return begin_main_frame_queue_duration_critical_history_.Percentile(
+      kBeginMainFrameQueueDurationCriticalEstimationPercentile);
+}
+
+base::TimeDelta
+CompositorTimingHistory::BeginMainFrameQueueDurationNotCriticalEstimate()
+    const {
+  return begin_main_frame_queue_duration_not_critical_history_.Percentile(
+      kBeginMainFrameQueueDurationNotCriticalEstimationPercentile);
+}
+
+base::TimeDelta
+CompositorTimingHistory::BeginMainFrameStartToCommitDurationEstimate() const {
+  return begin_main_frame_start_to_commit_duration_history_.Percentile(
+      kBeginMainFrameStartToCommitEstimationPercentile);
+}
+
+base::TimeDelta
 CompositorTimingHistory::CommitToReadyToActivateDurationEstimate() const {
   return commit_to_ready_to_activate_duration_history_.Percentile(
       kCommitToReadyToActivateEstimationPercentile);
@@ -273,11 +370,19 @@
   return draw_duration_history_.Percentile(kDrawEstimationPercentile);
 }
 
-void CompositorTimingHistory::WillBeginMainFrame() {
+void CompositorTimingHistory::WillBeginMainFrame(bool on_critical_path) {
   DCHECK_EQ(base::TimeTicks(), begin_main_frame_sent_time_);
+  begin_main_frame_on_critical_path_ = on_critical_path;
   begin_main_frame_sent_time_ = Now();
 }
 
+void CompositorTimingHistory::BeginMainFrameStarted(
+    base::TimeTicks main_thread_start_time) {
+  DCHECK_NE(base::TimeTicks(), begin_main_frame_sent_time_);
+  DCHECK_EQ(base::TimeTicks(), begin_main_frame_start_time_);
+  begin_main_frame_start_time_ = main_thread_start_time;
+}
+
 void CompositorTimingHistory::BeginMainFrameAborted() {
   DidCommit();
 }
@@ -287,26 +392,62 @@
 
   commit_time_ = Now();
 
-  base::TimeDelta begin_main_frame_to_commit_duration =
+  // If the BeginMainFrame start time isn't know, assume it was immediate
+  // for scheduling purposes, but don't report it for UMA to avoid skewing
+  // the results.
+  bool begin_main_frame_start_time_is_valid =
+      !begin_main_frame_start_time_.is_null();
+  if (!begin_main_frame_start_time_is_valid)
+    begin_main_frame_start_time_ = begin_main_frame_sent_time_;
+
+  base::TimeDelta begin_main_frame_sent_to_commit_duration =
       commit_time_ - begin_main_frame_sent_time_;
+  base::TimeDelta begin_main_frame_queue_duration =
+      begin_main_frame_start_time_ - begin_main_frame_sent_time_;
+  base::TimeDelta begin_main_frame_start_to_commit_duration =
+      commit_time_ - begin_main_frame_start_time_;
 
   // Before adding the new data point to the timing history, see what we would
   // have predicted for this frame. This allows us to keep track of the accuracy
   // of our predictions.
-  base::TimeDelta begin_main_frame_to_commit_estimate =
+  base::TimeDelta begin_main_frame_sent_to_commit_estimate =
       BeginMainFrameToCommitDurationEstimate();
   uma_reporter_->AddBeginMainFrameToCommitDuration(
-      begin_main_frame_to_commit_duration, begin_main_frame_to_commit_estimate,
-      enabled_);
+      begin_main_frame_sent_to_commit_duration,
+      begin_main_frame_sent_to_commit_estimate, enabled_);
   rendering_stats_instrumentation_->AddBeginMainFrameToCommitDuration(
-      begin_main_frame_to_commit_duration, begin_main_frame_to_commit_estimate);
+      begin_main_frame_sent_to_commit_duration,
+      begin_main_frame_sent_to_commit_estimate);
+
+  if (begin_main_frame_start_time_is_valid) {
+    if (begin_main_frame_on_critical_path_) {
+      uma_reporter_->AddBeginMainFrameQueueDurationCriticalDuration(
+          begin_main_frame_queue_duration, enabled_);
+    } else {
+      uma_reporter_->AddBeginMainFrameQueueDurationNotCriticalDuration(
+          begin_main_frame_queue_duration, enabled_);
+    }
+  }
+
+  uma_reporter_->AddBeginMainFrameStartToCommitDuration(
+      begin_main_frame_start_to_commit_duration, enabled_);
 
   if (enabled_) {
-    begin_main_frame_to_commit_duration_history_.InsertSample(
-        begin_main_frame_to_commit_duration);
+    begin_main_frame_sent_to_commit_duration_history_.InsertSample(
+        begin_main_frame_sent_to_commit_duration);
+    if (begin_main_frame_on_critical_path_) {
+      begin_main_frame_queue_duration_critical_history_.InsertSample(
+          begin_main_frame_queue_duration);
+    } else {
+      begin_main_frame_queue_duration_not_critical_history_.InsertSample(
+          begin_main_frame_queue_duration);
+    }
+    begin_main_frame_start_to_commit_duration_history_.InsertSample(
+        begin_main_frame_start_to_commit_duration);
   }
 
   begin_main_frame_sent_time_ = base::TimeTicks();
+  begin_main_frame_start_time_ = base::TimeTicks();
 }
 
 void CompositorTimingHistory::WillPrepareTiles() {
diff --git a/cc/scheduler/compositor_timing_history.h b/cc/scheduler/compositor_timing_history.h
index e580c5e..757072b8 100644
--- a/cc/scheduler/compositor_timing_history.h
+++ b/cc/scheduler/compositor_timing_history.h
@@ -34,7 +34,15 @@
 
   void AsValueInto(base::trace_event::TracedValue* state) const;
 
+  // Deprecated: http://crbug.com/552004
   virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() const;
+
+  // The main thread responsiveness depends heavily on whether or not the
+  // on_critical_path flag is set, so we record response times separately.
+  virtual base::TimeDelta BeginMainFrameQueueDurationCriticalEstimate() const;
+  virtual base::TimeDelta BeginMainFrameQueueDurationNotCriticalEstimate()
+      const;
+  virtual base::TimeDelta BeginMainFrameStartToCommitDurationEstimate() const;
   virtual base::TimeDelta CommitToReadyToActivateDurationEstimate() const;
   virtual base::TimeDelta PrepareTilesDurationEstimate() const;
   virtual base::TimeDelta ActivateDurationEstimate() const;
@@ -42,7 +50,8 @@
 
   void SetRecordingEnabled(bool enabled);
 
-  void WillBeginMainFrame();
+  void WillBeginMainFrame(bool on_critical_path);
+  void BeginMainFrameStarted(base::TimeTicks main_thread_start_time);
   void BeginMainFrameAborted();
   void DidCommit();
   void WillPrepareTiles();
@@ -59,13 +68,18 @@
 
   bool enabled_;
 
-  RollingTimeDeltaHistory begin_main_frame_to_commit_duration_history_;
+  RollingTimeDeltaHistory begin_main_frame_sent_to_commit_duration_history_;
+  RollingTimeDeltaHistory begin_main_frame_queue_duration_critical_history_;
+  RollingTimeDeltaHistory begin_main_frame_queue_duration_not_critical_history_;
+  RollingTimeDeltaHistory begin_main_frame_start_to_commit_duration_history_;
   RollingTimeDeltaHistory commit_to_ready_to_activate_duration_history_;
   RollingTimeDeltaHistory prepare_tiles_duration_history_;
   RollingTimeDeltaHistory activate_duration_history_;
   RollingTimeDeltaHistory draw_duration_history_;
 
+  bool begin_main_frame_on_critical_path_;
   base::TimeTicks begin_main_frame_sent_time_;
+  base::TimeTicks begin_main_frame_start_time_;
   base::TimeTicks commit_time_;
   base::TimeTicks start_prepare_tiles_time_;
   base::TimeTicks start_activate_time_;
diff --git a/cc/scheduler/compositor_timing_history_unittest.cc b/cc/scheduler/compositor_timing_history_unittest.cc
index 5ffd68e..6306f29 100644
--- a/cc/scheduler/compositor_timing_history_unittest.cc
+++ b/cc/scheduler/compositor_timing_history_unittest.cc
@@ -50,10 +50,12 @@
   return test_->Now();
 }
 
-TEST_F(CompositorTimingHistoryTest, AllSequentialCommit) {
+TEST_F(CompositorTimingHistoryTest, AllSequentialCommit_Critical) {
   base::TimeDelta one_second = base::TimeDelta::FromSeconds(1);
 
-  base::TimeDelta begin_main_frame_to_commit_duration =
+  base::TimeDelta begin_main_frame_queue_duration =
+      base::TimeDelta::FromMilliseconds(1);
+  base::TimeDelta begin_main_frame_start_to_commit_duration =
       base::TimeDelta::FromMilliseconds(1);
   base::TimeDelta prepare_tiles_duration = base::TimeDelta::FromMilliseconds(2);
   base::TimeDelta prepare_tiles_end_to_ready_to_activate_duration =
@@ -63,9 +65,10 @@
   base::TimeDelta activate_duration = base::TimeDelta::FromMilliseconds(4);
   base::TimeDelta draw_duration = base::TimeDelta::FromMilliseconds(5);
 
-  timing_history_.WillBeginMainFrame();
-  AdvanceNowBy(begin_main_frame_to_commit_duration);
-  // timing_history_.BeginMainFrameAborted();
+  timing_history_.WillBeginMainFrame(true);
+  AdvanceNowBy(begin_main_frame_queue_duration);
+  timing_history_.BeginMainFrameStarted(Now());
+  AdvanceNowBy(begin_main_frame_start_to_commit_duration);
   timing_history_.DidCommit();
   timing_history_.WillPrepareTiles();
   AdvanceNowBy(prepare_tiles_duration);
@@ -83,8 +86,19 @@
   AdvanceNowBy(draw_duration);
   timing_history_.DidDraw();
 
-  EXPECT_EQ(begin_main_frame_to_commit_duration,
+  EXPECT_EQ(begin_main_frame_queue_duration,
+            timing_history_.BeginMainFrameQueueDurationCriticalEstimate());
+  EXPECT_EQ(base::TimeDelta(),
+            timing_history_.BeginMainFrameQueueDurationNotCriticalEstimate());
+  EXPECT_EQ(begin_main_frame_start_to_commit_duration,
+            timing_history_.BeginMainFrameStartToCommitDurationEstimate());
+
+  base::TimeDelta begin_main_frame_to_commit_duration_expected_ =
+      begin_main_frame_queue_duration +
+      begin_main_frame_start_to_commit_duration;
+  EXPECT_EQ(begin_main_frame_to_commit_duration_expected_,
             timing_history_.BeginMainFrameToCommitDurationEstimate());
+
   EXPECT_EQ(commit_to_ready_to_activate_duration,
             timing_history_.CommitToReadyToActivateDurationEstimate());
   EXPECT_EQ(prepare_tiles_duration,
@@ -93,10 +107,13 @@
   EXPECT_EQ(draw_duration, timing_history_.DrawDurationEstimate());
 }
 
-TEST_F(CompositorTimingHistoryTest, AllSequentialBeginMainFrameAborted) {
+TEST_F(CompositorTimingHistoryTest,
+       AllSequentialBeginMainFrameAborted_NotCritical) {
   base::TimeDelta one_second = base::TimeDelta::FromSeconds(1);
 
-  base::TimeDelta begin_main_frame_to_commit_duration =
+  base::TimeDelta begin_main_frame_queue_duration =
+      base::TimeDelta::FromMilliseconds(1);
+  base::TimeDelta begin_main_frame_start_to_commit_duration =
       base::TimeDelta::FromMilliseconds(1);
   base::TimeDelta prepare_tiles_duration = base::TimeDelta::FromMilliseconds(2);
   base::TimeDelta prepare_tiles_end_to_ready_to_activate_duration =
@@ -106,8 +123,10 @@
   base::TimeDelta activate_duration = base::TimeDelta::FromMilliseconds(4);
   base::TimeDelta draw_duration = base::TimeDelta::FromMilliseconds(5);
 
-  timing_history_.WillBeginMainFrame();
-  AdvanceNowBy(begin_main_frame_to_commit_duration);
+  timing_history_.WillBeginMainFrame(false);
+  AdvanceNowBy(begin_main_frame_queue_duration);
+  timing_history_.BeginMainFrameStarted(Now());
+  AdvanceNowBy(begin_main_frame_start_to_commit_duration);
   // BeginMainFrameAborted counts as a commit complete.
   timing_history_.BeginMainFrameAborted();
   timing_history_.WillPrepareTiles();
@@ -126,8 +145,19 @@
   AdvanceNowBy(draw_duration);
   timing_history_.DidDraw();
 
-  EXPECT_EQ(begin_main_frame_to_commit_duration,
+  EXPECT_EQ(base::TimeDelta(),
+            timing_history_.BeginMainFrameQueueDurationCriticalEstimate());
+  EXPECT_EQ(begin_main_frame_queue_duration,
+            timing_history_.BeginMainFrameQueueDurationNotCriticalEstimate());
+  EXPECT_EQ(begin_main_frame_start_to_commit_duration,
+            timing_history_.BeginMainFrameStartToCommitDurationEstimate());
+
+  base::TimeDelta begin_main_frame_to_commit_duration_expected_ =
+      begin_main_frame_queue_duration +
+      begin_main_frame_start_to_commit_duration;
+  EXPECT_EQ(begin_main_frame_to_commit_duration_expected_,
             timing_history_.BeginMainFrameToCommitDurationEstimate());
+
   EXPECT_EQ(commit_to_ready_to_activate_duration,
             timing_history_.CommitToReadyToActivateDurationEstimate());
   EXPECT_EQ(prepare_tiles_duration,
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 69e45cd..184d0b1 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -263,9 +263,11 @@
   ProcessScheduledActions();
 }
 
-void Scheduler::NotifyBeginMainFrameStarted() {
+void Scheduler::NotifyBeginMainFrameStarted(
+    base::TimeTicks main_thread_start_time) {
   TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted");
   state_machine_.NotifyBeginMainFrameStarted();
+  compositor_timing_history_->BeginMainFrameStarted(main_thread_start_time);
 }
 
 base::TimeTicks Scheduler::LastBeginImplFrameTime() {
@@ -510,6 +512,7 @@
   DCHECK(state_machine_.HasInitializedOutputSurface());
 
   begin_impl_frame_tracker_.Start(args);
+  begin_main_frame_args_ = args;
   state_machine_.OnBeginImplFrame();
   devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
   client_->WillBeginImplFrame(begin_impl_frame_tracker_.Current());
@@ -648,8 +651,10 @@
         client_->ScheduledActionAnimate();
         break;
       case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
-        compositor_timing_history_->WillBeginMainFrame();
+        compositor_timing_history_->WillBeginMainFrame(
+            begin_main_frame_args_.on_critical_path);
         state_machine_.WillSendBeginMainFrame();
+        // TODO(brianderson): Pass begin_main_frame_args_ directly to client.
         client_->ScheduledActionSendBeginMainFrame();
         break;
       case SchedulerStateMachine::ACTION_COMMIT: {
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index 26bc13a..632dd14 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -128,7 +128,11 @@
     return state_machine_.impl_latency_takes_priority();
   }
 
-  void NotifyBeginMainFrameStarted();
+  // Pass in a main_thread_start_time of base::TimeTicks() if it is not
+  // known or not trustworthy (e.g. blink is running on a remote channel)
+  // to signal that the start time isn't known and should not be used for
+  // scheduling or statistics purposes.
+  void NotifyBeginMainFrameStarted(base::TimeTicks main_thread_start_time);
 
   base::TimeTicks LastBeginImplFrameTime();
 
@@ -176,6 +180,7 @@
   SchedulerStateMachine::BeginImplFrameDeadlineMode
       begin_impl_frame_deadline_mode_;
   BeginFrameTracker begin_impl_frame_tracker_;
+  BeginFrameArgs begin_main_frame_args_;
 
   base::Closure begin_retro_frame_closure_;
   base::Closure begin_impl_frame_deadline_closure_;
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index d9ce7676..01ac8cbb 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -1035,7 +1035,7 @@
 }
 
 void SchedulerStateMachine::NotifyReadyToCommit() {
-  DCHECK(begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_STARTED)
+  DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_STARTED)
       << AsValue()->ToString();
   begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT;
   // In commit_to_active_tree mode, commit should happen right after
@@ -1046,7 +1046,7 @@
 }
 
 void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) {
-  DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_SENT);
+  DCHECK_EQ(begin_main_frame_state_, BEGIN_MAIN_FRAME_STATE_STARTED);
   switch (reason) {
     case CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST:
     case CommitEarlyOutReason::ABORTED_NOT_VISIBLE:
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index 20e8188..fcd4516 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -1233,6 +1233,7 @@
 
   // Become invisible and abort BeginMainFrame.
   state.SetVisible(false);
+  state.NotifyBeginMainFrameStarted();
   state.BeginMainFrameAborted(CommitEarlyOutReason::ABORTED_NOT_VISIBLE);
 
   // NeedsCommit should now be true again because we never actually did a
@@ -1288,6 +1289,7 @@
 
   // Abort the commit, true means that the BeginMainFrame was sent but there
   // was no work to do on the main thread.
+  state.NotifyBeginMainFrameStarted();
   state.BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
 
   // NeedsCommit should now be false because the commit was actually handled.
@@ -1849,6 +1851,7 @@
 
   // Since only the scroll offset changed, the main thread will abort the
   // commit.
+  state.NotifyBeginMainFrameStarted();
   state.BeginMainFrameAborted(CommitEarlyOutReason::FINISHED_NO_UPDATES);
 
   // Since the commit was aborted, we should draw right away instead of waiting
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 70f6dec9..6349454b 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -326,7 +326,7 @@
       SCOPED_TRACE("Do first frame to commit after initialize.");
       AdvanceFrame();
 
-      scheduler_->NotifyBeginMainFrameStarted();
+      scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
       scheduler_->NotifyReadyToCommit();
       scheduler_->NotifyReadyToActivate();
       scheduler_->NotifyReadyToDraw();
@@ -555,7 +555,7 @@
   client_->Reset();
 
   // NotifyReadyToCommit should trigger the commit.
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
   EXPECT_TRUE(client_->needs_begin_frames());
@@ -678,7 +678,7 @@
   client_->Reset();
 
   // Finish the first commit.
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
   EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
@@ -709,7 +709,7 @@
 
   // Finishing the commit before the deadline should post a new deadline task
   // to trigger the deadline early.
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
   EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
@@ -892,7 +892,7 @@
   EXPECT_EQ(1, client->num_draws());
   EXPECT_TRUE(scheduler_->CommitPending());
   EXPECT_TRUE(client->needs_begin_frames());
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   scheduler_->NotifyReadyToActivate();
 
@@ -1278,7 +1278,7 @@
 
   // Begin new frame.
   EXPECT_SCOPED(AdvanceFrame());
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
 
@@ -1318,7 +1318,7 @@
 
   // Begin new frame.
   EXPECT_SCOPED(AdvanceFrame());
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
 
@@ -1355,7 +1355,7 @@
   EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
   task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
   EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   scheduler_->NotifyReadyToActivate();
   EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 5);
@@ -1478,7 +1478,7 @@
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 3, 4);
 
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   scheduler_->NotifyReadyToActivate();
   EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
@@ -1527,7 +1527,7 @@
     EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 3);
 
     client_->Reset();
-    scheduler_->NotifyBeginMainFrameStarted();
+    scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
     scheduler_->NotifyReadyToCommit();
     scheduler_->NotifyReadyToActivate();
     task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
@@ -1664,7 +1664,7 @@
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 3);
 
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   scheduler_->NotifyReadyToActivate();
   EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
@@ -1689,7 +1689,7 @@
 
     client_->Reset();
     scheduler_->DidSwapBuffersComplete();
-    scheduler_->NotifyBeginMainFrameStarted();
+    scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
     scheduler_->NotifyReadyToCommit();
     scheduler_->NotifyReadyToActivate();
     task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
@@ -1774,7 +1774,7 @@
   EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
   task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
   EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   scheduler_->NotifyReadyToActivate();
   EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
@@ -1792,7 +1792,7 @@
   EXPECT_SCOPED(AdvanceFrame());
   EXPECT_TRUE(scheduler_->MainThreadMissedLastDeadline());
   task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   scheduler_->NotifyReadyToActivate();
 
@@ -1863,7 +1863,7 @@
   EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
   SendNextBeginFrame();
   EXPECT_FALSE(scheduler_->MainThreadMissedLastDeadline());
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   scheduler_->NotifyReadyToActivate();
   task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
@@ -1905,7 +1905,7 @@
   EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
   task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
   EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   scheduler_->NotifyReadyToActivate();
   EXPECT_FALSE(scheduler_->CommitPending());
@@ -1922,7 +1922,7 @@
   EXPECT_FALSE(scheduler_->CommitPending());
   scheduler_->SetNeedsBeginMainFrame();
   EXPECT_SCOPED(AdvanceFrame());
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   scheduler_->NotifyReadyToActivate();
   EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
@@ -1977,7 +1977,7 @@
   task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
   EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
   scheduler_->DidSwapBuffersComplete();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_FALSE(scheduler_->CommitPending());
   EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 6);
@@ -1998,7 +1998,7 @@
   EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
   task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
   EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4);
   EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 4);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 4);
@@ -2058,7 +2058,7 @@
   task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
   EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
   scheduler_->DidSwapBuffersComplete();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_FALSE(scheduler_->CommitPending());
   EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 6);
@@ -2079,7 +2079,7 @@
   task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
   EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
   scheduler_->DidSwapBuffersComplete();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   EXPECT_ACTION("WillBeginImplFrame", client_, 0, 4);
   EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 4);
   EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 4);
@@ -2133,7 +2133,7 @@
   client_->Reset();
 
   // NotifyReadyToCommit should trigger the commit.
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
   EXPECT_TRUE(client_->needs_begin_frames());
@@ -2188,7 +2188,7 @@
   EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
 
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
 
   client_->Reset();
   BeginFrameArgs retro_frame_args = SendNextBeginFrame();
@@ -2249,7 +2249,7 @@
   EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
 
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
 
   client_->Reset();
   BeginFrameArgs retro_frame_args = SendNextBeginFrame();
@@ -2366,7 +2366,7 @@
   client_->Reset();
 
   // NotifyReadyToCommit should trigger the commit.
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
   client_->Reset();
@@ -2456,7 +2456,7 @@
   client_->Reset();
 
   // NotifyReadyToCommit should trigger the pending commit.
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
   client_->Reset();
@@ -2581,7 +2581,7 @@
   EXPECT_NO_ACTION(client_);
 
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_ACTION("ScheduledActionCommit", client_, 0, 2);
   EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 2);
@@ -2631,7 +2631,7 @@
   EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
 
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_ACTION("ScheduledActionCommit", client_, 0, 3);
   EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 3);
@@ -2653,7 +2653,7 @@
   EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
 
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
 
@@ -2732,7 +2732,7 @@
 
   // NotifyReadyToCommit should trigger the commit.
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
   EXPECT_TRUE(client_->needs_begin_frames());
@@ -2792,7 +2792,7 @@
 
   // NotifyReadyToCommit should trigger the commit.
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
   EXPECT_TRUE(client_->needs_begin_frames());
@@ -2849,7 +2849,7 @@
 
   // NotifyReadyToCommit should trigger the commit.
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
   EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames());
@@ -2888,7 +2888,7 @@
   EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
 
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
 
@@ -2924,7 +2924,7 @@
   EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
 
   client_->Reset();
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
   EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
@@ -3068,7 +3068,7 @@
 
   // Trigger a frame draw.
   EXPECT_SCOPED(AdvanceFrame());
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   scheduler_->NotifyReadyToActivate();
   task_runner().RunPendingTasks();
@@ -3226,7 +3226,7 @@
   EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
   client_->Reset();
 
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   EXPECT_NO_ACTION(client_);
 
   // Next vsync.
@@ -3283,7 +3283,7 @@
   EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
   client_->Reset();
 
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   EXPECT_NO_ACTION(client_);
 
   scheduler_->NotifyReadyToCommit();
@@ -3305,7 +3305,7 @@
   EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
   client_->Reset();
 
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   EXPECT_NO_ACTION(client_);
 
   // Allow new commit even though previous commit hasn't been drawn.
@@ -3402,7 +3402,7 @@
   EXPECT_SINGLE_ACTION("ScheduledActionSendBeginMainFrame", client_);
   client_->Reset();
 
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
   client_->Reset();
@@ -3461,7 +3461,7 @@
 
   EXPECT_EQ(initial_interval, scheduler_->BeginImplFrameInterval());
 
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
   scheduler_->NotifyReadyToActivate();
   task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index d42398a..b0fae93 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -218,9 +218,11 @@
     ThreadProxy::SetDeferCommitsOnImpl(defer_commits);
   }
 
-  void BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason) override {
+  void BeginMainFrameAbortedOnImpl(
+      CommitEarlyOutReason reason,
+      base::TimeTicks main_thread_start_time) override {
     test_hooks_->BeginMainFrameAbortedOnImpl(reason);
-    ThreadProxy::BeginMainFrameAbortedOnImpl(reason);
+    ThreadProxy::BeginMainFrameAbortedOnImpl(reason, main_thread_start_time);
   }
 
   void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) override {
@@ -255,9 +257,11 @@
 
   void StartCommitOnImpl(CompletionEvent* completion,
                          LayerTreeHost* layer_tree_host,
+                         base::TimeTicks main_thread_start_time,
                          bool hold_commit_for_activation) override {
     test_hooks_->StartCommitOnImpl();
     ThreadProxy::StartCommitOnImpl(completion, layer_tree_host,
+                                   main_thread_start_time,
                                    hold_commit_for_activation);
   }
 
diff --git a/cc/trees/channel_main.h b/cc/trees/channel_main.h
index 9c6689c..8f8c4ee 100644
--- a/cc/trees/channel_main.h
+++ b/cc/trees/channel_main.h
@@ -43,9 +43,12 @@
       bool* main_frame_will_happen) = 0;
   virtual void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) = 0;
   virtual void SetNeedsCommitOnImpl() = 0;
-  virtual void BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason) = 0;
+  virtual void BeginMainFrameAbortedOnImpl(
+      CommitEarlyOutReason reason,
+      base::TimeTicks main_thread_start_time) = 0;
   virtual void StartCommitOnImpl(CompletionEvent* completion,
                                  LayerTreeHost* layer_tree_host,
+                                 base::TimeTicks main_thread_start_time,
                                  bool hold_commit_for_activation) = 0;
   virtual void InitializeImplOnImpl(CompletionEvent* completion,
                                     LayerTreeHost* layer_tree_host) = 0;
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h
index b2f4cd1..4b0cdaa 100644
--- a/cc/trees/proxy_impl.h
+++ b/cc/trees/proxy_impl.h
@@ -35,7 +35,6 @@
   virtual void SetDeferCommitsOnImpl(bool defer_commits) const = 0;
   virtual void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) = 0;
   virtual void SetNeedsCommitOnImpl() = 0;
-  virtual void BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason) = 0;
   virtual void FinishAllRenderingOnImpl(CompletionEvent* completion) = 0;
   virtual void SetVisibleOnImpl(bool visible) = 0;
   virtual void ReleaseOutputSurfaceOnImpl(CompletionEvent* completion) = 0;
@@ -43,8 +42,12 @@
   virtual void MainFrameWillHappenOnImplForTesting(
       CompletionEvent* completion,
       bool* main_frame_will_happen) = 0;
+  virtual void BeginMainFrameAbortedOnImpl(
+      CommitEarlyOutReason reason,
+      base::TimeTicks main_thread_start_time) = 0;
   virtual void StartCommitOnImpl(CompletionEvent* completion,
                                  LayerTreeHost* layer_tree_host,
+                                 base::TimeTicks main_thread_start_time,
                                  bool hold_commit_for_activation) = 0;
   virtual void InitializeImplOnImpl(CompletionEvent* completion,
                                     LayerTreeHost* layer_tree_host) = 0;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index ce67d341..9ddf997 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -752,6 +752,11 @@
 }
 
 void SingleThreadProxy::BeginMainFrame(const BeginFrameArgs& begin_frame_args) {
+  if (scheduler_on_impl_thread_) {
+    scheduler_on_impl_thread_->NotifyBeginMainFrameStarted(
+        base::TimeTicks::Now());
+  }
+
   commit_requested_ = false;
   animate_requested_ = false;
 
@@ -805,10 +810,8 @@
   // TODO(enne): SingleThreadProxy does not support cancelling commits yet,
   // search for CommitEarlyOutReason::FINISHED_NO_UPDATES inside
   // thread_proxy.cc
-  if (scheduler_on_impl_thread_) {
-    scheduler_on_impl_thread_->NotifyBeginMainFrameStarted();
+  if (scheduler_on_impl_thread_)
     scheduler_on_impl_thread_->NotifyReadyToCommit();
-  }
 }
 
 void SingleThreadProxy::BeginMainFrameAbortedOnImplThread(
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index c50736a..5bd9c71 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -595,6 +595,9 @@
   benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
       benchmark_instrumentation::kDoBeginFrame,
       begin_main_frame_state->begin_frame_id);
+
+  base::TimeTicks begin_main_frame_start_time = base::TimeTicks::Now();
+
   TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("cc.BeginMainFrame");
   DCHECK(IsMainThread());
   DCHECK_EQ(NO_PIPELINE_STAGE, main().current_pipeline_stage);
@@ -603,7 +606,8 @@
     TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit",
                          TRACE_EVENT_SCOPE_THREAD);
     main().channel_main->BeginMainFrameAbortedOnImpl(
-        CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT);
+        CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT,
+        begin_main_frame_start_time);
     return;
   }
 
@@ -618,7 +622,7 @@
   if (!main().layer_tree_host->visible()) {
     TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
     main().channel_main->BeginMainFrameAbortedOnImpl(
-        CommitEarlyOutReason::ABORTED_NOT_VISIBLE);
+        CommitEarlyOutReason::ABORTED_NOT_VISIBLE, begin_main_frame_start_time);
     return;
   }
 
@@ -626,7 +630,8 @@
     TRACE_EVENT_INSTANT0(
         "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD);
     main().channel_main->BeginMainFrameAbortedOnImpl(
-        CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST);
+        CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST,
+        begin_main_frame_start_time);
     return;
   }
 
@@ -667,7 +672,7 @@
   if (!updated && can_cancel_this_commit) {
     TRACE_EVENT_INSTANT0("cc", "EarlyOut_NoUpdates", TRACE_EVENT_SCOPE_THREAD);
     main().channel_main->BeginMainFrameAbortedOnImpl(
-        CommitEarlyOutReason::FINISHED_NO_UPDATES);
+        CommitEarlyOutReason::FINISHED_NO_UPDATES, begin_main_frame_start_time);
 
     // Although the commit is internally aborted, this is because it has been
     // detected to be a no-op.  From the perspective of an embedder, this commit
@@ -696,6 +701,7 @@
 
     CompletionEvent completion;
     main().channel_main->StartCommitOnImpl(&completion, main().layer_tree_host,
+                                           begin_main_frame_start_time,
                                            main().commit_waits_for_activation);
     completion.Wait();
     main().commit_waits_for_activation = false;
@@ -714,6 +720,7 @@
 
 void ThreadProxy::StartCommitOnImpl(CompletionEvent* completion,
                                     LayerTreeHost* layer_tree_host,
+                                    base::TimeTicks main_thread_start_time,
                                     bool hold_commit_for_activation) {
   TRACE_EVENT0("cc", "ThreadProxy::StartCommitOnImplThread");
   DCHECK(!impl().commit_completion_event);
@@ -737,14 +744,16 @@
 
   // Ideally, we should inform to impl thread when BeginMainFrame is started.
   // But, we can avoid a PostTask in here.
-  impl().scheduler->NotifyBeginMainFrameStarted();
+  impl().scheduler->NotifyBeginMainFrameStarted(main_thread_start_time);
   impl().commit_completion_event = completion;
   DCHECK(!blocked_main_commit().layer_tree_host);
   blocked_main_commit().layer_tree_host = layer_tree_host;
   impl().scheduler->NotifyReadyToCommit();
 }
 
-void ThreadProxy::BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason) {
+void ThreadProxy::BeginMainFrameAbortedOnImpl(
+    CommitEarlyOutReason reason,
+    base::TimeTicks main_thread_start_time) {
   TRACE_EVENT1("cc", "ThreadProxy::BeginMainFrameAbortedOnImplThread", "reason",
                CommitEarlyOutReasonToString(reason));
   DCHECK(IsImplThread());
@@ -758,6 +767,7 @@
         impl().last_begin_main_frame_args;
   }
   impl().layer_tree_host_impl->BeginMainFrameAborted(reason);
+  impl().scheduler->NotifyBeginMainFrameStarted(main_thread_start_time);
   impl().scheduler->BeginMainFrameAborted(reason);
 }
 
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index 0b954bd..871d1b2 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -288,9 +288,12 @@
       bool* main_frame_will_happen) override;
   void SetNeedsCommitOnImpl() override;
   void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) override;
-  void BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason) override;
+  void BeginMainFrameAbortedOnImpl(
+      CommitEarlyOutReason reason,
+      base::TimeTicks main_thread_start_time) override;
   void StartCommitOnImpl(CompletionEvent* completion,
                          LayerTreeHost* layer_tree_host,
+                         base::TimeTicks main_thread_start_time,
                          bool hold_commit_for_activation) override;
   void InitializeImplOnImpl(CompletionEvent* completion,
                             LayerTreeHost* layer_tree_host) override;
diff --git a/cc/trees/threaded_channel.cc b/cc/trees/threaded_channel.cc
index b723f8c..1bcd638 100644
--- a/cc/trees/threaded_channel.cc
+++ b/cc/trees/threaded_channel.cc
@@ -80,10 +80,13 @@
                                               proxy_impl_->GetImplWeakPtr()));
 }
 
-void ThreadedChannel::BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason) {
+void ThreadedChannel::BeginMainFrameAbortedOnImpl(
+    CommitEarlyOutReason reason,
+    base::TimeTicks main_thread_start_time) {
   ImplThreadTaskRunner()->PostTask(
       FROM_HERE, base::Bind(&ProxyImpl::BeginMainFrameAbortedOnImpl,
-                            proxy_impl_->GetImplWeakPtr(), reason));
+                            proxy_impl_->GetImplWeakPtr(), reason,
+                            main_thread_start_time));
 }
 
 void ThreadedChannel::SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) {
@@ -94,11 +97,13 @@
 
 void ThreadedChannel::StartCommitOnImpl(CompletionEvent* completion,
                                         LayerTreeHost* layer_tree_host,
+                                        base::TimeTicks main_thread_start_time,
                                         bool hold_commit_for_activation) {
   ImplThreadTaskRunner()->PostTask(
       FROM_HERE,
       base::Bind(&ProxyImpl::StartCommitOnImpl, proxy_impl_->GetImplWeakPtr(),
-                 completion, layer_tree_host, hold_commit_for_activation));
+                 completion, layer_tree_host, main_thread_start_time,
+                 hold_commit_for_activation));
 }
 
 void ThreadedChannel::InitializeImplOnImpl(CompletionEvent* completion,
diff --git a/cc/trees/threaded_channel.h b/cc/trees/threaded_channel.h
index 1a4b8b7..2c7140d 100644
--- a/cc/trees/threaded_channel.h
+++ b/cc/trees/threaded_channel.h
@@ -85,7 +85,9 @@
   void SetInputThrottledUntilCommitOnImpl(bool is_throttled) override;
   void SetDeferCommitsOnImpl(bool defer_commits) override;
   void SetNeedsCommitOnImpl() override;
-  void BeginMainFrameAbortedOnImpl(CommitEarlyOutReason reason) override;
+  void BeginMainFrameAbortedOnImpl(
+      CommitEarlyOutReason reason,
+      base::TimeTicks main_thread_start_time) override;
   void SetNeedsRedrawOnImpl(const gfx::Rect& damage_rect) override;
   void SetVisibleOnImpl(bool visible) override;
 
@@ -98,6 +100,7 @@
       bool* main_frame_will_happen) override;
   void StartCommitOnImpl(CompletionEvent* completion,
                          LayerTreeHost* layer_tree_host,
+                         base::TimeTicks main_thread_start_time,
                          bool hold_commit_for_activation) override;
   void InitializeImplOnImpl(CompletionEvent* completion,
                             LayerTreeHost* layer_tree_host) override;
diff --git a/chrome/VERSION b/chrome/VERSION
index d54908d..567f494 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=48
 MINOR=0
-BUILD=2561
+BUILD=2562
 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 31c4d25..9c6dd33 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -347,26 +347,17 @@
   ]
 }
 
-copy_ex("chrome_public_apk_assets") {
-  clear_dir = true
-  dest = "$root_build_dir/chrome_public_apk_assets"
+android_assets("chrome_public_apk_assets") {
   sources = chrome_android_paks_gypi.chrome_android_pak_input_resources
-  if (icu_use_data_file) {
-    sources += [ "$root_build_dir/icudtl.dat" ]
-  }
+  sources += [ "$root_build_dir/resources.pak" ]
+  disable_compression = true
+
   deps = [
     "//chrome:packed_extra_resources",
     "//chrome:packed_resources",
-    "//third_party/icu:icudata",
+    "//third_party/icu:icu_assets",
+    "//v8:v8_external_startup_data_assets",
   ]
-
-  if (v8_use_external_startup_data) {
-    renaming_sources = v8_external_startup_data_renaming_sources
-    renaming_destinations = v8_external_startup_data_renaming_destinations
-    deps += [ "//v8" ]
-  }
-
-  sources += [ "$root_build_dir/resources.pak" ]
 }
 
 # GYP: //chrome/android/chrome_apk.gyp:chrome_apk_manifest
diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni
index ce8b74c0..b068b39 100644
--- a/chrome/android/chrome_public_apk_tmpl.gni
+++ b/chrome/android/chrome_public_apk_tmpl.gni
@@ -9,7 +9,6 @@
   forward_variables_from(invoker, "*")
 
   android_apk(target_name) {
-    asset_location = "$root_build_dir/chrome_public_apk_assets"
     _native_lib_file =
         rebase_path("$root_gen_dir/CHROME_VERSION.json", root_out_dir)
     native_lib_version_arg = "@FileArg($_native_lib_file:full-quoted)"
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index b90bd68b..6d932553 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -462,6 +462,16 @@
         </receiver>
         {% endif %}
 
+        <service android:name="org.chromium.components.variations.firstrun.VariationsSeedService"
+            android:exported="false" />
+
+        <receiver android:name="org.chromium.components.variations.firstrun.VariationsSeedServiceLauncher"
+            android:permission="{{ manifest_package }}.TOS_ACKED">
+            <intent-filter>
+                <action android:name="{{ manifest_package }}.TOS_ACKED" />
+            </intent-filter>
+        </receiver>
+
         <receiver android:name="org.chromium.chrome.browser.firstrun.ToSAckedReceiver"
             android:permission="{{ manifest_package }}.TOS_ACKED">
             <intent-filter>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
index df3d8bb8..c5c1564 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
@@ -7,7 +7,6 @@
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.preference.PreferenceManager;
-import android.util.Base64;
 import android.util.Log;
 
 import org.chromium.base.ThreadUtils;
@@ -220,45 +219,6 @@
         }
     }
 
-    // TODO(agulenko): Move this piece of code to a separate class.
-
-    private static final String VARIATIONS_FIRST_RUN_SEED_BASE64 = "variations_seed_base64";
-    private static final String VARIATIONS_FIRST_RUN_SEED_SIGNATURE = "variations_seed_signature";
-    private static final String VARIATIONS_FIRST_RUN_SEED_COUNTRY = "variations_seed_country";
-
-    private static String getVariationsFirstRunSeedPref(Context context, String prefName) {
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
-        return prefs.getString(prefName, "");
-    }
-
-    public static void setVariationsFirstRunSeed(
-            Context context, byte[] rawSeed, String signature, String country) {
-        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
-        prefs.edit()
-                .putString(VARIATIONS_FIRST_RUN_SEED_BASE64,
-                        Base64.encodeToString(rawSeed, Base64.NO_WRAP))
-                .putString(VARIATIONS_FIRST_RUN_SEED_SIGNATURE, signature)
-                .putString(VARIATIONS_FIRST_RUN_SEED_COUNTRY, country)
-                .apply();
-    }
-
-    @CalledByNative
-    private static byte[] getVariationsFirstRunSeedData(Context context) {
-        return Base64.decode(
-                getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_BASE64),
-                Base64.NO_WRAP);
-    }
-
-    @CalledByNative
-    private static String getVariationsFirstRunSeedSignature(Context context) {
-        return getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_SIGNATURE);
-    }
-
-    @CalledByNative
-    private static String getVariationsFirstRunSeedCountry(Context context) {
-        return getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_COUNTRY);
-    }
-
     public boolean isAcceptCookiesEnabled() {
         return nativeGetAcceptCookiesEnabled();
     }
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 9a0035b..c44e72ad 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -777,33 +777,15 @@
       </message>
 
       <!-- Data Use -->
-      <message name="IDS_DATA_USE_TRACKING_STARTED_SNACKBAR_MESSAGE" desc="Message shown when data use tracking starts.">
-        Data use is being measured
-      </message>
       <message name="IDS_DATA_USE_TRACKING_SNACKBAR_ACTION" desc="Button to learn more when data use tracking starts or ends.">
         More
       </message>
-      <message name="IDS_DATA_USE_TRACKING_ENDED_SNACKBAR_MESSAGE" desc="Message shown when data use tracking has ended.">
-        Data use measuring has ended
-      </message>
-      <message name="IDS_DATA_USE_TRACKING_ENDED_TITLE" desc="Message shown on the dialog when data use tracking has ended.">
-        Data use measuring ended
-      </message>
-      <message name="IDS_DATA_USE_TRACKING_ENDED_MESSAGE" desc="Message shown on the dialog when data use tracking has ended.">
-        Your data use will no longer be measured.
-      </message>
       <message name="IDS_DATA_USE_TRACKING_ENDED_CHECKBOX_MESSAGE" desc="Message shown to opt out of seeing dialogs when data use tracking has ended.">
         Don’t show this again
       </message>
       <message name="IDS_DATA_USE_TRACKING_ENDED_CONTINUE" desc="Continue button for the dialog shown when data use tracking has ended. When clicked, the page resumes loading.">
         Continue
       </message>
-      <message name="IDS_DATA_USE_LEARN_MORE_TITLE" desc="Title for the 'Learn more' link in the the dialog shown when data use tracking has ended">
-        Learn more
-      </message>
-      <message name="IDS_DATA_USE_LEARN_MORE_LINK_URL" desc="URL for the 'Learn more' link in the the dialog shown when data use tracking has ended">
-        <!-- Intentionally empty. This is overridden downstream. -->
-      </message>
 
       <!-- About Chrome preferences -->
       <message name="IDS_PREFS_ABOUT_CHROME" desc="Title for the About Chrome page. [CHAR-LIMIT=32]">
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index c230009c..72dfe469 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1023,6 +1023,46 @@
     Failed to retrieve space info
   </message>
 
+<!-- Common for Audio player and Media player -->
+  <message name="IDS_MEDIA_PLAYER_PLAY_BUTTON_LABEL" desc="Label for the Play button of media players (audio player / video player).">
+    Play
+  </message>
+  <message name="IDS_MEDIA_PLAYER_PAUSE_BUTTON_LABEL" desc="Label for the Pause button of media player (audio player / video player).">
+    Pause
+  </message>
+  <message name="IDS_MEDIA_PLAYER_MUTE_BUTTON_LABEL" desc="Label for the Mute button of media player (audio player / video player).">
+    Mute
+  </message>
+  <message name="IDS_MEDIA_PLAYER_UNMUTE_BUTTON_LABEL" desc="Label for the Unmute button of media player (audio player / video player).">
+    Unmute
+  </message>
+  <message name="IDS_MEDIA_PLAYER_PREVIOUS_BUTTON_LABEL" desc="Label for the Previous button, which is used to select previous video in the video player, or select previous track in the audio player.">
+    Previous
+  </message>
+  <message name="IDS_MEDIA_PLAYER_NEXT_BUTTON_LABEL" desc="Label for the Next button, which is used to select previous video in the video player, or select previous track in the audio player.">
+    Next
+  </message>
+  <message name="IDS_MEDIA_PLAYER_SEEK_SLIDER_LABEL" desc="Label for the seek bar of media player.">
+    Seek slider
+  </message>
+  <message name="IDS_MEDIA_PLAYER_VOLUME_SLIDER_LABEL" desc="Label for the volume slider of media player.">
+    Volume slider
+  </message>
+
+<!-- Audio Player -->
+  <message name="IDS_AUDIO_PLAYER_SHUFFLE_BUTTON_LABEL" desc="Label for the Shuffle button of audio player.">
+    Shuffle
+  </message>
+  <message name="IDS_AUDIO_PLAYER_REPEAT_BUTTON_LABEL" desc="Label for the Repeat button of audio player">
+    Repeat
+  </message>
+  <message name="IDS_AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL" desc="Label for a button which is used to open volume slider in audio player.">
+    Open volume slider
+  </message>
+  <message name="IDS_AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL" desc="Label for a button which is used to open play list in audio player.">
+    Open play list
+  </message>
+
 <!-- Video Player -->
   <message name="IDS_VIDEO_PLAYER_PLAY_THIS_COMPUTER" desc="In the video player app, message of menu item which is shown at the top of the list of Chromecasts. This menuitem is to play the video on this computer (locally), intead of on TVs with Chromecast.">
     This computer
@@ -1045,6 +1085,12 @@
   <message name="IDS_VIDEO_PLAYER_LOOPED_MODE" desc="In the video player app, message informing that the movie will be played in a loop.">
     This video will keep playing until the cows come home.
   </message>
+  <message name="IDS_VIDEO_PLAYER_FULL_SCREEN_BUTTON_LABEL" desc="Label for a button which is used to enter full screen mode in video player.">
+    Full screen
+  </message>
+  <message name="IDS_VIDEO_PLAYER_EXIT_FULL_SCREEN_BUTTON_LABEL" desc="Label for a button which is used to exit full screen mode in video player.">
+    Exit full screen
+  </message>
 
 <!-- Imageburn Strings -->
   <message name="IDS_CHECKING_FOR_UPDATES" desc="Notification for checking for update">
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 06591e4..a1b51d01 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -9347,10 +9347,10 @@
         This webpage is not available
       </message>
       <message name="IDS_ERRORPAGES_SUMMARY_SSL_VERSION_OR_CIPHER_MISMATCH" desc="Summary in the error page for SSL cipher and version errors.">
-        A secure connection cannot be established because this site uses an unsupported protocol or cipher suite. This is usually caused when the server needs RC4 support, which has been removed.
+        A secure connection cannot be established because this site uses an unsupported protocol or cipher suite. This is likely to be caused when the server needs RC4, which is no longer considered secure.
       </message>
       <message name="IDS_ERRORPAGES_DETAILS_SSL_VERSION_OR_CIPHER_MISMATCH" desc="The error message displayed for SSL cipher and version errors.">
-        The client and server don't support a common SSL protocol version or cipher suite. This is usually caused when the server needs RC4 support, which has been removed.
+        The client and server don't support a common SSL protocol version or cipher suite. This is likely to be caused when the server needs RC4, which is no longer considered secure.
       </message>
 
       <message name="IDS_ERRORPAGES_HEADING_PINNING_FAILURE" desc="Title of the error page for a certificate which doesn't match the built-in pins for that name">
@@ -15346,6 +15346,28 @@
           Default (pick up everything)
         </message>
       </if>
+      
+    <if expr="is_android">
+      <!-- Data Use -->
+      <message name="IDS_DATA_USE_TRACKING_STARTED_SNACKBAR_MESSAGE" desc="Message shown when data use tracking starts." formatter_data="android_java">
+        Data use is being measured
+      </message>
+      <message name="IDS_DATA_USE_TRACKING_ENDED_SNACKBAR_MESSAGE" desc="Message shown when data use tracking has ended." formatter_data="android_java">
+        Data use measuring has ended
+      </message>
+      <message name="IDS_DATA_USE_TRACKING_ENDED_TITLE" desc="Message shown on the dialog when data use tracking has ended." formatter_data="android_java">
+        Data use measuring ended
+      </message>
+      <message name="IDS_DATA_USE_TRACKING_ENDED_MESSAGE" desc="Message shown on the dialog when data use tracking has ended." formatter_data="android_java">
+        Your data use will no longer be measured.
+      </message>
+      <message name="IDS_DATA_USE_LEARN_MORE_TITLE" desc="Title for the 'Learn more' link in the the dialog shown when data use tracking has ended." formatter_data="android_java">
+        Learn more
+      </message>
+      <message name="IDS_DATA_USE_LEARN_MORE_LINK_URL" desc="URL for the 'Learn more' link in the the dialog shown when data use tracking has ended." formatter_data="android_java">
+        <!-- Intentionally empty. This is overridden via Finch. -->
+      </message>
+    </if>
 
     </messages>
   </release>
diff --git a/chrome/app/resources/terms/terms_am.html b/chrome/app/resources/terms/terms_am.html
index fdc79b6..427cc37 100644
--- a/chrome/app/resources/terms/terms_am.html
+++ b/chrome/app/resources/terms/terms_am.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>የGoogle Chrome የአግልግሎት ስምምነት ውሎች </h2>
-<p>እነዚህ ውሎች ለሚሰራ የGoogle Chrome ኮድ ስሪት ተግባራዊ ይሆናሉ። የGoogle Chrome ሶርስ ኮድ በክፍት ሶርስ (Open source) ሶፍተዌር የፈቃድ ስምምነት ስር በዚህ http://code.google.com/chromium/terms.html ይገኛሉ።</p>
+<p>እነዚህ ውሎች ለሚሰራ የGoogle Chrome ኮድ ስሪት ተግባራዊ ይሆናሉ። የGoogle Chrome ሶርስ ኮድ በክፍት ሶርስ (Open source) ሶፍተዌር የፈቃድ ስምምነት ስር በዚህ chrome://credits ይገኛሉ።</p>
 <p><strong>1. ከGoogle ጋር ያለዎት ግንኙነት</strong></p>
 <p>የGoogle ምርቶች፣ ሶፍትዌር፣ ግልጋሎቶች እና ድር ጣቢያዎች (በዚህ ሰነድ ውስጥ በአንድነት “ግልጋሎቶች” ተብለው የተጠቀሱት እና በተለየ የጽሁፍ ስምምነት ለርስዎ በGoogle አማካይነት ከቀረቡት ግልጋሎቶች ውጪ) በርስዎና በGoogle መካከል በሚደረግ ህጋዊ ስምምነት ለስምምነት ውሎቹ ተፈፃሚ ይሆናሉ። “Google” ማለት Google Inc. ማለት ሲሆን ዋናው የንግድ ቦታውም በ1600 Amphitheatre Parkway፣ Mountain View፣ CA 94043፣ ዩናይትድ ስቴትስ ነው። ይህ ሰነድ ስምምነቱ እንዴት እንደተዘጋጀ እና አንዳንድ የስምምነት ውሎች እንዴት ተፈፃሚ እንደሚሆኑ ይገልፃል።</p>
 <p>አልያም ከGoogle ጋር በጽሁፍ ስምምነት ካደረጉ፣ ከGoogle ጋር ያለዎት ስምምነት ቢያንስ በዚህ ሰነድ ውስጥ የተገለጹትን ውሎች እና አካሄዶች ሁልጊዜ የሚያካትት ይሆናል። እነዚህም “አለም አቀፍ ውሎች” ተብለው ከዚህ በታች ተጠቅሰዋል። የክፍት ሶርስ (Open source) ሶፍትዌር ፈቃዶች ለGoogle Chrome ሶርስ ኮድ የተለየ የጽሁፍ ስምምነቶች መስርተዋል። በተወሰነ መጠን የክፍት ሶርስ (Open source) ሶፍትዌር ፍቃዶች እነዚህን አለም አቀፍ ውሎች በግልጽ ይተካሉ፤ Google Chromeን ወይም በGoogle Chrome የተካተተን አንድ የተወሰነ አካል ስለመጠቀም ከGoogle ጋር ያለዎትን ስምምነት የክፍት ሶርስ (Open source) ፈቃዶች የሚያስተዳድሩት ይሆናል።</p>
diff --git a/chrome/app/resources/terms/terms_ar.html b/chrome/app/resources/terms/terms_ar.html
index 96ed5ed6..0f75911 100644
--- a/chrome/app/resources/terms/terms_ar.html
+++ b/chrome/app/resources/terms/terms_ar.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>بنود خدمة Google Chrome</h2>
-<p>تنطبق بنود الخدمة هذه على إصدار شفرة Google Chrome القابلة للتنفيذ. وتتوفر الشفرة المصدر للمتصفح Google Chrome مجانًا بموجب اتفاقيات ترخيص البرامج مفتوحة المصدر في http://code.google.com/intl/ar/chromium/terms.html.</p>
+<p>تنطبق بنود الخدمة هذه على إصدار شفرة Google Chrome القابلة للتنفيذ. وتتوفر الشفرة المصدر للمتصفح Google Chrome مجانًا بموجب اتفاقيات ترخيص البرامج مفتوحة المصدر في chrome://credits.</p>
 <p><strong>1. علاقتك مع Google</strong></p>
 <p>1-1 يخضع استخدامك لمنتجات Google وبرامجها وخدماتها ومواقع الويب التابعة لها (يشار إليها إجمالاً في هذا المستند باسم "الخدمات" وباستثناء أية خدمات مقدمة إليك من Google بموجب أية اتفاقية كتابية مستقلة) لبنود اتفاقية قانونية بينك وبين Google. ويشير المصطلح "Google" إلى شركة Google Inc.‎ التي يقع مقرها الرئيسي في العنوان &lrm;1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. ويفسر هذا المستند طريقة صياغة الاتفاقية، كما يحدد بعضًا من بنود هذه الاتفاقية. </p>
 <p>1-2 ما لم يتم الاتفاق على غير ذلك كتابيًا مع Google، تتضمن اتفاقيتك مع Google دائمًا البنود والشروط الواردة في هذا المستند على الأقل. ‏‫وهذه البنود والشروط يشار إليها في ما يلي باسم "البنود العامة".‬ ‏‫وتشكل تراخيص البرامج مفتوحة المصدر الخاصة بالشفرة المصدر للمتصفح Google Chrome اتفاقيات كتابية مستقلة. ‬ وإلى الحد المقيد الذي يسمح بأن تحل تراخيص البرامج مفتوحة المصدر صراحةً محل هذه البنود العامة، تخضع اتفاقيتك مع Google في ما يتعلق باستخدام Google Chrome أو مكونات معينة مضمنة في Google Chrome إلى تراخيص المصدر المفتوح.‬</p>
diff --git a/chrome/app/resources/terms/terms_bg.html b/chrome/app/resources/terms/terms_bg.html
index 9e483dc..fb0474a6 100644
--- a/chrome/app/resources/terms/terms_bg.html
+++ b/chrome/app/resources/terms/terms_bg.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Общи условия на Google Chrome</h2>
-<p>Тези Общи условия се прилагат към версията с изпълним код на Google Chrome. Изходният код на Google Chrome се предоставя безплатно съгласно лицензионните споразумения за софтуер с отворен код на адрес http://code.google.com/chromium/terms.html.</p>
+<p>Тези Общи условия се прилагат към версията с изпълним код на Google Chrome. Изходният код на Google Chrome се предоставя безплатно съгласно лицензионните споразумения за софтуер с отворен код на адрес chrome://credits.</p>
 <p><strong>1. Вашите отношения с Google</strong></p>
 <p>1.1 Използването от ваша страна на нашите продукти, софтуер, услуги и уебсайтове (наричани събирателно „Услуги“ в този документ и изключващи всички услуги, които ви предоставяме по силата на отделно писмено споразумение) е предмет на условията на правно споразумение между вас и Google. „Google“ означава Google Inc., чийто основен адрес на управление е 1600 Amphitheatre Parkway, Mountain View, CA 94043, САЩ. Този документ обяснява как е съставено това споразумение и посочва някои от условията в него.</p>
 <p>1.2 Ако не е уговорено друго в писмен вид с Google, споразумението ви с нас винаги включва като минимум Общите условия, посочени в този документ. По-нататък те се наричат „Универсални условия“. Лицензите за софтуер с отворен код за изходния код на Google Chrome представляват отделни писмени споразумения. В ограничената степен, в която лицензите за софтуер с отворен код се ползват изрично с приоритет над тези Универсални условия, те регламентират споразумението ви с нас по отношение на използването на Google Chrome или конкретни включени компоненти от него.</p>
diff --git a/chrome/app/resources/terms/terms_bn.html b/chrome/app/resources/terms/terms_bn.html
index dd93b5b7..ad4f38f8 100644
--- a/chrome/app/resources/terms/terms_bn.html
+++ b/chrome/app/resources/terms/terms_bn.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome পরিষেবার চুক্তি</h2>
-<p>পরিষেবার এই চুক্তিগুলি Google Chrome –এর প্রয়োগযোগ্য কোড সংস্করণে প্রয়োজ্য হয়৷ Google Chrome এর উত্স কোড http://code.google.com/chromium/terms.html-এ মুক্ত উত্স সফটওয়্যার লাইসেন্সের অধীনে বিনামূল্যে উপলব্ধ৷</p>
+<p>পরিষেবার এই চুক্তিগুলি Google Chrome –এর প্রয়োগযোগ্য কোড সংস্করণে প্রয়োজ্য হয়৷ Google Chrome এর উত্স কোড chrome://credits-এ মুক্ত উত্স সফটওয়্যার লাইসেন্সের অধীনে বিনামূল্যে উপলব্ধ৷</p>
 <p><strong>1. Google-এর সাথে আপনার সম্পর্ক</strong></p>
 <p>1.1 আপনার Google-এর পণ্যাদি, সফ্টওয়্যার, পরিষেবাদি এবং ওয়েব সাইটগুলির ব্যবহার (এই দস্তাবেজে একত্রে "পরিষেবাসমূহ" হিসাবে উল্লিখিত যার মধ্যে Google-এর সাথে কোনও লিখিত পৃথক চুক্তির অধীনে আপনাকে সরবরাহিত কোনও পরিষেবাসমূহ) আপনার এবং Google-এর মধ্যে আইনি চুক্তির শর্তাদির অধীন৷ "Google&"-এর অর্থ Google Inc., যার ব্যবসায়ের মূল কেন্দ্র 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States৷ কীভাবে চুক্তি করা হয় তা এই দস্তাবেজটি ব্যাখ্যা করে আর সেই চুক্তির কিছু শর্তাদি ঘোষণা করে৷</p>
 <p>1.2 Google-এর সাথে লিখিত সম্মতি না থাকলে, Google এর সাথে আপনার সম্মতিতে এই দস্তাবেজে ঘোষিত শর্তাদি এবং চুক্তিগুলি ন্যুনতম অন্তর্ভুক্ত থাকে৷ এগুলিই নীচে "আন্তর্জাতিক শর্তাদি" হিসাবে উল্লেখিত৷ Google Chrome উত্স কোডের জন্য মুক্ত উত্স সফ্টওয়্যার লাইসেন্সগুলি পৃথক লিখিত চুক্তি গঠন করে৷ মুক্ত উত্স সফ্টওয়্যার লাইসেন্সগুলি এই সর্বজনীন শর্তাদিকে বর্ণিতভাবে রহিত করার সীমা পর্যন্ত Google Chrome বা Google Chrome-এ অন্তর্ভুক্ত নির্দিষ্ট উপাদানগুলির ব্যবহারকে Google এর সাথে আপনার চুক্তিকে পরিচালিত করবে৷</p>
diff --git a/chrome/app/resources/terms/terms_ca.html b/chrome/app/resources/terms/terms_ca.html
index 97429fd..38d19f9 100644
--- a/chrome/app/resources/terms/terms_ca.html
+++ b/chrome/app/resources/terms/terms_ca.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Condicions d'ús de Google Chrome</h2>
-<p>Aquestes Condicions d'ús s'apliquen a la versió de codi executable de Google Chrome. El codi font de Google Chrome està disponible de manera gratuïta a l'empara dels acords de llicència de programari de codi obert a la pàgina http://code.google.com/chromium/terms.html.</p>
+<p>Aquestes Condicions d'ús s'apliquen a la versió de codi executable de Google Chrome. El codi font de Google Chrome està disponible de manera gratuïta a l'empara dels acords de llicència de programari de codi obert a la pàgina chrome://credits.</p>
 <p><strong>1. La seva relació amb Google</strong></p>
 <p>1.1 El seu ús dels productes, del programari, dels serveis i dels llocs web de Google (anomenats col·lectivament "Serveis" en aquest document i exceptuant els serveis que Google li proporcioni en aplicació d'un altre acord escrit) està subjecte a les condicions de l'acord legal entre vostè i Google. "Google" significa Google Inc., amb domicili social al núm. 1600 d'Amphitheatre Parkway, Mountain View, Califòrnia 94043, als Estats Units. Aquest document explica les parts de què consta aquest acord i en descriu algunes condicions.</p>
 <p>1.2 Tret que ho hagi acordat per escrit amb Google de manera diferent, el seu acord amb Google sempre inclourà, com a mínim, les condicions d'ús que s'estableixen en aquest document. En aquest document, aquestes condicions s'anomenaran "Condicions universals". Les llicències de codi obert del codi font de Google Chrome constitueixen acords escrits independents. En la mesura en què les llicències de programari de codi obert sobreseguin expressament aquestes Condicions universals, les llicències de codi obert regiran el seu acord amb Google per a l'ús de Google Chrome o per als components concrets de Google Chrome que s'incloguin.</p>
diff --git a/chrome/app/resources/terms/terms_cs.html b/chrome/app/resources/terms/terms_cs.html
index d111bf1..6661abc8 100644
--- a/chrome/app/resources/terms/terms_cs.html
+++ b/chrome/app/resources/terms/terms_cs.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Smluvní podmínky aplikace Google Chrome </h2>
-<p>Tyto Smluvní podmínky platí pro spustitelný kód aplikace Google Chrome. Zdrojový kód aplikace Google Chrome je k dispozici bezplatně na základě licenční smlouvy na software s otevřeným zdrojovým kódem na adrese http://code.google.com/chromium/terms.html.</p>
+<p>Tyto Smluvní podmínky platí pro spustitelný kód aplikace Google Chrome. Zdrojový kód aplikace Google Chrome je k dispozici bezplatně na základě licenční smlouvy na software s otevřeným zdrojovým kódem na adrese chrome://credits.</p>
 <p><strong>1. Vztah mezi vámi a společností Google</strong></p>
 <p>1.1 Předmětem podmínek právně závazné smlouvy mezi vámi a společností Google je používání produktů, softwaru, služeb a webových stránek společnosti Google (v tomto dokumentu společně označovaných jako „Služby“, mimo služeb, které vám společnost Google poskytuje na základě samostatné písemné smlouvy). „Google” znamená společnost Google Inc., s hlavním obchodním sídlem na adrese 1600 Amphitheatre Parkway, Mountain View, CA 94043, USA. Tento dokument vysvětluje, jak je smlouva sestavena, a stanovuje některé její podmínky.</p>
 <p>1.2 Není-li se společností Google písemně dohodnuto jinak, bude vaše smlouva se společností Google vždy obsahovat alespoň smluvní podmínky stanovené v tomto dokumentu. Tyto podmínky jsou dále v textu označovány jako „Univerzální smluvní podmínky“. Licence na software s otevřeným zdrojovým kódem, které se vztahují na zdrojový kód aplikace Google Chrome, jsou samostatnými smlouvami. V omezeném rozsahu, kdy licence na software s otevřeným zdrojovým kódem výslovně nahrazují tyto Univerzální smluvní podmínky, určují váš vztah se společností Google z hlediska použití aplikace Google Chrome nebo určitých zahrnutých komponent aplikace Google Chrome licence na software s otevřeným zdrojovým kódem.</p>
diff --git a/chrome/app/resources/terms/terms_da.html b/chrome/app/resources/terms/terms_da.html
index 2387adb3..dc70062 100644
--- a/chrome/app/resources/terms/terms_da.html
+++ b/chrome/app/resources/terms/terms_da.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome Servicevilkår</h2>
-<p>Disse Servicevilkår gælder for den version af Google Chrome, der indeholder eksekverbar kode. Kildekode til Google Chrome kan hentes gratis under open source-licensaftaler på http://code.google.com/chromium/terms.html.</p>
+<p>Disse Servicevilkår gælder for den version af Google Chrome, der indeholder eksekverbar kode. Kildekode til Google Chrome kan hentes gratis under open source-licensaftaler på chrome://credits.</p>
 <p><strong>1. Dit forhold til Google</strong></p>
 <p>1.1 Din anvendelse af Googles produkter, software, tjenester og websteder (i det følgende samlet betegnet som "Tjenester", undtaget tjenester, der stilles til rådighed for dig af Google i henhold til særlig skriftlig aftale), er underlagt vilkårene i en juridisk aftale mellem dig og Google. "Google" betyder Google Inc., der har hovedkvarter på 1600 Amphitheatre Parkway, Mountain View, CA 94043, USA. Dette dokument beskriver opbygningen af aftalen og nogle af aftalens vilkår.</p>
 <p>1.2 Medmindre andet aftales skriftligt med Google, omfatter din aftale med Google altid som minimum de vilkår og betingelser, der fremgår af dette dokument. Disse betegnes i det følgende som "Generelle vilkår". Open source-softwarelicenser til Google Chrome-kildekode udgør separate skriftlige aftaler. I den begrænsede udstrækning, hvor open source-softwarelicenserne udtrykkeligt tilsidesætter disse Generelle vilkår, er open source-licenserne gældende for din aftale med Google mht. brugen af Google Chrome eller specifikke inkluderede komponenter af Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_de.html b/chrome/app/resources/terms/terms_de.html
index bc2ced7..8ea96e2 100644
--- a/chrome/app/resources/terms/terms_de.html
+++ b/chrome/app/resources/terms/terms_de.html
@@ -30,12 +30,12 @@
 <h2>Google Chrome Nutzungsbedingungen</h2>
 <p>
 <strong>Diese Nutzungsbedingungen beziehen sich ausschließlich auf die herunterladbare Software-Version des Browsers Google Chrome.</strong>
-<p><strong>Der vollständige Quellcode für Google Chrome kann kostenfrei im Rahmen einer Open Source-Softwarelizenz unter&nbsp;http://code.google.com/chromium/terms.html&nbsp;bezogen werden.</strong>
+<p><strong>Der vollständige Quellcode für Google Chrome kann kostenfrei im Rahmen einer Open Source-Softwarelizenz unter&nbsp;chrome://credits&nbsp;bezogen werden.</strong>
 <p><strong>1. Ihr Verhältnis zu Google</strong>
 <p>Google bietet Ihnen eine Vielzahl von Diensten (die "Dienste") an. Die Dienste werden Ihnen von der Google Inc., 1600 Amphitheatre Parkway, Mountain View, CA 94043, USA ("Google") zur Verfügung gestellt. Auf die Erbringung der Dienste insgesamt oder einzelner Dienste besteht kein Anspruch.
 <p>Bevor Sie die Dienste nutzen, sollten Sie diese Nutzungsbedingungen sorgfältig lesen. Die Nutzung der Dienste setzt voraus, dass Sie diesen Nutzungsbedingungen zugestimmt haben.
 <p>Wenn Sie die Dienste nutzen, bilden diese Nutzungsbedingungen die grundlegenden Regeln für Ihre Nutzung der Dienste. Für manche der Dienste gelten zusätzliche Nutzungsbedingungen oder andere Regelungen, die diese Nutzungsbedingungen ergänzen oder ändern, Ihre Nutzung dieser Dienste im Detail regeln und Bestandteil des Nutzungsverhältnisses sind. Solche zusätzlichen Nutzungsbedingungen oder anderen Regelungen sind jeweils im Zusammenhang mit den bereit gestellten Diensten abrufbar.
-<p>Google Chrome wurde unter Einsatz von Open Source-Software entwickelt. Wenn Sie Software-Entwickler sind und Google Chrome weiterentwickeln möchten, müssen Sie hinsichtlich der Open Source-Komponenten von Google Chrome diejenigen Nutzungsbeschränkungen beachten, die sich aus den speziellen Open Source-Softwarelizenzbedingungen ergeben. Hinsichtlich der Open Source-Komponenten gehen die speziellen Open Source–Softwarelizenzbedingungen diesen Nutzungsbedingungen vor. Die speziellen Open Source–Softwarelizenzbedingungen sind unter&nbsp;http://code.google.com/chromium/terms.html&nbsp;abrufbar.
+<p>Google Chrome wurde unter Einsatz von Open Source-Software entwickelt. Wenn Sie Software-Entwickler sind und Google Chrome weiterentwickeln möchten, müssen Sie hinsichtlich der Open Source-Komponenten von Google Chrome diejenigen Nutzungsbeschränkungen beachten, die sich aus den speziellen Open Source-Softwarelizenzbedingungen ergeben. Hinsichtlich der Open Source-Komponenten gehen die speziellen Open Source–Softwarelizenzbedingungen diesen Nutzungsbedingungen vor. Die speziellen Open Source–Softwarelizenzbedingungen sind unter&nbsp;chrome://credits&nbsp;abrufbar.
 <p>Die Mehrzahl der Dienste wird Ihnen kostenlos zur Verfügung gestellt. Sollte Google Entgelte für bestimmte Dienste verlangen, müssen Sie möglicherweise zusätzlichen Nutzungsbedingungen oder anderen Regelungen zustimmen, in denen Ihnen insbesondere Informationen über das Entgelt, Rückerstattungen, Laufzeit der Dienste, Änderungen der Dienste und andere, für diese Dienste spezifische Informationen mitgeteilt werden.
 <p><strong>2. Ihr Google Konto</strong>
 <p>Für die Nutzung einiger Dienste benötigen Sie ein Google Konto. Um sich für ein Google Konto zu registrieren, benötigen Sie eventuell einen Nutzernamen, eine eigene Emailadresse und ein Passwort. Wenn Sie sich für einen Dienst registrieren, ist es wichtig, dass Sie Google richtige und vollständige Angaben machen, z.B. damit wir Sie im Einzelfall per Email kontaktieren können. Die Nutzung der Dienste ist auch unter einem Pseudonym möglich. Sie sind für die Nutzung Ihres Google Kontos selbst verantwortlich und sollten die Geheimhaltung Ihres Passworts sicherstellen. Sollten Sie eine unautorisierte Nutzung Ihres Passworts oder Ihres Kontos bemerken, sind Sie verpflichtet, Google dieses mitzuteilen. Einzelheiten zu dem Verfahren finden Sie unter&nbsp;https://support.google.com/accounts/answer/141113.
diff --git a/chrome/app/resources/terms/terms_el.html b/chrome/app/resources/terms/terms_el.html
index 6212ca7..e4fc3577 100644
--- a/chrome/app/resources/terms/terms_el.html
+++ b/chrome/app/resources/terms/terms_el.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Όροι Παροχής Υπηρεσιών του Google Chrome</h2>
-<p>Οι παρόντες Όροι Παροχής Υπηρεσιών ισχύουν για την έκδοση εκτελέσιμου κώδικα του Google Chrome. Ο πηγαίος κώδικας του Google Chrome διατίθεται δωρεάν μέσω των συμφωνητικών άδειας χρήσης λογισμικού ανοικτού κώδικα στη διεύθυνση http://code.google.com/chromium/terms.html.</p>
+<p>Οι παρόντες Όροι Παροχής Υπηρεσιών ισχύουν για την έκδοση εκτελέσιμου κώδικα του Google Chrome. Ο πηγαίος κώδικας του Google Chrome διατίθεται δωρεάν μέσω των συμφωνητικών άδειας χρήσης λογισμικού ανοικτού κώδικα στη διεύθυνση chrome://credits.</p>
 <p><strong>1. Η σχέση σας με την Google</strong></p>
 <p>1.1 Η εκ μέρους σας χρήση προϊόντων, λογισμικού, υπηρεσιών και ιστότοπων (το σύνολο των οποίων στο παρόν έγγραφο θα αναφέρεται στο εξής ως "Υπηρεσίες" και στις οποίες δεν περιλαμβάνονται τυχόν υπηρεσίες που σας παρέχονται από την Google υπό τους όρους διαφορετικού έγγραφου συμφωνητικού) της Google υπόκειται σε όρους και προϋποθέσεις που διέπουν τη νομικά δεσμευτική συμφωνία ανάμεσα σε εσάς και την Google. Ως "Google" νοείται η εταιρεία Google Inc., τα κεντρικά γραφεία της οποίας έχουν έδρα επί της οδού Amphitheatre Parkway 1600, Mountain View, CA 94043, Ηνωμένες Πολιτείες. Στο παρόν έγγραφο αναλύεται η δομή του παρόντος συμφωνητικού και διατυπώνονται ορισμένοι από τους όρους του εν λόγω συμφωνητικού.</p>
 <p>1.2 Εκτός εάν έχει συμφωνηθεί διαφορετικά γραπτώς με την Google, η συμφωνία σας με την Google περιλαμβάνει, σε κάθε περίπτωση, τουλάχιστον τους όρους και τις προϋποθέσεις που καθορίζονται στο παρόν. Οι όροι και οι προϋποθέσεις θα αναφέρονται στο εξής ως "Γενικοί όροι". Οι άδειες χρήσης λογισμικού ανοιχτού κώδικα για τον πηγαίο κώδικα του Google Chrome καθιστούν ξεχωριστά έγγραφα συμφωνητικά. Μόνο εάν οι άδειες χρήσης λογισμικού ανοιχτού κώδικα υπερισχύουν ρητώς των παρόντων Γενικών όρων, οι άδειες χρήσης λογισμικού ανοιχτού κώδικα θα διέπουν τη συμφωνία σας με την Google όσον αφορά τη χρήση του Google Chrome ή συγκεκριμένων επιμέρους στοιχείων που περιλαμβάνονται στο Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_en-GB.html b/chrome/app/resources/terms/terms_en-GB.html
index 1c6559e..c005145 100644
--- a/chrome/app/resources/terms/terms_en-GB.html
+++ b/chrome/app/resources/terms/terms_en-GB.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome Terms of Service</h2>
-<p>These Terms of Service apply to the executable code version of Google Chrome. Source code for Google Chrome is available free of charge under open source software licence agreements at http://code.google.com/chromium/terms.html.</p>
+<p>These Terms of Service apply to the executable code version of Google Chrome. Source code for Google Chrome is available free of charge under open source software licence agreements at chrome://credits.</p>
 <p><strong>1. Your relationship with Google</strong></p>
 <p>1.1 Your use of Google’s products, software, services and websites (referred to collectively as the “Services” in this document and excluding any services provided to you by Google under a separate written agreement) is subject to the terms of a legal agreement between you and Google. “Google” means Google Inc., whose principal place of business is at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. This document explains how the agreement is made up and sets out some of the terms of that agreement.</p>
 <p>1.2 Unless otherwise agreed in writing with Google, your agreement with Google will always include, at a minimum, the terms and conditions set out in this document. These are referred to below as the “Universal Terms”. Open-source software licences for Google Chrome source code constitute separate written agreements. To the limited extent that the open-source software licences expressly supersede these Universal Terms, the open-source licences govern your agreement with Google for the use of Google Chrome or specific included components of Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_en.html b/chrome/app/resources/terms/terms_en.html
index b9f7719..7fa43d65 100644
--- a/chrome/app/resources/terms/terms_en.html
+++ b/chrome/app/resources/terms/terms_en.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome Terms of Service</h2>
-<p>These Terms of Service apply to the executable code version of Google Chrome. Source code for Google Chrome is available free of charge under open source software license agreements at http://code.google.com/chromium/terms.html.</p>
+<p>These Terms of Service apply to the executable code version of Google Chrome. Source code for Google Chrome is available free of charge under open source software license agreements at chrome://credits.</p>
 <p><strong>1. Your relationship with Google</strong></p>
 <p>1.1 Your use of Google’s products, software, services and web sites (referred to collectively as the “Services” in this document and excluding any services provided to you by Google under a separate written agreement) is subject to the terms of a legal agreement between you and Google. “Google” means Google Inc., whose principal place of business is at 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. This document explains how the agreement is made up, and sets out some of the terms of that agreement.</p>
 <p>1.2 Unless otherwise agreed in writing with Google, your agreement with Google will always include, at a minimum, the terms and conditions set out in this document. These are referred to below as the “Universal Terms”. Open source software licenses for Google Chrome source code constitute separate written agreements. To the limited extent that the open source software licenses expressly supersede these Universal Terms, the open source licenses govern your agreement with Google for the use of Google Chrome or specific included components of Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_es-419.html b/chrome/app/resources/terms/terms_es-419.html
index a833d5c..5ae7518 100644
--- a/chrome/app/resources/terms/terms_es-419.html
+++ b/chrome/app/resources/terms/terms_es-419.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Condiciones del servicio de Google Chrome</h2>
-<p>Estas Condiciones del servicio se aplicarán a la versión de código ejecutable de Google Chrome. El código fuente de Google Chrome se encuentra disponible de forma gratuita sujeto a los acuerdos de licencia de software de código abierto que encontrará en la página http://code.google.com/chromium/terms.html.</p>
+<p>Estas Condiciones del servicio se aplicarán a la versión de código ejecutable de Google Chrome. El código fuente de Google Chrome se encuentra disponible de forma gratuita sujeto a los acuerdos de licencia de software de código abierto que encontrará en la página chrome://credits.</p>
 <p><strong>1. Su relación con Google</strong></p>
 <p>1.1 El uso que haga de los productos, software, servicios y sitios web de Google (en adelante, los "Servicios"; se excluyen los servicios que Google pueda proporcionarle en virtud de cualquier otro acuerdo consensuado por escrito) se rige por las condiciones de un acuerdo legal entre usted y Google. "Google" significa Google Inc., cuya sede central se encuentra en 1600 Amphitheatre Parkway, Mountain View, California 94043, United States. En el presente documento se describen los componentes del acuerdo y se exponen algunas de las condiciones que lo regirán.</p>
 <p>1.2 A menos que usted y Google establezcan lo contrario por escrito, el acuerdo con Google siempre incluirá, como mínimo, las condiciones de uso estipuladas en este documento. En adelante, se denominarán las "Condiciones universales". Las licencias de software de código abierto a las que está sujeto el código fuente de Google Chrome constituyen acuerdos por escrito independientes. En la medida en que las licencias de software de código abierto sustituyan expresamente estas Condiciones universales, las licencias de código abierto regirán su acuerdo con Google en lo referente al uso de Google Chrome o de sus componentes específicos.</p>
diff --git a/chrome/app/resources/terms/terms_es.html b/chrome/app/resources/terms/terms_es.html
index 47e972c..429da40c 100644
--- a/chrome/app/resources/terms/terms_es.html
+++ b/chrome/app/resources/terms/terms_es.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Condiciones del servicio de Google Chrome</h2>
-<p>Estas Condiciones del servicio se aplicarán a la versión de código ejecutable de Google Chrome. El código fuente de Google Chrome está disponible de forma gratuita de conformidad con los acuerdos sobre licencias de software libre que se encuentran en la página http://code.google.com/chromium/terms.html.</p>
+<p>Estas Condiciones del servicio se aplicarán a la versión de código ejecutable de Google Chrome. El código fuente de Google Chrome está disponible de forma gratuita de conformidad con los acuerdos sobre licencias de software libre que se encuentran en la página chrome://credits.</p>
 <p><strong>1. Su relación con Google</strong></p>
 <p>1.1 El uso que haga de los productos, del software, de los servicios y de los sitios web de Google (en adelante, los "Servicios", de los que se excluyen aquellos servicios que Google pueda proporcionarle en virtud de cualquier otro acuerdo escrito independiente) se rige por las condiciones de un acuerdo legal suscrito entre usted y Google. Por "Google" se entenderá Google Inc., cuyo domicilio social se encuentra en 1600 Amphitheatre Parkway, Mountain View, California 94043, Estados Unidos. En el presente documento se describen los componentes del acuerdo y se exponen algunas de las condiciones que lo regirán.</p>
 <p>1.2 A menos que usted y Google establezcan lo contrario por escrito, el acuerdo con Google siempre incluirá, como mínimo, las condiciones estipuladas en este documento. En adelante, estas condiciones se denominarán "Condiciones universales". Las licencias de software libre correspondientes al código fuente de Google Chrome constituyen acuerdos escritos independientes. En la medida en que las licencias de software libre anulen expresamente estas Condiciones universales, estas licencias regirán su acuerdo con Google para el uso de Google Chrome o de sus componentes específicos.</p>
diff --git a/chrome/app/resources/terms/terms_et.html b/chrome/app/resources/terms/terms_et.html
index 63d0db46..8493468 100644
--- a/chrome/app/resources/terms/terms_et.html
+++ b/chrome/app/resources/terms/terms_et.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome'i teenusetingimused</h2>
-<p>Käesolevad teenusetingimused kehtivad Google Chrome'i täitmiskoodi versiooni kohta. Google Chrome'i lähtekood on tasuta saadaval avatud allikaga tarkvara litsentsilepingutes aadressil http://code.google.com/chromium/terms.html.</p>
+<p>Käesolevad teenusetingimused kehtivad Google Chrome'i täitmiskoodi versiooni kohta. Google Chrome'i lähtekood on tasuta saadaval avatud allikaga tarkvara litsentsilepingutes aadressil chrome://credits.</p>
 <p><strong>1. Teie suhe Google'iga</strong></p>
 <p>1.1 Google'i toodete, tarkvara, teenuste ning veebilehtede (selles dokumendis ühtse nimega „teenused“ ning välja arvatud kõik teenused, mida Google osutab eraldi kirjaliku lepingu alusel) kasutamist reguleerib teie ning Google'i vahel sõlmitud õiguslik leping. „Google“ on äriühing Google Inc., mille peamine tegevuskoht on 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. Käesolevas dokumendis selgitatakse lepingu koostamisviisi ja tuuakse välja mõningad selle lepingu tingimused.</p>
 <p>1.2 Kui Google'iga pole kirjalikult teisiti kokku lepitud, sisaldab teie leping Google'iga alati vähemalt käesolevas dokumendis sätestatud nõudeid ja tingimusi. Neid nimetatakse edaspidi „üldtingimusteks“. Google Chrome'i lähtekoodi avatud allikaga tarkvaralitsentsid moodustavad eraldi kirjalikud lepingud. Kui avatud allikaga tarkvaralitsentsid asendavad selgesõnaliselt käesolevaid üldtingimusi, domineerivad avatud allikaga litsentsid teie lepingu üle Google'iga Google Chrome'i kasutuse või Google Chrome'i eraldi lisakomponentide suhtes.</p>
diff --git a/chrome/app/resources/terms/terms_fa.html b/chrome/app/resources/terms/terms_fa.html
index 385dbda1..d4b7bb52 100644
--- a/chrome/app/resources/terms/terms_fa.html
+++ b/chrome/app/resources/terms/terms_fa.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>شرایط سرویس Google Chrome</h2>
-<p>این شرایط سرویس در مورد نسخه Google Chrome که دارای کد قابل اجراست اعمال می شود. بر اساس قراردادهای مجوز در آدرس http://code.google.com/chromium/terms.html، کد منبع Google Chrome به طور رایگان و به صورت نرم افزار منبع باز در اختیار شما قرار می گیرد.</p>
+<p>این شرایط سرویس در مورد نسخه Google Chrome که دارای کد قابل اجراست اعمال می شود. بر اساس قراردادهای مجوز در آدرس chrome://credits، کد منبع Google Chrome به طور رایگان و به صورت نرم افزار منبع باز در اختیار شما قرار می گیرد.</p>
 <p><strong>1. ارتباط شما با Google</strong></p>
 <p>1.1 استفاده شما از محصولات، نرم افزارها، سرویس ها و سایت های Google (به طور کلی تحت عنوان "سرویس ها" در این سند شناخته می شود و سرویس های ارائه شده از طرف Google که تحت قرارداد کتبی دیگری باشند را شامل نخواهد بود) از یک قرارداد حقوقی بین شما و Google تبعیت می کند. "Google" به معنای شرکت Google است که محل اصلی فعالیت های تجاری آن در آدرس &lrm;1600 Amphitheatre Parkway, Mountain View, CA 94043, United States است. در این سند نحوه تهیه و تدوین این قرارداد و برخی از شرایط آن آورده شده است.</p>
 <p>1.2 بجز در مواردی که قرارداد کتبی با Google وجود داشته باشد، قرارداد بین شما و Google همیشه، حداقل، شرایط و ضوابط تنظیم شده در این سند را شامل خواهد بود. این شرایط و مقررات در زیر با عنوان "شرایط جهانی" نامیده می شود. مجوزهای نرم افزار منبع باز برای کد منبع Google Chrome دارای یک قرارداد کتبی جداگانه است. در موارد محدودی که مجوزهای نرم افزار منبع باز صراحتاً از این شرایط جهانی تبعیت نکنند، مجوزهای منبع آزاد قرارداد شما با Google Chrome را برای استفاده از Google Chrome و یا مؤلفه های خاصی از Google Chrome تحت پوشش خود قرار می دهند.</p>
diff --git a/chrome/app/resources/terms/terms_fi.html b/chrome/app/resources/terms/terms_fi.html
index 2395d1d6..67f70c6 100644
--- a/chrome/app/resources/terms/terms_fi.html
+++ b/chrome/app/resources/terms/terms_fi.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chromen käyttöehdot</h2>
-<p>Nämä käyttöehdot koskevat Google Chromen suoritettavaa koodiversiota. Google Chromen lähdekoodi on saatavilla maksutta avoimen lähdekoodin ohjelmistojen käyttöoikeussopimusten mukaisesti osoitteesta http://code.google.com/chromium/terms.html.</p>
+<p>Nämä käyttöehdot koskevat Google Chromen suoritettavaa koodiversiota. Google Chromen lähdekoodi on saatavilla maksutta avoimen lähdekoodin ohjelmistojen käyttöoikeussopimusten mukaisesti osoitteesta chrome://credits.</p>
 <p><strong>1. Käyttäjän suhde Googleen</strong></p>
 <p>1.1 Googlen tuotteiden, ohjelmien, palveluiden ja verkkosivustojen (joihin viitataan tässä asiakirjassa yhteisellä nimellä Palvelut ja joiden ulkopuolelle jätetään kaikki Googlen erillisellä kirjallisella sopimuksella toimittamat palvelut) käyttämistä sitovat käyttäjän ja Googlen välisen sopimuksen ehdot. "Googlella" tarkoitetaan Google Inc:ia, jonka pääkonttori sijaitsee osoitteessa 1600 Amphitheatre Parkway, Mountain View, CA 94043, Yhdysvallat. Tässä asiakirjassa selostetaan, miten sopimus syntyy, sekä esitetään eräät sopimuksen ehdot.</p>
 <p>1.2 Ellei Google kirjallisesti ilmoita toisin, sopimus Googlen kanssa sisältää aina vähintään tässä asiakirjassa esitetyt ehdot. Näihin viitataan jäljempänä nimityksellä Yleisehdot. Google Chromen lähdekoodia koskevat avoimen lähdekoodin ohjelmistojen käyttöoikeussopimukset muodostavat erilliset kirjalliset sopimukset. Siinä määrin kuin avoimen lähdekoodin ohjelmistojen käyttöoikeussopimukset nimenomaisesti korvaavat nämä Yleisehdot, avoimen lähdekoodin käyttöoikeudet säätelevät käyttäjän Google Chromen tai tiettyjen Google Chromen osien käyttöä koskevaa sopimusta Googlen kanssa.</p>
diff --git a/chrome/app/resources/terms/terms_fil.html b/chrome/app/resources/terms/terms_fil.html
index 6995fc8..0e51565 100644
--- a/chrome/app/resources/terms/terms_fil.html
+++ b/chrome/app/resources/terms/terms_fil.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Mga Tuntunin ng Serbisyo ng Google Chrome</h2>
-<p>Nalalapat ang Mga Tuntunin ng Serbisyong ito sa executable code na bersyon ng Google Chrome. Magagamit nang libre ang source code para sa Google Chrome alinsunod sa open source na mga kasunduan sa paglilisensya ng software sa://code.google.com.ph/chromium/terms.html.</p>
+<p>Nalalapat ang Mga Tuntunin ng Serbisyong ito sa executable code na bersyon ng Google Chrome. Magagamit nang libre ang source code para sa Google Chrome alinsunod sa open source na mga kasunduan sa paglilisensya ng software chrome://credits.</p>
 <p><strong>1. Ang iyong kaugnayan sa Google</strong></p>
 <p>1.1 Napapasailalim ang iyong paggamit ng mga produkto, software, serbisyo at web site ng Google (pinagsama-samang tinukoy bilang “Mga Serbisyo” sa dokumentong ito at ibinubukod ang anumang mga serbisyong ibinigay sa iyo ng Google sa ilalim ng hiwalay na nakasulat na kasunduan) sa mga tuntunin ng legal na kasunduan sa pagitan mo at ng Google. Ang "Google" ay nangangahulugang Google Inc., na nasa Amphitheatre Parkway, Mountain View, CA 94043, Estados Unidos ang pangunahing lugar ng negosyo. Ipinaliliwanag ng dokumentong ito kung papaano binuo ang kasunduan, at nililinaw ang ilan sa mga tuntunin ng kasunduang iyon.</p>
 <p>1.2 Maliban kung nakipagkasundo nang pasulat sa Google, palaging kabilang sa iyong kasunduan sa Google, sa pinakamababa, ang mga tuntunin at kundisyong tinukoy sa dokumentong ito. Tinukoy ang mga ito sa ibaba bilang “Mga Pangkalahatang Tuntunin”. Binubuo ng hiwalay na mga nakasulat na kasunduan ang mga lisensya sa software na open source na para sa Google Chrome source code. Hanggang sa limitadong saklaw na hayagang sinasapawan ng mga lisensya ng software na open source ang Mga Pangkalahatang Tuntuning ito, pinamamahalaan ng mga lisensya ng open source ang iyong kasunduan sa Google para sa paggamit ng Google Chrome o tukoy na isinamang mga bahagi ng Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_fr.html b/chrome/app/resources/terms/terms_fr.html
index 8b83ef3..68e18b0 100644
--- a/chrome/app/resources/terms/terms_fr.html
+++ b/chrome/app/resources/terms/terms_fr.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Conditions d'utilisation de Google Chrome</h2>
-<p>Ces Conditions d'utilisation s'appliquent à la version du code exécutable de Google Chrome. Le code source de Google Chrome est mis à disposition gratuitement dans le cadre des accords de licence des logiciels libres, sur la page http://code.google.com/chromium/terms.html.</p>
+<p>Ces Conditions d'utilisation s'appliquent à la version du code exécutable de Google Chrome. Le code source de Google Chrome est mis à disposition gratuitement dans le cadre des accords de licence des logiciels libres, sur la page chrome://credits.</p>
 <p><strong>1. Vos relations avec Google</strong></p>
 <p>1.1 L'utilisation des produits, logiciels, services et sites Web Google (dénommés collectivement "Services" dans le présent document et excluant tous les services fournis par Google faisant l'objet d'un accord écrit distinct) est régie par les termes d'un accord légal conclu entre vous et Google. "Google" désigne la société Google Inc., dont le siège principal est sis à l'adresse suivante : 1600 Amphitheatre Parkway, Mountain View, CA 94043, États-Unis. Le présent document décrit la teneur du contrat susvisé et définit certains termes de ce contrat.</p>
 <p>1.2 Sauf mention écrite contraire convenue avec Google, le contrat qui vous lie à Google inclut toujours au minimum les conditions et modalités énoncées dans le présent document. Ces conditions sont désignées ci-après par l'expression "Conditions universelles". Les licences de logiciel libre pour le code source de Google Chrome font l'objet d'accords écrits distincts. Dans la stricte mesure où les licences de logiciel libre remplacent expressément ces Conditions universelles, les licences de logiciel libre régissent votre accord avec Google pour l'utilisation de Google Chrome ou de composants inclus spécifiques de Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_gu.html b/chrome/app/resources/terms/terms_gu.html
index ac9a47b..da3a245 100644
--- a/chrome/app/resources/terms/terms_gu.html
+++ b/chrome/app/resources/terms/terms_gu.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome સેવાની શરતો</h2>
-<p>આ સેવાની શરતો Google Chrome ના એક્ઝિક્યૂટેબલ કોડ વર્ઝન પર લાગુ થાય છે. Google Chrome માટે સ્રોત કોડ http://code.google.com/chromium/terms.html પર ઓપન સોર્સ સૉફ્ટવેર લાઇસેંસ હેઠળ નિઃશુલ્ક ઉપલબ્ધ છે.</p>
+<p>આ સેવાની શરતો Google Chrome ના એક્ઝિક્યૂટેબલ કોડ વર્ઝન પર લાગુ થાય છે. Google Chrome માટે સ્રોત કોડ chrome://credits પર ઓપન સોર્સ સૉફ્ટવેર લાઇસેંસ હેઠળ નિઃશુલ્ક ઉપલબ્ધ છે.</p>
 <p><strong>1. Google સાથે આપનો સંબંધ</strong></p>
 <p>1.1 Google ના ઉત્પાદનો, સૉફ્ટવેર, સેવાઓ અને વેબસાઇટ્સનો આપના દ્વારા થતો ઉપયોગ (જેનો ઉલ્લેખ આ દસ્તાવેજમાં 'સેવાઓ' તરીકે થયો છે અને આ સેવા સિવાયની કોઈપણ સેવા વિશે Google દ્વારા આપને અલગથી લિખિત કરાર કરવામાં આવશે) એ આપની અને Google ની વચ્ચે કાનુની કરારની શરતનો વિષય છે. “Google” અર્થાત્ Google Inc., કે જેનું મુખ્ય કાર્યાલય 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States માં આવેલું છે. આ દસ્તાવેજ સ્પષ્ટ કરે છે કે કરાર કેવી રીતે થાય છે અને તે કરારની કેટલીક શરતો સેટ કરે છે.</p>
 <p>1.2 Google ને લિખિતમાં આપવા ઉપરાંત, આપના Google સાથેના કરારમાં હંમેશા, ઓછામાં ઓછા, આ દસ્તાવેજમાં સેટ કરેલા નિયમો અને શરતો સામેલ છે. આ નીચે "વૈશ્વિક શરતો" તરીકે ઉલ્લેખિત કરવામાં આવી છે. Google Chrome સોર્સ કોડ માટે ઓપન સોર્સ સૉફ્ટવેર લાઇસેંસ એક અલગ લિખિત કરારને રચે છે. સીમિત મર્યાદા સુધી કે જ્યાં ઓપન સોર્સ સૉફ્ટવેર લાઇસેંસ સ્પષ્ટ રૂપે આ વૈશ્વિક શરતોનું સ્થાન છે, ઓપન સોર્સ લાઇસેંસ Google Chrome ના અથવા Google Chrome ના વિશિષ્ટ ઘટકોના ઉપયોગ માટે Google સાથેના આપના કરારનું સંચાલન કરે છે.</p>
diff --git a/chrome/app/resources/terms/terms_he.html b/chrome/app/resources/terms/terms_he.html
index dbe729d..368bc34 100644
--- a/chrome/app/resources/terms/terms_he.html
+++ b/chrome/app/resources/terms/terms_he.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>התנאים וההגבלות של Google Chrome</h2>
-<p>תנאים והגבלות אלו חלים על גרסת הקוד להרצה של Google Chrome. קוד המקור עבור Google Chrome זמין, ללא תשלום, במסגרת הסכמי רישיון של תוכנת קוד פתוח, בכתובת http://code.google.com/chromium/terms.html.</p>
+<p>תנאים והגבלות אלו חלים על גרסת הקוד להרצה של Google Chrome. קוד המקור עבור Google Chrome זמין, ללא תשלום, במסגרת הסכמי רישיון של תוכנת קוד פתוח, בכתובת chrome://credits.</p>
 <p><strong>1. יחסיך עם Google‏</strong></p>
 <p>1.1 השימוש שלך במוצרים, בתוכנה, בשירותים ובאתרי האינטרנט של Google, (המכונים להלן במשותף במסמך זה "שירותים", למעט כל שירות שניתן לך מאת Google במסגרת הסכם כתוב נפרד), כפוף לתנאיו של הסכם משפטי בינך לבין Google. “Google” משמעו Google Inc.‎, אשר מקום העסקים העיקרי שלה הוא ‎&lrm;1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. מסמך זה מסביר כיצד ההסכם מורכב, והוא מציין כמה מהתנאים של הסכם זה.</p>
 <p>1.2 אלא אם הוסכם אחרת בכתב עם Google, ההסכם שלך עם Google יכלול תמיד את 'התנאים וההגבלות' המצוינים במסמך זה, לכל הפחות. אלו מכונים להלן "תנאים אוניברסליים". רישיונות תוכנה של קוד פתוח עבור קוד המקור של Google Chrome, מכילים הסכמים כתובים נפרדים. במידה המוגבלת שבה רישיונות התוכנה לקוד הפתוח מחליפים במפורש תנאים אוניברסליים אלו, הרישיונות לקוד הפתוח מחליפים את ההסכם שלך עם Google בכל הנוגע לשימוש ב-Google Chrome או ברכיבים ספציפיים מצורפים של Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_hi.html b/chrome/app/resources/terms/terms_hi.html
index 59147079..26a0b93e 100644
--- a/chrome/app/resources/terms/terms_hi.html
+++ b/chrome/app/resources/terms/terms_hi.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome सेवा की शर्तें</h2>
-<p>सेवा की ये शर्तें Google Chrome के निष्पादन योग्य कोड संस्करण पर लागू होती हैं. Google Chrome के लिए स्रोत कोड http://code.google.com/chromium/terms.html पर खुला स्रोत सॉफ़्टवेयर लाइसेंस अनुबंध के अंतर्गत निःशुल्क उपलब्ध है.</p>
+<p>सेवा की ये शर्तें Google Chrome के निष्पादन योग्य कोड संस्करण पर लागू होती हैं. Google Chrome के लिए स्रोत कोड chrome://credits पर खुला स्रोत सॉफ़्टवेयर लाइसेंस अनुबंध के अंतर्गत निःशुल्क उपलब्ध है.</p>
 <p><strong>1. Google के साथ आपका संबंध</strong></p>
 <p>1.1 आपका Google के उत्पादों, सॉफ़्टवेयर, सेवाओं और वेब साइट (इस दस्तावेज़ में सामूहिक रूप से “सेवाओं” के रूप में संदर्भित और पृथक लिखित अनुबंध के अंतर्गत Google द्वारा प्रदान की गई किसी सेवा के अलावा) का उपयोग आपके और Google के बीच हुए कानूनी अनुबंध की शर्तों के अधीन है. “Google” का अर्थ है Google Inc., जिसका प्रधान व्यावसायिक कार्यालय 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States में है. यह दस्तावेज़ स्पष्ट करता है कि अनुबंध कैसे बना है, और उस अनुबंध की कुछ शर्तों को निर्धारित करता है.</p>
 <p>1.2 जब तक Google के साथ लिखित रूप में सहमति न हो, Google के साथ हुए आपके अनुबंध में कम-से-कम, इस दस्तावेज़ में निर्धारित नियम और शर्तें हमेशा शामिल होंगी. नीचे इनका संदर्भ "सर्वव्यापी शर्तों" के रूप में दिया गया है. Google Chrome स्रोत कोड के लिए खुला स्रोत सॉफ़्टवेयर लाइसेंस पृथक लिखित अनुबंध बनाते हैं. खुला स्रोत सॉफ़्टवेयर लाइसेंस स्पष्ट रूप से इन सर्वव्‍यापी शर्तों का अधिलंघन करने की सीमित सीमा तक, खुला स्रोत लाइसेंस Google Chrome या Google Chrome के विशेष रूप से शामिल किए गए घटकों के उपयोग के लिए आपके Google के साथ अनुबंध को नियंत्रित करता है.</p>
diff --git a/chrome/app/resources/terms/terms_hr.html b/chrome/app/resources/terms/terms_hr.html
index 33d11a38..57d14be 100644
--- a/chrome/app/resources/terms/terms_hr.html
+++ b/chrome/app/resources/terms/terms_hr.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome uvjeti pružanja usluge</h2>
-<p>Ovi Uvjeti pružanja usluge primjenjuju se na izvršnu verziju koda preglednika Google Chrome. Izvorni kôd za Google Chrome dostupan je besplatno prema ugovorima o softverskoj licenci otvorenog koda na http://code.google.com/chromium/terms.html.</p>
+<p>Ovi Uvjeti pružanja usluge primjenjuju se na izvršnu verziju koda preglednika Google Chrome. Izvorni kôd za Google Chrome dostupan je besplatno prema ugovorima o softverskoj licenci otvorenog koda na chrome://credits.</p>
 <p><strong>1. Vaš ugovorni odnos s Googleom</strong></p>
 <p>1.1 Googleove proizvode, softver, usluge i web-lokacije (za koje se u daljnjem tekstu koristi zajednički naziv "Usluge", a koji ne uključuju one usluge koje vam Google pruža prema posebnom pisanom ugovoru) možete koristiti u skladu s uvjetima pravnog ugovora između vas i tvrtke Google. "Google" se odnosi na Google Inc., sa sjedištem na adresi 1600 Amphitheatre Parkway, Mountain View, CA 94043, SAD. U ovom se dokumentu objašnjava kako je ovaj ugovor sastavljen i navode se neki uvjeti ugovora.</p>
 <p>1.2 Vaš ugovor s Googleom uvijek uključuje barem uvjete i odredbe navedene u ovom dokumentu, osim ako nije drugačije u pisanom obliku dogovoreno s Googleom. Te se odredbe i uvjeti u daljnjem tekstu nazivaju "Općim uvjetima". Softverske licence otvorenog izvornog koda za Google Chrome izvorni kôd sačinjene su od posebnih pisanih sporazuma. Do određene mjere, u kojoj softverske licence otvorenog izvornog koda izričito nasljeđuju ove Opće uvjete, licence otvorenog izvornog koda upravljaju vašim sporazumom s Googleom za upotrebu preglednika Google Chrome ili određenih sadržanih komponenti preglednika Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_hu.html b/chrome/app/resources/terms/terms_hu.html
index 586ddb51..d623bc3 100644
--- a/chrome/app/resources/terms/terms_hu.html
+++ b/chrome/app/resources/terms/terms_hu.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome - Általános Szerződési Feltételek</h2>
-<p>A jelen Általános Szerződési Feltételek szabályozzák a Google Chrome futtatható kódú változatának az Ön által való használatát. A Google Chrome forráskódja a nyílt forráskódú szoftverekre vonatkozó licencszerződések keretében díjmentesen elérhető a következő címen: http://code.google.com/chromium/terms.html.</p>
+<p>A jelen Általános Szerződési Feltételek szabályozzák a Google Chrome futtatható kódú változatának az Ön által való használatát. A Google Chrome forráskódja a nyílt forráskódú szoftverekre vonatkozó licencszerződések keretében díjmentesen elérhető a következő címen: chrome://credits.</p>
 <p><strong>1. Az Ön kapcsolata a Google-lal</strong></p>
 <p>1.1 A Google termékeinek, szoftvereinek, szolgáltatásainak és webhelyeinek (a jelen dokumentumban együttesen "Szolgáltatások", kivéve a Google által Önnek esetleg külön írásos szerződés keretében nyújtott szolgáltatásokat) használatára az Ön és a Google között létrejött szerződés rendelkezései érvényesek. A "Google" a Google Inc. vállalatot jelenti, amelynek székhelye 1600 Amphitheatre Parkway, Mountain View, CA 94043, USA. Ez a dokumentum bemutatja a szerződés felépítését, valamint rögzíti a szerződés bizonyos rendelkezéseit.</p>
 <p>1.2 Ha ettől eltérő írásos megállapodás nem születik a Google-lal, az Ön és a Google közötti szerződésnek legalább a jelen dokumentumban rögzített feltételeket tartalmaznia kell. Ezekre a továbbiakban az "Általános feltételek" kifejezéssel utalunk. A Google Chrome forráskódjának nyílt forráskódú szoftverekre vonatkozó licencei több írásos szerződésből állnak. Abban a korlátozott mértékben, amennyire a nyílt forráskódú szoftverekre vonatkozó licencek kifejezetten felülbírálják ezeket az Általános feltételeket, a nyílt forráskódú szoftverekre vonatkozó licencek szabályozzák az Ön és a Google közötti, a Google Chrome használatával vagy a Google Chrome-ba foglalt összetevők használatával kapcsolatos megállapodást.</p>
diff --git a/chrome/app/resources/terms/terms_id.html b/chrome/app/resources/terms/terms_id.html
index 73ec3a6c..0d19c8c 100644
--- a/chrome/app/resources/terms/terms_id.html
+++ b/chrome/app/resources/terms/terms_id.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Persyaratan Layanan Google Chrome</h2>
-<p>Persyaratan Layanan ini berlaku untuk versi kode Google Chrome yang dapat dieksekusi. Kode sumber untuk Google Chrome tersedia secara gratis berdasarkan perjanjian lisensi perangkat lunak sumber terbuka di http://code.google.com/intl/id/chromium/terms.html.</p>
+<p>Persyaratan Layanan ini berlaku untuk versi kode Google Chrome yang dapat dieksekusi. Kode sumber untuk Google Chrome tersedia secara gratis berdasarkan perjanjian lisensi perangkat lunak sumber terbuka di chrome://credits.</p>
 <p><strong>1. Hubungan Anda dengan Google</strong></p>
 <p>1.1 Penggunaan produk, perangkat lunak, layanan, dan situs web Google oleh Anda (dalam dokumen ini secara keseluruhan disebut “Layanan” dan mengecualikan layanan apa pun yang disediakan Google untuk Anda dalam perjanjian tertulis yang terpisah) diatur dalam persyaratan perjanjian hukum antara Anda dengan Google. “Google” adalah Google Inc. yang berkantor pusat di 1600 Amphitheatre Parkway, Mountain View, CA 94043, Amerika Serikat. Dokumen ini menjelaskan cara pembuatan perjanjian dan menetapkan beberapa persyaratan untuk perjanjian tersebut.</p>
 <p>1.2 Kecuali jika disetujui sebaliknya secara tertulis oleh Google, perjanjian Anda dengan Google setidaknya akan selalu mencakup persyaratan dan ketentuan yang ditetapkan dalam dokumen ini. Selanjutnya disebut sebagai “Persyaratan Universal”. Lisensi perangkat lunak sumber terbuka untuk kode sumber Google Chrome membentuk perjanjian tertulis terpisah. Hingga jangkauan tertentu, lisensi perangkat lunak sumber terbuka ini secara tegas menggantikan Persyaratan Universal ini, lisensi sumber terbuka mengatur perjanjian Anda dengan Google terhadap penggunaan Google Chrome atau komponen tercakup tertentu Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_it.html b/chrome/app/resources/terms/terms_it.html
index 3187a691..6559d75 100644
--- a/chrome/app/resources/terms/terms_it.html
+++ b/chrome/app/resources/terms/terms_it.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Termini di servizio di Google Chrome</h2>
-<p>I presenti Termini di servizio si applicano alla versione di codice eseguibile di Google Chrome. Il codice sorgente di Google Chrome è disponibile gratuitamente ai sensi dei contratti di licenza del software open source all'indirizzo http://code.google.com/chromium/terms.html.</p>
+<p>I presenti Termini di servizio si applicano alla versione di codice eseguibile di Google Chrome. Il codice sorgente di Google Chrome è disponibile gratuitamente ai sensi dei contratti di licenza del software open source all'indirizzo chrome://credits.</p>
 <p><strong>1. Il rapporto dell'utente con Google</strong></p>
 <p>1.1 L'utilizzo da parte dell'utente di prodotti, software, servizi e siti web di Google (collettivamente definiti i "Servizi" nel presente documento e ad esclusione di qualsiasi servizio fornito da Google ai sensi di un accordo scritto distinto) è soggetto ai termini di un contratto legale tra l'utente e Google. Con "Google" si intende Google Inc., con sede principale in 1600 Amphitheatre Parkway, Mountain View, CA 94043, Stati Uniti. Il presente documento illustra le modalità di redazione del contratto e ne espone alcuni termini.</p>
 <p>1.2 Se non diversamente concordato per iscritto con Google, il contratto stipulato con Google comprenderà sempre, come minimo, i termini e le condizioni esposti nel presente documento, di seguito definiti "Termini universali". Le licenze del software open source per il codice sorgente di Google Chrome sono oggetto di contratti scritti distinti. Nei soli casi in cui le licenze del software open source sostituiscano espressamente questi Termini universali, le licenze open source regolano il contratto dell'utente con Google per l'uso di Google Chrome o degli specifici componenti inclusi di Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_ja.html b/chrome/app/resources/terms/terms_ja.html
index 49ca5ca..ef0dc7b 100644
--- a/chrome/app/resources/terms/terms_ja.html
+++ b/chrome/app/resources/terms/terms_ja.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome 利用規約</h2>
-<p>本利用規約は、実行コード バージョンの Google Chrome に適用されます。Google Chrome のソース コードは、http://code.google.com/chromium/terms.html のオープン ソース ソフトウェア ライセンスに基づき、無料でご利用いただけます。</p>
+<p>本利用規約は、実行コード バージョンの Google Chrome に適用されます。Google Chrome のソース コードは、chrome://credits のオープン ソース ソフトウェア ライセンスに基づき、無料でご利用いただけます。</p>
 <p><strong>1. ユーザーと Google の関係</strong></p>
 <p>1.1 ユーザーが Google のプロダクト、ソフトウェア、サービス、ウェブサイト(本規約では総称して「本サービス」と呼び、書面による別の契約に従って Google よりユーザーに提供されるサービスは含まない)をご利用いただく際は、ユーザーと Google との間に法的契約による規約が適用されます。「Google」とは、業務の拠点を 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States に置く Google Inc. のことです。本文書は Google とユーザー間において、どのようにこの契約が成立するかを説明すると共に、この契約のいくつかの条件を定めるものです。</p>
 <p>1.2 Google との間で書面により別途合意している場合を除き、ユーザーと Google との間で行われる契約には、最低でも本規約で示されている利用規約が常に含まれています。以下、これらの規約を「普遍的規約」と呼びます。Google Chrome ソース コードのオープン ソース ソフトウェア ライセンスは、書面による合意が別途必要です。オープン ソース ライセンスが普遍的規約よりも明確に優先される限られた範囲において、オープン ソース ライセンスは Google Chrome または Google Chrome に含まれている特定のコンポーネントの使用についてのユーザーと Google との合意に適用されます。</p>
diff --git a/chrome/app/resources/terms/terms_kn.html b/chrome/app/resources/terms/terms_kn.html
index 8802706..cec08ea 100644
--- a/chrome/app/resources/terms/terms_kn.html
+++ b/chrome/app/resources/terms/terms_kn.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome ಸೇವಾ ನಿಯಮಗಳು</h2>
-<p>ಈ ಸೇವೆಯ ನಿಯಮಗಳುGoogle Chrome ನ ಕಾರ್ಯಗತಗೊಳಿಸುವ ಕೋಡ್ ಆವೃತ್ತಿಗೆ ಅನ್ವಯಿಸುತ್ತದೆ. Google Chrome ನ ಮೂಲ ಕೋಡ್ http://code.google.com/chromium/terms.html ನಲ್ಲಿ ತೆರೆದ ಮೂಲ ಸಾಫ್ಟ್‌ವೇರ್ ಪರವಾನಗಿ ಒಪ್ಪಂದದ ಅಡಿಯಲ್ಲಿ ಉಚಿತವಾಗಿ ಲಭ್ಯವಿದೆ.</p>
+<p>ಈ ಸೇವೆಯ ನಿಯಮಗಳುGoogle Chrome ನ ಕಾರ್ಯಗತಗೊಳಿಸುವ ಕೋಡ್ ಆವೃತ್ತಿಗೆ ಅನ್ವಯಿಸುತ್ತದೆ. Google Chrome ನ ಮೂಲ ಕೋಡ್ chrome://credits ನಲ್ಲಿ ತೆರೆದ ಮೂಲ ಸಾಫ್ಟ್‌ವೇರ್ ಪರವಾನಗಿ ಒಪ್ಪಂದದ ಅಡಿಯಲ್ಲಿ ಉಚಿತವಾಗಿ ಲಭ್ಯವಿದೆ.</p>
 <p><strong>1. Google ನೊಂದಿಗೆ ನಿಮ್ಮ ಸಂಬಂಧ</strong></p>
 <p>1.1 Google ನ ಉತ್ಪನ್ನಗಳು, ಸಾಫ್ಟ್‌ವೇರ್, ಸೇವೆಗಳು ಮತ್ತು ವೆಬ್‌ಸೈಟ್‍ಗಳ (ಈ ಡಾಕ್ಯುಮೆಂಟಿನಲ್ಲಿ ಒಂದಾಗಿ "ಸೇವೆಗಳು" ಎಂದು ಉಲ್ಲೇಖಿಸಲಾಗಿದೆ ಮತ್ತು ಬೇರೊಂದು ಲಿಖಿತ ಒಪ್ಪಂದದಡಿಯಲ್ಲಿ Google ನಿಂದ ನಿಮಗೆ ಒದಗಿಸಲಾದಂತಹ ಯಾವುದೇ ಸೇವೆಗಳನ್ನು ಹೊರತುಪಡಿಸಿ) ನಿಮ್ಮ ಬಳಕೆಯು ನಿಮ್ಮ ಮತ್ತು Google ನ ನಡುವಣವಿರುವ ಕಾನೂನು ಒಪ್ಪಂದದ ನಿಯಮಗಳಿಗೆ  ಒಳಪಟ್ಟಿದೆ. “Google” ಎಂದರೆ Google Inc. ಇದರ ಪ್ರಧಾನ ವ್ಯವಹಾರ ಸ್ಥಳವು 1600 ಅಂಫಿಥಿಯೇಟರ್ ಪಾರ್ಕ್‌ವೇ, ಮೌಂಟೇನ್ ವ್ಯೂ, CA 94043, ಯುನೈಟೆಡ್ ಸ್ಟೇಟ್ಸ್‌ನಲ್ಲಿದೆ, ಈ ಡಾಕ್ಯುಮೆಂಟ್ ಒಪ್ಪಂದವು ಹೇಗೆ ಮಾಡಲ್ಪಟ್ಟಿದೆ ಎಂಬುದನ್ನು ವಿವರಿಸುತ್ತದೆ, ಮತ್ತು ಆ ಒಪ್ಪಂದದ ಕೆಲವೊಂದು ನಿಯಮಗಳನ್ನು  ಹೊರಗೆಡವುತ್ತದೆ.</p>
 <p>1.2 Google ನೊಂದಿಗೆ ಲಿಖಿತವಾಗಿ ಸಹಮತ ನೀಡದಿದ್ದಾಗಲೂ, ನಿಮ್ಮ Google ಜೊತೆಗಿನ ಒಪ್ಪಂದವು, ಕನಿಷ್ಠ,  ಈ ಡಾಕ್ಯುಮೆಂಟಿನಲ್ಲಿ ತಿಳಿಸಿರುವ ನಿಯಮಗಳು  ಮತ್ತು ಷರತ್ತುಗಳನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ. “ಸಾರ್ವತ್ರಿಕ ನಿಯಮಗಳು ” ಎಂಬ ಹೆಸರಿನಲ್ಲಿ ಅವುಗಳನ್ನು ಕೆಳಗೆ ಉಲ್ಲೇಖಿಸಲಾಗಿದೆ. Google Chrome ಮೂಲ ಕೋಡ್‌ಗಾಗಿ ತೆರೆದ ಮೂಲ ಸಾಫ್ಟ್‌ವೇರ್ ಪರವಾನಗಿಯು ಪ್ರತ್ಯೇಕವಾದ ಲಿಖಿತ ಒಪ್ಪಂದವನ್ನು ಹೊಂದಿರುತ್ತದೆ. ಕೆಲವು ಮಿತಿಯವರೆಗೆ ತೆರೆದ ಮೂಲ ಸಾಫ್ಟ್‌ವೇರ್ ಪರವಾನಗಿಯು ಈ ಸಾರ್ವತ್ರಿಕ ನಿಯಮಗಳನ್ನು ಬಹಿರಂಗವಾಗಿಯೇ ಅತಿಕ್ರಮಿಸುತ್ತದೆ. Google Chrome ಅಥವಾ Google Chrome ನ ನಿರ್ದಿಷ್ಟವಾಗಿ ಸೇರ್ಪಡಿಸಿದ ಅಂಶಗಳ ಬಳಕೆಗಾಗಿ ತೆರೆದ ಮೂಲ ಪರವಾನಗಿಗಳುGoogle ನೊಂದಿಗೆ ನಿಮ್ಮ ಒಪ್ಪಂದವನ್ನು  ನಿಯಂತ್ರಿಸುತ್ತವೆ.</p>
diff --git a/chrome/app/resources/terms/terms_ko.html b/chrome/app/resources/terms/terms_ko.html
index ceec6ba..c3ade40 100644
--- a/chrome/app/resources/terms/terms_ko.html
+++ b/chrome/app/resources/terms/terms_ko.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google 크롬 서비스 약관</h2>
-<p>본 서비스 약관은 Google 크롬의 실행 코드 버전에 적용됩니다. Google 크롬의 소스 코드는 오픈 소스 소프트웨어 라이센스 계약에 따라 무료로 제공됩니다. http://code.google.com/chromium/terms.html</p>
+<p>본 서비스 약관은 Google 크롬의 실행 코드 버전에 적용됩니다. Google 크롬의 소스 코드는 오픈 소스 소프트웨어 라이센스 계약에 따라 무료로 제공됩니다. chrome://credits</p>
 <p><strong>1. 귀하와 Google과의 관계</strong></p>
 <p>1.1 귀하는 귀하와 Google 간에 법적으로 합의한 계약 내용에 따라 Google의 제품, 소프트웨어, 서비스 및 웹사이트(본문에서 이하 '서비스'라고 통칭. 단, Google이 별도의 서면 계약에 따라 귀하에게 제공한 서비스는 제외)를 사용합니다. 'Google'이란 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States에 주 사업장을 둔 Google Inc.를 의미합니다. 본 문서는 계약의 구성 방식과 해당 계약의 일부 조건에 대한 설명입니다.</p>
 <p>1.2 Google과 서면으로 달리 합의하지 않는 한 Google과의 계약에는 본 문서에 명시되어 있는 이용약관이 항상 포함됩니다. 이를 '일반 약관'이라고 합니다. Google 크롬 소스 코드에 대한 오픈 소스 소프트웨어 라이센스는 별도의 서면 계약을 따릅니다. 오픈 소스 소프트웨어 라이센스가 본 일반 약관에 우선 적용되는 것으로 명시된 제한된 범위 내에서 오픈 소스 라이센스는 귀하의 Google 크롬 또는 Google 크롬에 포함된 특정 구성요소의 사용에 대한 Google과의 계약을 규제합니다.</p>
diff --git a/chrome/app/resources/terms/terms_lt.html b/chrome/app/resources/terms/terms_lt.html
index 344594b..edae303 100644
--- a/chrome/app/resources/terms/terms_lt.html
+++ b/chrome/app/resources/terms/terms_lt.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>„Google Chrome“ paslaugų teikimo sąlygos</h2>
-<p>Šios paslaugų teikimo sąlygos taikomos „Google Chrome“ vykdomajai kodo versijai. „Google Chrome“ šaltinio kodą galima naudoti nemokamai pagal atvirojo šaltinio programinės įrangos licencijos sutartis, pateiktas šiuo adresu: http://code.google.com/chromium/terms.html.</p>
+<p>Šios paslaugų teikimo sąlygos taikomos „Google Chrome“ vykdomajai kodo versijai. „Google Chrome“ šaltinio kodą galima naudoti nemokamai pagal atvirojo šaltinio programinės įrangos licencijos sutartis, pateiktas šiuo adresu: chrome://credits.</p>
 <p><strong>1. Jūsų santykis su „Google“</strong></p>
 <p>1.1 „Google“ produktų, programinės įrangos, paslaugų ir svetainių (šiame dokumente bendrai nurodytų kaip „Paslaugos“, išskyrus visas „Google“ teikiamas paslaugas pagal atskirą rašytinę sutartį) naudojimas apibrėžiamas jūsų ir „Google“ sudarytos teisinės sutarties sąlygomis. „Google“ reiškia įmonę „Google Inc.“, kurios pagrindinė būstinė įsikūrusi šiuo adresu: 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. Šiame dokumente paaiškinta, kaip sudaryta sutartis, ir išdėstytos kai kurios tos sutarties sąlygos.</p>
 <p>1.2 Jei su „Google“ raštu nesutarta priešingai, į sutartį su „Google“ visada bus įtrauktos šiame dokumente išdėstytos taisyklės ir nuostatos. Toliau šiame dokumente jos nurodomos kaip „Bendrosios sąlygos“. „Google Chrome“ šaltinio kodo atvirojo šaltinio programinės įrangos licencijos sudaro atskiras rašytines sutartis. Tiek, kiek atvirojo šaltinio programinės įrangos licencijos aiškiai pakeičia šias Bendrąsias sąlygas, atvirojo šaltinio licencijos lemia jūsų sutartį su „Google“ dėl „Google Chrome“ ar konkrečių sudėtinių „Google Chrome“ komponentų naudojimo.</p>
diff --git a/chrome/app/resources/terms/terms_lv.html b/chrome/app/resources/terms/terms_lv.html
index 0e1f6c9..3d4deb8b 100644
--- a/chrome/app/resources/terms/terms_lv.html
+++ b/chrome/app/resources/terms/terms_lv.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome pakalpojumu sniegšanas noteikumi</h2>
-<p>Šie pakalpojumu sniegšanas noteikumi attiecas uz Google Chrome izpildāmā koda versiju. Google Chrome pirmkods ir pieejams bez maksas saskaņā ar atvērtā koda programmatūras licences līgumu, kas pieejams vietnē http://code.google.com/chromium/terms.html.</p>
+<p>Šie pakalpojumu sniegšanas noteikumi attiecas uz Google Chrome izpildāmā koda versiju. Google Chrome pirmkods ir pieejams bez maksas saskaņā ar atvērtā koda programmatūras licences līgumu, kas pieejams vietnē chrome://credits.</p>
 <p><strong>1. Attiecības ar Google</strong></p>
 <p>1.1. Uz Google produktu, programmatūras, pakalpojumu un vietņu (šajā dokumentā turpmāk dēvētas par “Pakalpojumiem”, izņemot visus pakalpojumus, kurus Google nodrošina saskaņā ar atsevišķu rakstveida līgumu) izmantošanu attiecas tā juridiska līguma noteikumi, kas noslēgts starp jums un uzņēmumu Google. “Google” ir uzņēmums Google Inc., kura galvenais birojs atrodas 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. Šajā dokumentā ir izskaidrots, kā tiek veidots līgums, un ir minēti daži līguma noteikumi.</p>
 <p>1.2. Ja vien ar uzņēmumu Google nav noslēgts citāds rakstveida līgums, jūsu līgumā ar uzņēmumu Google vienmēr tiks iekļauti vismaz šajā dokumentā ietvertie pakalpojumu sniegšanas noteikumi. Šie noteikumi un nosacījumi turpmāk tekstā tiek dēvēti par “Vispārējiem noteikumiem”. Atvērtā pirmkoda programmatūras licences Google Chrome pirmkodam ir izmantotas kā atsevišķi rakstveida līgumi. Ierobežotā apjomā atvērtā pirmkoda programmatūras licences skaidri aizstāj šos Vispārējos noteikumus, atvērtā pirmkoda licences nosaka jūsu līgumu ar uzņēmumu Google, kas regulē pārlūkprogrammas Google Chrome vai citu noteiktu Google Chrome sastāvdaļu izmantošanu.</p>
diff --git a/chrome/app/resources/terms/terms_ml.html b/chrome/app/resources/terms/terms_ml.html
index e160d12..edc17b7 100644
--- a/chrome/app/resources/terms/terms_ml.html
+++ b/chrome/app/resources/terms/terms_ml.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome സേവനനിബന്ധനകള്‍‌</h2>
-<p>ഈ സേവനനിബന്ധനകള്‍‌ Google Chrome ന്‍റെ നടപ്പാക്കാന്‍‌ കഴിയുന്ന കോഡ് പതിപ്പിന് ബാധകമാണ്. Google Chrome നായുള്ള ഉറവിട കോഡ് http://code.google.com/chromium/terms.html ലെ ഓപ്പണ്‍‌ സോഴ്‌സ് സോഫ്റ്റ്‌വെയര്‍‌ ലൈസന്‍‌സ് കരാറുകള്‍‌ക്ക് ചുവടെ സൌജന്യമായി ലഭ്യമാണ്.</p>
+<p>ഈ സേവനനിബന്ധനകള്‍‌ Google Chrome ന്‍റെ നടപ്പാക്കാന്‍‌ കഴിയുന്ന കോഡ് പതിപ്പിന് ബാധകമാണ്. Google Chrome നായുള്ള ഉറവിട കോഡ് chrome://credits ലെ ഓപ്പണ്‍‌ സോഴ്‌സ് സോഫ്റ്റ്‌വെയര്‍‌ ലൈസന്‍‌സ് കരാറുകള്‍‌ക്ക് ചുവടെ സൌജന്യമായി ലഭ്യമാണ്.</p>
 <p><strong>1. Google</strong> മായുള്ള നിങ്ങളുടെ ബന്ധം</p>
 <p>1.1 നിങ്ങള്‍‌ Google ന്‍റെ ഉല്‍‌പ്പന്നങ്ങള്‍‌, സോഫ്റ്റ്‌വെയര്‍‌, സേവനങ്ങള്‍‌, വെബ്‌സൈറ്റുകള്‍‌ (ഈ പ്രമാണത്തില്‍‌ ഒന്നിച്ച് “സേവനങ്ങള്‍‌“ എന്ന് പരാമര്‍‌ശിച്ചിരിക്കുന്നു മാത്രമല്ല മറ്റൊരു രേഖാമൂലമുള്ള കരാറിന്‍റെ അടിസ്ഥാനത്തില്‍‌ Google നിങ്ങള്‍‌ക്ക് നല്‍‌കിയിരിക്കുന്ന എല്ലാ സേവനങ്ങളെയും ഒഴിവാക്കിയിരിക്കുന്നു) എന്നിവ ഉപയോഗിക്കുന്നത് നിങ്ങളും Google മായുള്ള ഒരു നിയമാനുസൃത കരാറിന് വിധേയമാണ്. Google Inc. എന്ന “Google” ന്‍റെ പ്രധാന വ്യാപാര സ്ഥലം 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States എന്ന സ്ഥലത്താണ്. കരാര്‍‌ നിര്‍‌മ്മിച്ചതെങ്ങനെയാണെന്ന് ഈ പ്രമാണം വിശദീകരിക്കുന്നു, മാത്രമല്ല ആ കരാറിന്‍റെ ചില നിബന്ധനകള്‍‌ പാലിക്കാനാരംഭിക്കുകയും ചെയ്യുന്നു.</p>
 <p>1.2 Google മായി രേഖാമൂലം സമ്മതിക്കുന്നില്ലെങ്കില്‍‌‍‌, Google മായുള്ള നിങ്ങളുടെ കരാര്‍‌ എല്ലായ്‌പ്പോഴും കുറഞ്ഞത് ഈ പ്രമാണത്തില്‍‌ പ്രതിപാദിച്ചിരിക്കുന്ന നിബന്ധനകളും വ്യവസ്ഥകളും ഉള്‍‌പ്പെടുത്തും. ഇവയെ ചുവടെ “ആഗോള നിബന്ധനകള്‍‌” എന്ന് പരാമര്‍‌ശിച്ചിരിക്കുന്നു. Google Chrome നായുള്ള ഓപ്പണ്‍‌ സോഴ്‌സ് സോഫ്റ്റ്വെയര്‍ ലൈസന്‍സുകള്‍ പ്രത്യേക രേഖാമൂലമുള്ള കരാറുകള്‍ നടപ്പിലാക്കുന്നു. ഓപ്പണ്‍‌ സോഴ്‌സ് സോഫ്റ്റ്‌വെയര്‍‌ ലൈസന്‍‌സുകള്‍‌ ഈ ആഗോള നിബന്ധനകളെ പ്രകടമായി ലംഘിക്കുന്ന പരിധിവരെ, Google Chrome അല്ലെങ്കില്‍‌ Google Chrome ന്‍റെ പ്രത്യേക ഘടകങ്ങള്‍‌ ഉപയോഗിക്കുന്നതിനായി Google മായുള്ള നിങ്ങളുടെ കരാറിനെ ഓപ്പണ്‍‌ സോഴ്‌സ് ലൈസന്‍‌സുകള്‍‌ നിയന്ത്രിക്കും.</p>
diff --git a/chrome/app/resources/terms/terms_mr.html b/chrome/app/resources/terms/terms_mr.html
index aed945a..1d78108 100644
--- a/chrome/app/resources/terms/terms_mr.html
+++ b/chrome/app/resources/terms/terms_mr.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome सेवा अटी</h2>
-<p>Google Chrome च्या कार्यवाहीयोग्य कोड आवृत्तीस या सेवा अटी लागू होतात. मुक्त स्रोत सॉफ्टवेअर परवाना करारा अंतर्गत http://code.google.com/chromium/terms.html येथे Google Chrome साठी स्रोत कोड विनामूल्य उपलब्ध आहे .</p>
+<p>Google Chrome च्या कार्यवाहीयोग्य कोड आवृत्तीस या सेवा अटी लागू होतात. मुक्त स्रोत सॉफ्टवेअर परवाना करारा अंतर्गत chrome://credits येथे Google Chrome साठी स्रोत कोड विनामूल्य उपलब्ध आहे .</p>
 <p><strong>1. आपले Google बरोबरचे संबंध</strong></p>
 <p>1.1 आपला Googleची उत्पादने, सॉफ्टवेअर, सेवा आणि वेबसाइट्सचा वापर (या दस्तऐवजात एकत्रितपणे “सेवा” म्हणून संदर्भित आणि Google ने आपल्याला स्वतंत्र लेखी कराराअंतर्गत प्रदान केलेल्या सेवांना वगळून) आपण आणि Google यांच्यातील कायदेशीर कराराचे अधीन आहे. “Google” म्हणजे Google Inc., ज्यांचे व्यवसाय मुख्यालय 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States येथे आहे. हा दस्तऐवज, करार कसा तयार केला जातो आणि त्या कराराच्या काही अटींची उत्पत्ती कशी होते याचे स्पष्टीकरण देतो.</p>
 <p>1.2 Google बरोबर अन्यथा लिखित करार होईपर्यंत, Google बरोबरच्या आपल्या करारात नेहमी, या दस्तऐवजात दिलेल्या अटी आणि नियम किमान अंतर्भूत राहतील. या खाली “सार्वत्रिक अटी” म्हणून उल्लेखित आहेत. Google Chrome स्रोत कोडसाठी मुक्त स्रोत सॉफ्टवेअर परवाना विभक्त लेखी करार तयार करतो. मर्यादित प्रमाणात मुक्त स्रोत सॉफ्टवेअर परवाना या सार्वत्रिक अटींचे स्पष्टपणे अधिग्रहण करतो, Google Chrome किंवा Google Chrome मध्ये विशिष्ट अंतर्भूत घटकांच्या वापरासाठी मुक्त स्रोत परवाना आपला Google बरोबरचा करार विनियमित करतो.</p>
diff --git a/chrome/app/resources/terms/terms_nb.html b/chrome/app/resources/terms/terms_nb.html
index 2de53de..86e42a5 100644
--- a/chrome/app/resources/terms/terms_nb.html
+++ b/chrome/app/resources/terms/terms_nb.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Vilkår for bruk av Google Chrome</h2>
-<p>Disse vilkårene for bruk gjelder versjonen av Google Chrome med kjørbar kode. Kildekoden for Google Chrome er tilgjengelig gratis under lisensavtalene for programvare med åpen kildekode på http://code.google.com/chromium/terms.html.</p>
+<p>Disse vilkårene for bruk gjelder versjonen av Google Chrome med kjørbar kode. Kildekoden for Google Chrome er tilgjengelig gratis under lisensavtalene for programvare med åpen kildekode på chrome://credits.</p>
 <p><strong>1. Ditt forhold til Google</strong></p>
 <p>1.1 Din bruk av Googles produkter, programvare, tjenester og nettsteder (omtalt samlet som «tjenester» i dette dokumentet, og med unntak av eventuelle tjenester som leveres til deg av Google i samsvar med separat, skriftlig avtale) reguleres av bestemmelsene i en juridisk avtale mellom deg og Google. «Google» betyr Google Inc., med primær forretningsadresse 1600 Amphitheatre Parkway, Mountain View, CA 94043, USA. Dette dokumentet forklarer hvordan avtalen er bygd opp, og etablerer noen av bestemmelsene i avtalen.</p>
 <p>1.2 Dersom annet ikke er skriftlig avtalt med Google, omfatter din avtale med Google alltid vilkårene som er angitt i dette dokumentet. Disse vilkårene omtales nedenfor som «generelle vilkår». Programvarelisenser for åpen kildekode for Google Chrome består av egne skriftlige avtaler. Med unntak av i den begrensede grad at programvarelisensene for åpen kildekode uttrykkelig tilsidesetter disse generelle vilkårene, styrer lisensene for åpen kildekode din avtale med Google for bruk av Google Chrome eller spesifikke komponenter som er innbefattet i Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_nl.html b/chrome/app/resources/terms/terms_nl.html
index 8cece8d..44148ab 100644
--- a/chrome/app/resources/terms/terms_nl.html
+++ b/chrome/app/resources/terms/terms_nl.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome - Servicevoorwaarden</h2>
-<p>Deze Servicevoorwaarden zijn van toepassing op de uitvoerbare code van Google Chrome. De broncode voor Google Chrome is gratis beschikbaar onder 'open source'-softwarelicentieovereenkomsten op http://code.google.com/chromium/terms.html.</p>
+<p>Deze Servicevoorwaarden zijn van toepassing op de uitvoerbare code van Google Chrome. De broncode voor Google Chrome is gratis beschikbaar onder 'open source'-softwarelicentieovereenkomsten op chrome://credits.</p>
 <p><strong>1. Uw relatie met Google</strong></p>
 <p>1.1 Uw gebruik van de producten, software, services en websites van Google (in dit document gezamenlijk de 'Services' genoemd en met uitsluiting van eventuele services die door Google aan u worden geleverd onder een afzonderlijke schriftelijke overeenkomst) is onderhevig aan de voorwaarden van een juridische overeenkomst tussen u en Google. 'Google' betekent Google Inc., kantoorhoudende te 1600 Amphitheatre Parkway, Mountain View, CA 94043, Verenigde Staten. In dit document wordt beschreven hoe de overeenkomst tot stand komt en worden enkele voorwaarden van de overeenkomst uiteengezet.</p>
 <p>1.2 Tenzij schriftelijk anders is overeengekomen met Google, zijn op uw overeenkomst met Google altijd ten minste de bepalingen en voorwaarden uit dit document van toepassing. Deze worden hierna aangeduid als de 'Universele voorwaarden'. 'Open source'-softwarelicenties voor de broncode van Google Chrome vormen afzonderlijke geschreven overeenkomsten. Voor zover de 'open source'-softwarelicenties expliciet voorrang krijgen op deze Universele voorwaarden, is uw overeenkomst met Google met betrekking tot het gebruik van Google Chrome of specifieke opgenomen componenten van Google Chrome onderworpen aan de 'open source'-softwarelicenties.</p>
diff --git a/chrome/app/resources/terms/terms_pl.html b/chrome/app/resources/terms/terms_pl.html
index 9e0856c..098b355 100644
--- a/chrome/app/resources/terms/terms_pl.html
+++ b/chrome/app/resources/terms/terms_pl.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome – Warunki korzystania z usługi</h2>
-<p>Niniejsze Warunki korzystania z usługi dotyczą korzystania z kodu wykonywalnego aplikacji Google Chrome. Kod źródłowy aplikacji Google Chrome jest dostępny bezpłatnie na mocy licencji oprogramowania typu open source zamieszczonej pod adresem http://code.google.com/chromium/terms.html.</p>
+<p>Niniejsze Warunki korzystania z usługi dotyczą korzystania z kodu wykonywalnego aplikacji Google Chrome. Kod źródłowy aplikacji Google Chrome jest dostępny bezpłatnie na mocy licencji oprogramowania typu open source zamieszczonej pod adresem chrome://credits.</p>
 <p><strong>1. Relacje Użytkownika z Google</strong></p>
 <p>1.1 Korzystanie przez Użytkownika z produktów, oprogramowania, usług i witryn internetowych Google (nazywanych zbiorczo w tym dokumencie „Usługami”, z wyłączeniem wszelkich usług świadczonych Użytkownikowi przez Google na mocy oddzielnej umowy pisemnej) podlega warunkom umowy prawnej między Użytkownikiem a Google. „Google” oznacza firmę Google Inc., której podstawowe miejsce wykonywania działalności znajduje się pod adresem 1600 Amphitheatre Parkway, Mountain View, CA 94043, Stany Zjednoczone. W niniejszym dokumencie wyjaśniono zasady umowy i określono niektóre z jej warunków.</p>
 <p>1.2 Jeśli pisemna umowa z Google nie stanowi inaczej, umowa Użytkownika z Google zawsze obejmuje, jako minimum, warunki korzystania z usługi przedstawione w niniejszym dokumencie. Poniżej są one nazywane „Warunkami uniwersalnymi”. Licencje oprogramowania typu open source (otwartego kodu źródłowego) dotyczące kodu źródłowego aplikacji Google Chrome stanowią oddzielne umowy pisemne. W ograniczonym zakresie, w którym licencje oprogramowania typu open source wyraźnie zastępują niniejsze Warunki uniwersalne, umowa Użytkownika z Google o korzystanie z Google Chrome lub określonych dołączonych składników tej aplikacji podlega tym licencjom.</p>
diff --git a/chrome/app/resources/terms/terms_pt-BR.html b/chrome/app/resources/terms/terms_pt-BR.html
index 9b4f2ad..f2b9025 100644
--- a/chrome/app/resources/terms/terms_pt-BR.html
+++ b/chrome/app/resources/terms/terms_pt-BR.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Termos de Serviço do Google Chrome</h2>
-<p>Esses Termos de Serviço aplicam-se à versão do código executável do Google Chrome. O código-fonte do Google Chrome está disponível gratuitamente conforme os acordos de licença de software de código aberto em http://code.google.com/chromium/terms.html.</p>
+<p>Esses Termos de Serviço aplicam-se à versão do código executável do Google Chrome. O código-fonte do Google Chrome está disponível gratuitamente conforme os acordos de licença de software de código aberto em chrome://credits.</p>
 <p><strong>1. Relação do usuário com o Google</strong></p>
 <p>1.1 O uso de produtos, softwares, serviços e sites do Google (denominados coletivamente “Serviços” neste documento e excluindo quaisquer serviços fornecidos ao usuário pelo Google de acordo com um contrato por escrito separado) por parte do usuário está sujeito aos termos de um contrato entre o usuário e o Google. “Google” significa Google Inc., empresa com sede em 1600 Amphitheatre Parkway, Mountain View, CA 94043, Estados Unidos. Este documento explica como é constituído o contrato e define alguns dos seus termos.</p>
 <p>1.2 Exceto se acordado de outra forma por escrito pelo Google, o contrato do usuário com o Google incluirá sempre, no mínimo, os termos e condições apresentados neste documento. Esses termos serão denominados a seguir como “Termos Universais”. As licenças de software do código-fonte do Google Chrome são concedidas por acordos firmados à parte. Até a extensão permitida pelas licenças de software de código aberto que substituem explicitamente estes Termos Universais, as licenças de código aberto regem seu contrato com o Google para uso do Google Chrome ou de componentes específicos incluídos no Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_pt-PT.html b/chrome/app/resources/terms/terms_pt-PT.html
index 509c7a1d..5b3fa3f8 100644
--- a/chrome/app/resources/terms/terms_pt-PT.html
+++ b/chrome/app/resources/terms/terms_pt-PT.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Termos de utilização do Google Chrome</h2>
-<p>Estes Termos de utilização são aplicáveis à versão de código executável do Google Chrome. O código fonte do Google Chrome está disponível gratuitamente nos contratos de licença de software de código aberto em http://code.google.com/chromium/terms.html.</p>
+<p>Estes Termos de utilização são aplicáveis à versão de código executável do Google Chrome. O código fonte do Google Chrome está disponível gratuitamente nos contratos de licença de software de código aberto em chrome://credits.</p>
 <p><strong>1. Relação do utilizador com a Google</strong></p>
 <p>1.1 A utilização de produtos, software, serviços e Web sites da Google (designados colectivamente por “Serviços” neste documento e excluindo quaisquer serviços fornecidos pela Google ao abrigo de um contrato escrito em separado) está sujeita aos termos de um contrato entre o utilizador e a Google. “Google” significa Google Inc., empresa com sede principal em 1600 Amphitheatre Parkway, Mountain View, CA 94043, EUA. Este documento explica como é constituído o contrato e apresenta alguns dos seus termos.</p>
 <p>1.2 Salvo disposição em contrário acordada por escrito com a Google, o contrato com a Google incluirá sempre, no mínimo, os termos de utilização apresentados neste documento. Estes são referidos em seguida como “Termos universais”. As licenças de software de código aberto para o código fonte do Google Chrome constituem contratos escritos em separado. Nos casos em que as licenças de software open source prevaleçam expressamente sobre estes Termos universais, as licenças de open source regularão o seu contrato com a Google para a utilização do Google Chrome ou de componentes incluídos específicos do Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_ro.html b/chrome/app/resources/terms/terms_ro.html
index 5d9c423b..cbc161d 100644
--- a/chrome/app/resources/terms/terms_ro.html
+++ b/chrome/app/resources/terms/terms_ro.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Termeni şi condiţii Google Chrome</h2>
-<p>Aceşti Termeni şi condiţii se aplică versiunii de cod executabil a Google Chrome. Codul sursă pentru Google Chrome este disponibil gratuit, în baza acordurilor de licenţiere pentru software open source, la adresa http://code.google.com/chromium/terms.html.</p>
+<p>Aceşti Termeni şi condiţii se aplică versiunii de cod executabil a Google Chrome. Codul sursă pentru Google Chrome este disponibil gratuit, în baza acordurilor de licenţiere pentru software open source, la adresa chrome://credits.</p>
 <p><strong>1. Relaţia dvs. cu Google</strong></p>
 <p>1.1 Utilizarea de către dvs. a produselor, software-ului, serviciilor şi a site-urilor web Google (numite colectiv „Servicii” în acest document şi excluzând orice servicii furnizate dvs. de către Google printr-un acord scris separat) este supusă termenilor unui acord legal între dvs. şi Google. „Google” înseamnă Google Inc., al cărui sediu principal este în 1600 Amphitheatre Parkway, Mountain View, CA 94043, Statele Unite ale Americii. Acest document explică modul în care este realizat acordul şi stabileşte o parte dintre termenii acordului.</p>
 <p>1.2 Dacă nu se stabileşte altfel în scris cu Google, acordul dintre dvs. şi Google va include întotdeauna cel puţin termenii şi condiţiile stabilite în acest document. Aceştia vor fi numiţi mai jos „Termeni universali”. Licenţele pentru software open source pentru codul sursă Google Chrome constituie acorduri scrise separate. În măsura în care licenţele pentru software open source înlocuiesc în mod explicit aceşti Termeni universali, licenţele open source guvernează acordul dvs. cu Google pentru utilizarea Google Chrome sau a componentelor specifice incluse ale acestuia.</p>
diff --git a/chrome/app/resources/terms/terms_ru.html b/chrome/app/resources/terms/terms_ru.html
index 230367bb..7748458 100644
--- a/chrome/app/resources/terms/terms_ru.html
+++ b/chrome/app/resources/terms/terms_ru.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Условия предоставления услуг Google Chrome</h2>
-<p>Настоящие Условия предоставления услуг распространяются на исполняемый код Google Chrome. Исходный код Google Chrome предоставляется бесплатно на условиях лицензионных соглашений на программное обеспечение с открытым исходным кодом по адресу http://code.google.com/intl/ru/chromium/terms.html.</p>
+<p>Настоящие Условия предоставления услуг распространяются на исполняемый код Google Chrome. Исходный код Google Chrome предоставляется бесплатно на условиях лицензионных соглашений на программное обеспечение с открытым исходным кодом по адресу chrome://credits.</p>
 <p><strong>1. Взаимоотношения с компанией Google</strong></p>
 <p>1.1. Использование продуктов, программного обеспечения, служб и сайтов, принадлежащих компании Google (далее по тексту все они именуются "Услуги", за исключением услуг, предоставляемых компанией Google в рамках отдельного письменного соглашения), означает принятие и выполнение условий юридического соглашения между Вами и компанией Google. Под "Google" понимается корпорация Google Inc., главный офис которой находится по адресу 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. В настоящем документе описываются основные положения соглашения, а также изложены некоторые условия данного соглашения.</p>
 <p>1.2. Если с компанией Google не заключено иное письменное соглашение, то Ваше соглашение с компанией Google всегда будет включать в себя по меньшей мере те положения и условия, которые изложены в данном документе. Далее они именуются "Универсальные условия". Лицензии на программное обеспечение с открытым исходным кодом для исходного кода Google Chrome составляют отдельные письменные соглашения. В тех случаях, когда лицензии на программное обеспечение с открытым исходным кодом явным образом заменяют собой эти Универсальные условия, Ваше соглашение с Google на использование Google Chrome или отдельных компонентов Google Chrome регулируется лицензиями на программное обеспечение с открытым исходным кодом.</p>
diff --git a/chrome/app/resources/terms/terms_sk.html b/chrome/app/resources/terms/terms_sk.html
index a88c695..26600c01 100644
--- a/chrome/app/resources/terms/terms_sk.html
+++ b/chrome/app/resources/terms/terms_sk.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome – Zmluvné podmienky</h2>
-<p>Tieto Zmluvné podmienky sa týkajú verzie spustiteľného kódu aplikácie Google Chrome. Zdrojový kód aplikácie Google Chrome je k dispozícii bezplatne na základe dohody o poskytnutí licencie na softvér open source na adrese http://code.google.com/chromium/terms.html.</p>
+<p>Tieto Zmluvné podmienky sa týkajú verzie spustiteľného kódu aplikácie Google Chrome. Zdrojový kód aplikácie Google Chrome je k dispozícii bezplatne na základe dohody o poskytnutí licencie na softvér open source na adrese chrome://credits.</p>
 <p><strong>1. Váš vzťah so spoločnosťou Google</strong></p>
 <p>1.1 Vaše využívanie produktov, softvéru, služieb a webových stránok spoločnosti Google (v tomto dokumente súhrnne označovaných ako Služby a nezahŕňajúcich služby, ktoré vám spoločnosť Google poskytuje na základe samostatnej písomnej dohody) podlieha podmienkam právnej dohody medzi vami a spoločnosťou Google. Označenie Google predstavuje spoločnosť Google Inc. so sídlom na adrese 1600 Amphitheatre Parkway, Mountain View, CA 94043, Spojené štáty americké. Tento dokument vysvetľuje vytvorenie tejto dohody a stanovuje niektoré podmienky tejto dohody.</p>
 <p>1.2 Pokiaľ nie je so spoločnosťou Google písomne dohodnuté inak, vaša dohoda so spoločnosťou Google bude vždy zahŕňať aspoň zmluvné podmienky stanovené v tomto dokumente. Tieto sú ďalej označované ako Všeobecné zmluvné podmienky. Licencie na softvér open source na zdrojový kód programu Google Chrome tvoria samostatné písomné dohody. Vaša zmluva so spoločnosťou Google na používanie programu Google Chrome alebo konkrétnych zahrnutých súčastí programu Google Chrome sa bude riadiť licenciami na softvér open source v takom obmedzenom rozsahu, v akom tieto licencie na softvér  open source nahrádzajú tieto Všeobecné zmluvné podmienky.</p>
diff --git a/chrome/app/resources/terms/terms_sl.html b/chrome/app/resources/terms/terms_sl.html
index 5b8edfd..52e5364 100644
--- a/chrome/app/resources/terms/terms_sl.html
+++ b/chrome/app/resources/terms/terms_sl.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Pogoji storitve Google Chrome</h2>
-<p>Ti pogoji storitve veljajo za različico brskalnika Google Chrome z izvedljivo kodo. Izvorna koda za Google Chrome je na voljo brezplačno v okviru licenčne pogodbe o odprtokodni programski opremi na strani http://code.google.com/chromium/terms.html.</p>
+<p>Ti pogoji storitve veljajo za različico brskalnika Google Chrome z izvedljivo kodo. Izvorna koda za Google Chrome je na voljo brezplačno v okviru licenčne pogodbe o odprtokodni programski opremi na strani chrome://credits.</p>
 <p><strong>1. Razmerje z Googlom</strong></p>
 <p>1.1 Googlove izdelke, programsko opremo, storitve in spletna mesta (za katere se v tem dokumentu uporablja skupno ime »storitve«, ki pa ne vključuje tistih Googlovih storitev, za katere velja ločena pisna pogodba) lahko uporabljate v skladu s pogoji pravne pogodbe med vami in Googlom. »Google« pomeni podjetje Google Inc., s sedežem na naslovu 1600 Amphitheatre Parkway, Mountain View, CA 94043, ZDA. Ta dokument razlaga vsebino pogodbe in izpostavlja nekatere pogoje, ki jih vsebuje.</p>
 <p>1.2 Če z Googlom nimate drugačnega pisnega dogovora, pogodba z Googlom vedno vključuje vsaj pogoje in določila, ki so navedeni v tem dokumentu. Ti se v nadaljevanju imenujejo »splošni pogoji«. Licenco o odprtokodni programski opremi za izvorno kodo brskalnika Google Chrome sestavljajo ločene pisne pogodbe. V omejenem obsegu, v katerem licence o odprtokodni programski opremi izrecno nadomeščajo te splošne pogoje, licence o odprti kodi urejajo vašo pogodbo z Googlom za uporabo brskalnika Google Chrome ali določenih njegovih vključenih komponent.</p>
diff --git a/chrome/app/resources/terms/terms_sr.html b/chrome/app/resources/terms/terms_sr.html
index 7c7677e4..b3b1d5a 100644
--- a/chrome/app/resources/terms/terms_sr.html
+++ b/chrome/app/resources/terms/terms_sr.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome услови коришћења услуге</h2>
-<p>Ови услови коришћења услуге односе се на верзију извршног кода Google Chrome прегледача. Изворни кôд за Google Chrome доступан је бесплатно према уговору о лиценцирању софтвера са отвореним кодом на адреси http://code.google.com/chromium/terms.html.</p>
+<p>Ови услови коришћења услуге односе се на верзију извршног кода Google Chrome прегледача. Изворни кôд за Google Chrome доступан је бесплатно према уговору о лиценцирању софтвера са отвореним кодом на адреси chrome://credits.</p>
 <p><strong>1. Однос између вас и Google-а</strong></p>
 <p>1.1 Начин на који користите Google производе, софтвер, услуге и веб сајтове (који се у даљем тексту овог документа наводе под заједничким називом „Услуге“, а у које није укључена ниједна услуга коју вам Google пружа на основу посебног уговора у писменом облику) подлеже условима законског уговора између вас и Google-а. „Google“ означава Google Inc. са седиштем на адреси 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. Овај документ објашњава како је уговор сачињен и одређује неке услове тог уговора.</p>
 <p>1.2 Уколико писменим путем није другачије договорено са Google-ом, уговор између вас и Google-а увек ће садржати најмање оне услове и одредбе који су одређени овим документом. У даљем тексту документа они се називају „Општи услови“. Лиценце за софтвер са отвореним кодом за Google Chrome изворни кôд чине одвојене писмене уговоре. У одређеној мери у којој лиценце за софтвер са отвореним кодом изричито замењују ове Опште услове, лиценце за отворени кôд регулишу уговор између вас и Google-а о коришћењу Google Chrome прегледача или одређених компоненти укључених у Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_sv.html b/chrome/app/resources/terms/terms_sv.html
index 08766d7..35659b6 100644
--- a/chrome/app/resources/terms/terms_sv.html
+++ b/chrome/app/resources/terms/terms_sv.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Användarvillkor för Google Chrome</h2>
-<p>Dessa användarvillkor gäller den körbara versionen av Google Chrome. Källkoden till Google Chrome är tillgänglig kostnadsfritt enligt de programlicensavtal för öppen källkod som finns på http://code.google.com/chromium/terms.html.</p>
+<p>Dessa användarvillkor gäller den körbara versionen av Google Chrome. Källkoden till Google Chrome är tillgänglig kostnadsfritt enligt de programlicensavtal för öppen källkod som finns på chrome://credits.</p>
 <p><strong>1. Din relation till Google</strong></p>
 <p>1.1 Användningen av Googles produkter, program, tjänster och webbplatser (som härefter gemensamt kallas "tjänster" i detta dokument och som inte omfattar tjänster som Google tillhandahåller under ett separat skrivet avtal) regleras av villkoren i ett juridiskt avtal mellan dig och Google. "Google" står för Google Inc., vars huvudkontor finns på 1600 Amphitheatre Parkway, Mountain View, CA 94043, USA. I detta dokument förklaras vad avtalet består av och några av villkoren i avtalet beskrivs.</p>
 <p>1.2 Såvida inget annat skriftligt avtal med Google anger något annat inkluderar ditt avtal med Google alltid minst de villkor som beskrivs i detta dokument. De kallas härefter för "allmänna villkor". Licenser för öppen källkod för Google Chrome utgör separata skriftliga avtal. I den begränsade utsträckning som licenserna för öppen källkod motsäger dessa allmänna villkor, bestämmer licenserna för öppen källkod ditt avtal med Google för bruket av Google Chrome eller specifika komponenter som ingår i Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_ta.html b/chrome/app/resources/terms/terms_ta.html
index bdd40fe..1a50a4c1 100644
--- a/chrome/app/resources/terms/terms_ta.html
+++ b/chrome/app/resources/terms/terms_ta.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome சேவை விதிமுறைகள்</h2>
-<p>Google Chrome இன் இயங்கும் குறியீட்டு பதிப்பிற்கு இந்த சேவை விதிமுறைகள் பொருந்தும். http://code.google.com/chromium/terms.html இல் உள்ள ஓப்பன் சோர்ஸ் மென்பொருள் உரிம ஒப்பந்தங்களின் கீழ் கட்டணம் இன்றி, Google Chrome க்கான மூல குறியீடு கிடைக்கும்.</p>
+<p>Google Chrome இன் இயங்கும் குறியீட்டு பதிப்பிற்கு இந்த சேவை விதிமுறைகள் பொருந்தும். chrome://credits இல் உள்ள ஓப்பன் சோர்ஸ் மென்பொருள் உரிம ஒப்பந்தங்களின் கீழ் கட்டணம் இன்றி, Google Chrome க்கான மூல குறியீடு கிடைக்கும்.</p>
 <p><strong>1. Google உடனான உங்கள் உறவு</strong></p>
 <p>1.1. நீங்கள் பயன்படுத்தும் Google இன் தயாரிப்புகள், மென்பொருட்கள், சேவைகள் மற்றும் வலைத்தளங்கள் (தனிப்பட்ட எழுத்துப்பூர்வ ஒப்பந்தத்தின் கீழ் உங்களுக்கு Google வழங்கியிருக்கும் சேவைகளைத் தவிர மற்ற அனைத்தும் இந்த ஆவணத்தில் பொதுவாக “சேவைகள்” எனக் குறிப்பிடப்படும்) ஆகிய அனைத்தும், உங்களுக்கும் Google க்கும் இடையேயான சட்டப்பூர்வ ஒப்பந்தத்திற்கு உட்பட்டது. “Google” என்பது, Google Inc., நிறுவனம் ஆகும். இந்நிறுவனத்தின் முதன்மை வர்த்தகம் நடைபெறும் முகவரி, 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. ஒப்பந்தம் எப்படி உருவாக்கப்பட்டது என்பதையும், அந்த ஒப்பந்தத்தின் சில விதிமுறைகளை அமைப்பது குறித்தும், இந்த ஆவணம் விளக்கும்.</p>
 <p>1.2 Google உடன் எழுத்துபூர்வமாக உடன்பட்டால் தவிர, Google உடனான உங்கள் ஒப்பந்தம், இந்த ஆவணத்தில் அமைக்கப்படும் விதிமுறைகள் மற்றும் நிபந்தனைகளுடன் குறைந்தபட்சமாக உட்பட்டிருக்கும். இவை அனைத்தும் “சர்வதேச விதிமுறைகள்” என்ற பெயரில் கீழே குறிப்பிடப்படும். Google Chrome மூலக் குறியீட்டிற்கான ஓப்பன் சோர்ஸ் மென்பொருள் உரிமங்கள், எழுத்துபூர்வமான தனி ஒப்பந்தங்களாக உள்ளன. ஓபன் சோர்ஸ் மென்பொருள் உரிமங்கள், இந்த உலகளாவிய விதிமுறைகளை குறிப்பிட்ட வரம்புக்குள் மீறி அமையும்போது, அவை Google Chrome அல்லது Google Chrome இன் குறிப்பிட்ட உறுப்புகளின் பயன்பாட்டுக்கான, Google உடனான உங்கள் ஒப்பந்தத்தை அவை கட்டுப்படுத்தும்.</p>
diff --git a/chrome/app/resources/terms/terms_te.html b/chrome/app/resources/terms/terms_te.html
index 0f3ff8c..c04c5a2 100644
--- a/chrome/app/resources/terms/terms_te.html
+++ b/chrome/app/resources/terms/terms_te.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome సేవా నిబంధనలు</h2>
-<p>ఈ సేవా నిబంధనలు Google Chrome యొక్క ఆచరించదగ్గ కోడ్ సంస్కరణకు వర్తిస్తాయి. Google Chrome కోసం సోర్స్ కోడ్ http://code.google.com/chromium/terms.html వద్ద ఓపెన్ సోర్స్ సాఫ్ట్‌వేర్ లైసెన్స్ ఒప్పందం క్రింద ఉచితంగా అందుబాటులో ఉంటుంది.</p>
+<p>ఈ సేవా నిబంధనలు Google Chrome యొక్క ఆచరించదగ్గ కోడ్ సంస్కరణకు వర్తిస్తాయి. Google Chrome కోసం సోర్స్ కోడ్ chrome://credits వద్ద ఓపెన్ సోర్స్ సాఫ్ట్‌వేర్ లైసెన్స్ ఒప్పందం క్రింద ఉచితంగా అందుబాటులో ఉంటుంది.</p>
 <p><strong>1. Googleతో మీ సంబంధం</strong></p>
 <p>1.1 మీరు ఉపయోగించే Google ఉత్పత్తులు, సాఫ్ట్‌వేర్, సేవలు మరియు వెబ్ సైట్‌లు (ఈ పత్రంలోని అన్నీ "సేవలు"గా ప్రస్తావించబడినవి మరియు మీకు వ్రాత పూర్వక ఒప్పందం ఉన్న Google ద్వారా అందించబడిన వేరే సేవలు మినహాయించి) మీకు మరియు Googleకు మధ్య ఉన్న చట్టపరమైన ఒప్పందం యొక్క నిబంధనలు. “Google” అంటే  Google Inc.,దాని ప్రధాన వ్యాపార ప్రాంతం 1600 Amphitheatre Parkway, Mountain View, CA 94043, United Statesలో ఉంది. ఆ ఒప్పందం ఎలా రూపొందించబడింది మరియు దాని నిబంధనలు కొన్ని ఎలా అమర్చబడ్డాయో ఈ పత్రం వివరిస్తుంది.</p>
 <p>1.2 మీరు Googleతో వ్రాతపూర్వకంగా అంగీకరించే వరకు, Googleతో ఉన్న మీ ఒప్పందం, ఈ పత్రంలోని నిబంధనలు మరియు షరతులు మీకు ఎల్లప్పుడూ వర్తిస్తాయి. వీటన్నింటిని కలిపి క్రింద "యూనివర్సల్ నిబంధనలు"గా ప్రస్తావించబడ్డాయి. Google Chrome సోర్స్ కోడ్ కోసం ఓపెన్ సోర్స్ సాప్ట్‌వేర్ లైసెన్స్‌లు ప్రత్యేక వ్రాతపూర్వక ఒప్పందాలు నిర్వచిస్తున్నాయి. పరిమితి విస్తరణ వరకు ఓపెన్ సోర్స్ సాఫ్ట్‌వేర్ లైసెన్స్‌లు కొన్నిసార్లు ఈ యూనివర్సల్ నిబంధనలను భర్తీ చేయవచ్చు మరియు ఓపెన్ సోర్స్ లైసెన్స్‌లు Google Chrome లేదా Google Chrome యొక్క నిర్దిష్ట జోడించబడిన భాగం ఉపయోగం కోసం Googleతో మీ ఒప్పందాన్ని నిర్వహిస్తుంది.</p>
diff --git a/chrome/app/resources/terms/terms_th.html b/chrome/app/resources/terms/terms_th.html
index 289b203..d36920e 100644
--- a/chrome/app/resources/terms/terms_th.html
+++ b/chrome/app/resources/terms/terms_th.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>ข้อกำหนดในการให้บริการของ Google Chrome</h2>
-<p>ข้อกำหนดในการให้บริการนี้จะมีผลบังคับกับโค้ดสั่งการของ Google Chrome ซอร์สโค้ดของ Google Chrome มีให้ฟรีภายใต้สัญญาอนุญาตซอฟต์แวร์แบบโอเพนซอร์สที่ http://code.google.com/chromium/terms.html</p>
+<p>ข้อกำหนดในการให้บริการนี้จะมีผลบังคับกับโค้ดสั่งการของ Google Chrome ซอร์สโค้ดของ Google Chrome มีให้ฟรีภายใต้สัญญาอนุญาตซอฟต์แวร์แบบโอเพนซอร์สที่ chrome://credits</p>
 <p><strong>1. ความสัมพันธ์ระหว่างคุณกับ Google</strong></p>
 <p>1.1 การใช้ผลิตภัณฑ์ ซอฟต์แวร์ บริการ และเว็บไซต์ของ Google (ซึ่งเรียกรวมกันว่า “บริการ” ในเอกสารนี้และไม่รวมบริการใดๆ ที่ Google มอบให้แก่คุณภายใต้ข้อตกลงที่เขียนขึ้นเป็นลายลักษณ์อักษรแยกต่างหาก) จะอยู่ภายใต้เงื่อนไขของข้อตกลงทางกฎหมายระหว่างคุณและ Google “Google” หมายถึง Google Inc. ซึ่งมีสำนักงานใหญ่ตั้งอยู่ที่ 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States เอกสารนี้อธิบายถึงการจัดทำข้อตกลงและระบุเงื่อนไขบางอย่างของข้อตกลงดังกล่าว</p>
 <p>1.2 ข้อตกลงระหว่างคุณกับ Google จะรวมถึงข้อกำหนดในการให้บริการที่ระบุอยู่ในเอกสารนี้เป็นอย่างน้อยเสมอ เว้นแต่จะตกลงโดยเขียนขึ้นเป็นลายลักษณ์อักษรไว้เป็นอย่างอื่นกับ Google ซึ่งต่อไปนี้จะเรียกว่า “ข้อกำหนดทั่วไป” สัญญาอนุญาตซอฟต์แวร์แบบโอเพนซอร์สสำหรับซอร์สโค้ดของ Google Chrome จะถือเป็นข้อตกลงที่ซอร์สโค้ดเขียนขึ้นเป็นลายลักษณ์อักษรแยกต่างหาก สำหรับขอบเขตที่จำกัดซึ่งสัญญาอนุญาตแบบโอเพนซอร์สมีผลแทนข้อกำหนดทั่วไปเหล่านี้อย่างชัดแจ้ง ใบอนุญาตแบบโอเพนซอร์สจะมีผลบังคับกับข้อตกลงของคุณกับ Google ในการใช้ Google Chrome หรือองค์ประกอบที่มีอยู่ซึ่งกำหนดไว้ของ Google Chrome</p>
diff --git a/chrome/app/resources/terms/terms_tr.html b/chrome/app/resources/terms/terms_tr.html
index ee8cc9d4..ee31ebf 100644
--- a/chrome/app/resources/terms/terms_tr.html
+++ b/chrome/app/resources/terms/terms_tr.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google Chrome Hizmet Şartları</h2>
-<p>Bu Hizmet Şartları, Google Chrome'un çalıştırılabilir kod sürümü için geçerlidir. Google Chrome kaynak kodu, http://code.google.com/chromium/terms.html?hl=tr adresindeki açık kaynaklı yazılım lisansı sözleşmeleri altında ücretsiz olarak kullanılabilir.</p>
+<p>Bu Hizmet Şartları, Google Chrome'un çalıştırılabilir kod sürümü için geçerlidir. Google Chrome kaynak kodu, chrome://credits?hl=tr adresindeki açık kaynaklı yazılım lisansı sözleşmeleri altında ücretsiz olarak kullanılabilir.</p>
 <p><strong>1. Google ile ilişkiniz</strong></p>
 <p>1.1 Google ürünlerini, yazılımlarını, hizmetlerini ve web sitelerini kullanımınız (işbu dokümanda hepsi birden “Hizmetler” olarak anılacaktır. Google’ın ayrı bir yazılı sözleşme altında size sunduğu hizmetleri kapsamaz), Google ile aranızdaki yasal bir sözleşmenin şartlarına tabidir. “Google”, esas iş merkezi 1600 Amphitheatre Parkway, Mountain View, CA 94043, ABD adresinde bulunan Google Inc. şirketini ifade etmektedir. Bu dokümanda sözleşmenin nasıl yapıldığı ve söz konusu sözleşmenin bazı şartları açıklanmaktadır.</p>
 <p>1.2 Google tarafından aksi yazılı olarak kabul edilmedikçe Google ile yaptığınız sözleşme, her zaman, asgari olarak bu dokümanda belirtilen şartları ve koşulları içerecektir. Bu şartlar ve koşullar, aşağıda “Genel Şartlar” olarak ifade edilmektedir. Google Chrome kaynak kodu için açık kaynaklı yazılım lisansları, ayrı yazılı sözleşmelerdir. Açık kaynaklı yazılım lisanslarının bu Genel Şartlar'ın açıkça yerini aldığı sınırlı ölçüde, Google Chrome veya Google Chrome'un belirli bileşenlerinin kullanımı için Google ile aranızdaki sözleşme açık kaynak lisanslarına tabidir.</p>
diff --git a/chrome/app/resources/terms/terms_uk.html b/chrome/app/resources/terms/terms_uk.html
index 7d7c22b..dea929a 100644
--- a/chrome/app/resources/terms/terms_uk.html
+++ b/chrome/app/resources/terms/terms_uk.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Загальні положення та умови Google Chrome</h2>
-<p>Ці Загальні положення та умови застосовуються до версії виконуваного коду Google Chrome. Вихідний код для Google Chrome доступний безкоштовно за адресою http://code.google.com/intl/uk/chromium/terms.html відповідно до умов ліцензійних угод про використання програмного забезпечення з відкритим кодом.</p>
+<p>Ці Загальні положення та умови застосовуються до версії виконуваного коду Google Chrome. Вихідний код для Google Chrome доступний безкоштовно за адресою chrome://credits відповідно до умов ліцензійних угод про використання програмного забезпечення з відкритим кодом.</p>
 <p><strong>1. Регулювання відносин із Google</strong></p>
 <p>1.1 Використання продуктів, програмного забезпечення, служб і веб-сайтів Google (які надалі сукупно згадуються в цьому документі як "Послуги", окрім послуг, надання яких регулюється окремими угодами з корпорацією Google) обумовлено юридичною угодою між Вами та корпорацією Google. "Google" позначає корпорацію Google Inc., головний офіс якої розташований за адресою: 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. Цей документ пояснює принципи угоди та визначає певні її умови.</p>
 <p>1.2 Якщо сторони в письмовій формі не домовилися про інше, Ваша угода з Google завжди включатиме принаймні положення та умови, викладені в цьому документі (які надалі згадуються тут як "Загальні умови"). Ліцензія на використання програмного забезпечення з відкритим кодом для Google Chrome є окремою письмовою угодою. За винятком прав, явно зазначених у ліцензії на використання програмного забезпечення з відкритим кодом, які скасовують ці Загальні умови, ліцензія на використання програмного забезпечення з відкритим кодом регулює Вашу угоду з Google щодо використання Google Chrome або окремих компонентів Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_vi.html b/chrome/app/resources/terms/terms_vi.html
index 452354f..5d7fb88 100644
--- a/chrome/app/resources/terms/terms_vi.html
+++ b/chrome/app/resources/terms/terms_vi.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Ðiều khoản Dịch vụ của Google Chrome</h2>
-<p>Các Điều khoản Dịch vụ này áp dụng cho phiên bản mã thực thi của Google Chrome. Mã nguồn dành cho Google Chrome có sẵn miễn phí theo thoả thuận cấp phép phần mềm nguồn mở tại http://code.google.com/intl/vi/chromium/terms.html.</p>
+<p>Các Điều khoản Dịch vụ này áp dụng cho phiên bản mã thực thi của Google Chrome. Mã nguồn dành cho Google Chrome có sẵn miễn phí theo thoả thuận cấp phép phần mềm nguồn mở tại chrome://credits.</p>
 <p><strong>1. Mối quan hệ của bạn với Google</strong></p>
 <p>1.1 Việc bạn sử dụng các sản phẩm, phần mềm, dịch vụ và trang web của Google (được gọi chung là “Dịch vụ” trong tài liệu này và loại trừ bất kỳ dịch vụ nào do Google cung cấp cho bạn theo thoả thuận bằng văn bản riêng biệt) đều phải tuân theo các điều khoản trong thoả thuận pháp lý giữa bạn và Google. “Google” nghĩa là Google Inc., có trụ sở chính đặt tại 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States. Văn bản này giải thích việc thoả thuận đó được tạo nên như thế nào và trình bày một vài điều khoản của thoả thuận đó.</p>
 <p>1.2 Mặt khác, trừ khi bạn đã thoả thuận bằng văn bản với Google, thoả thuận của bạn với Google sẽ luôn bao gồm, tối thiểu, các điều khoản và điều kiện được trình bày trong tài liệu này. Những điều này được nhắc đến bên dưới như là “Điều khoản Chung”. Giấy phép phần mềm nguồn mở cho mã nguồn Google Chrome tạo nên các thoả thuận bằng văn bản riêng biệt. Trong phạm vi giới hạn, giấy phép phần mềm nguồn mở sẽ thay thế cho các Điều khoản Chung này, giấy phép nguồn mở sẽ chi phối thoả thuận của bạn với Google về việc sử dụng Google Chrome hoặc các thành phần cụ thể được bao gồm trong Google Chrome.</p>
diff --git a/chrome/app/resources/terms/terms_zh-CN.html b/chrome/app/resources/terms/terms_zh-CN.html
index 8a933461..fd9b931 100644
--- a/chrome/app/resources/terms/terms_zh-CN.html
+++ b/chrome/app/resources/terms/terms_zh-CN.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>谷歌浏览器服务条款</h2>
-<p>本服务条款适用于谷歌浏览器的可执行代码版本。根据开放源代码软件许可协议 (http://code.google.com/intl/zh-CN/chromium/terms.html),我们免费提供谷歌浏览器的源代码。 </p>
+<p>本服务条款适用于谷歌浏览器的可执行代码版本。根据开放源代码软件许可协议 (chrome://credits),我们免费提供谷歌浏览器的源代码。 </p>
 <p><strong>1. 您与谷歌的关系</strong></p>
 <p>1.1 在使用谷歌产品、软件、服务及网站(在本文档中统称为“服务”,其中不包括谷歌根据单独的书面协议向您提供的任何服务)时,您必须遵守与谷歌之间签署的法律协议中所规定的各项条款。“谷歌”指 Google Inc.,其主要营业地点位于 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States。本文解释了协议的制定方式,并陈述了协议中的若干条款。</p>
 <p>1.2 除非与谷歌另有书面协议,否则,您与谷歌之间签定的协议将始终包括但不限于本文所陈述的各项条款。这些条款在下文统称为“通用条款”。针对谷歌浏览器源代码的开放源代码软件许可构成了单独的书面协议。只有在开放源代码软件许可明确取代了这些通用条款的情况下,您与谷歌之间就使用谷歌浏览器或其中所包含的特定组件所签署的协议才必须遵守开放源代码软件许可证中的相关规定。</p>
diff --git a/chrome/app/resources/terms/terms_zh-TW.html b/chrome/app/resources/terms/terms_zh-TW.html
index 5472b24..857d2b91 100644
--- a/chrome/app/resources/terms/terms_zh-TW.html
+++ b/chrome/app/resources/terms/terms_zh-TW.html
@@ -28,7 +28,7 @@
 
 <body>
 <h2>Google 瀏覽器服務條款</h2>
-<p>這些《服務條款》適用於「Google 瀏覽器」的可執行程式碼版本。依據位於 http://code.google.com/chromium/terms.html 的開放原始碼軟體授權合約,您可以免費取得「Google 瀏覽器」的原始碼。</p>
+<p>這些《服務條款》適用於「Google 瀏覽器」的可執行程式碼版本。依據位於 chrome://credits 的開放原始碼軟體授權合約,您可以免費取得「Google 瀏覽器」的原始碼。</p>
 <p><strong>1. 您與 Google 的關係</strong></p>
 <p>1.1 您對 Google 產品、軟體、服務和網站 (合稱「服務」,不包括 Google 依據個別書面協議向您提供的服務) 的使用行為必須遵守您與 Google 雙方同意的法律協議之條款。「Google」是指 Google Inc.,其總部位於 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States。本文件說明協議如何制定,並列出協議中的部分條款。</p>
 <p>1.2 除非另與 Google 簽訂書面協議,否則您與 Google 的協議必須至少包括本文件所規範之所有條款與細則。以下稱為「通用條款」。「Google 瀏覽器」原始碼的開放原始碼軟體授權構成個別的書面合約。在開放原始碼軟體授權之效力明顯高於這些「通用條款」的有限範圍內,您為了使用「Google 瀏覽器」或其特定內含元件而與 Google 簽訂的合約將受到開放原始碼授權之規範。</p>
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index 41e6895..aad6140 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -154,6 +154,7 @@
 #include "components/service_tab_launcher/component_jni_registrar.h"
 #include "components/signin/core/browser/android/component_jni_registrar.h"
 #include "components/variations/android/component_jni_registrar.h"
+#include "components/variations/android/variations_seed_bridge.h"
 #include "components/web_contents_delegate_android/component_jni_registrar.h"
 #include "sync/android/sync_jni_registrar.h"
 
@@ -344,6 +345,7 @@
     {"UmaSessionStats", RegisterUmaSessionStats},
     {"UrlUtilities", RegisterUrlUtilities},
     {"Variations", variations::android::RegisterVariations},
+    {"VariationsSeedBridge", variations::android::RegisterVariationsSeedBridge},
     {"VariationsSession", chrome::android::RegisterVariationsSession},
     {"WarmupManager", RegisterWarmupManager},
     {"WebappRegistry", WebappRegistry::RegisterWebappRegistry},
diff --git a/chrome/browser/android/compositor/OWNERS b/chrome/browser/android/compositor/OWNERS
index 51fec10..ccfdc97b 100644
--- a/chrome/browser/android/compositor/OWNERS
+++ b/chrome/browser/android/compositor/OWNERS
@@ -2,5 +2,5 @@
 dtrainor@chromium.org
 jaekyun@chromium.org
 
-per-file contextual_search*=donnd@chromium.org
-per-file contextual_search*=pedrosimonetti@chromium.org
+per-file *contextual_search*=donnd@chromium.org
+per-file *contextual_search*=pedrosimonetti@chromium.org
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc
index 96e721b..5b5f4b5 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.cc
+++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -5,16 +5,13 @@
 #include "chrome/browser/android/preferences/pref_service_bridge.h"
 
 #include <jni.h>
-#include <vector>
 
 #include "base/android/build_info.h"
 #include "base/android/jni_android.h"
-#include "base/android/jni_array.h"
 #include "base/android/jni_string.h"
 #include "base/android/jni_weak_ref.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
-#include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/prefs/pref_service.h"
 #include "base/strings/string_util.h"
@@ -39,7 +36,6 @@
 #include "components/signin/core/common/signin_pref_names.h"
 #include "components/translate/core/browser/translate_prefs.h"
 #include "components/translate/core/common/translate_pref_names.h"
-#include "components/variations/pref_names.h"
 #include "components/version_info/version_info.h"
 #include "components/web_resource/web_resource_pref_names.h"
 #include "content/public/browser/browser_thread.h"
@@ -51,7 +47,6 @@
 using base::android::CheckException;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertUTF8ToJavaString;
-using base::android::GetApplicationContext;
 using base::android::ScopedJavaLocalRef;
 using base::android::ScopedJavaGlobalRef;
 using content::BrowserThread;
@@ -116,14 +111,6 @@
   return GetOriginalProfile()->GetPrefs();
 }
 
-std::string JavaByteArrayToString(JNIEnv* env, jbyteArray byte_array) {
-  if (!byte_array)
-    return std::string();
-  std::vector<uint8> array_data;
-  base::android::JavaByteArrayToByteVector(env, byte_array, &array_data);
-  return std::string(array_data.begin(), array_data.end());
-}
-
 }  // namespace
 
 // ----------------------------------------------------------------------------
@@ -961,22 +948,3 @@
 
   return ConvertJavaStringToUTF8(android_permission);
 }
-
-// static
-void PrefServiceBridge::GetVariationsFirstRunSeed(std::string* seed_data,
-                                                  std::string* seed_signature,
-                                                  std::string* seed_country) {
-  JNIEnv* env = AttachCurrentThread();
-  ScopedJavaLocalRef<jbyteArray> j_seed_data =
-      Java_PrefServiceBridge_getVariationsFirstRunSeedData(
-          env, GetApplicationContext());
-  ScopedJavaLocalRef<jstring> j_seed_signature =
-      Java_PrefServiceBridge_getVariationsFirstRunSeedSignature(
-          env, GetApplicationContext());
-  ScopedJavaLocalRef<jstring> j_seed_country =
-      Java_PrefServiceBridge_getVariationsFirstRunSeedCountry(
-          env, GetApplicationContext());
-  *seed_data = JavaByteArrayToString(env, j_seed_data.obj());
-  *seed_signature = ConvertJavaStringToUTF8(j_seed_signature);
-  *seed_country = ConvertJavaStringToUTF8(j_seed_country);
-}
diff --git a/chrome/browser/android/preferences/pref_service_bridge.h b/chrome/browser/android/preferences/pref_service_bridge.h
index 282364b..656a0fec 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.h
+++ b/chrome/browser/android/preferences/pref_service_bridge.h
@@ -26,11 +26,6 @@
   // ContentSettingsType specified (or an empty string if no permission exists).
   static std::string GetAndroidPermissionForContentSetting(
       ContentSettingsType content_type);
-
-  // Return the first run seed data pulled from the Java side of application.
-  static void GetVariationsFirstRunSeed(std::string* seed_data,
-                                        std::string* seed_signature,
-                                        std::string* seed_country);
 };
 
 #endif  // CHROME_BROWSER_ANDROID_PREFERENCES_PREF_SERVICE_BRIDGE_H_
diff --git a/chrome/browser/apps/ephemeral_app_browsertest.cc b/chrome/browser/apps/ephemeral_app_browsertest.cc
index 61144b0..f831a3f 100644
--- a/chrome/browser/apps/ephemeral_app_browsertest.cc
+++ b/chrome/browser/apps/ephemeral_app_browsertest.cc
@@ -445,7 +445,8 @@
 
   void PromoteEphemeralAppAndVerify(
       const Extension* app,
-      ExtensionRegistry::IncludeFlag expected_set) {
+      ExtensionRegistry::IncludeFlag expected_set,
+      bool expect_sync_enabled) {
     ASSERT_TRUE(app);
 
     // Ephemeral apps should not be synced.
@@ -467,8 +468,14 @@
 
     // The installation should now be synced.
     sync_change = GetLastSyncChangeForApp(app->id());
-    VerifySyncChange(sync_change.get(),
-                     expected_set == ExtensionRegistry::ENABLED);
+    VerifySyncChange(sync_change.get(), expect_sync_enabled);
+  }
+
+  void PromoteEphemeralAppAndVerify(
+      const Extension* app,
+      ExtensionRegistry::IncludeFlag expected_set) {
+    PromoteEphemeralAppAndVerify(app, expected_set,
+                                 expected_set == ExtensionRegistry::ENABLED);
   }
 
   void PromoteEphemeralAppFromSyncAndVerify(
@@ -843,7 +850,11 @@
   DisableEphemeralApp(app, Extension::DISABLE_UNSUPPORTED_REQUIREMENT);
 
   // When promoted to a regular installed app, it should remain disabled.
-  PromoteEphemeralAppAndVerify(app, ExtensionRegistry::DISABLED);
+  // However, DISABLE_UNSUPPORTED_REQUIREMENT is not a syncable disable reason,
+  // so sync should still say "enabled".
+  bool expect_sync_enabled = true;
+  PromoteEphemeralAppAndVerify(app, ExtensionRegistry::DISABLED,
+                               expect_sync_enabled);
 }
 
 // Verifies that promoting an ephemeral app that is blacklisted will not enable
diff --git a/chrome/browser/browsing_data/cookies_tree_model.cc b/chrome/browser/browsing_data/cookies_tree_model.cc
index bc3b3c5c..b7715ae 100644
--- a/chrome/browser/browsing_data/cookies_tree_model.cc
+++ b/chrome/browser/browsing_data/cookies_tree_model.cc
@@ -641,7 +641,7 @@
 
 CookieTreeHostNode::~CookieTreeHostNode() {}
 
-const std::string CookieTreeHostNode::GetHost() const {
+std::string CookieTreeHostNode::GetHost() const {
   const std::string file_origin_node_name(
       std::string(url::kFileScheme) + url::kStandardSchemeSeparator);
   return url_.SchemeIsFile() ? file_origin_node_name : url_.host();
diff --git a/chrome/browser/browsing_data/cookies_tree_model.h b/chrome/browser/browsing_data/cookies_tree_model.h
index d3a9d44..51afbc5 100644
--- a/chrome/browser/browsing_data/cookies_tree_model.h
+++ b/chrome/browser/browsing_data/cookies_tree_model.h
@@ -237,7 +237,7 @@
   // True if a content exception can be created for this origin.
   bool CanCreateContentException() const;
 
-  const std::string GetHost() const;
+  std::string GetHost() const;
 
  private:
   // Pointers to the cookies, databases, local and session storage and appcache
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
index 6a9c6b7..87684e5e 100644
--- a/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
+++ b/chrome/browser/chromeos/extensions/file_manager/private_api_strings.cc
@@ -208,6 +208,25 @@
   SET_STRING("GALLERY_DONE", IDS_FILE_BROWSER_GALLERY_DONE);
 }
 
+void AddStringsForMediaPlayer(base::DictionaryValue* dict) {
+  SET_STRING("MEDIA_PLAYER_PLAY_BUTTON_LABEL",
+             IDS_MEDIA_PLAYER_PLAY_BUTTON_LABEL);
+  SET_STRING("MEDIA_PLAYER_PAUSE_BUTTON_LABEL",
+             IDS_MEDIA_PLAYER_PAUSE_BUTTON_LABEL);
+  SET_STRING("MEDIA_PLAYER_MUTE_BUTTON_LABEL",
+             IDS_MEDIA_PLAYER_MUTE_BUTTON_LABEL);
+  SET_STRING("MEDIA_PLAYER_UNMUTE_BUTTON_LABEL",
+             IDS_MEDIA_PLAYER_UNMUTE_BUTTON_LABEL);
+  SET_STRING("MEDIA_PLAYER_PREVIOUS_BUTTON_LABEL",
+             IDS_MEDIA_PLAYER_PREVIOUS_BUTTON_LABEL);
+  SET_STRING("MEDIA_PLAYER_NEXT_BUTTON_LABEL",
+             IDS_MEDIA_PLAYER_NEXT_BUTTON_LABEL);
+  SET_STRING("MEDIA_PLAYER_SEEK_SLIDER_LABEL",
+             IDS_MEDIA_PLAYER_SEEK_SLIDER_LABEL);
+  SET_STRING("MEDIA_PLAYER_VOLUME_SLIDER_LABEL",
+             IDS_MEDIA_PLAYER_VOLUME_SLIDER_LABEL);
+}
+
 void AddStringsForVideoPlayer(base::DictionaryValue* dict) {
   SET_STRING("VIDEO_PLAYER_LOOPED_MODE", IDS_VIDEO_PLAYER_LOOPED_MODE);
   SET_STRING("VIDEO_PLAYER_PLAYBACK_ERROR", IDS_VIDEO_PLAYER_PLAYBACK_ERROR);
@@ -219,6 +238,10 @@
              IDS_VIDEO_PLAYER_VIDEO_FILE_UNSUPPORTED);
   SET_STRING("VIDEO_PLAYER_VIDEO_FILE_UNSUPPORTED_FOR_CAST",
              IDS_VIDEO_PLAYER_VIDEO_FILE_UNSUPPORTED_FOR_CAST);
+  SET_STRING("VIDEO_PLAYER_FULL_SCREEN_BUTTON_LABEL",
+             IDS_VIDEO_PLAYER_FULL_SCREEN_BUTTON_LABEL);
+  SET_STRING("VIDEO_PLAYER_EXIT_FULL_SCREEN_BUTTON_LABEL",
+             IDS_VIDEO_PLAYER_EXIT_FULL_SCREEN_BUTTON_LABEL);
 }
 
 void AddStringsForAudioPlayer(base::DictionaryValue* dict) {
@@ -227,6 +250,14 @@
   SET_STRING("AUDIO_PLAYER_DEFAULT_ARTIST",
              IDS_FILE_BROWSER_AUDIO_PLAYER_DEFAULT_ARTIST);
   SET_STRING("AUDIO_PLAYER_TITLE", IDS_FILE_BROWSER_AUDIO_PLAYER_TITLE);
+  SET_STRING("AUDIO_PLAYER_SHUFFLE_BUTTON_LABEL",
+             IDS_AUDIO_PLAYER_SHUFFLE_BUTTON_LABEL);
+  SET_STRING("AUDIO_PLAYER_REPEAT_BUTTON_LABEL",
+             IDS_AUDIO_PLAYER_REPEAT_BUTTON_LABEL);
+  SET_STRING("AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL",
+             IDS_AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL);
+  SET_STRING("AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL",
+             IDS_AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL);
 }
 
 void AddStringsForCloudImport(base::DictionaryValue* dict) {
@@ -315,6 +346,7 @@
   AddStringsForDrive(dict);
   AddStringsForFileTypes(dict);
   AddStringsForGallery(dict);
+  AddStringsForMediaPlayer(dict);
   AddStringsForVideoPlayer(dict);
   AddStringsForAudioPlayer(dict);
   AddStringsForCloudImport(dict);
diff --git a/chrome/browser/chromeos/login/enrollment/OWNERS b/chrome/browser/chromeos/login/enrollment/OWNERS
new file mode 100644
index 0000000..c2cc133
--- /dev/null
+++ b/chrome/browser/chromeos/login/enrollment/OWNERS
@@ -0,0 +1,4 @@
+per-file auto_enrollment_controller.*=atwilson@chromium.org
+per-file auto_enrollment_controller.*=bartfab@chromium.org
+per-file auto_enrollment_controller.*=cschuet@chromium.org
+per-file auto_enrollment_controller.*=tnagel@chromium.org
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc
index 7f9fc254..b8c31c1 100644
--- a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc
+++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc
@@ -136,14 +136,16 @@
            chromeos::switches::kEnterpriseEnrollmentModulusLimit)) ||
       GetMode() == MODE_NONE ||
       IsFirstDeviceSetup()) {
-    VLOG(1) << "Auto-enrollment disabled.";
+    LOG(WARNING) << "Auto-enrollment disabled.";
     UpdateState(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT);
     return;
   }
 
   // If a client is being created or already existing, bail out.
-  if (client_start_weak_factory_.HasWeakPtrs() || client_)
+  if (client_start_weak_factory_.HasWeakPtrs() || client_) {
+    LOG(ERROR) << "Auto-enrollment client is already running.";
     return;
+  }
 
   // Arm the belts-and-suspenders timer to avoid hangs.
   safeguard_timer_.Start(
@@ -185,25 +187,35 @@
 
 void AutoEnrollmentController::OnOwnershipStatusCheckDone(
     DeviceSettingsService::OwnershipStatus status) {
-  if (status != DeviceSettingsService::OWNERSHIP_NONE) {
-    // The device is already owned. No need for auto-enrollment checks.
-    VLOG(1) << "Device already owned, skipping auto-enrollment check";
-    UpdateState(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT);
-    return;
+  switch (status) {
+    case DeviceSettingsService::OWNERSHIP_NONE: {
+      g_browser_process->platform_part()
+          ->browser_policy_connector_chromeos()
+          ->GetStateKeysBroker()
+          ->RequestStateKeys(
+              base::Bind(&AutoEnrollmentController::StartClient,
+                         client_start_weak_factory_.GetWeakPtr()));
+      break;
+    }
+    case DeviceSettingsService::OWNERSHIP_TAKEN: {
+      // This is part of normal operation.  Logging as "WARNING" nevertheless to
+      // make sure it's preserved in the logs.
+      LOG(WARNING) << "Device already owned, skipping auto-enrollment check.";
+      UpdateState(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT);
+      break;
+    }
+    case DeviceSettingsService::OWNERSHIP_UNKNOWN: {
+      LOG(ERROR) << "Ownership unknown, skipping auto-enrollment check.";
+      UpdateState(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT);
+      break;
+    }
   }
-
-  // Make sure state keys are available.
-  g_browser_process->platform_part()
-      ->browser_policy_connector_chromeos()
-      ->GetStateKeysBroker()
-      ->RequestStateKeys(base::Bind(&AutoEnrollmentController::StartClient,
-                                    client_start_weak_factory_.GetWeakPtr()));
 }
 
 void AutoEnrollmentController::StartClient(
     const std::vector<std::string>& state_keys) {
   if (state_keys.empty()) {
-    LOG(WARNING) << "No state keys available!";
+    LOG(ERROR) << "No state keys available!";
     UpdateState(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT);
     return;
   }
@@ -220,7 +232,7 @@
       chromeos::switches::kEnterpriseEnrollmentModulusLimit);
   if (power_initial > power_limit) {
     LOG(ERROR) << "Initial auto-enrollment modulus is larger than the limit, "
-               << "clamping to the limit.";
+                  "clamping to the limit.";
     power_initial = power_limit;
   }
 
@@ -240,7 +252,9 @@
 
 void AutoEnrollmentController::UpdateState(
     policy::AutoEnrollmentState new_state) {
-  VLOG(1) << "New state: " << new_state << ".";
+  // This is part of normal operation.  Logging as "WARNING" nevertheless to
+  // make sure it's preserved in the logs.
+  LOG(WARNING) << "New auto-enrollment state: " << new_state;
   state_ = new_state;
 
   // Stop the safeguard timer once a result comes in.
diff --git a/chrome/browser/chromeos/options/vpn_config_view.cc b/chrome/browser/chromeos/options/vpn_config_view.cc
index de4648c..23f0218 100644
--- a/chrome/browser/chromeos/options/vpn_config_view.cc
+++ b/chrome/browser/chromeos/options/vpn_config_view.cc
@@ -403,19 +403,19 @@
     view_to_focus->RequestFocus();
 }
 
-const std::string VPNConfigView::GetService() const {
+std::string VPNConfigView::GetService() const {
   if (service_textfield_ != NULL)
     return GetTextFromField(service_textfield_, true);
   return service_path_;
 }
 
-const std::string VPNConfigView::GetServer() const {
+std::string VPNConfigView::GetServer() const {
   if (server_textfield_ != NULL)
     return GetTextFromField(server_textfield_, true);
   return std::string();
 }
 
-const std::string VPNConfigView::GetPSKPassphrase() const {
+std::string VPNConfigView::GetPSKPassphrase() const {
   if (psk_passphrase_textfield_ &&
       enable_psk_passphrase_ &&
       psk_passphrase_textfield_->visible())
@@ -423,23 +423,23 @@
   return std::string();
 }
 
-const std::string VPNConfigView::GetUsername() const {
+std::string VPNConfigView::GetUsername() const {
   return GetTextFromField(username_textfield_, true);
 }
 
-const std::string VPNConfigView::GetUserPassphrase() const {
+std::string VPNConfigView::GetUserPassphrase() const {
   return GetPassphraseFromField(user_passphrase_textfield_);
 }
 
-const std::string VPNConfigView::GetGroupName() const {
+std::string VPNConfigView::GetGroupName() const {
   return GetTextFromField(group_name_textfield_, false);
 }
 
-const std::string VPNConfigView::GetOTP() const {
+std::string VPNConfigView::GetOTP() const {
   return GetTextFromField(otp_textfield_, true);
 }
 
-const std::string VPNConfigView::GetServerCACertPEM() const {
+std::string VPNConfigView::GetServerCACertPEM() const {
   int index = server_ca_cert_combobox_ ?
       server_ca_cert_combobox_->selected_index() : 0;
   if (index == 0) {
diff --git a/chrome/browser/chromeos/options/vpn_config_view.h b/chrome/browser/chromeos/options/vpn_config_view.h
index a316f1c..1d5f2c4 100644
--- a/chrome/browser/chromeos/options/vpn_config_view.h
+++ b/chrome/browser/chromeos/options/vpn_config_view.h
@@ -117,14 +117,14 @@
       PassphraseTextfield* textfield) const;
 
   // Convenience methods to get text from input field or cached VirtualNetwork.
-  const std::string GetService() const;
-  const std::string GetServer() const;
-  const std::string GetPSKPassphrase() const;
-  const std::string GetUsername() const;
-  const std::string GetUserPassphrase() const;
-  const std::string GetOTP() const;
-  const std::string GetGroupName() const;
-  const std::string GetServerCACertPEM() const;
+  std::string GetService() const;
+  std::string GetServer() const;
+  std::string GetPSKPassphrase() const;
+  std::string GetUsername() const;
+  std::string GetUserPassphrase() const;
+  std::string GetOTP() const;
+  std::string GetGroupName() const;
+  std::string GetServerCACertPEM() const;
   bool GetSaveCredentials() const;
   int GetProviderTypeIndex() const;
   std::string GetProviderTypeString() const;
diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client.cc b/chrome/browser/chromeos/policy/auto_enrollment_client.cc
index 49b97096..edce444 100644
--- a/chrome/browser/chromeos/policy/auto_enrollment_client.cc
+++ b/chrome/browser/chromeos/policy/auto_enrollment_client.cc
@@ -324,9 +324,9 @@
     int64 modulus = enrollment_response.expected_modulus();
     int power = NextPowerOf2(modulus);
     if ((INT64_C(1) << power) != modulus) {
-      LOG(WARNING) << "Auto enrollment: the server didn't ask for a power-of-2 "
-                   << "modulus. Using the closest power-of-2 instead "
-                   << "(" << modulus << " vs 2^" << power << ")";
+      LOG(ERROR) << "Auto enrollment: the server didn't ask for a power-of-2 "
+                 << "modulus. Using the closest power-of-2 instead "
+                 << "(" << modulus << " vs 2^" << power << ")";
     }
     if (modulus_updates_received_ >= 2) {
       LOG(ERROR) << "Auto enrollment error: already retried with an updated "
diff --git a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
index a6e0d8c..59822df 100644
--- a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
+++ b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
@@ -250,6 +250,8 @@
   specifics.mutable_extension()->set_id(extension_id);
   specifics.mutable_extension()->set_enabled(false);
   specifics.mutable_extension()->set_remote_install(true);
+  specifics.mutable_extension()->set_disable_reasons(
+      Extension::DISABLE_REMOTE_INSTALL);
   specifics.mutable_extension()->set_update_url(
       "http://localhost/autoupdate/updates.xml");
   specifics.mutable_extension()->set_version("2");
diff --git a/chrome/browser/extensions/extension_service_sync_unittest.cc b/chrome/browser/extensions/extension_service_sync_unittest.cc
index a8ea9a23..c399a69 100644
--- a/chrome/browser/extensions/extension_service_sync_unittest.cc
+++ b/chrome/browser/extensions/extension_service_sync_unittest.cc
@@ -307,6 +307,80 @@
   EXPECT_EQ(extension->name(), data->name());
 }
 
+TEST_F(ExtensionServiceSyncTest, GetSyncDataDisableReasons) {
+  InitializeEmptyExtensionService();
+  const Extension* extension =
+      InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
+  ASSERT_TRUE(extension);
+
+  syncer::FakeSyncChangeProcessor processor;
+  extension_sync_service()->MergeDataAndStartSyncing(
+      syncer::EXTENSIONS,
+      syncer::SyncDataList(),
+      scoped_ptr<syncer::SyncChangeProcessor>(
+          new syncer::FakeSyncChangeProcessor),
+      scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock()));
+
+  {
+    syncer::SyncDataList list =
+        extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
+    ASSERT_EQ(list.size(), 1U);
+    scoped_ptr<ExtensionSyncData> data =
+        ExtensionSyncData::CreateFromSyncData(list[0]);
+    ASSERT_TRUE(data.get());
+    EXPECT_TRUE(data->enabled());
+    EXPECT_TRUE(data->supports_disable_reasons());
+    EXPECT_EQ(Extension::DISABLE_NONE, data->disable_reasons());
+  }
+
+  // Syncable disable reason, should propagate to sync.
+  service()->DisableExtension(good_crx, Extension::DISABLE_USER_ACTION);
+  {
+    syncer::SyncDataList list =
+        extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
+    ASSERT_EQ(list.size(), 1U);
+    scoped_ptr<ExtensionSyncData> data =
+        ExtensionSyncData::CreateFromSyncData(list[0]);
+    ASSERT_TRUE(data.get());
+    EXPECT_FALSE(data->enabled());
+    EXPECT_TRUE(data->supports_disable_reasons());
+    EXPECT_EQ(Extension::DISABLE_USER_ACTION, data->disable_reasons());
+  }
+  service()->EnableExtension(good_crx);
+
+  // Non-syncable disable reason. The sync data should still say "enabled".
+  service()->DisableExtension(good_crx, Extension::DISABLE_RELOAD);
+  {
+    syncer::SyncDataList list =
+        extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
+    ASSERT_EQ(list.size(), 1U);
+    scoped_ptr<ExtensionSyncData> data =
+        ExtensionSyncData::CreateFromSyncData(list[0]);
+    ASSERT_TRUE(data.get());
+    EXPECT_TRUE(data->enabled());
+    EXPECT_TRUE(data->supports_disable_reasons());
+    EXPECT_EQ(Extension::DISABLE_NONE, data->disable_reasons());
+  }
+  service()->EnableExtension(good_crx);
+
+  // Both a syncable and a non-syncable disable reason, only the former should
+  // propagate to sync.
+  service()->DisableExtension(
+      good_crx, Extension::DISABLE_USER_ACTION | Extension::DISABLE_RELOAD);
+  {
+    syncer::SyncDataList list =
+        extension_sync_service()->GetAllSyncData(syncer::EXTENSIONS);
+    ASSERT_EQ(list.size(), 1U);
+    scoped_ptr<ExtensionSyncData> data =
+        ExtensionSyncData::CreateFromSyncData(list[0]);
+    ASSERT_TRUE(data.get());
+    EXPECT_FALSE(data->enabled());
+    EXPECT_TRUE(data->supports_disable_reasons());
+    EXPECT_EQ(Extension::DISABLE_USER_ACTION, data->disable_reasons());
+  }
+  service()->EnableExtension(good_crx);
+}
+
 TEST_F(ExtensionServiceSyncTest, GetSyncDataTerminated) {
   InitializeEmptyExtensionService();
   InstallCRX(data_dir().AppendASCII("good.crx"), INSTALL_NEW);
@@ -1085,19 +1159,35 @@
     { "NopEnable", 0, true, 0, 0 },
     { "NopDisable", Extension::DISABLE_USER_ACTION, false,
       Extension::DISABLE_USER_ACTION, Extension::DISABLE_USER_ACTION },
+    { "Enable", Extension::DISABLE_USER_ACTION, true, 0, 0 },
     { "Disable", 0, false, Extension::DISABLE_USER_ACTION,
       Extension::DISABLE_USER_ACTION },
-    { "DisableLegacy", 0, false, -1, Extension::DISABLE_USER_ACTION },
     { "AddDisableReason", Extension::DISABLE_REMOTE_INSTALL, false,
       Extension::DISABLE_REMOTE_INSTALL | Extension::DISABLE_USER_ACTION,
       Extension::DISABLE_REMOTE_INSTALL | Extension::DISABLE_USER_ACTION },
-    { "AddDisableReasonLegacy", Extension::DISABLE_USER_ACTION, false, -1,
-      Extension::DISABLE_USER_ACTION},
     { "RemoveDisableReason",
       Extension::DISABLE_REMOTE_INSTALL | Extension::DISABLE_USER_ACTION, false,
       Extension::DISABLE_USER_ACTION, Extension::DISABLE_USER_ACTION },
-    { "Enable", Extension::DISABLE_USER_ACTION, true, 0, 0 },
-    { "EnableLegacy", Extension::DISABLE_USER_ACTION, true, -1, 0 },
+    { "PreserveLocalDisableReason", Extension::DISABLE_RELOAD, true, 0,
+      Extension::DISABLE_RELOAD },
+    { "PreserveOnlyLocalDisableReason",
+      Extension::DISABLE_USER_ACTION | Extension::DISABLE_RELOAD, true, 0,
+      Extension::DISABLE_RELOAD },
+
+    // Interaction with Chrome clients <=M44, which don't sync disable_reasons
+    // at all (any existing reasons are preserved).
+    { "M44Enable", Extension::DISABLE_USER_ACTION, true, -1, 0 },
+    // An M44 client enables an extension that had been disabled on a new
+    // client. The disable reasons are still be there, but should be ignored.
+    { "M44ReEnable", Extension::DISABLE_USER_ACTION, true,
+      Extension::DISABLE_USER_ACTION, 0 },
+    { "M44Disable", 0, false, -1, Extension::DISABLE_USER_ACTION },
+    { "M44ReDisable", 0, false, 0, Extension::DISABLE_USER_ACTION },
+    { "M44AlreadyDisabledByUser", Extension::DISABLE_USER_ACTION, false, -1,
+      Extension::DISABLE_USER_ACTION},
+    { "M44AlreadyDisabledWithOtherReason", Extension::DISABLE_REMOTE_INSTALL,
+      false, -1,
+      Extension::DISABLE_REMOTE_INSTALL | Extension::DISABLE_USER_ACTION },
   };
 
   for (const TestCase& test_case : test_cases) {
diff --git a/chrome/browser/extensions/extension_sync_data.cc b/chrome/browser/extensions/extension_sync_data.cc
index c3667c0f..70ccc91 100644
--- a/chrome/browser/extensions/extension_sync_data.cc
+++ b/chrome/browser/extensions/extension_sync_data.cc
@@ -49,8 +49,8 @@
   // No ExtensionSpecifics in the EntitySpecifics.
   NO_EXTENSION_SPECIFICS,
 
-  // Enabled extensions can't have disable reasons.
-  BAD_DISABLE_REASONS,
+  // Not used anymore; still here because of UMA.
+  DEPRECATED_BAD_DISABLE_REASONS,
 
   // Must be at the end.
   NUM_BAD_SYNC_DATA_REASONS
@@ -253,17 +253,6 @@
     return false;
   }
 
-  // Enabled extensions can't have disable reasons. (The proto field may be
-  // unset, in which case it defaults to DISABLE_NONE.)
-  if (specifics.enabled() &&
-      specifics.disable_reasons() != Extension::DISABLE_NONE) {
-    LOG(ERROR) << "Attempt to sync bad ExtensionSpecifics "
-               << "(enabled extension can't have disable reasons):\n"
-               << GetExtensionSpecificsLogMessage(specifics);
-    RecordBadSyncData(BAD_DISABLE_REASONS);
-    return false;
-  }
-
   id_ = specifics.id();
   update_url_ = specifics_update_url;
   version_ = specifics_version;
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc
index 8c95c7b..e0a8cdf 100644
--- a/chrome/browser/extensions/extension_sync_service.cc
+++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -95,6 +95,21 @@
   return result;
 }
 
+static_assert(Extension::DISABLE_REASON_LAST == (1 << 15),
+              "Please consider whether your new disable reason should be"
+              " syncable, and if so update this bitmask accordingly!");
+const int kKnownSyncableDisableReasons =
+    Extension::DISABLE_USER_ACTION |
+    Extension::DISABLE_PERMISSIONS_INCREASE |
+    Extension::DISABLE_SIDELOAD_WIPEOUT |
+    Extension::DISABLE_GREYLIST |
+    Extension::DISABLE_REMOTE_INSTALL;
+const int kAllKnownDisableReasons = Extension::DISABLE_REASON_LAST - 1;
+// We also include any future bits for newer clients that added another disable
+// reason.
+const int kSyncableDisableReasons =
+    kKnownSyncableDisableReasons | ~kAllKnownDisableReasons;
+
 }  // namespace
 
 struct ExtensionSyncService::PendingUpdate {
@@ -236,43 +251,38 @@
 
 ExtensionSyncData ExtensionSyncService::CreateSyncData(
     const Extension& extension) const {
+  const std::string& id = extension.id();
   const ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(profile_);
-  // Query the enabled state from ExtensionPrefs rather than
-  // ExtensionService::IsExtensionEnabled - the latter uses ExtensionRegistry
-  // which might not have been updated yet (ExtensionPrefs are updated first,
-  // and we're listening for changes to these).
-  bool enabled = !extension_prefs->IsExtensionDisabled(extension.id());
-  enabled = enabled &&
-      !extension_prefs->IsExternalExtensionUninstalled(extension.id());
-  // Blacklisted extensions are not marked as disabled in ExtensionPrefs.
+  int disable_reasons =
+      extension_prefs->GetDisableReasons(id) & kSyncableDisableReasons;
+  // Note that we're ignoring the enabled state during ApplySyncData (we check
+  // for the existence of disable reasons instead), we're just setting it here
+  // for older Chrome versions (<M48).
+  bool enabled = (disable_reasons == Extension::DISABLE_NONE);
   enabled = enabled &&
       extension_prefs->GetExtensionBlacklistState(extension.id()) ==
           extensions::NOT_BLACKLISTED;
-  int disable_reasons = extension_prefs->GetDisableReasons(extension.id());
-  bool incognito_enabled = extensions::util::IsIncognitoEnabled(extension.id(),
-                                                                profile_);
+  bool incognito_enabled = extensions::util::IsIncognitoEnabled(id, profile_);
   bool remote_install =
-      extension_prefs->HasDisableReason(extension.id(),
-                                        Extension::DISABLE_REMOTE_INSTALL);
+      extension_prefs->HasDisableReason(id, Extension::DISABLE_REMOTE_INSTALL);
   ExtensionSyncData::OptionalBoolean allowed_on_all_url =
-      GetAllowedOnAllUrlsOptionalBoolean(extension.id(), profile_);
+      GetAllowedOnAllUrlsOptionalBoolean(id, profile_);
   AppSorting* app_sorting = ExtensionSystem::Get(profile_)->app_sorting();
 
   ExtensionSyncData result = extension.is_app()
       ? ExtensionSyncData(
             extension, enabled, disable_reasons, incognito_enabled,
             remote_install, allowed_on_all_url,
-            app_sorting->GetAppLaunchOrdinal(extension.id()),
-            app_sorting->GetPageOrdinal(extension.id()),
-            extensions::GetLaunchTypePrefValue(extension_prefs,
-                                               extension.id()))
+            app_sorting->GetAppLaunchOrdinal(id),
+            app_sorting->GetPageOrdinal(id),
+            extensions::GetLaunchTypePrefValue(extension_prefs, id))
       : ExtensionSyncData(
             extension, enabled, disable_reasons, incognito_enabled,
             remote_install, allowed_on_all_url);
 
   // If there's a pending update, send the new version to sync instead of the
   // installed one.
-  auto it = pending_updates_.find(extension.id());
+  auto it = pending_updates_.find(id);
   if (it != pending_updates_.end()) {
     const base::Version& version = it->second.version;
     // If we have a pending version, it should be newer than the installed one.
@@ -324,72 +334,100 @@
     return;
   }
 
-  int version_compare_result = extension ?
-      extension->version()->CompareTo(extension_sync_data.version()) : 0;
+  enum {
+    NOT_INSTALLED,
+    INSTALLED_OUTDATED,
+    INSTALLED_MATCHING,
+    INSTALLED_NEWER,
+  } state = NOT_INSTALLED;
+  if (extension) {
+    switch (extension->version()->CompareTo(extension_sync_data.version())) {
+      case -1: state = INSTALLED_OUTDATED; break;
+      case 0: state = INSTALLED_MATCHING; break;
+      case 1: state = INSTALLED_NEWER; break;
+      default: NOTREACHED();
+    }
+  }
+
+  // Figure out the resulting set of disable reasons.
+  int disable_reasons = extension_prefs->GetDisableReasons(id);
+
+  // Chrome versions M37-M44 used |extension_sync_data.remote_install()| to tag
+  // not-yet-approved remote installs. It's redundant now that disable reasons
+  // are synced (DISABLE_REMOTE_INSTALL should be among them already), but some
+  // old sync data may still be around, and it doesn't hurt to add the reason.
+  // TODO(treib,devlin): Deprecate and eventually remove |remote_install|?
+  if (extension_sync_data.remote_install())
+    disable_reasons |= Extension::DISABLE_REMOTE_INSTALL;
+
+  // Add/remove disable reasons based on the incoming sync data.
+  int incoming_disable_reasons = extension_sync_data.disable_reasons();
+  if (!!incoming_disable_reasons == extension_sync_data.enabled()) {
+    // The enabled flag disagrees with the presence of disable reasons. This
+    // must come from an old (<M45) client which doesn't sync disable reasons.
+    // Update |disable_reasons| based on the enabled flag.
+    if (extension_sync_data.enabled())
+      disable_reasons &= ~kKnownSyncableDisableReasons;
+    else  // Assume the extension was likely disabled by the user.
+      disable_reasons |= Extension::DISABLE_USER_ACTION;
+  } else {
+    // Replace the syncable disable reasons:
+    // 1. Remove any syncable disable reasons we might have.
+    disable_reasons &= ~kSyncableDisableReasons;
+    // 2. Add the incoming reasons. Mask with |kSyncableDisableReasons|, because
+    //    Chrome M45-M47 also wrote local disable reasons to sync, and we don't
+    //    want those.
+    disable_reasons |= incoming_disable_reasons & kSyncableDisableReasons;
+  }
 
   // Enable/disable the extension.
+  bool should_be_enabled = (disable_reasons == Extension::DISABLE_NONE);
   bool reenable_after_update = false;
-  if (extension_sync_data.enabled()) {
-    DCHECK(!extension_sync_data.disable_reasons());
-
+  if (should_be_enabled && !extension_service()->IsExtensionEnabled(id)) {
     if (extension) {
       // Only grant permissions if the sync data explicitly sets the disable
       // reasons to Extension::DISABLE_NONE (as opposed to the legacy (<M45)
       // case where they're not set at all), and if the version from sync
       // matches our local one.
       bool grant_permissions = extension_sync_data.supports_disable_reasons() &&
-                               (version_compare_result == 0);
-      if (grant_permissions) {
-        extension_service()->GrantPermissionsAndEnableExtension(extension);
-      } else if (!extension_service()->IsExtensionEnabled(extension->id())) {
-        // Only enable if the extension already has all required permissions.
-        scoped_ptr<const extensions::PermissionSet> granted_permissions =
-            extension_prefs->GetGrantedPermissions(extension->id());
-        DCHECK(granted_permissions.get());
-        bool is_privilege_increase =
-            extensions::PermissionMessageProvider::Get()->IsPrivilegeIncrease(
-                *granted_permissions,
-                extension->permissions_data()->active_permissions(),
-                extension->GetType());
-        if (!is_privilege_increase)
-          extension_service()->EnableExtension(id);
-        else if (extension_sync_data.supports_disable_reasons())
-          reenable_after_update = true;
+                               (state == INSTALLED_MATCHING);
+      if (grant_permissions)
+        extension_service()->GrantPermissions(extension);
+
+      // Only enable if the extension has all required permissions.
+      // (Even if the version doesn't match - if the new version needs more
+      // permissions, it'll get disabled after the update.)
+      bool has_all_permissions =
+          grant_permissions ||
+          !extensions::PermissionMessageProvider::Get()->IsPrivilegeIncrease(
+              *extension_prefs->GetGrantedPermissions(id),
+              extension->permissions_data()->active_permissions(),
+              extension->GetType());
+      if (has_all_permissions)
+        extension_service()->EnableExtension(id);
+      else if (extension_sync_data.supports_disable_reasons())
+        reenable_after_update = true;
 
 #if defined(ENABLE_SUPERVISED_USERS)
-        if (is_privilege_increase && version_compare_result > 0 &&
-            extensions::util::IsExtensionSupervised(extension, profile_)) {
-          SupervisedUserServiceFactory::GetForProfile(profile_)
-              ->AddExtensionUpdateRequest(id, *extension->version());
-        }
-#endif
+      if (!has_all_permissions && (state == INSTALLED_NEWER) &&
+          extensions::util::IsExtensionSupervised(extension, profile_)) {
+        SupervisedUserServiceFactory::GetForProfile(profile_)
+            ->AddExtensionUpdateRequest(id, *extension->version());
       }
+#endif
     } else {
       // The extension is not installed yet. Set it to enabled; we'll check for
-      // permission increase when it's actually installed.
+      // permission increase (more accurately, for a version change) when it's
+      // actually installed.
       extension_service()->EnableExtension(id);
     }
-  } else {
-    int disable_reasons = extension_sync_data.disable_reasons();
-    if (extension_sync_data.remote_install()) {
-      if (!(disable_reasons & Extension::DISABLE_REMOTE_INSTALL)) {
-        // Since disabled reasons are synced since M45, DISABLE_REMOTE_INSTALL
-        // should be among them already.
-        DCHECK(!extension_sync_data.supports_disable_reasons());
-        disable_reasons |= Extension::DISABLE_REMOTE_INSTALL;
-      }
-    } else if (!extension_sync_data.supports_disable_reasons()) {
-      // Legacy case (<M45), from before we synced disable reasons (see
-      // crbug.com/484214). Assume the extension was likely disabled by the
-      // user, so add DISABLE_USER_ACTION to any existing disable reasons.
-      disable_reasons = extension_prefs->GetDisableReasons(id);
-      disable_reasons |= Extension::DISABLE_USER_ACTION;
-    }
-
-    // Clear any existing disable reasons first, otherwise sync can't remove
-    // just some of them.
-    extension_prefs->ClearDisableReasons(id);
-    extension_service()->DisableExtension(id, disable_reasons);
+  } else if (!should_be_enabled) {
+    // Note that |disable_reasons| includes any pre-existing reasons that
+    // weren't explicitly removed above.
+    if (extension_service()->IsExtensionEnabled(id))
+      extension_service()->DisableExtension(id, disable_reasons);
+    else  // Already disabled, just replace the disable reasons.
+      extension_prefs->ReplaceDisableReasons(id, disable_reasons);
   }
 
   // If the target extension has already been installed ephemerally, it can
@@ -398,11 +436,6 @@
   if (extension && extensions::util::IsEphemeralApp(id, profile_))
     extension_service()->PromoteEphemeralApp(extension, true);
 
-  // Cache whether the extension was already installed because setting the
-  // incognito flag invalidates the |extension| pointer (it reloads the
-  // extension).
-  bool extension_installed = (extension != nullptr);
-
   // Update the incognito flag.
   extensions::util::SetIsIncognitoEnabled(
       id, profile_, extension_sync_data.incognito_enabled());
@@ -441,14 +474,12 @@
 
   // Finally, trigger installation/update as required.
   bool check_for_updates = false;
-  if (extension_installed) {
+  if (state == INSTALLED_OUTDATED) {
     // If the extension is installed but outdated, store the new version.
-    if (version_compare_result < 0) {
-      pending_updates_[id] = PendingUpdate(extension_sync_data.version(),
-                                           reenable_after_update);
-      check_for_updates = true;
-    }
-  } else {
+    pending_updates_[id] =
+        PendingUpdate(extension_sync_data.version(), reenable_after_update);
+    check_for_updates = true;
+  } else if (state == NOT_INSTALLED) {
     if (!extension_service()->pending_extension_manager()->AddFromSync(
             id,
             extension_sync_data.update_url(),
diff --git a/chrome/browser/extensions/extension_sync_service.h b/chrome/browser/extensions/extension_sync_service.h
index 04525a5..2c225330 100644
--- a/chrome/browser/extensions/extension_sync_service.h
+++ b/chrome/browser/extensions/extension_sync_service.h
@@ -47,7 +47,7 @@
 
   // Returns whether the extension with the given |id| will be re-enabled once
   // it is updated to the given |version|. This happens when we get a Sync
-  // update telling us to re-enable a newer version that what is currently
+  // update telling us to re-enable a newer version than what is currently
   // installed.
   bool HasPendingReenable(const std::string& id,
                           const base::Version& version) const;
diff --git a/chrome/browser/metrics/variations/chrome_variations_service_client.cc b/chrome/browser/metrics/variations/chrome_variations_service_client.cc
index 8e6b4be..3ddbb141 100644
--- a/chrome/browser/metrics/variations/chrome_variations_service_client.cc
+++ b/chrome/browser/metrics/variations/chrome_variations_service_client.cc
@@ -10,10 +10,6 @@
 #include "components/version_info/version_info.h"
 #include "content/public/browser/browser_thread.h"
 
-#if defined(OS_ANDROID)
-#include "chrome/browser/android/preferences/pref_service_bridge.h"
-#endif  // OS_ANDROID
-
 #if !defined(OS_ANDROID) && !defined(OS_IOS) && !defined(OS_CHROMEOS)
 #include "chrome/browser/upgrade_detector_impl.h"
 #endif
@@ -22,6 +18,10 @@
 #include "chrome/browser/chromeos/settings/cros_settings.h"
 #endif
 
+#if defined(OS_ANDROID)
+#include "components/variations/android/variations_seed_bridge.h"
+#endif  // OS_ANDROID
+
 namespace {
 
 // Gets the version number to use for variations seed simulation. Must be called
@@ -86,7 +86,7 @@
 variations::VariationsFirstRunSeedCallback
 ChromeVariationsServiceClient::GetVariationsFirstRunSeedCallback() {
 #if defined(OS_ANDROID)
-  return base::Bind(&PrefServiceBridge::GetVariationsFirstRunSeed);
+  return base::Bind(&variations::android::GetVariationsFirstRunSeed);
 #else   // OS_ANDROID
   return variations::VariationsFirstRunSeedCallback();
 #endif  // OS_ANDROID
diff --git a/chrome/browser/resources/ntp4/apps_page.js b/chrome/browser/resources/ntp4/apps_page.js
index 8136080e..647ec82 100644
--- a/chrome/browser/resources/ntp4/apps_page.js
+++ b/chrome/browser/resources/ntp4/apps_page.js
@@ -295,7 +295,7 @@
 
       this.addEventListener('mousedown', this.onMousedown_, true);
       this.addEventListener('keydown', this.onKeydown_);
-      this.addEventListener('keyup', this.onKeyup_);
+      this.addEventListener('blur', this.onBlur_);
     },
 
     /**
@@ -378,6 +378,11 @@
       this.style.top = toCssPx(y);
     },
 
+    onBlur_: function(e) {
+      this.classList.remove('click-focus');
+      this.appContents_.classList.remove('suppress-active');
+    },
+
     /**
      * Invoked when an app is clicked.
      * @param {Event} e The click event.
@@ -410,33 +415,6 @@
         e.preventDefault();
         e.stopPropagation();
       }
-      this.onKeyboardUsed_(e.keyCode);
-    },
-
-    /**
-     * Invoked when the user releases a key while the app is focused.
-     * @param {Event} e The key event.
-     * @private
-     */
-    onKeyup_: function(e) {
-      this.onKeyboardUsed_(e.keyCode);
-    },
-
-    /**
-     * Called when the keyboard has been used (key down or up). The .click-focus
-     * hack is removed if the user presses a key that can change focus.
-     * @param {number} keyCode The key code of the keyboard event.
-     * @private
-     */
-    onKeyboardUsed_: function(keyCode) {
-      switch (keyCode) {
-        case 9:  // Tab.
-        case 37:  // Left arrow.
-        case 38:  // Up arrow.
-        case 39:  // Right arrow.
-        case 40:  // Down arrow.
-          this.classList.remove('click-focus');
-      }
     },
 
     /**
diff --git a/chrome/browser/resources/ntp4/tile_page.js b/chrome/browser/resources/ntp4/tile_page.js
index f20d0f36..6cda72c 100644
--- a/chrome/browser/resources/ntp4/tile_page.js
+++ b/chrome/browser/resources/ntp4/tile_page.js
@@ -703,12 +703,8 @@
             Array.prototype.indexOf.call(this.focusableElements_,
                                          focusable);
         this.updateFocusElement_();
-      } else {
-        // This prevents the tile page from getting focus when the user clicks
-        // inside the grid but outside of any tile.
-        e.preventDefault();
       }
-    },
+  },
 
     /**
      * Handle arrow key focus nav.
diff --git a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
index d5cbd78..119108ed 100644
--- a/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/glass_browser_frame_view.cc
@@ -367,7 +367,7 @@
     dest_y += kPreMDToolbarTopEdgeExclusion;
   canvas->TileImageInt(
       *theme_toolbar, x + GetThemeBackgroundXInset(),
-      dest_y - GetTopInset(false) + Tab::GetYOffsetForActiveTabBackground(),
+      dest_y - GetTopInset(false) - Tab::GetYInsetForActiveTabBackground(),
       x, dest_y, w, theme_toolbar->height());
 
   // Toolbar edges.
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
index d9a744aa..4c29832 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view.cc
@@ -676,7 +676,7 @@
   gfx::ImageSkia* theme_toolbar = tp->GetImageSkiaNamed(IDR_THEME_TOOLBAR);
   canvas->TileImageInt(
       *theme_toolbar, x + GetThemeBackgroundXInset(),
-      bottom_y - GetTopInset(false) + Tab::GetYOffsetForActiveTabBackground(),
+      bottom_y - GetTopInset(false) - Tab::GetYInsetForActiveTabBackground(),
       x, bottom_y, w, theme_toolbar->height());
 
   // Draw rounded corners for the tab.
diff --git a/chrome/browser/ui/views/tabs/tab.cc b/chrome/browser/ui/views/tabs/tab.cc
index ccd5786c..38574494 100644
--- a/chrome/browser/ui/views/tabs/tab.cc
+++ b/chrome/browser/ui/views/tabs/tab.cc
@@ -626,14 +626,14 @@
 }
 
 // static
-int Tab::GetYOffsetForActiveTabBackground() {
+int Tab::GetYInsetForActiveTabBackground() {
   // The computed value here is strangely less than the height of the area atop
   // the tab that doesn't get a background painted; otherwise, we could compute
   // the value by simply using GetLayoutInsets(TAB).top().  My suspicion is that
   // originally there was some sort of off-by-one error in how this background
   // was painted, and theme authors compensated; now we're stuck perpetuating it
   // as a result.
-  return -GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) - 1;
+  return GetLayoutConstant(TAB_TOP_EXCLUSION_HEIGHT) + 1;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1141,7 +1141,7 @@
   const int kActiveTabFillId = IDR_THEME_TOOLBAR;
   const bool has_custom_image =
       GetThemeProvider()->HasCustomImage(kActiveTabFillId);
-  const int y_offset = GetYOffsetForActiveTabBackground();
+  const int y_offset = -GetYInsetForActiveTabBackground();
   if (IsActive()) {
     PaintTabBackgroundUsingFillId(canvas, true, kActiveTabFillId,
                                   has_custom_image, y_offset);
diff --git a/chrome/browser/ui/views/tabs/tab.h b/chrome/browser/ui/views/tabs/tab.h
index 7b42ee6f..e3f4814 100644
--- a/chrome/browser/ui/views/tabs/tab.h
+++ b/chrome/browser/ui/views/tabs/tab.h
@@ -154,14 +154,10 @@
   // Returns the height for immersive mode tabs.
   static int GetImmersiveHeight();
 
-  // Returns the Y offset within the tab background image to begin drawing at
-  // the top of the active tab bounds.  This is a negative value, which will
-  // result in the top of the tab background image being drawn below the top of
-  // the tab.  None of this offset area is actually visible.
-  //
+  // Returns the Y inset within the tab bounds for drawing the background image.
   // This is necessary for correct vertical alignment of the frame, tab, and
   // toolbar images with custom themes.
-  static int GetYOffsetForActiveTabBackground();
+  static int GetYInsetForActiveTabBackground();
 
  private:
   friend class TabTest;
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index a795e123..541a044 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1618,10 +1618,11 @@
 
     android_manifest =
         "//chrome/test/android/unit_tests_apk/AndroidManifest.xml"
-    apk_asset_location = "$root_out_dir/unit_tests_apk/assets"
-    apk_deps = [ ":unit_tests_java" ]
+    apk_deps = [
+      ":unit_tests_java",
+      "//v8:v8_external_startup_data_assets",
+    ]
     isolate_file = "../unit_tests.isolate"
-    deps += [ ":copy_unit_tests_apk_assets" ]
 
     # Some android targets still depend on --gc-sections to link.
     # TODO: remove --gc-sections for Debug builds (crbug.com/159847).
@@ -2198,19 +2199,6 @@
 }
 
 if (is_android) {
-  copy_ex("copy_unit_tests_apk_assets") {
-    clear_dir = true
-    dest = "$root_out_dir/unit_tests_apk/assets"
-
-    if (v8_use_external_startup_data) {
-      renaming_sources = v8_external_startup_data_renaming_sources
-      renaming_destinations = v8_external_startup_data_renaming_destinations
-      deps = [
-        "//v8",
-      ]
-    }
-  }
-
   android_library("unit_tests_java") {
     DEPRECATED_java_in_dir = "//chrome/test/android/unit_tests_apk/src"
     deps = [
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 85ca3f5e..9d0fe0f 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7626.0.0
\ No newline at end of file
+7630.0.0
\ No newline at end of file
diff --git a/components/dom_distiller/core/javascript/dom_distiller_viewer.js b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
index ebc2f060..69a08b0 100644
--- a/components/dom_distiller/core/javascript/dom_distiller_viewer.js
+++ b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
@@ -393,6 +393,7 @@
     },
 
     handleTouchCancel: function(e) {
+      if (!pinching) return;
       endPinch();
     },
 
diff --git a/components/mus/surfaces/surfaces_scheduler.cc b/components/mus/surfaces/surfaces_scheduler.cc
index 50789e58..c02a8d7 100644
--- a/components/mus/surfaces/surfaces_scheduler.cc
+++ b/components/mus/surfaces/surfaces_scheduler.cc
@@ -60,7 +60,7 @@
 void SurfacesScheduler::DidFinishImplFrame() {}
 
 void SurfacesScheduler::ScheduledActionSendBeginMainFrame() {
-  scheduler_->NotifyBeginMainFrameStarted();
+  scheduler_->NotifyBeginMainFrameStarted(base::TimeTicks());
   scheduler_->NotifyReadyToCommit();
 }
 
diff --git a/components/test/data/password_manager/automated_tests/tests.py b/components/test/data/password_manager/automated_tests/tests.py
index e506529..5af1ce1 100644
--- a/components/test/data/password_manager/automated_tests/tests.py
+++ b/components/test/data/password_manager/automated_tests/tests.py
@@ -365,16 +365,20 @@
       self.Wait(1)
 
 
-# Fails due to test framework issue.
+# Saves wrong username -- http://crbug.com/554004
 class Flipkart(WebsiteTest):
 
   def Login(self):
     self.GoTo("http://www.flipkart.com/")
-    self.Wait(2)
+    while (not self.IsDisplayed(".appDownloadInterstitialDialog .window .close")
+           or not self.IsDisplayed(".header-links .js-login")):
+      self.Wait(1)
+    if self.IsDisplayed(".appDownloadInterstitialDialog .window .close"):
+      self.Click(".appDownloadInterstitialDialog .window .close")
     self.Click(".header-links .js-login")
-    self.FillUsernameInto("#login_email_id")
-    self.FillPasswordInto("#login_password")
-    self.Submit("#login_password")
+    self.FillUsernameInto(".login-input-wrap .user-email")
+    self.FillPasswordInto(".login-input-wrap .user-pwd")
+    self.Click(".login-btn-wrap .login-btn")
 
 
 class Instagram(WebsiteTest):
diff --git a/components/variations.gypi b/components/variations.gypi
index 4d9ce3f..d0f5a56e 100644
--- a/components/variations.gypi
+++ b/components/variations.gypi
@@ -30,6 +30,8 @@
         'variations/android/component_jni_registrar.h',
         'variations/android/variations_associated_data_android.cc',
         'variations/android/variations_associated_data_android.h',
+        'variations/android/variations_seed_bridge.cc',
+        'variations/android/variations_seed_bridge.h',
         'variations/caching_permuted_entropy_provider.cc',
         'variations/caching_permuted_entropy_provider.h',
         'variations/entropy_provider.cc',
@@ -161,6 +163,7 @@
           'type': 'none',
           'sources': [
             'variations/android/java/src/org/chromium/components/variations/VariationsAssociatedData.java',
+            'variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedBridge.java',
           ],
           'variables': {
             'jni_gen_package': 'variations',
diff --git a/components/variations/BUILD.gn b/components/variations/BUILD.gn
index 7908526..a65148a 100644
--- a/components/variations/BUILD.gn
+++ b/components/variations/BUILD.gn
@@ -14,6 +14,8 @@
     "android/component_jni_registrar.h",
     "android/variations_associated_data_android.cc",
     "android/variations_associated_data_android.h",
+    "android/variations_seed_bridge.cc",
+    "android/variations_seed_bridge.h",
     "caching_permuted_entropy_provider.cc",
     "caching_permuted_entropy_provider.h",
     "entropy_provider.cc",
@@ -80,6 +82,7 @@
   generate_jni("jni") {
     sources = [
       "android/java/src/org/chromium/components/variations/VariationsAssociatedData.java",
+      "android/java/src/org/chromium/components/variations/firstrun/VariationsSeedBridge.java",
     ]
     jni_package = "variations"
   }
diff --git a/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedBridge.java b/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedBridge.java
new file mode 100644
index 0000000..3af546bf
--- /dev/null
+++ b/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedBridge.java
@@ -0,0 +1,60 @@
+// Copyright 2015 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.components.variations.firstrun;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Base64;
+
+import org.chromium.base.annotations.CalledByNative;
+
+/**
+ * VariationsSeedBridge is a class which used to pass variations first run seed that was fetched
+ * before the actual Chrome first run to Chromium core. Class provides methods to store the seed
+ * in SharedPreferences and to get the seed from there. To store raw seed data class serializes
+ * byte[] to Base64 encoded string and decodes this string before passing to C++ side.
+ */
+public final class VariationsSeedBridge {
+    private static final String VARIATIONS_FIRST_RUN_SEED_BASE64 = "variations_seed_base64";
+    private static final String VARIATIONS_FIRST_RUN_SEED_SIGNATURE = "variations_seed_signature";
+    private static final String VARIATIONS_FIRST_RUN_SEED_COUNTRY = "variations_seed_country";
+
+    private static String getVariationsFirstRunSeedPref(Context context, String prefName) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        return prefs.getString(prefName, "");
+    }
+
+    /**
+     * Stores variations seed data (raw data, seed signature and country code) in SharedPreferences.
+     */
+    public static void setVariationsFirstRunSeed(
+            Context context, byte[] rawSeed, String signature, String country) {
+        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+        prefs.edit()
+                .putString(VARIATIONS_FIRST_RUN_SEED_BASE64,
+                        Base64.encodeToString(rawSeed, Base64.NO_WRAP))
+                .putString(VARIATIONS_FIRST_RUN_SEED_SIGNATURE, signature)
+                .putString(VARIATIONS_FIRST_RUN_SEED_COUNTRY, country)
+                .apply();
+    }
+
+    @CalledByNative
+    private static byte[] getVariationsFirstRunSeedData(Context context) {
+        return Base64.decode(
+                getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_BASE64),
+                Base64.NO_WRAP);
+    }
+
+    @CalledByNative
+    private static String getVariationsFirstRunSeedSignature(Context context) {
+        return getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_SIGNATURE);
+    }
+
+    @CalledByNative
+    private static String getVariationsFirstRunSeedCountry(Context context) {
+        return getVariationsFirstRunSeedPref(context, VARIATIONS_FIRST_RUN_SEED_COUNTRY);
+    }
+}
diff --git a/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedService.java b/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedService.java
new file mode 100644
index 0000000..c752d884
--- /dev/null
+++ b/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedService.java
@@ -0,0 +1,97 @@
+// Copyright 2015 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.components.variations.firstrun;
+
+import android.app.IntentService;
+import android.content.Intent;
+
+import org.chromium.base.Log;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Background service that fetches the variations seed before the actual first run of Chrome.
+ */
+public class VariationsSeedService extends IntentService {
+    private static final String TAG = "VariationsSeedServ";
+    private static final String VARIATIONS_SERVER_URL =
+            "https://clients4.google.com/chrome-variations/seed?osname=android";
+    private static final int BUFFER_SIZE = 4096;
+    private static final int READ_TIMEOUT = 10000; // time in ms
+    private static final int REQUEST_TIMEOUT = 15000; // time in ms
+
+    public VariationsSeedService() {
+        super(TAG);
+    }
+
+    @Override
+    public void onHandleIntent(Intent intent) {
+        try {
+            downloadContent(new URL(VARIATIONS_SERVER_URL));
+        } catch (MalformedURLException e) {
+            Log.w(TAG, "Variations server URL is malformed.", e);
+        }
+    }
+
+    private boolean downloadContent(URL variationsServerUrl) {
+        HttpURLConnection connection = null;
+        try {
+            connection = (HttpURLConnection) variationsServerUrl.openConnection();
+            connection.setReadTimeout(READ_TIMEOUT);
+            connection.setConnectTimeout(REQUEST_TIMEOUT);
+            connection.setDoInput(true);
+            // TODO(agulenko): add gzip compression support.
+            // connection.setRequestProperty("A-IM", "gzip");
+            connection.connect();
+            int responseCode = connection.getResponseCode();
+            if (responseCode != HttpURLConnection.HTTP_OK) {
+                Log.w(TAG, "Non-OK response code = %d", responseCode);
+                return false;
+            }
+
+            // Convert the InputStream into a byte array.
+            byte[] rawSeed = getRawSeed(connection);
+            String signature = connection.getHeaderField("X-Seed-Signature");
+            String country = connection.getHeaderField("X-Country");
+            VariationsSeedBridge.setVariationsFirstRunSeed(
+                    getApplicationContext(), rawSeed, signature, country);
+            return true;
+        } catch (IOException e) {
+            Log.w(TAG, "IOException fetching first run seed: ", e);
+            return false;
+        } finally {
+            if (connection != null) {
+                connection.disconnect();
+            }
+        }
+    }
+
+    private byte[] getRawSeed(HttpURLConnection connection) throws IOException {
+        InputStream inputStream = null;
+        try {
+            inputStream = connection.getInputStream();
+            return convertInputStreamToByteArray(inputStream);
+        } finally {
+            if (inputStream != null) {
+                inputStream.close();
+            }
+        }
+    }
+
+    private byte[] convertInputStreamToByteArray(InputStream inputStream) throws IOException {
+        ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
+        byte[] buffer = new byte[BUFFER_SIZE];
+        int charactersReadCount = 0;
+        while ((charactersReadCount = inputStream.read(buffer)) != -1) {
+            byteBuffer.write(buffer, 0, charactersReadCount);
+        }
+        return byteBuffer.toByteArray();
+    }
+}
\ No newline at end of file
diff --git a/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedServiceLauncher.java b/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedServiceLauncher.java
new file mode 100644
index 0000000..69f04c8a
--- /dev/null
+++ b/components/variations/android/java/src/org/chromium/components/variations/firstrun/VariationsSeedServiceLauncher.java
@@ -0,0 +1,27 @@
+// Copyright 2015 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.components.variations.firstrun;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * This receiver is notified when a user goes through the Setup Wizard and acknowledges
+ * the Chrome ToS and after that we start a variations service to fetch variations seed
+ * before the actual first Chrome launch.
+ *
+ * TODO(agulenko): Implement working with another broadcast (e.g. connectivity change).
+ */
+public class VariationsSeedServiceLauncher extends BroadcastReceiver {
+    private static final String TAG = "VariationsSeedServiceLauncher";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        // Start of service to fetch variations seed from the server to use it on Chrome first run
+        Intent serviceIntent = new Intent(context, VariationsSeedService.class);
+        context.startService(serviceIntent);
+    }
+}
\ No newline at end of file
diff --git a/components/variations/android/variations_seed_bridge.cc b/components/variations/android/variations_seed_bridge.cc
new file mode 100644
index 0000000..cf5cbe4
--- /dev/null
+++ b/components/variations/android/variations_seed_bridge.cc
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/variations/android/variations_seed_bridge.h"
+
+#include <jni.h>
+#include <vector>
+
+#include "base/android/jni_android.h"
+#include "base/android/jni_array.h"
+#include "base/android/jni_string.h"
+#include "base/android/jni_weak_ref.h"
+#include "jni/VariationsSeedBridge_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertJavaStringToUTF8;
+using base::android::GetApplicationContext;
+using base::android::ScopedJavaLocalRef;
+
+namespace {
+
+std::string JavaByteArrayToString(JNIEnv* env, jbyteArray byte_array) {
+  if (!byte_array)
+    return std::string();
+  std::vector<uint8> array_data;
+  base::android::JavaByteArrayToByteVector(env, byte_array, &array_data);
+  return std::string(array_data.begin(), array_data.end());
+}
+
+}  // namespace
+
+namespace variations {
+namespace android {
+
+bool RegisterVariationsSeedBridge(JNIEnv* env) {
+  return RegisterNativesImpl(env);
+}
+
+void GetVariationsFirstRunSeed(std::string* seed_data,
+                               std::string* seed_signature,
+                               std::string* seed_country) {
+  JNIEnv* env = AttachCurrentThread();
+  ScopedJavaLocalRef<jbyteArray> j_seed_data =
+      Java_VariationsSeedBridge_getVariationsFirstRunSeedData(
+          env, GetApplicationContext());
+  ScopedJavaLocalRef<jstring> j_seed_signature =
+      Java_VariationsSeedBridge_getVariationsFirstRunSeedSignature(
+          env, GetApplicationContext());
+  ScopedJavaLocalRef<jstring> j_seed_country =
+      Java_VariationsSeedBridge_getVariationsFirstRunSeedCountry(
+          env, GetApplicationContext());
+  *seed_data = JavaByteArrayToString(env, j_seed_data.obj());
+  *seed_signature = ConvertJavaStringToUTF8(j_seed_signature);
+  *seed_country = ConvertJavaStringToUTF8(j_seed_country);
+}
+
+}  // namespace android
+}  // namespace variations
diff --git a/components/variations/android/variations_seed_bridge.h b/components/variations/android/variations_seed_bridge.h
new file mode 100644
index 0000000..83381fa
--- /dev/null
+++ b/components/variations/android/variations_seed_bridge.h
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_VARIATIONS_ANDROID_VARIATIONS_SEED_BRIDGE_H_
+#define COMPONENTS_VARIATIONS_ANDROID_VARIATIONS_SEED_BRIDGE_H_
+
+#include <jni.h>
+#include <string>
+
+namespace variations {
+namespace android {
+
+bool RegisterVariationsSeedBridge(JNIEnv* env);
+
+// Return the first run seed data pulled from the Java side of application.
+void GetVariationsFirstRunSeed(std::string* seed_data,
+                               std::string* seed_signature,
+                               std::string* seed_country);
+
+}  // namespace android
+}  // namespace variations
+
+#endif  // COMPONENTS_VARIATIONS_ANDROID_FIRSTRUN_VARIATIONS_SEED_BRIDGE_H_
diff --git a/components/web_view/test_runner/BUILD.gn b/components/web_view/test_runner/BUILD.gn
index 96434bfd..d8f63abe3d 100644
--- a/components/web_view/test_runner/BUILD.gn
+++ b/components/web_view/test_runner/BUILD.gn
@@ -23,6 +23,7 @@
     "//mojo/environment:chromium",
     "//mojo/runner:lib",
     "//mojo/runner:register_local_aliases_fwd",
+    "//mojo/runner/host:lib",
     "//url",
   ]
 
diff --git a/components/web_view/test_runner/main.cc b/components/web_view/test_runner/main.cc
index 95bf3df3..c499c68 100644
--- a/components/web_view/test_runner/main.cc
+++ b/components/web_view/test_runner/main.cc
@@ -5,7 +5,7 @@
 #include "base/at_exit.h"
 #include "base/command_line.h"
 #include "components/web_view/test_runner/launcher.h"
-#include "mojo/runner/child_process.h"
+#include "mojo/runner/host/child_process.h"
 #include "mojo/runner/init.h"
 
 int main(int argc, char** argv) {
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc
index 13d3621a..8b00dfb 100644
--- a/content/browser/frame_host/frame_tree_node.cc
+++ b/content/browser/frame_host/frame_tree_node.cc
@@ -129,6 +129,7 @@
                              int frame_routing_id) {
   // Child frame must always be created in the same process as the parent.
   CHECK_EQ(process_id, render_manager_.current_host()->GetProcess()->GetID());
+  child->set_parent(this);
 
   // Initialize the RenderFrameHost for the new node.  We always create child
   // frames in the same SiteInstance as the current frame, and they can swap to
@@ -137,7 +138,6 @@
       render_manager_.current_host()->GetSiteInstance(),
       render_manager_.current_host()->GetRoutingID(), frame_routing_id,
       MSG_ROUTING_NONE);
-  child->set_parent(this);
 
   // Other renderer processes in this BrowsingInstance may need to find out
   // about the new frame.  Create a proxy for the child frame in all
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 373f010..1c93b3d3 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -103,6 +103,55 @@
             controller.GetEntryAtIndex(1)->GetUniqueID());
 }
 
+// Ensures that RenderFrameHosts end up with the correct nav_entry_id() after
+// navigations.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest, UniqueIDsOnFrames) {
+  NavigationController& controller = shell()->web_contents()->GetController();
+
+  // Load a main frame with an about:blank subframe.
+  GURL main_url(embedded_test_server()->GetURL(
+      "/navigation_controller/page_with_iframe.html"));
+  NavigateToURL(shell(), main_url);
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  ASSERT_EQ(1U, root->child_count());
+  ASSERT_NE(nullptr, root->child_at(0));
+
+  // The main frame's nav_entry_id should match the last committed entry.
+  int unique_id = controller.GetLastCommittedEntry()->GetUniqueID();
+  EXPECT_EQ(unique_id, root->current_frame_host()->nav_entry_id());
+
+  // The about:blank iframe should have inherited the same nav_entry_id.
+  EXPECT_EQ(unique_id, root->child_at(0)->current_frame_host()->nav_entry_id());
+
+  // Use NavigateFrameToURL to go cross-site in the subframe.
+  GURL foo_url(embedded_test_server()->GetURL(
+      "foo.com", "/navigation_controller/simple_page_1.html"));
+  NavigateFrameToURL(root->child_at(0), foo_url);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+
+  // The unique ID should have stayed the same for the auto-subframe navigation,
+  // since the new page replaces the initial about:blank page in the subframe.
+  EXPECT_EQ(unique_id, controller.GetLastCommittedEntry()->GetUniqueID());
+  EXPECT_EQ(unique_id, root->current_frame_host()->nav_entry_id());
+  EXPECT_EQ(unique_id, root->child_at(0)->current_frame_host()->nav_entry_id());
+
+  // Navigating in the subframe again should create a new entry.
+  GURL foo_url2(embedded_test_server()->GetURL(
+      "foo.com", "/navigation_controller/simple_page_2.html"));
+  NavigateFrameToURL(root->child_at(0), foo_url2);
+  EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
+  int unique_id2 = controller.GetLastCommittedEntry()->GetUniqueID();
+  EXPECT_NE(unique_id, unique_id2);
+
+  // The unique ID should have updated for the current RenderFrameHost in both
+  // frames, not just the subframe.
+  EXPECT_EQ(unique_id2, root->current_frame_host()->nav_entry_id());
+  EXPECT_EQ(unique_id2,
+            root->child_at(0)->current_frame_host()->nav_entry_id());
+}
+
 // This test used to make sure that a scheme used to prevent spoofs didn't ever
 // interfere with navigations. We switched to a different scheme, so now this is
 // just a test to make sure we can still navigate once we prune the history
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 9e0d43a..5b766ce 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -211,6 +211,12 @@
     GetSiteInstance()->increment_active_frame_count();
   }
 
+  // New child frames should inherit the nav_entry_id of their parent.
+  if (frame_tree_node_->parent()) {
+    set_nav_entry_id(
+        frame_tree_node_->parent()->current_frame_host()->nav_entry_id());
+  }
+
   SetUpMojoIfNeeded();
   swapout_event_monitor_timeout_.reset(new TimeoutMonitor(base::Bind(
       &RenderFrameHostImpl::OnSwappedOut, weak_ptr_factory_.GetWeakPtr())));
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index c07fa27..bfae0c2 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4145,7 +4145,13 @@
   if (!frame_entry)
     return;
 
-  CHECK_EQ(frame_entry->site_instance(), rfhi->GetSiteInstance());
+  // The SiteInstance might not match if we do a cross-process navigation with
+  // replacement (e.g., auto-subframe), in which case the swap out of the old
+  // RenderFrameHost runs in the background after the old FrameNavigationEntry
+  // has already been replaced and destroyed.
+  if (frame_entry->site_instance() != rfhi->GetSiteInstance())
+    return;
+
   if (page_state == frame_entry->page_state())
     return;  // Nothing to update.
 
diff --git a/content/common/media/media_player_messages_android.h b/content/common/media/media_player_messages_android.h
index 909c273..3d140f5 100644
--- a/content/common/media/media_player_messages_android.h
+++ b/content/common/media/media_player_messages_android.h
@@ -11,7 +11,6 @@
 #include "content/common/media/media_player_messages_enums_android.h"
 #include "ipc/ipc_message_macros.h"
 #include "media/base/android/demuxer_stream_player_params.h"
-#include "media/base/android/media_player_android.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "url/gurl.h"
 
diff --git a/content/content_unittests.isolate b/content/content_unittests.isolate
index b2fde54..eedd3758 100644
--- a/content/content_unittests.isolate
+++ b/content/content_unittests.isolate
@@ -43,14 +43,7 @@
         ],
       },
     }],
-    ['OS=="android"', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/content_shell/assets/content_shell.pak',
-        ],
-      },
-    }],
-    ['OS=="linux" or OS=="mac" or OS=="win"', {
+    ['OS=="linux" or OS=="mac" or OS=="win" or OS=="android"', {
       'variables': {
         'files': [
           '<(PRODUCT_DIR)/content_shell.pak',
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index 9253822..34bf7e6 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -3247,6 +3247,14 @@
 
     @Override
     public void onScreenOrientationChanged(int orientation) {
+        // ActionMode#invalidate() won't be able to re-layout the floating
+        // action mode menu items according to the new orientation. So Chrome
+        // has to re-create the action mode.
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mActionMode != null) {
+            hidePopupsAndPreserveSelection();
+            showSelectActionMode(true);
+        }
+
         sendOrientationChangeEvent(orientation);
     }
 
diff --git a/content/renderer/media/android/renderer_demuxer_android.cc b/content/renderer/media/android/renderer_demuxer_android.cc
index 6d40b20..884331cb 100644
--- a/content/renderer/media/android/renderer_demuxer_android.cc
+++ b/content/renderer/media/android/renderer_demuxer_android.cc
@@ -9,8 +9,6 @@
 #include "content/child/thread_safe_sender.h"
 #include "content/common/media/media_player_messages_android.h"
 #include "content/renderer/media/android/media_source_delegate.h"
-#include "content/renderer/media/android/renderer_media_player_manager.h"
-#include "content/renderer/media/android/webmediaplayer_android.h"
 #include "content/renderer/render_thread_impl.h"
 
 namespace content {
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index bb33815..2dea4b4d 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -5,7 +5,6 @@
 #ifndef CONTENT_RENDERER_MEDIA_ANDROID_WEBMEDIAPLAYER_ANDROID_H_
 #define CONTENT_RENDERER_MEDIA_ANDROID_WEBMEDIAPLAYER_ANDROID_H_
 
-#include <jni.h>
 #include <string>
 #include <vector>
 
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 804e018..4515836 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1228,8 +1228,13 @@
 
   v8_sampling_profiler_.reset(new V8SamplingProfiler());
 
-  if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
+  if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden()) {
     ScheduleIdleHandler(kLongIdleHandlerDelayMs);
+  } else {
+    // If we do not track widget visibility, then assume conservatively that
+    // the isolate is in background. This reduces memory usage.
+    isolate->IsolateInBackgroundNotification();
+  }
 
   renderer_scheduler_->SetTimerQueueSuspensionWhenBackgroundedEnabled(
       GetContentClient()
@@ -1996,18 +2001,19 @@
 }
 
 void RenderThreadImpl::OnRendererHidden() {
-  blink::mainThreadIsolate()->IsolateInBackgroundNotification();
   // TODO(rmcilroy): Remove IdleHandler and replace it with an IdleTask
   // scheduled by the RendererScheduler - http://crbug.com/469210.
-  if (GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
-    ScheduleIdleHandler(kInitialIdleHandlerDelayMs);
+  if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
+    return;
+  ScheduleIdleHandler(kInitialIdleHandlerDelayMs);
+  blink::mainThreadIsolate()->IsolateInBackgroundNotification();
 }
 
 void RenderThreadImpl::OnRendererVisible() {
-  blink::mainThreadIsolate()->IsolateInForegroundNotification();
   if (!GetContentClient()->renderer()->RunIdleHandlerWhenWidgetsHidden())
     return;
   ScheduleIdleHandler(kLongIdleHandlerDelayMs);
+  blink::mainThreadIsolate()->IsolateInForegroundNotification();
 }
 
 void RenderThreadImpl::ReleaseFreeMemory() {
diff --git a/content/shell/android/BUILD.gn b/content/shell/android/BUILD.gn
index 94e0d9f..ae88a8c 100644
--- a/content/shell/android/BUILD.gn
+++ b/content/shell/android/BUILD.gn
@@ -86,26 +86,16 @@
   DEPRECATED_java_in_dir = "shell_apk/src"
 }
 
-content_shell_assets_dir = "$root_build_dir/content_shell/assets"
-copy_ex("copy_content_shell_assets") {
-  clear_dir = true
-  dest = content_shell_assets_dir
+android_assets("content_shell_assets") {
   sources = [
     "$root_out_dir/content_shell.pak",
   ]
+  disable_compression = true
   deps = [
     "//content/shell:pak",
+    "//third_party/icu:icu_assets",
+    "//v8:v8_external_startup_data_assets",
   ]
-
-  if (icu_use_data_file) {
-    sources += [ "$root_build_dir/icudtl.dat" ]
-    deps += [ "//third_party/icu:icudata" ]
-  }
-  if (v8_use_external_startup_data) {
-    renaming_sources = v8_external_startup_data_renaming_sources
-    renaming_destinations = v8_external_startup_data_renaming_destinations
-    deps += [ "//v8" ]
-  }
 }
 
 android_apk("content_shell_apk") {
@@ -116,9 +106,9 @@
   deps = [
     ":content_shell_apk_java",
     ":content_shell_apk_resources",
+    ":content_shell_assets",
     ":content_shell_java",
     ":content_shell_manifest",
-    ":copy_content_shell_assets",
     ":libcontent_shell_content_view",
     "//base:base_java",
     "//content/public/android:content_java",
@@ -131,7 +121,6 @@
   apk_name = "ContentShell"
   android_manifest = content_shell_manifest
   native_libs = [ "libcontent_shell_content_view.so" ]
-  asset_location = content_shell_assets_dir
 
   # TODO(GYP)
   #'extra_native_libs': ['<(SHARED_LIB_DIR)/libosmesa.so'],
@@ -190,8 +179,8 @@
     testonly = true
     deps = [
       ":chromium_linker_test_manifest",
+      ":content_shell_assets",
       ":content_shell_java",
-      ":copy_content_shell_assets",
       ":linker_resources",
       ":linker_test",
       "//base:base_java",
@@ -199,7 +188,6 @@
       "//ui/android:ui_java",
     ]
     android_manifest = chromium_linker_test_manifest
-    asset_location = content_shell_assets_dir
     apk_name = "ChromiumLinkerTest"
     DEPRECATED_java_in_dir = "linker_test_apk/src"
     native_libs = [ "liblinker_test.so" ]
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 363acdf..2e0102e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -157,7 +157,6 @@
 
     if (is_android) {
       deps += [
-        "//content/shell/android:copy_content_shell_assets",
         "//ui/android",
         "//ui/shell_dialogs",
       ]
@@ -483,23 +482,6 @@
   }
 }
 
-if (is_android) {
-  _content_unittests_apk_assets_dir =
-      "$root_out_dir/content_unittests_apk/assets"
-  copy_ex("copy_content_unittests_apk_assets") {
-    clear_dir = true
-    dest = _content_unittests_apk_assets_dir
-
-    if (v8_use_external_startup_data) {
-      renaming_sources = v8_external_startup_data_renaming_sources
-      renaming_destinations = v8_external_startup_data_renaming_destinations
-      deps = [
-        "//v8",
-      ]
-    }
-  }
-}
-
 # TODO(GYP): Delete this after we've converted everything to GN.
 # The _run targets exist only for compatibility w/ GYP.
 group("content_unittests_run") {
@@ -686,12 +668,11 @@
       "../browser/webui/url_data_manager_backend_unittest.cc",
     ]
     deps -= [ "//device/battery" ]
-    deps += [ ":copy_content_unittests_apk_assets" ]
 
-    apk_asset_location = _content_unittests_apk_assets_dir
     apk_deps = [
       "//base:base_java_unittest_support",
       "//content/public/android:content_java",
+      "//v8:v8_external_startup_data_assets",
     ]
 
     defines += [ "APPCACHE_USE_SIMPLE_CACHE" ]
@@ -812,9 +793,8 @@
   if (is_android) {
     apk_deps = [
       "//content/public/test/android:content_java_test_support",
-      "//content/shell/android:copy_content_shell_assets",
+      "//content/shell/android:content_shell_assets",
     ]
-    apk_asset_location = "$root_build_dir/content_shell/assets"
   } else {
     data_deps = [
       "//third_party/ffmpeg",
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn
index 06a657a..82c266f 100644
--- a/device/bluetooth/BUILD.gn
+++ b/device/bluetooth/BUILD.gn
@@ -1,6 +1,7 @@
 # Copyright 2014 The Chromium Authors. All rights reserved.
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
+import("//build/config/features.gni")
 
 if (is_android) {
   import("//build/config/android/rules.gni")  # For generate_jni().
@@ -129,10 +130,6 @@
     deps += [ "//chromeos" ]
   }
 
-  if (is_chromeos || is_linux) {
-    deps += [ "//dbus" ]
-  }
-
   if (is_mac) {
     libs = [ "IOBluetooth.framework" ]
   }
@@ -142,115 +139,121 @@
   }
 
   if (is_chromeos || is_linux) {
-    sources += [
-      "bluetooth_adapter_bluez.cc",
-      "bluetooth_adapter_bluez.h",
-      "bluetooth_adapter_profile_bluez.cc",
-      "bluetooth_adapter_profile_bluez.h",
-      "bluetooth_advertisement_bluez.cc",
-      "bluetooth_advertisement_bluez.h",
-      "bluetooth_audio_sink_bluez.cc",
-      "bluetooth_audio_sink_bluez.h",
-      "bluetooth_device_bluez.cc",
-      "bluetooth_device_bluez.h",
-      "bluetooth_gatt_connection_bluez.cc",
-      "bluetooth_gatt_connection_bluez.h",
-      "bluetooth_gatt_notify_session_bluez.cc",
-      "bluetooth_gatt_notify_session_bluez.h",
-      "bluetooth_pairing_bluez.cc",
-      "bluetooth_pairing_bluez.h",
-      "bluetooth_remote_gatt_characteristic_bluez.cc",
-      "bluetooth_remote_gatt_characteristic_bluez.h",
-      "bluetooth_remote_gatt_descriptor_bluez.cc",
-      "bluetooth_remote_gatt_descriptor_bluez.h",
-      "bluetooth_remote_gatt_service_bluez.cc",
-      "bluetooth_remote_gatt_service_bluez.h",
-      "bluetooth_socket_bluez.cc",
-      "bluetooth_socket_bluez.h",
-      "dbus/bluetooth_adapter_client.cc",
-      "dbus/bluetooth_adapter_client.h",
-      "dbus/bluetooth_agent_manager_client.cc",
-      "dbus/bluetooth_agent_manager_client.h",
-      "dbus/bluetooth_agent_service_provider.cc",
-      "dbus/bluetooth_agent_service_provider.h",
-      "dbus/bluetooth_dbus_client_bundle.cc",
-      "dbus/bluetooth_dbus_client_bundle.h",
-      "dbus/bluetooth_device_client.cc",
-      "dbus/bluetooth_device_client.h",
-      "dbus/bluetooth_gatt_characteristic_client.cc",
-      "dbus/bluetooth_gatt_characteristic_client.h",
-      "dbus/bluetooth_gatt_characteristic_service_provider.cc",
-      "dbus/bluetooth_gatt_characteristic_service_provider.h",
-      "dbus/bluetooth_gatt_descriptor_client.cc",
-      "dbus/bluetooth_gatt_descriptor_client.h",
-      "dbus/bluetooth_gatt_descriptor_service_provider.cc",
-      "dbus/bluetooth_gatt_descriptor_service_provider.h",
-      "dbus/bluetooth_gatt_manager_client.cc",
-      "dbus/bluetooth_gatt_manager_client.h",
-      "dbus/bluetooth_gatt_service_client.cc",
-      "dbus/bluetooth_gatt_service_client.h",
-      "dbus/bluetooth_gatt_service_service_provider.cc",
-      "dbus/bluetooth_gatt_service_service_provider.h",
-      "dbus/bluetooth_input_client.cc",
-      "dbus/bluetooth_input_client.h",
-      "dbus/bluetooth_le_advertisement_service_provider.cc",
-      "dbus/bluetooth_le_advertisement_service_provider.h",
-      "dbus/bluetooth_le_advertising_manager_client.cc",
-      "dbus/bluetooth_le_advertising_manager_client.h",
-      "dbus/bluetooth_media_client.cc",
-      "dbus/bluetooth_media_client.h",
-      "dbus/bluetooth_media_endpoint_service_provider.cc",
-      "dbus/bluetooth_media_endpoint_service_provider.h",
-      "dbus/bluetooth_media_transport_client.cc",
-      "dbus/bluetooth_media_transport_client.h",
-      "dbus/bluetooth_profile_manager_client.cc",
-      "dbus/bluetooth_profile_manager_client.h",
-      "dbus/bluetooth_profile_service_provider.cc",
-      "dbus/bluetooth_profile_service_provider.h",
-      "dbus/bluez_dbus_client.h",
-      "dbus/bluez_dbus_manager.cc",
-      "dbus/bluez_dbus_manager.h",
-      "dbus/dbus_thread_manager_linux.cc",
-      "dbus/dbus_thread_manager_linux.h",
-      "dbus/fake_bluetooth_adapter_client.cc",
-      "dbus/fake_bluetooth_adapter_client.h",
-      "dbus/fake_bluetooth_agent_manager_client.cc",
-      "dbus/fake_bluetooth_agent_manager_client.h",
-      "dbus/fake_bluetooth_agent_service_provider.cc",
-      "dbus/fake_bluetooth_agent_service_provider.h",
-      "dbus/fake_bluetooth_device_client.cc",
-      "dbus/fake_bluetooth_device_client.h",
-      "dbus/fake_bluetooth_gatt_characteristic_client.cc",
-      "dbus/fake_bluetooth_gatt_characteristic_client.h",
-      "dbus/fake_bluetooth_gatt_characteristic_service_provider.cc",
-      "dbus/fake_bluetooth_gatt_characteristic_service_provider.h",
-      "dbus/fake_bluetooth_gatt_descriptor_client.cc",
-      "dbus/fake_bluetooth_gatt_descriptor_client.h",
-      "dbus/fake_bluetooth_gatt_descriptor_service_provider.cc",
-      "dbus/fake_bluetooth_gatt_descriptor_service_provider.h",
-      "dbus/fake_bluetooth_gatt_manager_client.cc",
-      "dbus/fake_bluetooth_gatt_manager_client.h",
-      "dbus/fake_bluetooth_gatt_service_client.cc",
-      "dbus/fake_bluetooth_gatt_service_client.h",
-      "dbus/fake_bluetooth_gatt_service_service_provider.cc",
-      "dbus/fake_bluetooth_gatt_service_service_provider.h",
-      "dbus/fake_bluetooth_input_client.cc",
-      "dbus/fake_bluetooth_input_client.h",
-      "dbus/fake_bluetooth_le_advertisement_service_provider.cc",
-      "dbus/fake_bluetooth_le_advertisement_service_provider.h",
-      "dbus/fake_bluetooth_le_advertising_manager_client.cc",
-      "dbus/fake_bluetooth_le_advertising_manager_client.h",
-      "dbus/fake_bluetooth_media_client.cc",
-      "dbus/fake_bluetooth_media_client.h",
-      "dbus/fake_bluetooth_media_endpoint_service_provider.cc",
-      "dbus/fake_bluetooth_media_endpoint_service_provider.h",
-      "dbus/fake_bluetooth_media_transport_client.cc",
-      "dbus/fake_bluetooth_media_transport_client.h",
-      "dbus/fake_bluetooth_profile_manager_client.cc",
-      "dbus/fake_bluetooth_profile_manager_client.h",
-      "dbus/fake_bluetooth_profile_service_provider.cc",
-      "dbus/fake_bluetooth_profile_service_provider.h",
-    ]
+    if (use_dbus) {
+      sources += [
+        "bluetooth_adapter_bluez.cc",
+        "bluetooth_adapter_bluez.h",
+        "bluetooth_adapter_profile_bluez.cc",
+        "bluetooth_adapter_profile_bluez.h",
+        "bluetooth_advertisement_bluez.cc",
+        "bluetooth_advertisement_bluez.h",
+        "bluetooth_audio_sink_bluez.cc",
+        "bluetooth_audio_sink_bluez.h",
+        "bluetooth_device_bluez.cc",
+        "bluetooth_device_bluez.h",
+        "bluetooth_gatt_connection_bluez.cc",
+        "bluetooth_gatt_connection_bluez.h",
+        "bluetooth_gatt_notify_session_bluez.cc",
+        "bluetooth_gatt_notify_session_bluez.h",
+        "bluetooth_pairing_bluez.cc",
+        "bluetooth_pairing_bluez.h",
+        "bluetooth_remote_gatt_characteristic_bluez.cc",
+        "bluetooth_remote_gatt_characteristic_bluez.h",
+        "bluetooth_remote_gatt_descriptor_bluez.cc",
+        "bluetooth_remote_gatt_descriptor_bluez.h",
+        "bluetooth_remote_gatt_service_bluez.cc",
+        "bluetooth_remote_gatt_service_bluez.h",
+        "bluetooth_socket_bluez.cc",
+        "bluetooth_socket_bluez.h",
+        "dbus/bluetooth_adapter_client.cc",
+        "dbus/bluetooth_adapter_client.h",
+        "dbus/bluetooth_agent_manager_client.cc",
+        "dbus/bluetooth_agent_manager_client.h",
+        "dbus/bluetooth_agent_service_provider.cc",
+        "dbus/bluetooth_agent_service_provider.h",
+        "dbus/bluetooth_dbus_client_bundle.cc",
+        "dbus/bluetooth_dbus_client_bundle.h",
+        "dbus/bluetooth_device_client.cc",
+        "dbus/bluetooth_device_client.h",
+        "dbus/bluetooth_gatt_characteristic_client.cc",
+        "dbus/bluetooth_gatt_characteristic_client.h",
+        "dbus/bluetooth_gatt_characteristic_service_provider.cc",
+        "dbus/bluetooth_gatt_characteristic_service_provider.h",
+        "dbus/bluetooth_gatt_descriptor_client.cc",
+        "dbus/bluetooth_gatt_descriptor_client.h",
+        "dbus/bluetooth_gatt_descriptor_service_provider.cc",
+        "dbus/bluetooth_gatt_descriptor_service_provider.h",
+        "dbus/bluetooth_gatt_manager_client.cc",
+        "dbus/bluetooth_gatt_manager_client.h",
+        "dbus/bluetooth_gatt_service_client.cc",
+        "dbus/bluetooth_gatt_service_client.h",
+        "dbus/bluetooth_gatt_service_service_provider.cc",
+        "dbus/bluetooth_gatt_service_service_provider.h",
+        "dbus/bluetooth_input_client.cc",
+        "dbus/bluetooth_input_client.h",
+        "dbus/bluetooth_le_advertisement_service_provider.cc",
+        "dbus/bluetooth_le_advertisement_service_provider.h",
+        "dbus/bluetooth_le_advertising_manager_client.cc",
+        "dbus/bluetooth_le_advertising_manager_client.h",
+        "dbus/bluetooth_media_client.cc",
+        "dbus/bluetooth_media_client.h",
+        "dbus/bluetooth_media_endpoint_service_provider.cc",
+        "dbus/bluetooth_media_endpoint_service_provider.h",
+        "dbus/bluetooth_media_transport_client.cc",
+        "dbus/bluetooth_media_transport_client.h",
+        "dbus/bluetooth_profile_manager_client.cc",
+        "dbus/bluetooth_profile_manager_client.h",
+        "dbus/bluetooth_profile_service_provider.cc",
+        "dbus/bluetooth_profile_service_provider.h",
+        "dbus/bluez_dbus_client.h",
+        "dbus/bluez_dbus_manager.cc",
+        "dbus/bluez_dbus_manager.h",
+        "dbus/dbus_thread_manager_linux.cc",
+        "dbus/dbus_thread_manager_linux.h",
+        "dbus/fake_bluetooth_adapter_client.cc",
+        "dbus/fake_bluetooth_adapter_client.h",
+        "dbus/fake_bluetooth_agent_manager_client.cc",
+        "dbus/fake_bluetooth_agent_manager_client.h",
+        "dbus/fake_bluetooth_agent_service_provider.cc",
+        "dbus/fake_bluetooth_agent_service_provider.h",
+        "dbus/fake_bluetooth_device_client.cc",
+        "dbus/fake_bluetooth_device_client.h",
+        "dbus/fake_bluetooth_gatt_characteristic_client.cc",
+        "dbus/fake_bluetooth_gatt_characteristic_client.h",
+        "dbus/fake_bluetooth_gatt_characteristic_service_provider.cc",
+        "dbus/fake_bluetooth_gatt_characteristic_service_provider.h",
+        "dbus/fake_bluetooth_gatt_descriptor_client.cc",
+        "dbus/fake_bluetooth_gatt_descriptor_client.h",
+        "dbus/fake_bluetooth_gatt_descriptor_service_provider.cc",
+        "dbus/fake_bluetooth_gatt_descriptor_service_provider.h",
+        "dbus/fake_bluetooth_gatt_manager_client.cc",
+        "dbus/fake_bluetooth_gatt_manager_client.h",
+        "dbus/fake_bluetooth_gatt_service_client.cc",
+        "dbus/fake_bluetooth_gatt_service_client.h",
+        "dbus/fake_bluetooth_gatt_service_service_provider.cc",
+        "dbus/fake_bluetooth_gatt_service_service_provider.h",
+        "dbus/fake_bluetooth_input_client.cc",
+        "dbus/fake_bluetooth_input_client.h",
+        "dbus/fake_bluetooth_le_advertisement_service_provider.cc",
+        "dbus/fake_bluetooth_le_advertisement_service_provider.h",
+        "dbus/fake_bluetooth_le_advertising_manager_client.cc",
+        "dbus/fake_bluetooth_le_advertising_manager_client.h",
+        "dbus/fake_bluetooth_media_client.cc",
+        "dbus/fake_bluetooth_media_client.h",
+        "dbus/fake_bluetooth_media_endpoint_service_provider.cc",
+        "dbus/fake_bluetooth_media_endpoint_service_provider.h",
+        "dbus/fake_bluetooth_media_transport_client.cc",
+        "dbus/fake_bluetooth_media_transport_client.h",
+        "dbus/fake_bluetooth_profile_manager_client.cc",
+        "dbus/fake_bluetooth_profile_manager_client.h",
+        "dbus/fake_bluetooth_profile_service_provider.cc",
+        "dbus/fake_bluetooth_profile_service_provider.h",
+      ]
+
+      deps += [ "//dbus" ]
+    } else {  # !use_dbus
+      sources += [ "bluetooth_adapter_stub.cc" ]
+    }
   }
 }
 
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp
index b4f90f2..a064db4 100644
--- a/device/bluetooth/bluetooth.gyp
+++ b/device/bluetooth/bluetooth.gyp
@@ -111,128 +111,132 @@
         'bluetooth_uuid.h',
       ],
       'conditions': [
-        # This block will also build for Linux once we write the linux
-        # implementation of BluezDbusManager.
         ['chromeos==1 or OS=="linux"', {
-         'defines': [
-            'DEVICE_BLUETOOTH_IMPLEMENTATION',
+         'conditions': [
+           ['use_dbus==1', {
+             'defines': [
+                'DEVICE_BLUETOOTH_IMPLEMENTATION',
+              ],
+              'sources': [
+                'bluetooth_adapter_bluez.cc',
+                'bluetooth_adapter_bluez.h',
+                'bluetooth_adapter_profile_bluez.cc',
+                'bluetooth_adapter_profile_bluez.h',
+                'bluetooth_advertisement_bluez.cc',
+                'bluetooth_advertisement_bluez.h',
+                'bluetooth_audio_sink_bluez.cc',
+                'bluetooth_audio_sink_bluez.h',
+                'bluetooth_device_bluez.cc',
+                'bluetooth_device_bluez.h',
+                'bluetooth_gatt_connection_bluez.cc',
+                'bluetooth_gatt_connection_bluez.h',
+                'bluetooth_gatt_notify_session_bluez.cc',
+                'bluetooth_gatt_notify_session_bluez.h',
+                'bluetooth_pairing_bluez.cc',
+                'bluetooth_pairing_bluez.h',
+                'bluetooth_remote_gatt_characteristic_bluez.cc',
+                'bluetooth_remote_gatt_characteristic_bluez.h',
+                'bluetooth_remote_gatt_descriptor_bluez.cc',
+                'bluetooth_remote_gatt_descriptor_bluez.h',
+                'bluetooth_remote_gatt_service_bluez.cc',
+                'bluetooth_remote_gatt_service_bluez.h',
+                'bluetooth_socket_bluez.cc',
+                'bluetooth_socket_bluez.h',
+                'dbus/bluetooth_adapter_client.cc',
+                'dbus/bluetooth_adapter_client.h',
+                'dbus/bluetooth_le_advertising_manager_client.cc',
+                'dbus/bluetooth_le_advertising_manager_client.h',
+                'dbus/bluetooth_le_advertisement_service_provider.cc',
+                'dbus/bluetooth_le_advertisement_service_provider.h',
+                'dbus/bluetooth_agent_manager_client.cc',
+                'dbus/bluetooth_agent_manager_client.h',
+                'dbus/bluetooth_agent_service_provider.cc',
+                'dbus/bluetooth_agent_service_provider.h',
+                'dbus/bluetooth_dbus_client_bundle.cc',
+                'dbus/bluetooth_dbus_client_bundle.h',
+                'dbus/bluetooth_device_client.cc',
+                'dbus/bluetooth_device_client.h',
+                'dbus/bluetooth_gatt_characteristic_client.cc',
+                'dbus/bluetooth_gatt_characteristic_client.h',
+                'dbus/bluetooth_gatt_characteristic_service_provider.cc',
+                'dbus/bluetooth_gatt_characteristic_service_provider.h',
+                'dbus/bluetooth_gatt_descriptor_client.cc',
+                'dbus/bluetooth_gatt_descriptor_client.h',
+                'dbus/bluetooth_gatt_descriptor_service_provider.cc',
+                'dbus/bluetooth_gatt_descriptor_service_provider.h',
+                'dbus/bluetooth_gatt_manager_client.cc',
+                'dbus/bluetooth_gatt_manager_client.h',
+                'dbus/bluetooth_gatt_service_client.cc',
+                'dbus/bluetooth_gatt_service_client.h',
+                'dbus/bluetooth_gatt_service_service_provider.cc',
+                'dbus/bluetooth_gatt_service_service_provider.h',
+                'dbus/bluetooth_input_client.cc',
+                'dbus/bluetooth_input_client.h',
+                'dbus/bluetooth_media_client.cc',
+                'dbus/bluetooth_media_client.h',
+                'dbus/bluetooth_media_endpoint_service_provider.cc',
+                'dbus/bluetooth_media_endpoint_service_provider.h',
+                'dbus/bluetooth_media_transport_client.cc',
+                'dbus/bluetooth_media_transport_client.h',
+                'dbus/bluetooth_profile_manager_client.cc',
+                'dbus/bluetooth_profile_manager_client.h',
+                'dbus/bluetooth_profile_service_provider.cc',
+                'dbus/bluetooth_profile_service_provider.h',
+                'dbus/bluez_dbus_client.h',
+                'dbus/bluez_dbus_manager.cc',
+                'dbus/bluez_dbus_manager.h',
+                'dbus/dbus_thread_manager_linux.cc',
+                'dbus/dbus_thread_manager_linux.h',
+                'dbus/fake_bluetooth_adapter_client.cc',
+                'dbus/fake_bluetooth_adapter_client.h',
+                'dbus/fake_bluetooth_le_advertising_manager_client.cc',
+                'dbus/fake_bluetooth_le_advertising_manager_client.h',
+                'dbus/fake_bluetooth_le_advertisement_service_provider.cc',
+                'dbus/fake_bluetooth_le_advertisement_service_provider.h',
+                'dbus/fake_bluetooth_agent_manager_client.cc',
+                'dbus/fake_bluetooth_agent_manager_client.h',
+                'dbus/fake_bluetooth_agent_service_provider.cc',
+                'dbus/fake_bluetooth_agent_service_provider.h',
+                'dbus/fake_bluetooth_device_client.cc',
+                'dbus/fake_bluetooth_device_client.h',
+                'dbus/fake_bluetooth_gatt_characteristic_client.cc',
+                'dbus/fake_bluetooth_gatt_characteristic_client.h',
+                'dbus/fake_bluetooth_gatt_characteristic_service_provider.cc',
+                'dbus/fake_bluetooth_gatt_characteristic_service_provider.h',
+                'dbus/fake_bluetooth_gatt_descriptor_client.cc',
+                'dbus/fake_bluetooth_gatt_descriptor_client.h',
+                'dbus/fake_bluetooth_gatt_descriptor_service_provider.cc',
+                'dbus/fake_bluetooth_gatt_descriptor_service_provider.h',
+                'dbus/fake_bluetooth_gatt_manager_client.cc',
+                'dbus/fake_bluetooth_gatt_manager_client.h',
+                'dbus/fake_bluetooth_gatt_service_client.cc',
+                'dbus/fake_bluetooth_gatt_service_client.h',
+                'dbus/fake_bluetooth_gatt_service_service_provider.cc',
+                'dbus/fake_bluetooth_gatt_service_service_provider.h',
+                'dbus/fake_bluetooth_input_client.cc',
+                'dbus/fake_bluetooth_input_client.h',
+                'dbus/fake_bluetooth_media_client.cc',
+                'dbus/fake_bluetooth_media_client.h',
+                'dbus/fake_bluetooth_media_endpoint_service_provider.cc',
+                'dbus/fake_bluetooth_media_endpoint_service_provider.h',
+                'dbus/fake_bluetooth_media_transport_client.cc',
+                'dbus/fake_bluetooth_media_transport_client.h',
+                'dbus/fake_bluetooth_profile_manager_client.cc',
+                'dbus/fake_bluetooth_profile_manager_client.h',
+                'dbus/fake_bluetooth_profile_service_provider.cc',
+                'dbus/fake_bluetooth_profile_service_provider.h',
+              ],
+              'dependencies': [
+                '../../build/linux/system.gyp:dbus',
+                '../../dbus/dbus.gyp:dbus',
+              ],
+              'export_dependent_settings': [
+                '../../build/linux/system.gyp:dbus'
+              ]
+            }, {  # !use_dbus
+              'sources': [ 'bluetooth_adapter_stub.cc' ]
+            }],
           ],
-          'sources': [
-            'bluetooth_adapter_bluez.cc',
-            'bluetooth_adapter_bluez.h',
-            'bluetooth_adapter_profile_bluez.cc',
-            'bluetooth_adapter_profile_bluez.h',
-            'bluetooth_advertisement_bluez.cc',
-            'bluetooth_advertisement_bluez.h',
-            'bluetooth_audio_sink_bluez.cc',
-            'bluetooth_audio_sink_bluez.h',
-            'bluetooth_device_bluez.cc',
-            'bluetooth_device_bluez.h',
-            'bluetooth_gatt_connection_bluez.cc',
-            'bluetooth_gatt_connection_bluez.h',
-            'bluetooth_gatt_notify_session_bluez.cc',
-            'bluetooth_gatt_notify_session_bluez.h',
-            'bluetooth_pairing_bluez.cc',
-            'bluetooth_pairing_bluez.h',
-            'bluetooth_remote_gatt_characteristic_bluez.cc',
-            'bluetooth_remote_gatt_characteristic_bluez.h',
-            'bluetooth_remote_gatt_descriptor_bluez.cc',
-            'bluetooth_remote_gatt_descriptor_bluez.h',
-            'bluetooth_remote_gatt_service_bluez.cc',
-            'bluetooth_remote_gatt_service_bluez.h',
-            'bluetooth_socket_bluez.cc',
-            'bluetooth_socket_bluez.h',
-            'dbus/bluetooth_adapter_client.cc',
-            'dbus/bluetooth_adapter_client.h',
-            'dbus/bluetooth_le_advertising_manager_client.cc',
-            'dbus/bluetooth_le_advertising_manager_client.h',
-            'dbus/bluetooth_le_advertisement_service_provider.cc',
-            'dbus/bluetooth_le_advertisement_service_provider.h',
-            'dbus/bluetooth_agent_manager_client.cc',
-            'dbus/bluetooth_agent_manager_client.h',
-            'dbus/bluetooth_agent_service_provider.cc',
-            'dbus/bluetooth_agent_service_provider.h',
-            'dbus/bluetooth_dbus_client_bundle.cc',
-            'dbus/bluetooth_dbus_client_bundle.h',
-            'dbus/bluetooth_device_client.cc',
-            'dbus/bluetooth_device_client.h',
-            'dbus/bluetooth_gatt_characteristic_client.cc',
-            'dbus/bluetooth_gatt_characteristic_client.h',
-            'dbus/bluetooth_gatt_characteristic_service_provider.cc',
-            'dbus/bluetooth_gatt_characteristic_service_provider.h',
-            'dbus/bluetooth_gatt_descriptor_client.cc',
-            'dbus/bluetooth_gatt_descriptor_client.h',
-            'dbus/bluetooth_gatt_descriptor_service_provider.cc',
-            'dbus/bluetooth_gatt_descriptor_service_provider.h',
-            'dbus/bluetooth_gatt_manager_client.cc',
-            'dbus/bluetooth_gatt_manager_client.h',
-            'dbus/bluetooth_gatt_service_client.cc',
-            'dbus/bluetooth_gatt_service_client.h',
-            'dbus/bluetooth_gatt_service_service_provider.cc',
-            'dbus/bluetooth_gatt_service_service_provider.h',
-            'dbus/bluetooth_input_client.cc',
-            'dbus/bluetooth_input_client.h',
-            'dbus/bluetooth_media_client.cc',
-            'dbus/bluetooth_media_client.h',
-            'dbus/bluetooth_media_endpoint_service_provider.cc',
-            'dbus/bluetooth_media_endpoint_service_provider.h',
-            'dbus/bluetooth_media_transport_client.cc',
-            'dbus/bluetooth_media_transport_client.h',
-            'dbus/bluetooth_profile_manager_client.cc',
-            'dbus/bluetooth_profile_manager_client.h',
-            'dbus/bluetooth_profile_service_provider.cc',
-            'dbus/bluetooth_profile_service_provider.h',
-            'dbus/bluez_dbus_client.h',
-            'dbus/bluez_dbus_manager.cc',
-            'dbus/bluez_dbus_manager.h',
-            'dbus/dbus_thread_manager_linux.cc',
-            'dbus/dbus_thread_manager_linux.h',
-            'dbus/fake_bluetooth_adapter_client.cc',
-            'dbus/fake_bluetooth_adapter_client.h',
-            'dbus/fake_bluetooth_le_advertising_manager_client.cc',
-            'dbus/fake_bluetooth_le_advertising_manager_client.h',
-            'dbus/fake_bluetooth_le_advertisement_service_provider.cc',
-            'dbus/fake_bluetooth_le_advertisement_service_provider.h',
-            'dbus/fake_bluetooth_agent_manager_client.cc',
-            'dbus/fake_bluetooth_agent_manager_client.h',
-            'dbus/fake_bluetooth_agent_service_provider.cc',
-            'dbus/fake_bluetooth_agent_service_provider.h',
-            'dbus/fake_bluetooth_device_client.cc',
-            'dbus/fake_bluetooth_device_client.h',
-            'dbus/fake_bluetooth_gatt_characteristic_client.cc',
-            'dbus/fake_bluetooth_gatt_characteristic_client.h',
-            'dbus/fake_bluetooth_gatt_characteristic_service_provider.cc',
-            'dbus/fake_bluetooth_gatt_characteristic_service_provider.h',
-            'dbus/fake_bluetooth_gatt_descriptor_client.cc',
-            'dbus/fake_bluetooth_gatt_descriptor_client.h',
-            'dbus/fake_bluetooth_gatt_descriptor_service_provider.cc',
-            'dbus/fake_bluetooth_gatt_descriptor_service_provider.h',
-            'dbus/fake_bluetooth_gatt_manager_client.cc',
-            'dbus/fake_bluetooth_gatt_manager_client.h',
-            'dbus/fake_bluetooth_gatt_service_client.cc',
-            'dbus/fake_bluetooth_gatt_service_client.h',
-            'dbus/fake_bluetooth_gatt_service_service_provider.cc',
-            'dbus/fake_bluetooth_gatt_service_service_provider.h',
-            'dbus/fake_bluetooth_input_client.cc',
-            'dbus/fake_bluetooth_input_client.h',
-            'dbus/fake_bluetooth_media_client.cc',
-            'dbus/fake_bluetooth_media_client.h',
-            'dbus/fake_bluetooth_media_endpoint_service_provider.cc',
-            'dbus/fake_bluetooth_media_endpoint_service_provider.h',
-            'dbus/fake_bluetooth_media_transport_client.cc',
-            'dbus/fake_bluetooth_media_transport_client.h',
-            'dbus/fake_bluetooth_profile_manager_client.cc',
-            'dbus/fake_bluetooth_profile_manager_client.h',
-            'dbus/fake_bluetooth_profile_service_provider.cc',
-            'dbus/fake_bluetooth_profile_service_provider.h',
-          ],
-          'dependencies': [
-            '../../build/linux/system.gyp:dbus',
-            '../../dbus/dbus.gyp:dbus',
-          ],
-          'export_dependent_settings': [
-            '../../build/linux/system.gyp:dbus'
-          ]
         }],
         ['chromeos==1', {
           'dependencies': [
diff --git a/device/bluetooth/bluetooth_adapter_factory.cc b/device/bluetooth/bluetooth_adapter_factory.cc
index 9771439..2162034 100644
--- a/device/bluetooth/bluetooth_adapter_factory.cc
+++ b/device/bluetooth/bluetooth_adapter_factory.cc
@@ -12,10 +12,6 @@
 #include "base/memory/weak_ptr.h"
 #include "device/bluetooth/bluetooth_adapter.h"
 
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
-#include "device/bluetooth/bluetooth_adapter_bluez.h"
-#endif
-
 #if defined(OS_MACOSX)
 #include "base/mac/mac_util.h"
 #endif
diff --git a/device/bluetooth/bluetooth_adapter_stub.cc b/device/bluetooth/bluetooth_adapter_stub.cc
new file mode 100644
index 0000000..fc62f95
--- /dev/null
+++ b/device/bluetooth/bluetooth_adapter_stub.cc
@@ -0,0 +1,18 @@
+// Copyright 2015 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 "base/memory/weak_ptr.h"
+#include "device/bluetooth/bluetooth_adapter.h"
+
+namespace device {
+
+// Return a null ptr. Link this when there is no suitable BluetoothAdapter for
+// a particular platform.
+// static
+base::WeakPtr<BluetoothAdapter> BluetoothAdapter::CreateAdapter(
+    const InitCallback& init_callback) {
+  return base::WeakPtr<BluetoothAdapter>();
+}
+
+}  // namespace device
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index 28d8db8c..78a966f 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -753,6 +753,11 @@
   ModifyDisableReasons(extension_id, disable_reason, DISABLE_REASON_REMOVE);
 }
 
+void ExtensionPrefs::ReplaceDisableReasons(const std::string& extension_id,
+                                           int disable_reasons) {
+  ModifyDisableReasons(extension_id, disable_reasons, DISABLE_REASON_REPLACE);
+}
+
 void ExtensionPrefs::ClearDisableReasons(const std::string& extension_id) {
   ModifyDisableReasons(extension_id, Extension::DISABLE_NONE,
                        DISABLE_REASON_CLEAR);
@@ -770,6 +775,9 @@
     case DISABLE_REASON_REMOVE:
       new_value &= ~reasons;
       break;
+    case DISABLE_REASON_REPLACE:
+      new_value = reasons;
+      break;
     case DISABLE_REASON_CLEAR:
       new_value = Extension::DISABLE_NONE;
       break;
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h
index 2e9e840..892dd74 100644
--- a/extensions/browser/extension_prefs.h
+++ b/extensions/browser/extension_prefs.h
@@ -269,6 +269,8 @@
   void AddDisableReasons(const std::string& extension_id, int disable_reasons);
   void RemoveDisableReason(const std::string& extension_id,
                            Extension::DisableReason disable_reason);
+  void ReplaceDisableReasons(const std::string& extension_id,
+                             int disable_reasons);
   void ClearDisableReasons(const std::string& extension_id);
 
   // Gets the set of extensions that have been blacklisted in prefs. This will
@@ -558,6 +560,7 @@
   enum DisableReasonChange {
     DISABLE_REASON_ADD,
     DISABLE_REASON_REMOVE,
+    DISABLE_REASON_REPLACE,
     DISABLE_REASON_CLEAR
   };
 
diff --git a/extensions/common/extension.h b/extensions/common/extension.h
index f2c24d6..75495fb8e 100644
--- a/extensions/common/extension.h
+++ b/extensions/common/extension.h
@@ -85,6 +85,8 @@
   // not remove/reorder entries - only add at the end just before
   // DISABLE_REASON_LAST (and update the shift value for it). Also remember to
   // update the enum listing in tools/metrics/histograms.xml.
+  // Also carefully consider if your reason should sync to other devices, and if
+  // so, add it to kKnownSyncableDisableReasons in extension_sync_service.cc.
   enum DisableReason {
     DISABLE_NONE = 0,
     DISABLE_USER_ACTION = 1 << 0,
diff --git a/mandoline/app/desktop/BUILD.gn b/mandoline/app/desktop/BUILD.gn
index 9a6723c..ac6d769 100644
--- a/mandoline/app/desktop/BUILD.gn
+++ b/mandoline/app/desktop/BUILD.gn
@@ -25,6 +25,8 @@
     "//mojo/package_manager",
     "//mojo/runner:lib",
     "//mojo/runner:register_local_aliases_fwd",
+    "//mojo/runner/host:lib",
+    "//mojo/runner/host:switches",
     "//mojo/shell",
   ]
 
diff --git a/mandoline/app/desktop/main.cc b/mandoline/app/desktop/main.cc
index d0a7a99..989d8ec4 100644
--- a/mandoline/app/desktop/main.cc
+++ b/mandoline/app/desktop/main.cc
@@ -7,9 +7,9 @@
 #include "base/debug/stack_trace.h"
 #include "base/process/launch.h"
 #include "mandoline/app/desktop/launcher_process.h"
-#include "mojo/runner/child_process.h"
+#include "mojo/runner/host/child_process.h"
+#include "mojo/runner/host/switches.h"
 #include "mojo/runner/init.h"
-#include "mojo/runner/switches.h"
 
 int main(int argc, char** argv) {
   base::CommandLine::Init(argc, argv);
diff --git a/mojo/message_pump/handle_watcher.cc b/mojo/message_pump/handle_watcher.cc
index 964f1e2..1397dee 100644
--- a/mojo/message_pump/handle_watcher.cc
+++ b/mojo/message_pump/handle_watcher.cc
@@ -222,7 +222,13 @@
 }
 
 WatcherThreadManager* WatcherThreadManager::GetInstance() {
-  return base::Singleton<WatcherThreadManager>::get();
+  // We need to leak this because otherwise when the process dies, AtExitManager
+  // waits for destruction which waits till the handle watcher thread is joined.
+  // But that can't happen since the pump uses mojo message pipes to wake up the
+  // pump. Since mojo EDK has been shutdown already, this never completes.
+  return base::Singleton<WatcherThreadManager,
+                         base::LeakySingletonTraits<WatcherThreadManager>>::
+      get();
 }
 
 WatcherID WatcherThreadManager::StartWatching(
diff --git a/mojo/runner/BUILD.gn b/mojo/runner/BUILD.gn
index 3c1dec9..a26595b3 100644
--- a/mojo/runner/BUILD.gn
+++ b/mojo/runner/BUILD.gn
@@ -37,6 +37,8 @@
     "//mojo/common",
     "//mojo/environment:chromium",
     "//mojo/message_pump",
+    "//mojo/runner/host:lib",
+    "//mojo/runner/host:switches",
   ]
 
   if (!is_android) {
@@ -47,7 +49,10 @@
       "register_local_aliases.cc",
       "register_local_aliases.h",
     ]
-    deps += [ "//components/tracing:startup_tracing" ]
+    deps += [
+      "//components/tracing:startup_tracing",
+      "//mojo/shell",
+    ]
   } else {
     sources += [
       "android/context_init.h",
@@ -98,23 +103,15 @@
   ]
 
   deps = [
-    ":switches",
+    "//mojo/runner/host:switches",
     "//base",
   ]
 }
 
 source_set("lib") {
   sources = [
-    "child_process.cc",
-    "child_process.h",
-    "child_process_host.cc",
-    "child_process_host.h",
     "context.cc",
     "context.h",
-    "in_process_native_runner.cc",
-    "in_process_native_runner.h",
-    "out_of_process_native_runner.cc",
-    "out_of_process_native_runner.h",
     "scoped_user_data_dir.cc",
     "scoped_user_data_dir.h",
     "task_runners.cc",
@@ -125,7 +122,6 @@
 
   deps = [
     ":init",
-    ":native_application_support",
     "//base",
     "//base/third_party/dynamic_annotations",
     "//base:base_static",
@@ -135,6 +131,7 @@
     "//mojo/message_pump",
     "//mojo/package_manager",
     "//mojo/runner/child:interfaces",
+    "//mojo/runner/host:lib",
     "//mojo/services/network/public/interfaces",
     "//mojo/services/tracing/public/cpp",
     "//mojo/services/tracing/public/interfaces",
@@ -145,18 +142,6 @@
     "//url",
   ]
 
-  if (is_linux && !is_android) {
-    sources += [
-      "linux_sandbox.cc",
-      "linux_sandbox.h",
-    ]
-
-    deps += [
-      "//sandbox/linux:sandbox",
-      "//sandbox/linux:sandbox_services",
-    ]
-  }
-
   public_deps = [
     ":init",
     ":switches",
@@ -198,28 +183,6 @@
   check_includes = false
 }
 
-source_set("native_application_support") {
-  sources = [
-    "native_application_support.cc",
-    "native_application_support.h",
-  ]
-
-  deps = [
-    "//base",
-    "//mojo/gles2",
-    "//mojo/platform_handle:platform_handle_impl",
-    "//mojo/shell",
-  ]
-
-  # This target has to include the public thunk headers, which generally
-  # shouldn't be included without picking an implementation. We are providing
-  # the implementation but the thunk header target cannot declare that we are
-  # permitted to include it since it's in the public SDK and we are not.
-  # Suppress include checking so we can still check the rest of the targets in
-  # this file.
-  check_includes = false
-}
-
 source_set("switches") {
   sources = [
     "switches.cc",
@@ -416,9 +379,7 @@
     "../fetcher/data_fetcher_unittest.cc",
     "../fetcher/network_fetcher_unittest.cc",
     "../fetcher/url_resolver_unittest.cc",
-    "child_process_host_unittest.cc",
     "data_pipe_peek_unittest.cc",
-    "in_process_native_runner_unittest.cc",
     "native_runner_unittest.cc",
     "register_local_aliases.cc",
     "register_local_aliases.h",
diff --git a/mojo/runner/android/android_handler.cc b/mojo/runner/android/android_handler.cc
index 354720a..98313e3 100644
--- a/mojo/runner/android/android_handler.cc
+++ b/mojo/runner/android/android_handler.cc
@@ -14,7 +14,7 @@
 #include "mojo/common/data_pipe_utils.h"
 #include "mojo/public/c/system/main.h"
 #include "mojo/runner/android/run_android_application_function.h"
-#include "mojo/runner/native_application_support.h"
+#include "mojo/runner/host/native_application_support.h"
 #include "mojo/util/filename_util.h"
 #include "url/gurl.h"
 
diff --git a/mojo/runner/android/main.cc b/mojo/runner/android/main.cc
index 10b9c31..ec59d793 100644
--- a/mojo/runner/android/main.cc
+++ b/mojo/runner/android/main.cc
@@ -27,8 +27,8 @@
 #include "mojo/runner/android/background_application_loader.h"
 #include "mojo/runner/android/context_init.h"
 #include "mojo/runner/android/ui_application_loader_android.h"
-#include "mojo/runner/child_process.h"
 #include "mojo/runner/context.h"
+#include "mojo/runner/host/child_process.h"
 #include "mojo/runner/init.h"
 #include "mojo/shell/application_loader.h"
 #include "ui/gl/gl_surface_egl.h"
diff --git a/mojo/runner/context.cc b/mojo/runner/context.cc
index 1923bad..6c2a90d2 100644
--- a/mojo/runner/context.cc
+++ b/mojo/runner/context.cc
@@ -26,8 +26,8 @@
 #include "mojo/application/public/cpp/application_delegate.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/package_manager/package_manager_impl.h"
-#include "mojo/runner/in_process_native_runner.h"
-#include "mojo/runner/out_of_process_native_runner.h"
+#include "mojo/runner/host/in_process_native_runner.h"
+#include "mojo/runner/host/out_of_process_native_runner.h"
 #include "mojo/runner/register_local_aliases.h"
 #include "mojo/runner/switches.h"
 #include "mojo/runner/tracer.h"
diff --git a/mojo/runner/desktop/launcher_process.cc b/mojo/runner/desktop/launcher_process.cc
index fb2c896cb..d79f45b 100644
--- a/mojo/runner/desktop/launcher_process.cc
+++ b/mojo/runner/desktop/launcher_process.cc
@@ -21,21 +21,27 @@
 #include "mojo/runner/context.h"
 #include "mojo/runner/switches.h"
 #include "mojo/runner/tracer.h"
+#include "mojo/shell/switches.h"
 
 namespace mojo {
 namespace runner {
 
 int LauncherProcessMain(int argc, char** argv) {
   mojo::runner::Tracer tracer;
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (!command_line->HasSwitch(switches::kMojoSingleProcess) &&
+      !command_line->HasSwitch("gtest_list_tests"))
+    command_line->AppendSwitch(switches::kEnableMultiprocess);
+  command_line->AppendSwitch("use-new-edk");
+  // http://crbug.com/546644
+  command_line->AppendSwitch(switches::kMojoNoSandbox);
 
-  bool trace_startup = command_line.HasSwitch(switches::kTraceStartup);
+  bool trace_startup = command_line->HasSwitch(switches::kTraceStartup);
   if (trace_startup) {
     tracer.Start(
-        command_line.GetSwitchValueASCII(switches::kTraceStartup),
-        command_line.GetSwitchValueASCII(switches::kTraceStartupDuration),
-        "mandoline.trace");
+        command_line->GetSwitchValueASCII(switches::kTraceStartup),
+        command_line->GetSwitchValueASCII(switches::kTraceStartupDuration),
+        "mojo_runner.trace");
   }
 
   // We want the shell::Context to outlive the MessageLoop so that pipes are
diff --git a/mojo/runner/desktop/main.cc b/mojo/runner/desktop/main.cc
index 93c2376..0815c023 100644
--- a/mojo/runner/desktop/main.cc
+++ b/mojo/runner/desktop/main.cc
@@ -7,10 +7,10 @@
 #include "base/debug/stack_trace.h"
 #include "base/process/launch.h"
 #include "build/build_config.h"
-#include "mojo/runner/child_process.h"
 #include "mojo/runner/desktop/launcher_process.h"
+#include "mojo/runner/host/child_process.h"
+#include "mojo/runner/host/switches.h"
 #include "mojo/runner/init.h"
-#include "mojo/runner/switches.h"
 
 int main(int argc, char** argv) {
   base::AtExitManager at_exit;
diff --git a/mojo/runner/host/BUILD.gn b/mojo/runner/host/BUILD.gn
new file mode 100644
index 0000000..aba7b53
--- /dev/null
+++ b/mojo/runner/host/BUILD.gn
@@ -0,0 +1,110 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//mojo/generate_mojo_shell_assets_list.gni")
+import("//mojo/public/mojo_application.gni")
+import("//testing/test.gni")
+import("//third_party/mojo/src/mojo/public/tools/bindings/mojom.gni")
+
+group("host") {
+  testonly = true
+
+  deps = [
+    ":lib",
+    ":unittests",
+  ]
+}
+
+source_set("switches") {
+  sources = [
+    "switches.cc",
+    "switches.h",
+  ]
+}
+
+source_set("native_application_support") {
+  sources = [
+    "native_application_support.cc",
+    "native_application_support.h",
+  ]
+
+  deps = [
+    "//base",
+    "//mojo/gles2",
+    "//mojo/platform_handle:platform_handle_impl",
+    "//mojo/shell",
+  ]
+
+  # This target has to include the public thunk headers, which generally
+  # shouldn't be included without picking an implementation. We are providing
+  # the implementation but the thunk header target cannot declare that we are
+  # permitted to include it since it's in the public SDK and we are not.
+  # Suppress include checking so we can still check the rest of the targets in
+  # this file.
+  check_includes = false
+}
+
+source_set("lib") {
+  sources = [
+    "child_process.cc",
+    "child_process.h",
+    "child_process_host.cc",
+    "child_process_host.h",
+    "in_process_native_runner.cc",
+    "in_process_native_runner.h",
+    "out_of_process_native_runner.cc",
+    "out_of_process_native_runner.h",
+  ]
+
+  deps = [
+    ":native_application_support",
+    ":switches",
+    "//base",
+    "//base:base_static",
+    "//mojo/gles2",
+    "//mojo/message_pump",
+    "//mojo/platform_handle:platform_handle_impl",
+    "//mojo/runner/child:interfaces",
+    "//mojo/runner:init",
+    "//mojo/shell",
+    "//third_party/mojo/src/mojo/edk/system",
+  ]
+
+  if (is_linux && !is_android) {
+    sources += [
+      "linux_sandbox.cc",
+      "linux_sandbox.h",
+    ]
+
+    deps += [
+      "//sandbox/linux:sandbox",
+      "//sandbox/linux:sandbox_services",
+      "//sandbox/linux:seccomp_bpf",
+      "//sandbox/linux:seccomp_bpf_helpers",
+    ]
+  }
+}
+
+test("unittests") {
+  output_name = "mojo_runner_host_unittests"
+
+  sources = [
+    "child_process_host_unittest.cc",
+    "host_unittests.cc",
+    "in_process_native_runner_unittest.cc",
+  ]
+
+  deps = [
+    ":lib",
+    ":switches",
+    "//base",
+    "//base/test:test_support",
+    "//mojo/common",
+    "//mojo/environment:chromium",
+    "//mojo/message_pump",
+    "//mojo/runner:init",
+    "//testing/gtest",
+    "//third_party/mojo/src/mojo/edk/system",
+  ]
+}
diff --git a/mojo/runner/host/DEPS b/mojo/runner/host/DEPS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/mojo/runner/host/DEPS
diff --git a/mojo/runner/child_process.cc b/mojo/runner/host/child_process.cc
similarity index 96%
rename from mojo/runner/child_process.cc
rename to mojo/runner/host/child_process.cc
index 33ac3cd..dc04176 100644
--- a/mojo/runner/child_process.cc
+++ b/mojo/runner/host/child_process.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/runner/child_process.h"
+#include "mojo/runner/host/child_process.h"
 
 #include "base/base_switches.h"
 #include "base/bind.h"
@@ -24,8 +24,8 @@
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/system/core.h"
 #include "mojo/runner/child/child_controller.mojom.h"
-#include "mojo/runner/native_application_support.h"
-#include "mojo/runner/switches.h"
+#include "mojo/runner/host/native_application_support.h"
+#include "mojo/runner/host/switches.h"
 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 #include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
 #include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h"
@@ -34,7 +34,7 @@
 #if defined(OS_LINUX) && !defined(OS_ANDROID)
 #include "base/rand_util.h"
 #include "base/sys_info.h"
-#include "mojo/runner/linux_sandbox.h"
+#include "mojo/runner/host/linux_sandbox.h"
 #endif
 
 namespace mojo {
@@ -92,7 +92,7 @@
 
 // Should be created and initialized on the main thread.
 // TODO(use_chrome_edk)
-//class AppContext : public edk::ProcessDelegate {
+// class AppContext : public edk::ProcessDelegate {
 class AppContext : public embedder::ProcessDelegate {
  public:
   AppContext()
@@ -284,7 +284,7 @@
 
 #if defined(OS_LINUX) && !defined(OS_ANDROID)
   using sandbox::syscall_broker::BrokerFilePermission;
-  scoped_ptr<mandoline::LinuxSandbox> sandbox;
+  scoped_ptr<mojo::runner::LinuxSandbox> sandbox;
 #endif
   base::NativeLibrary app_library = 0;
   if (command_line.HasSwitch(switches::kChildProcess)) {
@@ -315,7 +315,7 @@
       std::vector<BrokerFilePermission> permissions;
       permissions.push_back(
           BrokerFilePermission::ReadWriteCreateUnlinkRecursive("/dev/shm/"));
-      sandbox.reset(new mandoline::LinuxSandbox(permissions));
+      sandbox.reset(new mojo::runner::LinuxSandbox(permissions));
       sandbox->Warmup();
       sandbox->EngageNamespaceSandbox();
       sandbox->EngageSeccompSandbox();
diff --git a/mojo/runner/child_process.h b/mojo/runner/host/child_process.h
similarity index 70%
rename from mojo/runner/child_process.h
rename to mojo/runner/host/child_process.h
index 2b94301f..f144bc6e 100644
--- a/mojo/runner/child_process.h
+++ b/mojo/runner/host/child_process.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MOJO_RUNNER_CHILD_PROCESS_H_
-#define MOJO_RUNNER_CHILD_PROCESS_H_
+#ifndef MOJO_RUNNER_HOST_CHILD_PROCESS_H_
+#define MOJO_RUNNER_HOST_CHILD_PROCESS_H_
 
 namespace mojo {
 namespace runner {
@@ -14,4 +14,4 @@
 }  // namespace runner
 }  // namespace mojo
 
-#endif  // MOJO_RUNNER_CHILD_PROCESS_H_
+#endif  // MOJO_RUNNER_HOST_CHILD_PROCESS_H_
diff --git a/mojo/runner/child_process_host.cc b/mojo/runner/host/child_process_host.cc
similarity index 95%
rename from mojo/runner/child_process_host.cc
rename to mojo/runner/host/child_process_host.cc
index 298fb80..6074b5b 100644
--- a/mojo/runner/child_process_host.cc
+++ b/mojo/runner/host/child_process_host.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/runner/child_process_host.h"
+#include "mojo/runner/host/child_process_host.h"
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -16,8 +16,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
 #include "mojo/public/cpp/system/core.h"
-#include "mojo/runner/switches.h"
-#include "mojo/runner/task_runners.h"
+#include "mojo/runner/host/switches.h"
 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 
 #if defined(OS_LINUX) && !defined(OS_ANDROID)
@@ -49,9 +48,8 @@
   DCHECK(platform_channel_.is_valid());
 
   ScopedMessagePipeHandle handle(embedder::CreateChannel(
-      platform_channel_.Pass(),
-      base::Bind(&ChildProcessHost::DidCreateChannel,
-                 weak_factory_.GetWeakPtr()),
+      platform_channel_.Pass(), base::Bind(&ChildProcessHost::DidCreateChannel,
+                                           weak_factory_.GetWeakPtr()),
       base::ThreadTaskRunnerHandle::Get()));
 
   controller_.Bind(InterfacePtrInfo<ChildController>(handle.Pass(), 0u));
diff --git a/mojo/runner/child_process_host.h b/mojo/runner/host/child_process_host.h
similarity index 94%
rename from mojo/runner/child_process_host.h
rename to mojo/runner/host/child_process_host.h
index 42f0773d4..68ea6c2 100644
--- a/mojo/runner/child_process_host.h
+++ b/mojo/runner/host/child_process_host.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MOJO_RUNNER_CHILD_PROCESS_HOST_H_
-#define MOJO_RUNNER_CHILD_PROCESS_HOST_H_
+#ifndef MOJO_RUNNER_HOST_CHILD_PROCESS_HOST_H_
+#define MOJO_RUNNER_HOST_CHILD_PROCESS_HOST_H_
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
@@ -11,7 +11,7 @@
 #include "base/process/process.h"
 #include "base/synchronization/waitable_event.h"
 #include "mojo/runner/child/child_controller.mojom.h"
-#include "mojo/runner/child_process_host.h"
+#include "mojo/runner/host/child_process_host.h"
 #include "third_party/mojo/src/mojo/edk/embedder/channel_info_forward.h"
 #include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
 #include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
@@ -92,4 +92,4 @@
 }  // namespace runner
 }  // namespace mojo
 
-#endif  // MOJO_RUNNER_CHILD_PROCESS_HOST_H_
+#endif  // MOJO_RUNNER_HOST_CHILD_PROCESS_HOST_H_
diff --git a/mojo/runner/child_process_host_unittest.cc b/mojo/runner/host/child_process_host_unittest.cc
similarity index 92%
rename from mojo/runner/child_process_host_unittest.cc
rename to mojo/runner/host/child_process_host_unittest.cc
index 8d07843..cded872 100644
--- a/mojo/runner/child_process_host_unittest.cc
+++ b/mojo/runner/host/child_process_host_unittest.cc
@@ -4,7 +4,7 @@
 
 // Note: This file also tests child_process.*.
 
-#include "mojo/runner/child_process_host.h"
+#include "mojo/runner/host/child_process_host.h"
 
 #include "base/logging.h"
 #include "base/macros.h"
@@ -12,7 +12,6 @@
 #include "base/path_service.h"
 #include "base/threading/thread.h"
 #include "mojo/message_pump/message_pump_mojo.h"
-#include "mojo/runner/context.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 #include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h"
@@ -56,9 +55,6 @@
 // Just tests starting the child process and joining it (without starting an
 // app).
 TEST(ChildProcessHostTest, MAYBE_StartJoin) {
-  // TODO(beng): will have to call embedder::Init() here once we move to a
-  //             different suite.
-  Context::EnsureEmbedderIsInitialized();
   base::FilePath shell_dir;
   PathService::Get(base::DIR_MODULE, &shell_dir);
   base::MessageLoop message_loop(
diff --git a/mojo/runner/host/host_unittests.cc b/mojo/runner/host/host_unittests.cc
new file mode 100644
index 0000000..37ae221
--- /dev/null
+++ b/mojo/runner/host/host_unittests.cc
@@ -0,0 +1,36 @@
+// Copyright 2014 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 "base/at_exit.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/test/launcher/unit_test_launcher.h"
+#include "base/test/test_suite.h"
+#include "mojo/runner/host/child_process.h"
+#include "mojo/runner/host/switches.h"
+#include "mojo/runner/init.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+
+int main(int argc, char** argv) {
+  base::CommandLine::Init(argc, argv);
+  const base::CommandLine& command_line =
+      *base::CommandLine::ForCurrentProcess();
+
+  mojo::runner::WaitForDebuggerIfNecessary();
+
+  if (command_line.HasSwitch(switches::kChildProcess)) {
+    base::AtExitManager at_exit;
+
+    return mojo::runner::ChildProcessMain();
+  }
+
+  mojo::embedder::Init();
+
+  base::TestSuite test_suite(argc, argv);
+  return base::LaunchUnitTests(
+      argc, argv,
+      base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
+}
diff --git a/mojo/runner/in_process_native_runner.cc b/mojo/runner/host/in_process_native_runner.cc
similarity index 93%
rename from mojo/runner/in_process_native_runner.cc
rename to mojo/runner/host/in_process_native_runner.cc
index 654f365..19cc88c6 100644
--- a/mojo/runner/in_process_native_runner.cc
+++ b/mojo/runner/host/in_process_native_runner.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/runner/in_process_native_runner.h"
+#include "mojo/runner/host/in_process_native_runner.h"
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
@@ -10,8 +10,8 @@
 #include "base/task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/platform_thread.h"
-#include "mojo/runner/native_application_support.h"
-#include "mojo/runner/out_of_process_native_runner.h"
+#include "mojo/runner/host/native_application_support.h"
+#include "mojo/runner/host/out_of_process_native_runner.h"
 
 namespace mojo {
 namespace runner {
diff --git a/mojo/runner/in_process_native_runner.h b/mojo/runner/host/in_process_native_runner.h
similarity index 89%
rename from mojo/runner/in_process_native_runner.h
rename to mojo/runner/host/in_process_native_runner.h
index 3c69e0b..ddd8395 100644
--- a/mojo/runner/in_process_native_runner.h
+++ b/mojo/runner/host/in_process_native_runner.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MOJO_RUNNER_IN_PROCESS_NATIVE_RUNNER_H_
-#define MOJO_RUNNER_IN_PROCESS_NATIVE_RUNNER_H_
+#ifndef MOJO_RUNNER_HOST_IN_PROCESS_NATIVE_RUNNER_H_
+#define MOJO_RUNNER_HOST_IN_PROCESS_NATIVE_RUNNER_H_
 
 #include "base/callback.h"
 #include "base/files/file_path.h"
@@ -11,7 +11,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/scoped_native_library.h"
 #include "base/threading/simple_thread.h"
-#include "mojo/runner/native_application_support.h"
+#include "mojo/runner/host/native_application_support.h"
 #include "mojo/shell/native_runner.h"
 
 namespace base {
@@ -67,4 +67,4 @@
 }  // namespace runner
 }  // namespace mojo
 
-#endif  // MOJO_RUNNER_IN_PROCESS_NATIVE_RUNNER_H_
+#endif  // MOJO_RUNNER_HOST_IN_PROCESS_NATIVE_RUNNER_H_
diff --git a/mojo/runner/in_process_native_runner_unittest.cc b/mojo/runner/host/in_process_native_runner_unittest.cc
similarity index 88%
rename from mojo/runner/in_process_native_runner_unittest.cc
rename to mojo/runner/host/in_process_native_runner_unittest.cc
index 5fe2b5da..c5597061 100644
--- a/mojo/runner/in_process_native_runner_unittest.cc
+++ b/mojo/runner/host/in_process_native_runner_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/runner/in_process_native_runner.h"
+#include "mojo/runner/host/in_process_native_runner.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 
diff --git a/mojo/runner/linux_sandbox.cc b/mojo/runner/host/linux_sandbox.cc
similarity index 97%
rename from mojo/runner/linux_sandbox.cc
rename to mojo/runner/host/linux_sandbox.cc
index 81e27eb..23b84432 100644
--- a/mojo/runner/linux_sandbox.cc
+++ b/mojo/runner/host/linux_sandbox.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/runner/linux_sandbox.h"
+#include "mojo/runner/host/linux_sandbox.h"
 
 #include <fcntl.h>
 #include <sys/syscall.h>
@@ -26,7 +26,8 @@
 
 using sandbox::syscall_broker::BrokerFilePermission;
 
-namespace mandoline {
+namespace mojo {
+namespace runner {
 
 namespace {
 
@@ -150,4 +151,5 @@
   proc_fd_.reset();
 }
 
-}  // namespace mandoline
+}  // namespace runner
+}  // namespace mojo
diff --git a/mojo/runner/linux_sandbox.h b/mojo/runner/host/linux_sandbox.h
similarity index 78%
rename from mojo/runner/linux_sandbox.h
rename to mojo/runner/host/linux_sandbox.h
index 4111cf58..088cf00 100644
--- a/mojo/runner/linux_sandbox.h
+++ b/mojo/runner/host/linux_sandbox.h
@@ -2,17 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MOJO_RUNNER_LINUX_SANDBOX_H_
-#define MOJO_RUNNER_LINUX_SANDBOX_H_
+#ifndef MOJO_RUNNER_HOST_LINUX_SANDBOX_H_
+#define MOJO_RUNNER_HOST_LINUX_SANDBOX_H_
 
 #include "base/files/scoped_file.h"
+#include "base/macros.h"
 #include "sandbox/linux/bpf_dsl/bpf_dsl.h"
 #include "sandbox/linux/bpf_dsl/policy.h"
 #include "sandbox/linux/syscall_broker/broker_process.h"
 
-namespace mandoline {
+namespace mojo {
+namespace runner {
 
-// Encapsulates all tasks related to raising the sandbox for mandoline.
+// Encapsulates all tasks related to raising the sandbox for mojo runner.
 class LinuxSandbox {
  public:
   explicit LinuxSandbox(
@@ -43,6 +45,7 @@
   DISALLOW_COPY_AND_ASSIGN(LinuxSandbox);
 };
 
-}  // namespace mandoline
+}  // namespace runner
+}  // namespace mojo
 
-#endif  // MOJO_RUNNER_LINUX_SANDBOX_H_
+#endif  // MOJO_RUNNER_HOST_LINUX_SANDBOX_H_
diff --git a/mojo/runner/native_application_support.cc b/mojo/runner/host/native_application_support.cc
similarity index 95%
rename from mojo/runner/native_application_support.cc
rename to mojo/runner/host/native_application_support.cc
index 0e46803..5b53744 100644
--- a/mojo/runner/native_application_support.cc
+++ b/mojo/runner/host/native_application_support.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/runner/native_application_support.h"
+#include "mojo/runner/host/native_application_support.h"
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -81,8 +81,8 @@
     SetThunks(MojoMakeGLES2ImplChromiumExtensionThunks,
               "MojoSetGLES2ImplChromiumExtensionThunks", app_library);
   }
-  // Unlike system thunks, we don't warn on a lack of GLES2 thunks because
-  // not everything is a visual app.
+// Unlike system thunks, we don't warn on a lack of GLES2 thunks because
+// not everything is a visual app.
 
 #if !defined(OS_WIN)
   // On Windows, initializing base::CommandLine with null parameters gets the
@@ -97,7 +97,7 @@
   if (init_command_line_args) {
     int argc = 0;
     base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
-    const char** argv = new const char* [cmd_line->argv().size()];
+    const char** argv = new const char*[cmd_line->argv().size()];
     for (auto& arg : cmd_line->argv())
       argv[argc++] = arg.c_str();
     init_command_line_args(argc, argv);
diff --git a/mojo/runner/native_application_support.h b/mojo/runner/host/native_application_support.h
similarity index 88%
rename from mojo/runner/native_application_support.h
rename to mojo/runner/host/native_application_support.h
index 5fbbea06..dca22de 100644
--- a/mojo/runner/native_application_support.h
+++ b/mojo/runner/host/native_application_support.h
@@ -2,12 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MOJO_RUNNER_NATIVE_APPLICATION_SUPPORT_H_
-#define MOJO_RUNNER_NATIVE_APPLICATION_SUPPORT_H_
+#ifndef MOJO_RUNNER_HOST_NATIVE_APPLICATION_SUPPORT_H_
+#define MOJO_RUNNER_HOST_NATIVE_APPLICATION_SUPPORT_H_
 
 #include "base/native_library.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/shell/native_runner.h"
 
 namespace base {
 class FilePath;
@@ -41,4 +40,4 @@
 }  // namespace runner
 }  // namespace mojo
 
-#endif  // MOJO_RUNNER_NATIVE_APPLICATION_SUPPORT_H_
+#endif  // MOJO_RUNNER_HOST_NATIVE_APPLICATION_SUPPORT_H_
diff --git a/mojo/runner/out_of_process_native_runner.cc b/mojo/runner/host/out_of_process_native_runner.cc
similarity index 91%
rename from mojo/runner/out_of_process_native_runner.cc
rename to mojo/runner/host/out_of_process_native_runner.cc
index f2a394e..0388c953 100644
--- a/mojo/runner/out_of_process_native_runner.cc
+++ b/mojo/runner/host/out_of_process_native_runner.cc
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/runner/out_of_process_native_runner.h"
+#include "mojo/runner/host/out_of_process_native_runner.h"
 
 #include "base/bind.h"
 #include "base/callback_helpers.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/task_runner.h"
-#include "mojo/runner/child_process_host.h"
-#include "mojo/runner/in_process_native_runner.h"
+#include "mojo/runner/host/child_process_host.h"
+#include "mojo/runner/host/in_process_native_runner.h"
 
 namespace mojo {
 namespace runner {
diff --git a/mojo/runner/out_of_process_native_runner.h b/mojo/runner/host/out_of_process_native_runner.h
similarity index 91%
rename from mojo/runner/out_of_process_native_runner.h
rename to mojo/runner/host/out_of_process_native_runner.h
index b4e2b92..6cec241 100644
--- a/mojo/runner/out_of_process_native_runner.h
+++ b/mojo/runner/host/out_of_process_native_runner.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MOJO_RUNNER_OUT_OF_PROCESS_NATIVE_RUNNER_H_
-#define MOJO_RUNNER_OUT_OF_PROCESS_NATIVE_RUNNER_H_
+#ifndef MOJO_RUNNER_HOST_OUT_OF_PROCESS_NATIVE_RUNNER_H_
+#define MOJO_RUNNER_HOST_OUT_OF_PROCESS_NATIVE_RUNNER_H_
 
 #include "base/callback.h"
 #include "base/files/file_path.h"
@@ -66,4 +66,4 @@
 }  // namespace runner
 }  // namespace mojo
 
-#endif  // MOJO_RUNNER_OUT_OF_PROCESS_NATIVE_RUNNER_H_
+#endif  // MOJO_RUNNER_HOST_OUT_OF_PROCESS_NATIVE_RUNNER_H_
diff --git a/mojo/runner/host/switches.cc b/mojo/runner/host/switches.cc
new file mode 100644
index 0000000..f2276138
--- /dev/null
+++ b/mojo/runner/host/switches.cc
@@ -0,0 +1,17 @@
+// Copyright 2015 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 "mojo/runner/host/switches.h"
+
+namespace switches {
+
+// Used internally by the main process to indicate that a new process should be
+// a child process. Takes the absolute path to the mojo application to load as
+// an argument. Not for user use.
+const char kChildProcess[] = "child-process";
+
+// Enables the sandbox on this process.
+const char kEnableSandbox[] = "enable-sandbox";
+
+}  // namespace switches
diff --git a/mojo/runner/host/switches.h b/mojo/runner/host/switches.h
new file mode 100644
index 0000000..54b767fe
--- /dev/null
+++ b/mojo/runner/host/switches.h
@@ -0,0 +1,17 @@
+// Copyright 2015 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 MOJO_RUNNER_HOST_SWITCHES_H_
+#define MOJO_RUNNER_HOST_SWITCHES_H_
+
+namespace switches {
+
+// All switches in alphabetical order. The switches should be documented
+// alongside the definition of their values in the .cc file.
+extern const char kChildProcess[];
+extern const char kEnableSandbox[];
+
+}  // namespace switches
+
+#endif  // MOJO_RUNNER_CHILD_SWITCHES_H_
diff --git a/mojo/runner/init.cc b/mojo/runner/init.cc
index 2c7d289..a5cc9e1a6 100644
--- a/mojo/runner/init.cc
+++ b/mojo/runner/init.cc
@@ -12,7 +12,7 @@
 #include "base/stl_util.h"
 #include "base/strings/string_split.h"
 #include "base/strings/utf_string_conversions.h"
-#include "mojo/runner/switches.h"
+#include "mojo/runner/host/switches.h"
 
 #if defined(OS_WIN)
 #include <windows.h>
diff --git a/mojo/runner/shell_test_main.cc b/mojo/runner/shell_test_main.cc
index 9c4d1c7e..0697bd81 100644
--- a/mojo/runner/shell_test_main.cc
+++ b/mojo/runner/shell_test_main.cc
@@ -2,29 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/at_exit.h"
 #include "base/bind.h"
-#include "base/command_line.h"
-#include "base/logging.h"
 #include "base/test/launcher/unit_test_launcher.h"
 #include "base/test/test_suite.h"
-#include "mojo/runner/child_process.h"
-#include "mojo/runner/switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 int main(int argc, char** argv) {
-  base::CommandLine::Init(argc, argv);
-  const base::CommandLine& command_line =
-      *base::CommandLine::ForCurrentProcess();
-
-  if (command_line.HasSwitch(switches::kChildProcess)) {
-    base::AtExitManager at_exit;
-
-    return mojo::runner::ChildProcessMain();
-  }
-
   base::TestSuite test_suite(argc, argv);
-
   return base::LaunchUnitTests(
       argc, argv,
       base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
diff --git a/mojo/runner/switches.cc b/mojo/runner/switches.cc
index 976ba4a..dfb7c88 100644
--- a/mojo/runner/switches.cc
+++ b/mojo/runner/switches.cc
@@ -6,18 +6,10 @@
 
 namespace switches {
 
-// Used internally by the main process to indicate that a new process should be
-// a child process. Takes the absolute path to the mojo application to load as
-// an argument. Not for user use.
-const char kChildProcess[] = "child-process";
-
 // Comma separated list like:
 // text/html,mojo:html_viewer,application/bravo,https://abarth.com/bravo
 const char kContentHandlers[] = "content-handlers";
 
-// Enables the sandbox on this process.
-const char kEnableSandbox[] = "enable-sandbox";
-
 // In multiprocess mode, force these apps to be loaded in the main process.
 // This is a comma-separated list of URLs. Example:
 // --force-in-process=mojo:native_viewport_service,mojo:network_service
diff --git a/mojo/runner/switches.h b/mojo/runner/switches.h
index aee2ac2..c5c38ae 100644
--- a/mojo/runner/switches.h
+++ b/mojo/runner/switches.h
@@ -10,9 +10,7 @@
 // All switches in alphabetical order. The switches should be documented
 // alongside the definition of their values in the .cc file.
 extern const char kApp[];
-extern const char kChildProcess[];
 extern const char kContentHandlers[];
-extern const char kEnableSandbox[];
 extern const char kForceInProcess[];
 extern const char kHelp[];
 extern const char kMapOrigin[];
diff --git a/mojo/services/network/url_loader_impl_apptest.cc b/mojo/services/network/url_loader_impl_apptest.cc
index f21d684..7bbbba6 100644
--- a/mojo/services/network/url_loader_impl_apptest.cc
+++ b/mojo/services/network/url_loader_impl_apptest.cc
@@ -60,18 +60,24 @@
 
   void NotifyReadComplete(int bytes_read) {
     if (bytes_read < 0) {
-      status_ = COMPLETED;
       NotifyDone(net::URLRequestStatus(
           net::URLRequestStatus::FromError(net::ERR_FAILED)));
       net::URLRequestJob::NotifyReadComplete(0);
-    } else if (bytes_read == 0) {
+      // Set this after calling ReadRawDataComplete since that ends up calling
+      // ReadRawData.
       status_ = COMPLETED;
+    } else if (bytes_read == 0) {
       NotifyDone(net::URLRequestStatus());
       net::URLRequestJob::NotifyReadComplete(bytes_read);
+      // Set this after calling ReadRawDataComplete since that ends up calling
+      // ReadRawData.
+      status_ = COMPLETED;
     } else {
-      status_ = STARTED;
       SetStatus(net::URLRequestStatus());
       net::URLRequestJob::NotifyReadComplete(bytes_read);
+      // Set this after calling ReadRawDataComplete since that ends up calling
+      // ReadRawData.
+      status_ = STARTED;
     }
   }
 
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 7963a0a..6d9c9bc 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -1208,21 +1208,6 @@
     ]
     jni_package = "net/test"
   }
-
-  _net_unittests_apk_assets_dir = "$root_out_dir/net_unittests_apk/assets"
-
-  copy_ex("copy_net_unittests_apk_assets") {
-    clear_dir = true
-    dest = _net_unittests_apk_assets_dir
-
-    if (v8_use_external_startup_data) {
-      renaming_sources = v8_external_startup_data_renaming_sources
-      renaming_destinations = v8_external_startup_data_renaming_destinations
-      deps = [
-        "//v8",
-      ]
-    }
-  }
 }
 
 if (is_android || is_linux) {
@@ -1616,7 +1601,7 @@
       "//net/android:net_javatests",
       "//net/android:net_java_test_support",
       "//net/android:net_unittests_apk_resources",
-      ":copy_net_unittests_apk_assets",
+      "//v8:v8_external_startup_data_assets",
     ]
     android_manifest = "//net/android/unittest_support/AndroidManifest.xml"
     sources -= [
@@ -1633,7 +1618,6 @@
     set_sources_assignment_filter([])
     sources += [ "base/address_tracker_linux_unittest.cc" ]
     set_sources_assignment_filter(sources_assignment_filter)
-    apk_asset_location = _net_unittests_apk_assets_dir
     isolate_file = "net_unittests.isolate"
   }
 
diff --git a/net/cert/internal/parse_certificate.cc b/net/cert/internal/parse_certificate.cc
index d2bc980..74222e8 100644
--- a/net/cert/internal/parse_certificate.cc
+++ b/net/cert/internal/parse_certificate.cc
@@ -4,6 +4,8 @@
 
 #include "net/cert/internal/parse_certificate.h"
 
+#include <utility>
+
 #include "net/der/input.h"
 #include "net/der/parse_values.h"
 #include "net/der/parser.h"
@@ -172,6 +174,17 @@
   return true;
 }
 
+// Returns true if every bit in |bits| is zero (including empty).
+WARN_UNUSED_RESULT bool BitStringIsAllZeros(const der::BitString& bits) {
+  // Note that it is OK to read from the unused bits, since BitString parsing
+  // guarantees they are all zero.
+  for (size_t i = 0; i < bits.bytes().Length(); ++i) {
+    if (bits.bytes().UnsafeData()[i] != 0)
+      return false;
+  }
+  return true;
+}
+
 }  // namespace
 
 ParsedTbsCertificate::ParsedTbsCertificate() {}
@@ -405,4 +418,186 @@
   return true;
 }
 
+der::Input KeyUsageOid() {
+  // From RFC 5280:
+  //
+  //     id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
+  //
+  // In dotted notation: 2.5.29.15
+  static const uint8_t oid[] = {0x55, 0x1d, 0x0f};
+  return der::Input(oid);
+}
+
+der::Input SubjectAltNameOid() {
+  // From RFC 5280:
+  //
+  //     id-ce-subjectAltName OBJECT IDENTIFIER ::=  { id-ce 17 }
+  //
+  // In dotted notation: 2.5.29.17
+  static const uint8_t oid[] = {0x55, 0x1d, 0x11};
+  return der::Input(oid);
+}
+
+der::Input BasicConstraintsOid() {
+  // From RFC 5280:
+  //
+  //     id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }
+  //
+  // In dotted notation: 2.5.29.19
+  static const uint8_t oid[] = {0x55, 0x1d, 0x13};
+  return der::Input(oid);
+}
+
+der::Input NameConstraintsOid() {
+  // From RFC 5280:
+  //
+  //     id-ce-nameConstraints OBJECT IDENTIFIER ::=  { id-ce 30 }
+  //
+  // In dotted notation: 2.5.29.30
+  static const uint8_t oid[] = {0x55, 0x1d, 0x1e};
+  return der::Input(oid);
+}
+
+der::Input CertificatePoliciesOid() {
+  // From RFC 5280:
+  //
+  //     id-ce-certificatePolicies OBJECT IDENTIFIER ::=  { id-ce 32 }
+  //
+  // In dotted notation: 2.5.29.32
+  static const uint8_t oid[] = {0x55, 0x1d, 0x20};
+  return der::Input(oid);
+}
+
+der::Input PolicyConstraintsOid() {
+  // From RFC 5280:
+  //
+  //     id-ce-policyConstraints OBJECT IDENTIFIER ::=  { id-ce 36 }
+  //
+  // In dotted notation: 2.5.29.36
+  static const uint8_t oid[] = {0x55, 0x1d, 0x24};
+  return der::Input(oid);
+}
+
+der::Input ExtKeyUsageOid() {
+  // From RFC 5280:
+  //
+  //     id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }
+  //
+  // In dotted notation: 2.5.29.37
+  static const uint8_t oid[] = {0x55, 0x1d, 0x25};
+  return der::Input(oid);
+}
+
+NET_EXPORT bool ParseExtensions(
+    const der::Input& extensions_tlv,
+    std::map<der::Input, ParsedExtension>* extensions) {
+  der::Parser parser(extensions_tlv);
+
+  //    Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+  der::Parser extensions_parser;
+  if (!parser.ReadSequence(&extensions_parser))
+    return false;
+
+  // The Extensions SEQUENCE must contains at least 1 element (otherwise it
+  // should have been omitted).
+  if (!extensions_parser.HasMore())
+    return false;
+
+  extensions->clear();
+
+  while (extensions_parser.HasMore()) {
+    ParsedExtension extension;
+
+    der::Input extension_tlv;
+    if (!extensions_parser.ReadRawTLV(&extension_tlv))
+      return false;
+
+    if (!ParseExtension(extension_tlv, &extension))
+      return false;
+
+    bool is_duplicate =
+        !extensions->insert(std::make_pair(extension.oid, extension)).second;
+
+    // RFC 5280 says that an extension should not appear more than once.
+    if (is_duplicate)
+      return false;
+  }
+
+  // By definition the input was a single Extensions sequence, so there
+  // shouldn't be unconsumed data.
+  if (parser.HasMore())
+    return false;
+
+  return true;
+}
+
+bool ParseBasicConstraints(const der::Input& basic_constraints_tlv,
+                           ParsedBasicConstraints* out) {
+  der::Parser parser(basic_constraints_tlv);
+
+  //    BasicConstraints ::= SEQUENCE {
+  der::Parser sequence_parser;
+  if (!parser.ReadSequence(&sequence_parser))
+    return false;
+
+  //         cA                      BOOLEAN DEFAULT FALSE,
+  out->is_ca = false;
+  bool has_ca;
+  der::Input ca;
+  if (!sequence_parser.ReadOptionalTag(der::kBool, &ca, &has_ca))
+    return false;
+  if (has_ca) {
+    if (!der::ParseBool(ca, &out->is_ca))
+      return false;
+    // TODO(eroman): Should reject if CA was set to false, since
+    // DER-encoding requires DEFAULT values be omitted. In
+    // practice however there are a lot of certificates that use
+    // the broken encoding.
+  }
+
+  //         pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
+  der::Input encoded_path_len;
+  if (!sequence_parser.ReadOptionalTag(der::kInteger, &encoded_path_len,
+                                       &out->has_path_len)) {
+    return false;
+  }
+  if (out->has_path_len) {
+    if (!der::ParseUint8(encoded_path_len, &out->path_len))
+      return false;
+  } else {
+    // Default initialize to 0 as a precaution.
+    out->path_len = 0;
+  }
+
+  // There shouldn't be any unconsumed data in the extension.
+  if (sequence_parser.HasMore())
+    return false;
+
+  // By definition the input was a single BasicConstraints sequence, so there
+  // shouldn't be unconsumed data.
+  if (parser.HasMore())
+    return false;
+
+  return true;
+}
+
+bool ParseKeyUsage(const der::Input& key_usage_tlv, der::BitString* key_usage) {
+  der::Parser parser(key_usage_tlv);
+  if (!parser.ReadBitString(key_usage))
+    return false;
+
+  // By definition the input was a single BIT STRING.
+  if (parser.HasMore())
+    return false;
+
+  // RFC 5280 section 4.2.1.3:
+  //
+  //     When the keyUsage extension appears in a certificate, at least
+  //     one of the bits MUST be set to 1.
+  if (BitStringIsAllZeros(*key_usage))
+    return false;
+
+  return true;
+}
+
 }  // namespace net
diff --git a/net/cert/internal/parse_certificate.h b/net/cert/internal/parse_certificate.h
index 7d2d826..75f7700 100644
--- a/net/cert/internal/parse_certificate.h
+++ b/net/cert/internal/parse_certificate.h
@@ -5,6 +5,8 @@
 #ifndef NET_CERT_INTERNAL_PARSE_CERTIFICATE_H_
 #define NET_CERT_INTERNAL_PARSE_CERTIFICATE_H_
 
+#include <map>
+
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "net/base/net_export.h"
@@ -245,6 +247,126 @@
 NET_EXPORT bool ParseExtension(const der::Input& extension_tlv,
                                ParsedExtension* out) WARN_UNUSED_RESULT;
 
+// From RFC 5280:
+//
+//     id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
+//
+// In dotted notation: 2.5.29.15
+NET_EXPORT der::Input KeyUsageOid();
+
+// From RFC 5280:
+//
+//     id-ce-subjectAltName OBJECT IDENTIFIER ::=  { id-ce 17 }
+//
+// In dotted notation: 2.5.29.17
+NET_EXPORT der::Input SubjectAltNameOid();
+
+// From RFC 5280:
+//
+//     id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }
+//
+// In dotted notation: 2.5.29.19
+NET_EXPORT der::Input BasicConstraintsOid();
+
+// From RFC 5280:
+//
+//     id-ce-nameConstraints OBJECT IDENTIFIER ::=  { id-ce 30 }
+//
+// In dotted notation: 2.5.29.30
+NET_EXPORT der::Input NameConstraintsOid();
+
+// From RFC 5280:
+//
+//     id-ce-certificatePolicies OBJECT IDENTIFIER ::=  { id-ce 32 }
+//
+// In dotted notation: 2.5.29.32
+NET_EXPORT der::Input CertificatePoliciesOid();
+
+// From RFC 5280:
+//
+//     id-ce-policyConstraints OBJECT IDENTIFIER ::=  { id-ce 36 }
+//
+// In dotted notation: 2.5.29.36
+NET_EXPORT der::Input PolicyConstraintsOid();
+
+// From RFC 5280:
+//
+//     id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 }
+//
+// In dotted notation: 2.5.29.37
+NET_EXPORT der::Input ExtKeyUsageOid();
+
+// Parses the Extensions sequence as defined by RFC 5280. Extensions are added
+// to the map |extensions| keyed by the OID. Parsing guarantees that each OID
+// is unique. Note that certificate verification must consume each extension
+// marked as critical.
+//
+// Returns true on success and fills |extensions|. The output will reference
+// bytes in |extensions_tlv|, so that data must be kept alive.
+// On failure |extensions| may be partially written to and should not be used.
+NET_EXPORT bool ParseExtensions(
+    const der::Input& extensions_tlv,
+    std::map<der::Input, ParsedExtension>* extensions) WARN_UNUSED_RESULT;
+
+struct ParsedBasicConstraints {
+  bool is_ca = false;
+  bool has_path_len = false;
+  uint8_t path_len = 0;
+};
+
+// Parses the BasicConstraints extension as defined by RFC 5280:
+//
+//    BasicConstraints ::= SEQUENCE {
+//         cA                      BOOLEAN DEFAULT FALSE,
+//         pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
+//
+// The maximum allowed value of pathLenConstraints will be whatever can fit
+// into a uint8_t.
+NET_EXPORT bool ParseBasicConstraints(const der::Input& basic_constraints_tlv,
+                                      ParsedBasicConstraints* out)
+    WARN_UNUSED_RESULT;
+
+// KeyUsageBit contains the index for a particular key usage. The index is
+// measured from the most significant bit of a bit string.
+//
+// From RFC 5280 section 4.2.1.3:
+//
+//     KeyUsage ::= BIT STRING {
+//          digitalSignature        (0),
+//          nonRepudiation          (1), -- recent editions of X.509 have
+//                               -- renamed this bit to contentCommitment
+//          keyEncipherment         (2),
+//          dataEncipherment        (3),
+//          keyAgreement            (4),
+//          keyCertSign             (5),
+//          cRLSign                 (6),
+//          encipherOnly            (7),
+//          decipherOnly            (8) }
+enum KeyUsageBit {
+  KEY_USAGE_BIT_DIGITAL_SIGNATURE = 0,
+  KEY_USAGE_BIT_NON_REPUDIATION = 1,
+  KEY_USAGE_BIT_KEY_ENCIPHERMENT = 2,
+  KEY_USAGE_BIT_DATA_ENCIPHERMENT = 3,
+  KEY_USAGE_BIT_KEY_AGREEMENT = 4,
+  KEY_USAGE_BIT_KEY_CERT_SIGN = 5,
+  KEY_USAGE_BIT_CRL_SIGN = 6,
+  KEY_USAGE_BIT_ENCIPHER_ONLY = 7,
+  KEY_USAGE_BIT_DECIPHER_ONLY = 8,
+};
+
+// Parses the KeyUsage extension as defined by RFC 5280. Returns true on
+// success, and |key_usage| will alias data in |key_usage_tlv|. On failure
+// returns false, and |key_usage| may have been modified.
+//
+// In addition to validating that key_usage_tlv is a BIT STRING, this does
+// additional KeyUsage specific validations such as requiring at least 1 bit to
+// be set.
+//
+// To test if a particular key usage is set, call, e.g.:
+//     key_usage->AssertsBit(KEY_USAGE_BIT_DIGITAL_SIGNATURE);
+NET_EXPORT bool ParseKeyUsage(const der::Input& key_usage_tlv,
+                              der::BitString* key_usage) WARN_UNUSED_RESULT;
+
 }  // namespace net
 
 #endif  // NET_CERT_INTERNAL_PARSE_CERTIFICATE_H_
diff --git a/net/cert/internal/parse_certificate_unittest.cc b/net/cert/internal/parse_certificate_unittest.cc
index 99312cd..727644c 100644
--- a/net/cert/internal/parse_certificate_unittest.cc
+++ b/net/cert/internal/parse_certificate_unittest.cc
@@ -391,6 +391,402 @@
       ParseExtensionFromFile("extension_critical_3.pem", &extension, &data));
 }
 
+// Runs a test for extensions parsing. The input file is a PEM file which
+// contains a DER-encoded Extensions sequence, as well as the expected value
+// for each contained extension.
+void EnsureParsingExtensionsSucceeds(
+    const std::string& file_name,
+    std::map<der::Input, ParsedExtension>* extensions,
+    std::string* data) {
+  const PemBlockMapping mappings[] = {
+      // Test Input.
+      {"EXTENSIONS", data},
+  };
+
+  ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name), mappings));
+  ASSERT_TRUE(ParseExtensions(InputFromString(data), extensions));
+}
+
+// Runs a test that verifies extensions parsing fails. The input file is a PEM
+// file which contains a DER-encoded Extensions sequence.
+void EnsureParsingExtensionsFails(const std::string& file_name) {
+  std::string data;
+
+  const PemBlockMapping mappings[] = {
+      {"EXTENSIONS", &data},
+  };
+
+  std::map<der::Input, ParsedExtension> extensions;
+  ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name), mappings));
+  ASSERT_FALSE(ParseExtensions(InputFromString(&data), &extensions));
+}
+
+// Parses an Extensions that is an empty sequence.
+TEST(ParseExtensionsTest, EmptySequence) {
+  EnsureParsingExtensionsFails("extensions_empty_sequence.pem");
+}
+
+// Parses an Extensions that is not a sequence.
+TEST(ParseExtensionsTest, NotSequence) {
+  EnsureParsingExtensionsFails("extensions_not_sequence.pem");
+}
+
+// Parses an Extensions that has data after the sequence.
+TEST(ParseExtensionsTest, DataAfterSequence) {
+  EnsureParsingExtensionsFails("extensions_data_after_sequence.pem");
+}
+
+// Parses an Extensions that contains duplicated key usages.
+TEST(ParseExtensionsTest, DuplicateKeyUsage) {
+  EnsureParsingExtensionsFails("extensions_duplicate_key_usage.pem");
+}
+
+// Parses an Extensions that contains an unknown critical extension.
+TEST(ParseExtensionsTest, UnknownCritical) {
+  std::string data;
+  std::map<der::Input, ParsedExtension> extensions;
+  EnsureParsingExtensionsSucceeds("extensions_unknown_critical.pem",
+                                  &extensions, &data);
+
+  ASSERT_EQ(1u, extensions.size());
+  // This OID corresponds with
+  // 1.2.840.113554.4.1.72585.0 (https://davidben.net/oid)
+  const uint8_t oid[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12,
+                         0x04, 0x01, 0x84, 0xb7, 0x09, 0x00};
+
+  auto iter = extensions.find(der::Input(oid));
+  ASSERT_TRUE(iter != extensions.end());
+  EXPECT_TRUE(iter->second.critical);
+  EXPECT_EQ(4u, iter->second.value.Length());
+}
+
+// Parses an Extensions that contains an unknown non-critical extension.
+TEST(ParseExtensionsTest, UnknownNonCritical) {
+  std::string data;
+  std::map<der::Input, ParsedExtension> extensions;
+  EnsureParsingExtensionsSucceeds("extensions_unknown_non_critical.pem",
+                                  &extensions, &data);
+
+  ASSERT_EQ(1u, extensions.size());
+  // This OID corresponds with
+  // 1.2.840.113554.4.1.72585.0 (https://davidben.net/oid)
+  const uint8_t oid[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12,
+                         0x04, 0x01, 0x84, 0xb7, 0x09, 0x00};
+
+  auto iter = extensions.find(der::Input(oid));
+  ASSERT_TRUE(iter != extensions.end());
+  EXPECT_FALSE(iter->second.critical);
+  EXPECT_EQ(4u, iter->second.value.Length());
+}
+
+// Parses an Extensions that contains a basic constraints.
+TEST(ParseExtensionsTest, BasicConstraints) {
+  std::string data;
+  std::map<der::Input, ParsedExtension> extensions;
+  EnsureParsingExtensionsSucceeds("extensions_basic_constraints.pem",
+                                  &extensions, &data);
+
+  ASSERT_EQ(1u, extensions.size());
+
+  auto iter = extensions.find(BasicConstraintsOid());
+  ASSERT_TRUE(iter != extensions.end());
+  EXPECT_TRUE(iter->second.critical);
+  EXPECT_EQ(2u, iter->second.value.Length());
+}
+
+// Parses an Extensions that contains an extended key usages.
+TEST(ParseExtensionsTest, ExtendedKeyUsage) {
+  std::string data;
+  std::map<der::Input, ParsedExtension> extensions;
+  EnsureParsingExtensionsSucceeds("extensions_extended_key_usage.pem",
+                                  &extensions, &data);
+
+  ASSERT_EQ(1u, extensions.size());
+
+  auto iter = extensions.find(ExtKeyUsageOid());
+  ASSERT_TRUE(iter != extensions.end());
+  EXPECT_FALSE(iter->second.critical);
+  EXPECT_EQ(45u, iter->second.value.Length());
+}
+
+// Parses an Extensions that contains a key usage.
+TEST(ParseExtensionsTest, KeyUsage) {
+  std::string data;
+  std::map<der::Input, ParsedExtension> extensions;
+  EnsureParsingExtensionsSucceeds("extensions_key_usage.pem", &extensions,
+                                  &data);
+
+  ASSERT_EQ(1u, extensions.size());
+
+  auto iter = extensions.find(KeyUsageOid());
+  ASSERT_TRUE(iter != extensions.end());
+  EXPECT_TRUE(iter->second.critical);
+  EXPECT_EQ(4u, iter->second.value.Length());
+}
+
+// Parses an Extensions that contains a policies extension.
+TEST(ParseExtensionsTest, Policies) {
+  std::string data;
+  std::map<der::Input, ParsedExtension> extensions;
+  EnsureParsingExtensionsSucceeds("extensions_policies.pem", &extensions,
+                                  &data);
+
+  ASSERT_EQ(1u, extensions.size());
+
+  auto iter = extensions.find(CertificatePoliciesOid());
+  ASSERT_TRUE(iter != extensions.end());
+  EXPECT_FALSE(iter->second.critical);
+  EXPECT_EQ(95u, iter->second.value.Length());
+}
+
+// Parses an Extensions that contains a subjectaltname extension.
+TEST(ParseExtensionsTest, SubjectAltName) {
+  std::string data;
+  std::map<der::Input, ParsedExtension> extensions;
+  EnsureParsingExtensionsSucceeds("extensions_subject_alt_name.pem",
+                                  &extensions, &data);
+
+  ASSERT_EQ(1u, extensions.size());
+
+  auto iter = extensions.find(SubjectAltNameOid());
+  ASSERT_TRUE(iter != extensions.end());
+  EXPECT_FALSE(iter->second.critical);
+  EXPECT_EQ(23u, iter->second.value.Length());
+}
+
+// Parses an Extensions that contains multiple extensions, sourced from a
+// real-world certificate.
+TEST(ParseExtensionsTest, Real) {
+  std::string data;
+  std::map<der::Input, ParsedExtension> extensions;
+  EnsureParsingExtensionsSucceeds("extensions_real.pem", &extensions, &data);
+
+  ASSERT_EQ(7u, extensions.size());
+
+  auto iter = extensions.find(KeyUsageOid());
+  ASSERT_TRUE(iter != extensions.end());
+  EXPECT_TRUE(iter->second.critical);
+  EXPECT_EQ(4u, iter->second.value.Length());
+
+  iter = extensions.find(BasicConstraintsOid());
+  ASSERT_TRUE(iter != extensions.end());
+  EXPECT_TRUE(iter->second.critical);
+  EXPECT_EQ(8u, iter->second.value.Length());
+
+  iter = extensions.find(CertificatePoliciesOid());
+  ASSERT_TRUE(iter != extensions.end());
+  EXPECT_FALSE(iter->second.critical);
+  EXPECT_EQ(16u, iter->second.value.Length());
+
+  // TODO(eroman): Verify the other 4 extensions' values.
+}
+
+// Reads a PEM file containing a block "BASIC CONSTRAINTS". This input will
+// be passed to ParseExtension, and the results filled in |out|.
+bool ParseBasicConstraintsFromFile(const std::string& file_name,
+                                   ParsedBasicConstraints* out) {
+  std::string data;
+  const PemBlockMapping mappings[] = {
+      {"BASIC CONSTRAINTS", &data},
+  };
+
+  EXPECT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name), mappings));
+  return ParseBasicConstraints(InputFromString(&data), out);
+}
+
+// Parses a BasicConstraints with no CA or pathlen.
+TEST(ParseBasicConstraintsTest, NotCa) {
+  ParsedBasicConstraints constraints;
+  ASSERT_TRUE(ParseBasicConstraintsFromFile("basic_constraints_not_ca.pem",
+                                            &constraints));
+  EXPECT_FALSE(constraints.is_ca);
+  EXPECT_FALSE(constraints.has_path_len);
+}
+
+// Parses a BasicConstraints with CA but no pathlen.
+TEST(ParseBasicConstraintsTest, CaNoPath) {
+  ParsedBasicConstraints constraints;
+  ASSERT_TRUE(ParseBasicConstraintsFromFile("basic_constraints_ca_no_path.pem",
+                                            &constraints));
+  EXPECT_TRUE(constraints.is_ca);
+  EXPECT_FALSE(constraints.has_path_len);
+}
+
+// Parses a BasicConstraints with CA and pathlen of 9.
+TEST(ParseBasicConstraintsTest, CaPath9) {
+  ParsedBasicConstraints constraints;
+  ASSERT_TRUE(ParseBasicConstraintsFromFile("basic_constraints_ca_path_9.pem",
+                                            &constraints));
+  EXPECT_TRUE(constraints.is_ca);
+  EXPECT_TRUE(constraints.has_path_len);
+  EXPECT_EQ(9u, constraints.path_len);
+}
+
+// Parses a BasicConstraints with CA and pathlen of 255 (largest allowed size).
+TEST(ParseBasicConstraintsTest, Pathlen255) {
+  ParsedBasicConstraints constraints;
+  ASSERT_TRUE(ParseBasicConstraintsFromFile("basic_constraints_pathlen_255.pem",
+                                            &constraints));
+  EXPECT_TRUE(constraints.is_ca);
+  EXPECT_TRUE(constraints.has_path_len);
+  EXPECT_EQ(255, constraints.path_len);
+}
+
+// Parses a BasicConstraints with CA and pathlen of 256 (too large).
+TEST(ParseBasicConstraintsTest, Pathlen256) {
+  ParsedBasicConstraints constraints;
+  ASSERT_FALSE(ParseBasicConstraintsFromFile(
+      "basic_constraints_pathlen_256.pem", &constraints));
+}
+
+// Parses a BasicConstraints with CA and a negative pathlen.
+TEST(ParseBasicConstraintsTest, NegativePath) {
+  ParsedBasicConstraints constraints;
+  ASSERT_FALSE(ParseBasicConstraintsFromFile(
+      "basic_constraints_negative_path.pem", &constraints));
+}
+
+// Parses a BasicConstraints with CA and pathlen that is very large (and
+// couldn't fit in a 64-bit integer).
+TEST(ParseBasicConstraintsTest, PathTooLarge) {
+  ParsedBasicConstraints constraints;
+  ASSERT_FALSE(ParseBasicConstraintsFromFile(
+      "basic_constraints_path_too_large.pem", &constraints));
+}
+
+// Parses a BasicConstraints with CA explicitly set to false. This violates
+// DER-encoding rules, however is commonly used, so it is accepted.
+TEST(ParseBasicConstraintsTest, CaFalse) {
+  ParsedBasicConstraints constraints;
+  ASSERT_TRUE(ParseBasicConstraintsFromFile("basic_constraints_ca_false.pem",
+                                            &constraints));
+  EXPECT_FALSE(constraints.is_ca);
+  EXPECT_FALSE(constraints.has_path_len);
+}
+
+// Parses a BasicConstraints with CA set to true and an unexpected NULL at
+// the end.
+TEST(ParseBasicConstraintsTest, UnconsumedData) {
+  ParsedBasicConstraints constraints;
+  ASSERT_FALSE(ParseBasicConstraintsFromFile(
+      "basic_constraints_unconsumed_data.pem", &constraints));
+}
+
+// Parses a BasicConstraints with CA omitted (false), but with a pathlen of 1.
+// This is valid DER for the ASN.1, however is not valid when interpreting the
+// BasicConstraints at a higher level.
+TEST(ParseBasicConstraintsTest, PathLenButNotCa) {
+  ParsedBasicConstraints constraints;
+  ASSERT_TRUE(ParseBasicConstraintsFromFile(
+      "basic_constraints_pathlen_not_ca.pem", &constraints));
+  EXPECT_FALSE(constraints.is_ca);
+  EXPECT_TRUE(constraints.has_path_len);
+  EXPECT_EQ(1u, constraints.path_len);
+}
+
+// Parses a KeyUsage with a single 0 bit.
+TEST(ParseKeyUsageTest, OneBitAllZeros) {
+  const uint8_t der[] = {
+      0x03, 0x02,  // BIT STRING
+      0x07,        // Number of unused bits
+      0x00,        // bits
+  };
+
+  der::BitString key_usage;
+  ASSERT_FALSE(ParseKeyUsage(der::Input(der), &key_usage));
+}
+
+// Parses a KeyUsage with 32 bits that are all 0.
+TEST(ParseKeyUsageTest, 32BitsAllZeros) {
+  const uint8_t der[] = {
+      0x03, 0x05,  // BIT STRING
+      0x00,        // Number of unused bits
+      0x00, 0x00, 0x00, 0x00,
+  };
+
+  der::BitString key_usage;
+  ASSERT_FALSE(ParseKeyUsage(der::Input(der), &key_usage));
+}
+
+// Parses a KeyUsage with 32 bits, one of which is 1 (but not in recognized
+// set).
+TEST(ParseKeyUsageTest, 32BitsOneSet) {
+  const uint8_t der[] = {
+      0x03, 0x05,  // BIT STRING
+      0x00,        // Number of unused bits
+      0x00, 0x00, 0x00, 0x02,
+  };
+
+  der::BitString key_usage;
+  ASSERT_TRUE(ParseKeyUsage(der::Input(der), &key_usage));
+
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DIGITAL_SIGNATURE));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_NON_REPUDIATION));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_ENCIPHERMENT));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DATA_ENCIPHERMENT));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_AGREEMENT));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_CRL_SIGN));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_ENCIPHER_ONLY));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DECIPHER_ONLY));
+}
+
+// Parses a KeyUsage containing bit string 101.
+TEST(ParseKeyUsageTest, ThreeBits) {
+  const uint8_t der[] = {
+      0x03, 0x02,  // BIT STRING
+      0x05,        // Number of unused bits
+      0xA0,        // bits
+  };
+
+  der::BitString key_usage;
+  ASSERT_TRUE(ParseKeyUsage(der::Input(der), &key_usage));
+
+  EXPECT_TRUE(key_usage.AssertsBit(KEY_USAGE_BIT_DIGITAL_SIGNATURE));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_NON_REPUDIATION));
+  EXPECT_TRUE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_ENCIPHERMENT));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DATA_ENCIPHERMENT));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_AGREEMENT));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_CRL_SIGN));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_ENCIPHER_ONLY));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DECIPHER_ONLY));
+}
+
+// Parses a KeyUsage containing DECIPHER_ONLY, which is the
+// only bit that doesn't fit in the first byte.
+TEST(ParseKeyUsageTest, DecipherOnly) {
+  const uint8_t der[] = {
+      0x03, 0x03,  // BIT STRING
+      0x07,        // Number of unused bits
+      0x00, 0x80,  // bits
+  };
+
+  der::BitString key_usage;
+  ASSERT_TRUE(ParseKeyUsage(der::Input(der), &key_usage));
+
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DIGITAL_SIGNATURE));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_NON_REPUDIATION));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_ENCIPHERMENT));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_DATA_ENCIPHERMENT));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_AGREEMENT));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_KEY_CERT_SIGN));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_CRL_SIGN));
+  EXPECT_FALSE(key_usage.AssertsBit(KEY_USAGE_BIT_ENCIPHER_ONLY));
+  EXPECT_TRUE(key_usage.AssertsBit(KEY_USAGE_BIT_DECIPHER_ONLY));
+}
+
+// Parses an empty KeyUsage.
+TEST(ParseKeyUsageTest, Empty) {
+  const uint8_t der[] = {
+      0x03, 0x01,  // BIT STRING
+      0x00,        // Number of unused bits
+  };
+
+  der::BitString key_usage;
+  ASSERT_FALSE(ParseKeyUsage(der::Input(der), &key_usage));
+}
+
 }  // namespace
 
 }  // namespace net
diff --git a/net/data/parse_certificate_unittest/basic_constraints_ca_false.pem b/net/data/parse_certificate_unittest/basic_constraints_ca_false.pem
new file mode 100644
index 0000000..9acb44bc
--- /dev/null
+++ b/net/data/parse_certificate_unittest/basic_constraints_ca_false.pem
@@ -0,0 +1,7 @@
+$ openssl asn1parse -i < [BASIC CONSTRAINTS]
+    0:d=0  hl=2 l=   3 cons: SEQUENCE          
+    2:d=1  hl=2 l=   1 prim:  BOOLEAN           :0
+-----BEGIN BASIC CONSTRAINTS-----
+MAMBAQA=
+-----END BASIC CONSTRAINTS-----
+
diff --git a/net/data/parse_certificate_unittest/basic_constraints_ca_no_path.pem b/net/data/parse_certificate_unittest/basic_constraints_ca_no_path.pem
new file mode 100644
index 0000000..7d25c801
--- /dev/null
+++ b/net/data/parse_certificate_unittest/basic_constraints_ca_no_path.pem
@@ -0,0 +1,7 @@
+$ openssl asn1parse -i < [BASIC CONSTRAINTS]
+    0:d=0  hl=2 l=   3 cons: SEQUENCE          
+    2:d=1  hl=2 l=   1 prim:  BOOLEAN           :255
+-----BEGIN BASIC CONSTRAINTS-----
+MAMBAf8=
+-----END BASIC CONSTRAINTS-----
+
diff --git a/net/data/parse_certificate_unittest/basic_constraints_ca_path_9.pem b/net/data/parse_certificate_unittest/basic_constraints_ca_path_9.pem
new file mode 100644
index 0000000..7bb05d2
--- /dev/null
+++ b/net/data/parse_certificate_unittest/basic_constraints_ca_path_9.pem
@@ -0,0 +1,8 @@
+$ openssl asn1parse -i < [BASIC CONSTRAINTS]
+    0:d=0  hl=2 l=   6 cons: SEQUENCE          
+    2:d=1  hl=2 l=   1 prim:  BOOLEAN           :255
+    5:d=1  hl=2 l=   1 prim:  INTEGER           :09
+-----BEGIN BASIC CONSTRAINTS-----
+MAYBAf8CAQk=
+-----END BASIC CONSTRAINTS-----
+
diff --git a/net/data/parse_certificate_unittest/basic_constraints_negative_path.pem b/net/data/parse_certificate_unittest/basic_constraints_negative_path.pem
new file mode 100644
index 0000000..cc2ef3b
--- /dev/null
+++ b/net/data/parse_certificate_unittest/basic_constraints_negative_path.pem
@@ -0,0 +1,8 @@
+$ openssl asn1parse -i < [BASIC CONSTRAINTS]
+    0:d=0  hl=2 l=   6 cons: SEQUENCE          
+    2:d=1  hl=2 l=   1 prim:  BOOLEAN           :255
+    5:d=1  hl=2 l=   1 prim:  INTEGER           :-01
+-----BEGIN BASIC CONSTRAINTS-----
+MAYBAf8CAf8=
+-----END BASIC CONSTRAINTS-----
+
diff --git a/net/data/parse_certificate_unittest/basic_constraints_not_ca.pem b/net/data/parse_certificate_unittest/basic_constraints_not_ca.pem
new file mode 100644
index 0000000..15ad4162
--- /dev/null
+++ b/net/data/parse_certificate_unittest/basic_constraints_not_ca.pem
@@ -0,0 +1,6 @@
+$ openssl asn1parse -i < [BASIC CONSTRAINTS]
+    0:d=0  hl=2 l=   0 cons: SEQUENCE          
+-----BEGIN BASIC CONSTRAINTS-----
+MAA=
+-----END BASIC CONSTRAINTS-----
+
diff --git a/net/data/parse_certificate_unittest/basic_constraints_path_too_large.pem b/net/data/parse_certificate_unittest/basic_constraints_path_too_large.pem
new file mode 100644
index 0000000..dd986d1
--- /dev/null
+++ b/net/data/parse_certificate_unittest/basic_constraints_path_too_large.pem
@@ -0,0 +1,8 @@
+$ openssl asn1parse -i < [BASIC CONSTRAINTS]
+    0:d=0  hl=2 l=  29 cons: SEQUENCE          
+    2:d=1  hl=2 l=   1 prim:  BOOLEAN           :255
+    5:d=1  hl=2 l=  24 prim:  INTEGER           :0FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+-----BEGIN BASIC CONSTRAINTS-----
+MB0BAf8CGA///////////////////////////////w==
+-----END BASIC CONSTRAINTS-----
+
diff --git a/net/data/parse_certificate_unittest/basic_constraints_pathlen_255.pem b/net/data/parse_certificate_unittest/basic_constraints_pathlen_255.pem
new file mode 100644
index 0000000..b97e27415
--- /dev/null
+++ b/net/data/parse_certificate_unittest/basic_constraints_pathlen_255.pem
@@ -0,0 +1,8 @@
+$ openssl asn1parse -i < [BASIC CONSTRAINTS]
+    0:d=0  hl=2 l=   7 cons: SEQUENCE          
+    2:d=1  hl=2 l=   1 prim:  BOOLEAN           :255
+    5:d=1  hl=2 l=   2 prim:  INTEGER           :FF
+-----BEGIN BASIC CONSTRAINTS-----
+MAcBAf8CAgD/
+-----END BASIC CONSTRAINTS-----
+
diff --git a/net/data/parse_certificate_unittest/basic_constraints_pathlen_256.pem b/net/data/parse_certificate_unittest/basic_constraints_pathlen_256.pem
new file mode 100644
index 0000000..23c2101
--- /dev/null
+++ b/net/data/parse_certificate_unittest/basic_constraints_pathlen_256.pem
@@ -0,0 +1,8 @@
+$ openssl asn1parse -i < [BASIC CONSTRAINTS]
+    0:d=0  hl=2 l=   7 cons: SEQUENCE          
+    2:d=1  hl=2 l=   1 prim:  BOOLEAN           :255
+    5:d=1  hl=2 l=   2 prim:  INTEGER           :0100
+-----BEGIN BASIC CONSTRAINTS-----
+MAcBAf8CAgEA
+-----END BASIC CONSTRAINTS-----
+
diff --git a/net/data/parse_certificate_unittest/basic_constraints_pathlen_not_ca.pem b/net/data/parse_certificate_unittest/basic_constraints_pathlen_not_ca.pem
new file mode 100644
index 0000000..f462f1c54
--- /dev/null
+++ b/net/data/parse_certificate_unittest/basic_constraints_pathlen_not_ca.pem
@@ -0,0 +1,7 @@
+$ openssl asn1parse -i < [BASIC CONSTRAINTS]
+    0:d=0  hl=2 l=   3 cons: SEQUENCE          
+    2:d=1  hl=2 l=   1 prim:  INTEGER           :01
+-----BEGIN BASIC CONSTRAINTS-----
+MAMCAQE=
+-----END BASIC CONSTRAINTS-----
+
diff --git a/net/data/parse_certificate_unittest/basic_constraints_unconsumed_data.pem b/net/data/parse_certificate_unittest/basic_constraints_unconsumed_data.pem
new file mode 100644
index 0000000..b31bb58
--- /dev/null
+++ b/net/data/parse_certificate_unittest/basic_constraints_unconsumed_data.pem
@@ -0,0 +1,7 @@
+$ openssl asn1parse -i < [BASIC CONSTRAINTS]
+    0:d=0  hl=2 l=   2 cons: SEQUENCE          
+    2:d=1  hl=2 l=   0 prim:  NULL              
+-----BEGIN BASIC CONSTRAINTS-----
+MAIFAA==
+-----END BASIC CONSTRAINTS-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_basic_constraints.pem b/net/data/parse_certificate_unittest/extensions_basic_constraints.pem
new file mode 100644
index 0000000..211cef0
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_basic_constraints.pem
@@ -0,0 +1,16 @@
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=2 l=  14 cons: SEQUENCE          
+    2:d=1  hl=2 l=  12 cons:  SEQUENCE          
+    4:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Basic Constraints
+    9:d=2  hl=2 l=   1 prim:   BOOLEAN           :255
+   12:d=2  hl=2 l=   2 prim:   OCTET STRING      [HEX DUMP]:3000
+-----BEGIN EXTENSIONS-----
+MA4wDAYDVR0TAQH/BAIwAA==
+-----END EXTENSIONS-----
+
+$ openssl asn1parse -i < [BASIC CONSTRAINTS]
+    0:d=0  hl=2 l=   0 cons: SEQUENCE          
+-----BEGIN BASIC CONSTRAINTS-----
+MAA=
+-----END BASIC CONSTRAINTS-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_data_after_sequence.pem b/net/data/parse_certificate_unittest/extensions_data_after_sequence.pem
new file mode 100644
index 0000000..5bf26ac
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_data_after_sequence.pem
@@ -0,0 +1,11 @@
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=2 l=  18 cons: SEQUENCE          
+    2:d=1  hl=2 l=  14 cons:  SEQUENCE          
+    4:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Key Usage
+    9:d=2  hl=2 l=   1 prim:   BOOLEAN           :255
+   12:d=2  hl=2 l=   4 prim:   OCTET STRING      [HEX DUMP]:030203B8
+   18:d=1  hl=2 l=   0 prim:  NULL              
+-----BEGIN EXTENSIONS-----
+MBIwDgYDVR0PAQH/BAQDAgO4BQA=
+-----END EXTENSIONS-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_duplicate_key_usage.pem b/net/data/parse_certificate_unittest/extensions_duplicate_key_usage.pem
new file mode 100644
index 0000000..c263384
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_duplicate_key_usage.pem
@@ -0,0 +1,14 @@
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=2 l=  32 cons: SEQUENCE          
+    2:d=1  hl=2 l=  14 cons:  SEQUENCE          
+    4:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Key Usage
+    9:d=2  hl=2 l=   1 prim:   BOOLEAN           :255
+   12:d=2  hl=2 l=   4 prim:   OCTET STRING      [HEX DUMP]:030203B8
+   18:d=1  hl=2 l=  14 cons:  SEQUENCE          
+   20:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Key Usage
+   25:d=2  hl=2 l=   1 prim:   BOOLEAN           :255
+   28:d=2  hl=2 l=   4 prim:   OCTET STRING      [HEX DUMP]:030203B8
+-----BEGIN EXTENSIONS-----
+MCAwDgYDVR0PAQH/BAQDAgO4MA4GA1UdDwEB/wQEAwIDuA==
+-----END EXTENSIONS-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_empty_sequence.pem b/net/data/parse_certificate_unittest/extensions_empty_sequence.pem
new file mode 100644
index 0000000..d3f1a73d
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_empty_sequence.pem
@@ -0,0 +1,6 @@
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=2 l=   0 cons: SEQUENCE          
+-----BEGIN EXTENSIONS-----
+MAA=
+-----END EXTENSIONS-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_extended_key_usage.pem b/net/data/parse_certificate_unittest/extensions_extended_key_usage.pem
new file mode 100644
index 0000000..9cda6e21
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_extended_key_usage.pem
@@ -0,0 +1,20 @@
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=2 l=  54 cons: SEQUENCE          
+    2:d=1  hl=2 l=  52 cons:  SEQUENCE          
+    4:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Extended Key Usage
+    9:d=2  hl=2 l=  45 prim:   OCTET STRING      [HEX DUMP]:302B06082B0601050507030106082B06010505070302060A2B0601040182370A030306096086480186F8420401
+-----BEGIN EXTENSIONS-----
+MDYwNAYDVR0lBC0wKwYIKwYBBQUHAwEGCCsGAQUFBwMCBgorBgEEAYI3CgMDBglghkgBhvhCBAE
+=
+-----END EXTENSIONS-----
+
+$ openssl asn1parse -i < [EXTENDED KEY USAGE]
+    0:d=0  hl=2 l=  43 cons: SEQUENCE          
+    2:d=1  hl=2 l=   8 prim:  OBJECT            :TLS Web Server Authentication
+   12:d=1  hl=2 l=   8 prim:  OBJECT            :TLS Web Client Authentication
+   22:d=1  hl=2 l=  10 prim:  OBJECT            :Microsoft Server Gated Crypto
+   34:d=1  hl=2 l=   9 prim:  OBJECT            :Netscape Server Gated Crypto
+-----BEGIN EXTENDED KEY USAGE-----
+MCsGCCsGAQUFBwMBBggrBgEFBQcDAgYKKwYBBAGCNwoDAwYJYIZIAYb4QgQB
+-----END EXTENDED KEY USAGE-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_key_usage.pem b/net/data/parse_certificate_unittest/extensions_key_usage.pem
new file mode 100644
index 0000000..1b56edd
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_key_usage.pem
@@ -0,0 +1,16 @@
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=2 l=  16 cons: SEQUENCE          
+    2:d=1  hl=2 l=  14 cons:  SEQUENCE          
+    4:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Key Usage
+    9:d=2  hl=2 l=   1 prim:   BOOLEAN           :255
+   12:d=2  hl=2 l=   4 prim:   OCTET STRING      [HEX DUMP]:030205A0
+-----BEGIN EXTENSIONS-----
+MBAwDgYDVR0PAQH/BAQDAgWg
+-----END EXTENSIONS-----
+
+$ openssl asn1parse -i < [KEY USAGE]
+    0:d=0  hl=2 l=   2 prim: BIT STRING        
+-----BEGIN KEY USAGE-----
+AwIFoA==
+-----END KEY USAGE-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_not_sequence.pem b/net/data/parse_certificate_unittest/extensions_not_sequence.pem
new file mode 100644
index 0000000..f8cb11b
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_not_sequence.pem
@@ -0,0 +1,6 @@
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=2 l=   0 prim: NULL              
+-----BEGIN EXTENSIONS-----
+BQA=
+-----END EXTENSIONS-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_policies.pem b/net/data/parse_certificate_unittest/extensions_policies.pem
new file mode 100644
index 0000000..79a1c90
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_policies.pem
@@ -0,0 +1,25 @@
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=2 l= 104 cons: SEQUENCE          
+    2:d=1  hl=2 l= 102 cons:  SEQUENCE          
+    4:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Certificate Policies
+    9:d=2  hl=2 l=  95 prim:   OCTET STRING      [HEX DUMP]:305D304D060A2A83088C9C1E01020201303F303D06082B06010505070201163168747470733A2F2F7265706F312E7365636F6D74727573742E6E65742F73706370702F6370732F696E6465782E68746D6C300C060A2A83088C9B1B64870501
+-----BEGIN EXTENSIONS-----
+MGgwZgYDVR0gBF8wXTBNBgoqgwiMnB4BAgIBMD8wPQYIKwYBBQUHAgEWMWh0dHBzOi8vcmVwbzE
+uc2Vjb210cnVzdC5uZXQvc3BjcHAvY3BzL2luZGV4Lmh0bWwwDAYKKoMIjJsbZIcFAQ==
+-----END EXTENSIONS-----
+
+$ openssl asn1parse -i < [POLICIES]
+    0:d=0  hl=2 l=  93 cons: SEQUENCE          
+    2:d=1  hl=2 l=  77 cons:  SEQUENCE          
+    4:d=2  hl=2 l=  10 prim:   OBJECT            :1.2.392.200222.1.2.2.1
+   16:d=2  hl=2 l=  63 cons:   SEQUENCE          
+   18:d=3  hl=2 l=  61 cons:    SEQUENCE          
+   20:d=4  hl=2 l=   8 prim:     OBJECT            :Policy Qualifier CPS
+   30:d=4  hl=2 l=  49 prim:     IA5STRING         :https://repo1.secomtrust.net/spcpp/cps/index.html
+   81:d=1  hl=2 l=  12 cons:  SEQUENCE          
+   83:d=2  hl=2 l=  10 prim:   OBJECT            :1.2.392.200091.100.901.1
+-----BEGIN POLICIES-----
+MF0wTQYKKoMIjJweAQICATA/MD0GCCsGAQUFBwIBFjFodHRwczovL3JlcG8xLnNlY29tdHJ1c3Q
+ubmV0L3NwY3BwL2Nwcy9pbmRleC5odG1sMAwGCiqDCIybG2SHBQE=
+-----END POLICIES-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_real.pem b/net/data/parse_certificate_unittest/extensions_real.pem
new file mode 100644
index 0000000..5ece71c4
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_real.pem
@@ -0,0 +1,35 @@
+A real world extensions sequence (taken from Google's GAI2).
+
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=3 l= 228 cons: SEQUENCE          
+    3:d=1  hl=2 l=  31 cons:  SEQUENCE          
+    5:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Authority Key Identifier
+   10:d=2  hl=2 l=  24 prim:   OCTET STRING      [HEX DUMP]:30168014C07A98688D89FBAB05640C117DAA7D65B8CACC4E
+   36:d=1  hl=2 l=  29 cons:  SEQUENCE          
+   38:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Subject Key Identifier
+   43:d=2  hl=2 l=  22 prim:   OCTET STRING      [HEX DUMP]:04144ADD06161BBCF668B576F581B6BB621ABA5A812F
+   67:d=1  hl=2 l=  14 cons:  SEQUENCE          
+   69:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Key Usage
+   74:d=2  hl=2 l=   1 prim:   BOOLEAN           :255
+   77:d=2  hl=2 l=   4 prim:   OCTET STRING      [HEX DUMP]:03020106
+   83:d=1  hl=2 l=  46 cons:  SEQUENCE          
+   85:d=2  hl=2 l=   8 prim:   OBJECT            :Authority Information Access
+   95:d=2  hl=2 l=  34 prim:   OCTET STRING      [HEX DUMP]:3020301E06082B060105050730018612687474703A2F2F672E73796D63642E636F6D
+  131:d=1  hl=2 l=  18 cons:  SEQUENCE          
+  133:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Basic Constraints
+  138:d=2  hl=2 l=   1 prim:   BOOLEAN           :255
+  141:d=2  hl=2 l=   8 prim:   OCTET STRING      [HEX DUMP]:30060101FF020100
+  151:d=1  hl=2 l=  53 cons:  SEQUENCE          
+  153:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 CRL Distribution Points
+  158:d=2  hl=2 l=  46 prim:   OCTET STRING      [HEX DUMP]:302C302AA028A0268624687474703A2F2F672E73796D63622E636F6D2F63726C732F6774676C6F62616C2E63726C
+  206:d=1  hl=2 l=  23 cons:  SEQUENCE          
+  208:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Certificate Policies
+  213:d=2  hl=2 l=  16 prim:   OCTET STRING      [HEX DUMP]:300E300C060A2B06010401D679020501
+-----BEGIN EXTENSIONS-----
+MIHkMB8GA1UdIwQYMBaAFMB6mGiNifurBWQMEX2qfWW4ysxOMB0GA1UdDgQWBBRK3QYWG7z2aLV
+29YG2u2IaulqBLzAOBgNVHQ8BAf8EBAMCAQYwLgYIKwYBBQUHAQEEIjAgMB4GCCsGAQUFBzABhh
+JodHRwOi8vZy5zeW1jZC5jb20wEgYDVR0TAQH/BAgwBgEB/wIBADA1BgNVHR8ELjAsMCqgKKAmh
+iRodHRwOi8vZy5zeW1jYi5jb20vY3Jscy9ndGdsb2JhbC5jcmwwFwYDVR0gBBAwDjAMBgorBgEE
+AdZ5AgUB
+-----END EXTENSIONS-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_subject_alt_name.pem b/net/data/parse_certificate_unittest/extensions_subject_alt_name.pem
new file mode 100644
index 0000000..3ce5fda
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_subject_alt_name.pem
@@ -0,0 +1,16 @@
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=2 l=  32 cons: SEQUENCE          
+    2:d=1  hl=2 l=  30 cons:  SEQUENCE          
+    4:d=2  hl=2 l=   3 prim:   OBJECT            :X509v3 Subject Alternative Name
+    9:d=2  hl=2 l=  23 prim:   OCTET STRING      [HEX DUMP]:30158213656D657267656E6379737570706F72742E7573
+-----BEGIN EXTENSIONS-----
+MCAwHgYDVR0RBBcwFYITZW1lcmdlbmN5c3VwcG9ydC51cw==
+-----END EXTENSIONS-----
+
+$ openssl asn1parse -i < [SUBJECT ALT NAME]
+    0:d=0  hl=2 l=  21 cons: SEQUENCE          
+    2:d=1  hl=2 l=  19 prim:  cont [ 2 ]        
+-----BEGIN SUBJECT ALT NAME-----
+MBWCE2VtZXJnZW5jeXN1cHBvcnQudXM=
+-----END SUBJECT ALT NAME-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_unknown_critical.pem b/net/data/parse_certificate_unittest/extensions_unknown_critical.pem
new file mode 100644
index 0000000..3913615
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_unknown_critical.pem
@@ -0,0 +1,10 @@
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=2 l=  25 cons: SEQUENCE          
+    2:d=1  hl=2 l=  23 cons:  SEQUENCE          
+    4:d=2  hl=2 l=  12 prim:   OBJECT            :1.2.840.113554.4.1.72585.0
+   18:d=2  hl=2 l=   1 prim:   BOOLEAN           :255
+   21:d=2  hl=2 l=   4 prim:   OCTET STRING      [HEX DUMP]:030203B8
+-----BEGIN EXTENSIONS-----
+MBkwFwYMKoZIhvcSBAGEtwkAAQH/BAQDAgO4
+-----END EXTENSIONS-----
+
diff --git a/net/data/parse_certificate_unittest/extensions_unknown_non_critical.pem b/net/data/parse_certificate_unittest/extensions_unknown_non_critical.pem
new file mode 100644
index 0000000..532cb2ab
--- /dev/null
+++ b/net/data/parse_certificate_unittest/extensions_unknown_non_critical.pem
@@ -0,0 +1,9 @@
+$ openssl asn1parse -i < [EXTENSIONS]
+    0:d=0  hl=2 l=  22 cons: SEQUENCE          
+    2:d=1  hl=2 l=  20 cons:  SEQUENCE          
+    4:d=2  hl=2 l=  12 prim:   OBJECT            :1.2.840.113554.4.1.72585.0
+   18:d=2  hl=2 l=   4 prim:   OCTET STRING      [HEX DUMP]:030203B8
+-----BEGIN EXTENSIONS-----
+MBYwFAYMKoZIhvcSBAGEtwkABAQDAgO4
+-----END EXTENSIONS-----
+
diff --git a/net/der/parse_values.cc b/net/der/parse_values.cc
index 7920d9f..8786f9db 100644
--- a/net/der/parse_values.cc
+++ b/net/der/parse_values.cc
@@ -191,10 +191,48 @@
   return true;
 }
 
+bool ParseUint8(const Input& in, uint8_t* out) {
+  // TODO(eroman): Implement this more directly.
+  uint64_t value;
+  if (!ParseUint64(in, &value))
+    return false;
+
+  if (value > 0xFF)
+    return false;
+
+  *out = static_cast<uint8_t>(value);
+  return true;
+}
+
 BitString::BitString(const Input& bytes, uint8_t unused_bits)
     : bytes_(bytes), unused_bits_(unused_bits) {
   DCHECK_LT(unused_bits, 8);
   DCHECK(unused_bits == 0 || bytes.Length() != 0);
+  // The unused bits must be zero.
+  DCHECK(bytes.Length() == 0 ||
+         (bytes.UnsafeData()[bytes.Length() - 1] & ((1u << unused_bits) - 1)) ==
+             0);
+}
+
+bool BitString::AssertsBit(size_t bit_index) const {
+  // Index of the byte that contains the bit.
+  size_t byte_index = bit_index / 8;
+
+  // If the bit is outside of the bitstring, by definition it is not
+  // asserted.
+  if (byte_index >= bytes_.Length())
+    return false;
+
+  // Within a byte, bits are ordered from most significant to least significant.
+  // Convert |bit_index| to an index within the |byte_index| byte, measured from
+  // its least significant bit.
+  uint8_t bit_index_in_byte = 7 - (bit_index - byte_index * 8);
+
+  // BIT STRING parsing already guarantees that unused bits in a byte are zero
+  // (otherwise it wouldn't be valid DER). Therefore it isn't necessary to check
+  // |unused_bits_|
+  uint8_t byte = bytes_.UnsafeData()[byte_index];
+  return 0 != (byte & (1 << bit_index_in_byte));
 }
 
 bool ParseBitString(const Input& in, BitString* out) {
diff --git a/net/der/parse_values.h b/net/der/parse_values.h
index 27a6f5fb7..d46fa803 100644
--- a/net/der/parse_values.h
+++ b/net/der/parse_values.h
@@ -41,6 +41,9 @@
 // integer.
 NET_EXPORT bool ParseUint64(const Input& in, uint64_t* out) WARN_UNUSED_RESULT;
 
+// Same as ParseUint64() but for a uint8_t.
+NET_EXPORT bool ParseUint8(const Input& in, uint8_t* out) WARN_UNUSED_RESULT;
+
 // The BitString class is a helper for representing a valid parsed BIT STRING.
 //
 // * The bits are ordered within each octet of bytes() from most to least
@@ -59,6 +62,14 @@
   const Input& bytes() const { return bytes_; }
   uint8_t unused_bits() const { return unused_bits_; }
 
+  // Returns true if the bit string contains 1 at the specified position.
+  // Otherwise returns false.
+  //
+  // A return value of false can mean either:
+  //  * The bit value at |bit_index| is 0.
+  //  * There is no bit at |bit_index| (index is beyond the end).
+  bool AssertsBit(size_t bit_index) const WARN_UNUSED_RESULT;
+
  private:
   Input bytes_;
   uint8_t unused_bits_;
diff --git a/net/der/parse_values_unittest.cc b/net/der/parse_values_unittest.cc
index b76c4c99..b29634f 100644
--- a/net/der/parse_values_unittest.cc
+++ b/net/der/parse_values_unittest.cc
@@ -214,6 +214,42 @@
   }
 }
 
+struct Uint8TestData {
+  bool should_pass;
+  const uint8_t input[9];
+  size_t length;
+  uint8_t expected_value;
+};
+
+const Uint8TestData kUint8TestData[] = {
+    {true, {0x00}, 1, 0},
+    // This number fails because it is not a minimal representation.
+    {false, {0x00, 0x00}, 2},
+    {true, {0x01}, 1, 1},
+    {false, {0x01, 0xFF}, 2},
+    {false, {0x03, 0x83}, 2},
+    {true, {0x7F}, 1, 0x7F},
+    {true, {0x00, 0xFF}, 2, 0xFF},
+    // This number fails because it is negative.
+    {false, {0xFF}, 1},
+    {false, {0x80}, 1},
+    {false, {0x00, 0x01}, 2},
+    {false, {0}, 0},
+};
+
+TEST(ParseValuesTest, ParseUint8) {
+  for (size_t i = 0; i < arraysize(kUint8TestData); i++) {
+    const Uint8TestData& test_case = kUint8TestData[i];
+    SCOPED_TRACE(i);
+
+    uint8_t result;
+    EXPECT_EQ(test_case.should_pass,
+              ParseUint8(Input(test_case.input, test_case.length), &result));
+    if (test_case.should_pass)
+      EXPECT_EQ(test_case.expected_value, result);
+  }
+}
+
 struct IsValidIntegerTestData {
   bool should_pass;
   const uint8_t input[2];
@@ -269,6 +305,10 @@
 
   EXPECT_EQ(0u, bit_string.unused_bits());
   EXPECT_EQ(0u, bit_string.bytes().Length());
+
+  EXPECT_FALSE(bit_string.AssertsBit(0));
+  EXPECT_FALSE(bit_string.AssertsBit(1));
+  EXPECT_FALSE(bit_string.AssertsBit(3));
 }
 
 // Tests parsing an empty BIT STRING that incorrectly claims one unused bit.
@@ -298,6 +338,16 @@
   EXPECT_EQ(1u, bit_string.unused_bits());
   EXPECT_EQ(1u, bit_string.bytes().Length());
   EXPECT_EQ(0xFE, bit_string.bytes().UnsafeData()[0]);
+
+  EXPECT_TRUE(bit_string.AssertsBit(0));
+  EXPECT_TRUE(bit_string.AssertsBit(1));
+  EXPECT_TRUE(bit_string.AssertsBit(2));
+  EXPECT_TRUE(bit_string.AssertsBit(3));
+  EXPECT_TRUE(bit_string.AssertsBit(4));
+  EXPECT_TRUE(bit_string.AssertsBit(5));
+  EXPECT_TRUE(bit_string.AssertsBit(6));
+  EXPECT_FALSE(bit_string.AssertsBit(7));
+  EXPECT_FALSE(bit_string.AssertsBit(8));
 }
 
 // Tests parsing a BIT STRING of 7 bits each of which are 1. The unused bit
diff --git a/net/quic/quic_end_to_end_unittest.cc b/net/quic/quic_end_to_end_unittest.cc
index 14d542f..1d23456f 100644
--- a/net/quic/quic_end_to_end_unittest.cc
+++ b/net/quic/quic_end_to_end_unittest.cc
@@ -181,7 +181,7 @@
                   StringPiece response_detail,
                   StringPiece body) {
     QuicInMemoryCache::GetInstance()->AddSimpleResponse(
-        "test.example.com", path, response_code, response_detail, body);
+        "test.example.com", path, response_code, body);
   }
 
   // Populates |request_body_| with |length_| ASCII bytes.
diff --git a/net/quic/spdy_utils.cc b/net/quic/spdy_utils.cc
index 7bcac4d..d66c200 100644
--- a/net/quic/spdy_utils.cc
+++ b/net/quic/spdy_utils.cc
@@ -14,19 +14,6 @@
 namespace net {
 
 // static
-SpdyHeaderBlock SpdyUtils::ConvertSpdy3ResponseHeadersToSpdy4(
-    SpdyHeaderBlock response_headers) {
-  // SPDY/4 headers include neither the version field nor the response details.
-  response_headers.erase(":version");
-  StringPiece status_value = response_headers[":status"];
-  size_t end_of_code = status_value.find(' ');
-  if (end_of_code != string::npos) {
-    response_headers[":status"] = status_value.substr(0, end_of_code);
-  }
-  return response_headers;
-}
-
-// static
 string SpdyUtils::SerializeUncompressedHeaders(const SpdyHeaderBlock& headers) {
   SpdyMajorVersion spdy_version = HTTP2;
 
diff --git a/net/quic/spdy_utils.h b/net/quic/spdy_utils.h
index bfcde92..28b48dbe 100644
--- a/net/quic/spdy_utils.h
+++ b/net/quic/spdy_utils.h
@@ -15,9 +15,6 @@
 
 class NET_EXPORT_PRIVATE SpdyUtils {
  public:
-  static SpdyHeaderBlock ConvertSpdy3ResponseHeadersToSpdy4(
-      SpdyHeaderBlock response_headers);
-
   static std::string SerializeUncompressedHeaders(
       const SpdyHeaderBlock& headers);
 
diff --git a/net/socket/client_socket_pool_manager.cc b/net/socket/client_socket_pool_manager.cc
index 07072db..ac1c1e8 100644
--- a/net/socket/client_socket_pool_manager.cc
+++ b/net/socket/client_socket_pool_manager.cc
@@ -39,14 +39,12 @@
 // as home routers blocking the connections!?!?  See http://crbug.com/12066.
 //
 // WebSocket connections are long-lived, and should be treated differently
-// than normal other connections. 6 connections per group sounded too small
-// for such use, thus we use a larger limit which was determined somewhat
-// arbitrarily.
-// TODO(yutak): Look at the usage and determine the right value after
-// WebSocket protocol stack starts to work.
+// than normal other connections. Use a limit of 255, so the limit for wss will
+// be the same as the limit for ws. Also note that Firefox uses a limit of 200.
+// See http://crbug.com/486800
 int g_max_sockets_per_group[] = {
   6,  // NORMAL_SOCKET_POOL
-  30  // WEBSOCKET_SOCKET_POOL
+  255 // WEBSOCKET_SOCKET_POOL
 };
 
 static_assert(arraysize(g_max_sockets_per_group) ==
diff --git a/net/socket/client_socket_pool_manager_impl.cc b/net/socket/client_socket_pool_manager_impl.cc
index 9dbb19e..5cf98f3 100644
--- a/net/socket/client_socket_pool_manager_impl.cc
+++ b/net/socket/client_socket_pool_manager_impl.cc
@@ -4,6 +4,8 @@
 
 #include "net/socket/client_socket_pool_manager_impl.h"
 
+#include <algorithm>
+
 #include "base/logging.h"
 #include "base/values.h"
 #include "net/http/http_network_session.h"
@@ -208,14 +210,17 @@
   }
 
   DCHECK(!ContainsKey(transport_socket_pools_for_socks_proxies_, socks_proxy));
+  int sockets_per_proxy_server = max_sockets_per_proxy_server(pool_type_);
+  int sockets_per_group = std::min(sockets_per_proxy_server,
+                                   max_sockets_per_group(pool_type_));
 
   std::pair<TransportSocketPoolMap::iterator, bool> tcp_ret =
       transport_socket_pools_for_socks_proxies_.insert(
           std::make_pair(
               socks_proxy,
               new TransportClientSocketPool(
-                  max_sockets_per_proxy_server(pool_type_),
-                  max_sockets_per_group(pool_type_),
+                  sockets_per_proxy_server,
+                  sockets_per_group,
                   host_resolver_,
                   socket_factory_,
                   net_log_)));
@@ -224,8 +229,8 @@
   std::pair<SOCKSSocketPoolMap::iterator, bool> ret =
       socks_socket_pools_.insert(
           std::make_pair(socks_proxy, new SOCKSClientSocketPool(
-              max_sockets_per_proxy_server(pool_type_),
-              max_sockets_per_group(pool_type_),
+              sockets_per_proxy_server,
+              sockets_per_group,
               host_resolver_,
               tcp_ret.first->second,
               net_log_)));
@@ -249,13 +254,17 @@
   DCHECK(!ContainsKey(transport_socket_pools_for_https_proxies_, http_proxy));
   DCHECK(!ContainsKey(ssl_socket_pools_for_https_proxies_, http_proxy));
 
+  int sockets_per_proxy_server = max_sockets_per_proxy_server(pool_type_);
+  int sockets_per_group = std::min(sockets_per_proxy_server,
+                                   max_sockets_per_group(pool_type_));
+
   std::pair<TransportSocketPoolMap::iterator, bool> tcp_http_ret =
       transport_socket_pools_for_http_proxies_.insert(
           std::make_pair(
               http_proxy,
               new TransportClientSocketPool(
-                  max_sockets_per_proxy_server(pool_type_),
-                  max_sockets_per_group(pool_type_),
+                  sockets_per_proxy_server,
+                  sockets_per_group,
                   host_resolver_,
                   socket_factory_,
                   net_log_)));
@@ -266,8 +275,8 @@
           std::make_pair(
               http_proxy,
               new TransportClientSocketPool(
-                  max_sockets_per_proxy_server(pool_type_),
-                  max_sockets_per_group(pool_type_),
+                  sockets_per_proxy_server,
+                  sockets_per_group,
                   host_resolver_,
                   socket_factory_,
                   net_log_)));
@@ -276,8 +285,8 @@
   std::pair<SSLSocketPoolMap::iterator, bool> ssl_https_ret =
       ssl_socket_pools_for_https_proxies_.insert(std::make_pair(
           http_proxy, new SSLClientSocketPool(
-                          max_sockets_per_proxy_server(pool_type_),
-                          max_sockets_per_group(pool_type_), cert_verifier_,
+                          sockets_per_proxy_server,
+                          sockets_per_group, cert_verifier_,
                           channel_id_service_, transport_security_state_,
                           cert_transparency_verifier_, cert_policy_enforcer_,
                           ssl_session_cache_shard_, socket_factory_,
@@ -291,8 +300,8 @@
           std::make_pair(
               http_proxy,
               new HttpProxyClientSocketPool(
-                  max_sockets_per_proxy_server(pool_type_),
-                  max_sockets_per_group(pool_type_),
+                  sockets_per_proxy_server,
+                  sockets_per_group,
                   tcp_http_ret.first->second,
                   ssl_https_ret.first->second,
                   net_log_)));
@@ -307,9 +316,13 @@
   if (it != ssl_socket_pools_for_proxies_.end())
     return it->second;
 
+  int sockets_per_proxy_server = max_sockets_per_proxy_server(pool_type_);
+  int sockets_per_group = std::min(sockets_per_proxy_server,
+                                   max_sockets_per_group(pool_type_));
+
   SSLClientSocketPool* new_pool = new SSLClientSocketPool(
-      max_sockets_per_proxy_server(pool_type_),
-      max_sockets_per_group(pool_type_), cert_verifier_, channel_id_service_,
+      sockets_per_proxy_server,
+      sockets_per_group, cert_verifier_, channel_id_service_,
       transport_security_state_, cert_transparency_verifier_,
       cert_policy_enforcer_, ssl_session_cache_shard_, socket_factory_,
       NULL, /* no tcp pool, we always go through a proxy */
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 0d82d6d..ed5491a 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -260,8 +260,8 @@
         3 * kInitialSessionFlowControlWindowForTest);
 
     QuicInMemoryCachePeer::ResetForTests();
-    AddToCache("/foo", 200, "OK", kFooResponseBody);
-    AddToCache("/bar", 200, "OK", kBarResponseBody);
+    AddToCache("/foo", 200, kFooResponseBody);
+    AddToCache("/bar", 200, kBarResponseBody);
   }
 
   ~EndToEndTest() override {
@@ -416,12 +416,9 @@
     }
   }
 
-  void AddToCache(StringPiece path,
-                  int response_code,
-                  StringPiece response_detail,
-                  StringPiece body) {
-    QuicInMemoryCache::GetInstance()->AddSimpleResponse(
-        "www.google.com", path, response_code, response_detail, body);
+  void AddToCache(StringPiece path, int response_code, StringPiece body) {
+    QuicInMemoryCache::GetInstance()->AddSimpleResponse("www.google.com", path,
+                                                        response_code, body);
   }
 
   void SetPacketLossPercentage(int32 loss) {
@@ -606,7 +603,7 @@
 TEST_P(EndToEndTest, RequestOverMultiplePackets) {
   // Send a large enough request to guarantee fragmentation.
   string huge_request = "/some/path?query=" + string(kMaxPacketSize, '.');
-  AddToCache(huge_request, 200, "OK", kBarResponseBody);
+  AddToCache(huge_request, 200, kBarResponseBody);
 
   ASSERT_TRUE(Initialize());
 
@@ -617,7 +614,7 @@
 TEST_P(EndToEndTest, MultiplePacketsRandomOrder) {
   // Send a large enough request to guarantee fragmentation.
   string huge_request = "/some/path?query=" + string(kMaxPacketSize, '.');
-  AddToCache(huge_request, 200, "OK", kBarResponseBody);
+  AddToCache(huge_request, 200, kBarResponseBody);
 
   ASSERT_TRUE(Initialize());
   SetPacketSendDelay(QuicTime::Delta::FromMilliseconds(2));
@@ -1338,7 +1335,8 @@
   GenerateBody(&large_body, 10240);
   int max_streams = 100;
 
-  AddToCache("/large_response", 200, "OK", large_body);;
+  AddToCache("/large_response", 200, large_body);
+  ;
 
   client_->client()->WaitForCryptoHandshakeConfirmed();
   SetPacketLossPercentage(10);
@@ -1358,7 +1356,7 @@
   string small_body;
   GenerateBody(&small_body, 256);
 
-  AddToCache("/small_response", 200, "OK", small_body);
+  AddToCache("/small_response", 200, small_body);
 
   client_->client()->WaitForCryptoHandshakeConfirmed();
 
diff --git a/net/tools/quic/quic_in_memory_cache.cc b/net/tools/quic/quic_in_memory_cache.cc
index e4af722..eed6c78 100644
--- a/net/tools/quic/quic_in_memory_cache.cc
+++ b/net/tools/quic/quic_in_memory_cache.cc
@@ -46,13 +46,9 @@
 void QuicInMemoryCache::AddSimpleResponse(StringPiece host,
                                           StringPiece path,
                                           int response_code,
-                                          StringPiece response_detail,
                                           StringPiece body) {
   SpdyHeaderBlock response_headers;
-  response_headers[":version"] = "HTTP/1.1";
-  string status = IntToString(response_code) + " ";
-  response_detail.AppendToString(&status);
-  response_headers[":status"] = status;
+  response_headers[":status"] = IntToString(response_code);
   response_headers["content-length"] =
       IntToString(static_cast<int>(body.length()));
   AddResponse(host, path, response_headers, body);
diff --git a/net/tools/quic/quic_in_memory_cache.h b/net/tools/quic/quic_in_memory_cache.h
index e96ad01..5703b9f5 100644
--- a/net/tools/quic/quic_in_memory_cache.h
+++ b/net/tools/quic/quic_in_memory_cache.h
@@ -79,7 +79,6 @@
   void AddSimpleResponse(base::StringPiece host,
                          base::StringPiece path,
                          int response_code,
-                         base::StringPiece response_detail,
                          base::StringPiece body);
 
   // Add a response to the cache.
diff --git a/net/tools/quic/quic_in_memory_cache_test.cc b/net/tools/quic/quic_in_memory_cache_test.cc
index 534edff..3e02bcfa 100644
--- a/net/tools/quic/quic_in_memory_cache_test.cc
+++ b/net/tools/quic/quic_in_memory_cache_test.cc
@@ -57,7 +57,7 @@
 TEST_F(QuicInMemoryCacheTest, AddSimpleResponseGetResponse) {
   string response_body("hello response");
   QuicInMemoryCache* cache = QuicInMemoryCache::GetInstance();
-  cache->AddSimpleResponse("www.google.com", "/", 200, "OK", response_body);
+  cache->AddSimpleResponse("www.google.com", "/", 200, response_body);
 
   BalsaHeaders request_headers;
   CreateRequest("www.google.com", "/", &request_headers);
@@ -65,7 +65,7 @@
       cache->GetResponse("www.google.com", "/");
   ASSERT_TRUE(response);
   ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
-  EXPECT_EQ("200 OK", response->headers().find(":status")->second);
+  EXPECT_EQ("200", response->headers().find(":status")->second);
   EXPECT_EQ(response_body.size(), response->body().length());
 }
 
@@ -105,7 +105,7 @@
   // Add a default response.
   SpdyHeaderBlock response_headers;
   response_headers[":version"] = "HTTP/1.1";
-  response_headers[":status"] = "200 OK";
+  response_headers[":status"] = "200";
   response_headers["content-length"] = "0";
   QuicInMemoryCache::Response* default_response =
       new QuicInMemoryCache::Response;
@@ -116,20 +116,20 @@
   response = cache->GetResponse("www.google.com", "/");
   ASSERT_TRUE(response);
   ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
-  EXPECT_EQ("200 OK", response->headers().find(":status")->second);
+  EXPECT_EQ("200", response->headers().find(":status")->second);
 
   // Now add a set response for / and make sure it is returned
-  cache->AddSimpleResponse("www.google.com", "/", 302, "foo", "");
+  cache->AddSimpleResponse("www.google.com", "/", 302, "");
   response = cache->GetResponse("www.google.com", "/");
   ASSERT_TRUE(response);
   ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
-  EXPECT_EQ("302 foo", response->headers().find(":status")->second);
+  EXPECT_EQ("302", response->headers().find(":status")->second);
 
   // We should get the default response for other requests.
   response = cache->GetResponse("www.google.com", "/asd");
   ASSERT_TRUE(response);
   ASSERT_TRUE(ContainsKey(response->headers(), ":status"));
-  EXPECT_EQ("200 OK", response->headers().find(":status")->second);
+  EXPECT_EQ("200", response->headers().find(":status")->second);
 }
 
 }  // namespace test
diff --git a/net/tools/quic/quic_spdy_server_stream.cc b/net/tools/quic/quic_spdy_server_stream.cc
index 6aac97a7..aa1c713 100644
--- a/net/tools/quic/quic_spdy_server_stream.cc
+++ b/net/tools/quic/quic_spdy_server_stream.cc
@@ -153,9 +153,7 @@
   }
 
   DVLOG(1) << "Sending response for stream " << id();
-  SendHeadersAndBody(
-      SpdyUtils::ConvertSpdy3ResponseHeadersToSpdy4(response->headers()),
-      response->body());
+  SendHeadersAndBody(response->headers(), response->body());
 }
 
 void QuicSpdyServerStream::SendErrorResponse() {
diff --git a/ppapi/proxy/ppb_image_data_proxy.cc b/ppapi/proxy/ppb_image_data_proxy.cc
index adcea09..ead31cb 100644
--- a/ppapi/proxy/ppb_image_data_proxy.cc
+++ b/ppapi/proxy/ppb_image_data_proxy.cc
@@ -387,6 +387,9 @@
 
 void* PlatformImageData::Map() {
   if (!mapped_canvas_.get()) {
+    if (!transport_dib_.get())
+      return NULL;
+
     const bool is_opaque = false;
     mapped_canvas_.reset(transport_dib_->GetPlatformCanvas(desc_.size.width,
                                                            desc_.size.height,
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 324fce2..8c11511 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -4,6 +4,7 @@
       "accessibility_unittests",
       "app_list_unittests",
       "aura_unittests",
+      "blimp",
       "browser_tests",
       "cacheinvalidation_unittests",
       "chromedriver_unittests",
@@ -65,6 +66,7 @@
       "accessibility_unittests",
       "app_list_unittests",
       "aura_unittests",
+      "blimp",
       "browser_tests",
       "cacheinvalidation_unittests",
       "chromedriver_unittests",
diff --git a/testing/buildbot/chromium.goma.json b/testing/buildbot/chromium.goma.json
new file mode 100644
index 0000000..0967ef4
--- /dev/null
+++ b/testing/buildbot/chromium.goma.json
@@ -0,0 +1 @@
+{}
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index e5499ada..502294f 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -298,12 +298,14 @@
   },
   "Linux Builder": {
     "additional_compile_targets": [
+      "blimp",
       "components/mus/example:all",
       "mandoline:all"
     ]
   },
   "Linux Builder (dbg)": {
     "additional_compile_targets": [
+      "blimp",
       "mandoline:all"
     ]
   },
diff --git a/third_party/WebKit/LayoutTests/http/tests/preload/dynamic_adding_preload.html b/third_party/WebKit/LayoutTests/http/tests/preload/dynamic_adding_preload.html
new file mode 100644
index 0000000..21b0a9b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/preload/dynamic_adding_preload.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+<script>
+    var t = async_test('Makes sure that dynamically added preloaded resource is downloaded');
+</script>
+<body>
+<script>
+    var link = document.createElement("link");
+    link.as = "script";
+    link.rel = "preload";
+    link.href = "../resources/dummy.js";
+    document.body.appendChild(link);
+    window.addEventListener("load", t.step_func(function() {
+        assert_equals(performance.getEntriesByType("resource").length, 4);
+        t.done();
+    }));
+</script>
+<script src="../resources/slow-script.pl?delay=200"></script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
index 6a198a0..8eec2ab 100644
--- a/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/element-instance-property-listing-expected.txt
@@ -661,6 +661,7 @@
     property type
     property value
 html element link
+    property as
     property charset
     property crossOrigin
     property disabled
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 eaff1f67..dfc20cf2 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -2303,6 +2303,7 @@
     method constructor
     setter align
 interface HTMLLinkElement : HTMLElement
+    getter as
     getter charset
     getter crossOrigin
     getter disabled
@@ -2318,6 +2319,7 @@
     getter target
     getter type
     method constructor
+    setter as
     setter charset
     setter crossOrigin
     setter disabled
diff --git a/third_party/WebKit/Source/core/css/StylePropertySet.cpp b/third_party/WebKit/Source/core/css/StylePropertySet.cpp
index e8d5465..62200c2 100644
--- a/third_party/WebKit/Source/core/css/StylePropertySet.cpp
+++ b/third_party/WebKit/Source/core/css/StylePropertySet.cpp
@@ -42,7 +42,7 @@
 
 static size_t sizeForImmutableStylePropertySetWithPropertyCount(unsigned count)
 {
-    return sizeof(ImmutableStylePropertySet) - sizeof(void*) + sizeof(CSSValue*) * count + sizeof(StylePropertyMetadata) * count;
+    return sizeof(ImmutableStylePropertySet) - sizeof(void*) + sizeof(RawPtrWillBeMember<CSSValue>) * count + sizeof(StylePropertyMetadata) * count;
 }
 
 PassRefPtrWillBeRawPtr<ImmutableStylePropertySet> ImmutableStylePropertySet::create(const CSSProperty* properties, unsigned count, CSSParserMode cssParserMode)
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index d1a47d0..c24eb41 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -3401,7 +3401,7 @@
         return;
     bool contains = node->containsIncludingShadowDOM(m_focusedElement.get());
     if (contains && (m_focusedElement != node || !amongChildrenOnly))
-        setFocusedElement(nullptr);
+        clearFocusedElement();
 }
 
 void Document::hoveredNodeDetached(Element& element)
@@ -3453,7 +3453,7 @@
     setAnnotatedRegionsDirty(false);
 }
 
-bool Document::setFocusedElement(PassRefPtrWillBeRawPtr<Element> prpNewFocusedElement, WebFocusType type, InputDeviceCapabilities* sourceCapabilities)
+bool Document::setFocusedElement(PassRefPtrWillBeRawPtr<Element> prpNewFocusedElement, const FocusParams& params)
 {
     ASSERT(!m_lifecycle.inDetach());
 
@@ -3485,7 +3485,7 @@
         // Dispatch the blur event and let the node do any other blur related activities (important for text fields)
         // If page lost focus, blur event will have already been dispatched
         if (page() && (page()->focusController().isFocused())) {
-            oldFocusedElement->dispatchBlurEvent(newFocusedElement.get(), type, sourceCapabilities);
+            oldFocusedElement->dispatchBlurEvent(newFocusedElement.get(), params.type, params.sourceCapabilities);
 
             if (m_focusedElement) {
                 // handler shifted focus
@@ -3493,10 +3493,10 @@
                 newFocusedElement = nullptr;
             }
 
-            oldFocusedElement->dispatchFocusOutEvent(EventTypeNames::focusout, newFocusedElement.get(), sourceCapabilities); // DOM level 3 name for the bubbling blur event.
+            oldFocusedElement->dispatchFocusOutEvent(EventTypeNames::focusout, newFocusedElement.get(), params.sourceCapabilities); // DOM level 3 name for the bubbling blur event.
             // FIXME: We should remove firing DOMFocusOutEvent event when we are sure no content depends
             // on it, probably when <rdar://problem/8503958> is resolved.
-            oldFocusedElement->dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, newFocusedElement.get(), sourceCapabilities); // DOM level 2 name for compatibility.
+            oldFocusedElement->dispatchFocusOutEvent(EventTypeNames::DOMFocusOut, newFocusedElement.get(), params.sourceCapabilities); // DOM level 2 name for compatibility.
 
             if (m_focusedElement) {
                 // handler shifted focus
@@ -3510,9 +3510,9 @@
         if (view()) {
             Widget* oldWidget = widgetForElement(*oldFocusedElement);
             if (oldWidget)
-                oldWidget->setFocus(false, type);
+                oldWidget->setFocus(false, params.type);
             else
-                view()->setFocus(false, type);
+                view()->setFocus(false, params.type);
         }
     }
 
@@ -3530,7 +3530,7 @@
         // Dispatch the focus event and let the node do any other focus related activities (important for text fields)
         // If page lost focus, event will be dispatched on page focus, don't duplicate
         if (page() && (page()->focusController().isFocused())) {
-            m_focusedElement->dispatchFocusEvent(oldFocusedElement.get(), type, sourceCapabilities);
+            m_focusedElement->dispatchFocusEvent(oldFocusedElement.get(), params.type, params.sourceCapabilities);
 
 
             if (m_focusedElement != newFocusedElement) {
@@ -3538,7 +3538,7 @@
                 focusChangeBlocked = true;
                 goto SetFocusedElementDone;
             }
-            m_focusedElement->dispatchFocusInEvent(EventTypeNames::focusin, oldFocusedElement.get(), type, sourceCapabilities); // DOM level 3 bubbling focus event.
+            m_focusedElement->dispatchFocusInEvent(EventTypeNames::focusin, oldFocusedElement.get(), params.type, params.sourceCapabilities); // DOM level 3 bubbling focus event.
 
             if (m_focusedElement != newFocusedElement) {
                 // handler shifted focus
@@ -3548,7 +3548,7 @@
 
             // FIXME: We should remove firing DOMFocusInEvent event when we are sure no content depends
             // on it, probably when <rdar://problem/8503958> is m.
-            m_focusedElement->dispatchFocusInEvent(EventTypeNames::DOMFocusIn, oldFocusedElement.get(), type, sourceCapabilities); // DOM level 2 for compatibility.
+            m_focusedElement->dispatchFocusInEvent(EventTypeNames::DOMFocusIn, oldFocusedElement.get(), params.type, params.sourceCapabilities); // DOM level 2 for compatibility.
 
             if (m_focusedElement != newFocusedElement) {
                 // handler shifted focus
@@ -3573,9 +3573,9 @@
                 focusWidget = widgetForElement(*m_focusedElement);
             }
             if (focusWidget)
-                focusWidget->setFocus(true, type);
+                focusWidget->setFocus(true, params.type);
             else
-                view()->setFocus(true, type);
+                view()->setFocus(true, params.type);
         }
     }
 
@@ -3595,6 +3595,11 @@
     return !focusChangeBlocked;
 }
 
+void Document::clearFocusedElement()
+{
+    setFocusedElement(nullptr, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
+}
+
 void Document::setCSSTarget(Element* newTarget)
 {
     if (m_cssTarget)
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h
index 885d0ad1..617b7e5 100644
--- a/third_party/WebKit/Source/core/dom/Document.h
+++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -170,6 +170,7 @@
 class WebGLRenderingContext;
 enum class SelectionBehaviorOnFocus;
 struct AnnotatedRegionValue;
+struct FocusParams;
 struct IconURL;
 
 using MouseEventWithHitTestResults = EventWithHitTestResults<PlatformMouseEvent>;
@@ -583,7 +584,8 @@
     String selectedStylesheetSet() const;
     void setSelectedStylesheetSet(const String&);
 
-    bool setFocusedElement(PassRefPtrWillBeRawPtr<Element>, WebFocusType = WebFocusTypeNone, InputDeviceCapabilities* sourceCapabilities = nullptr);
+    bool setFocusedElement(PassRefPtrWillBeRawPtr<Element>, const FocusParams&);
+    void clearFocusedElement();
     Element* focusedElement() const { return m_focusedElement.get(); }
     UserActionElementSet& userActionElements()  { return m_userActionElements; }
     const UserActionElementSet& userActionElements() const { return m_userActionElements; }
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp
index ff7212a..2351061 100644
--- a/third_party/WebKit/Source/core/dom/Element.cpp
+++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -2376,7 +2376,7 @@
     }
 
     RefPtrWillBeRawPtr<Node> protect(this);
-    if (!document().page()->focusController().setFocusedElement(this, document().frame(), params.type, params.sourceCapabilities))
+    if (!document().page()->focusController().setFocusedElement(this, document().frame(), params))
         return;
 
     // Setting the focused node above might have invalidated the layout due to scripts.
@@ -2427,7 +2427,7 @@
         if (doc.page())
             doc.page()->focusController().setFocusedElement(0, doc.frame());
         else
-            doc.setFocusedElement(nullptr);
+            doc.clearFocusedElement();
     }
 }
 
diff --git a/third_party/WebKit/Source/core/dom/Element.h b/third_party/WebKit/Source/core/dom/Element.h
index 1252079..b4b5cbb 100644
--- a/third_party/WebKit/Source/core/dom/Element.h
+++ b/third_party/WebKit/Source/core/dom/Element.h
@@ -90,6 +90,7 @@
 enum class SelectionBehaviorOnFocus {
     Reset,
     Restore,
+    None,
 };
 
 struct FocusParams {
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index 902a4e3..dbc7677 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -1097,7 +1097,7 @@
             }
             target = target->parentOrShadowHostElement();
         }
-        m_frame->document()->setFocusedElement(nullptr);
+        m_frame->document()->clearFocusedElement();
     }
 
     if (caretBrowsing)
diff --git a/third_party/WebKit/Source/core/fetch/Resource.h b/third_party/WebKit/Source/core/fetch/Resource.h
index 5f864ae..7e63e3d 100644
--- a/third_party/WebKit/Source/core/fetch/Resource.h
+++ b/third_party/WebKit/Source/core/fetch/Resource.h
@@ -283,6 +283,7 @@
     // (ResourcePtrs and ResourceClients registering themselves) don't work in this case, so
     // have a separate internal protector).
     class InternalResourcePtr {
+        STACK_ALLOCATED();
     public:
         explicit InternalResourcePtr(Resource* resource)
             : m_resource(resource)
@@ -296,7 +297,7 @@
             m_resource->deleteIfPossible();
         }
     private:
-        Resource* m_resource;
+        RawPtrWillBeMember<Resource> m_resource;
     };
 
     void incrementProtectorCount() { m_protectorCount++; }
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index 597e7c8..24fc091 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -1454,7 +1454,7 @@
     // If the anchor accepts keyboard focus, move focus there to aid users relying on keyboard navigation.
     // If anchorNode is not focusable, setFocusedElement() will still clear focus, which matches the behavior of other browsers.
     if (anchorNode)
-        m_frame->document()->setFocusedElement(anchorNode);
+        m_frame->document()->setFocusedElement(anchorNode, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
 
     return true;
 }
diff --git a/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp b/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp
index efacfc6..a06dc57 100644
--- a/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp
+++ b/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp
@@ -26,7 +26,7 @@
 static const double kViewportTimerPollDelay = 0.5;
 
 AutoplayExperimentHelper::AutoplayExperimentHelper(HTMLMediaElement& element)
-    : m_element(element)
+    : m_element(&element)
     , m_mode(Mode::ExperimentOff)
     , m_playPending(false)
     , m_registeredWithLayoutObject(false)
@@ -85,7 +85,7 @@
             }
         }
 
-    } else if (m_element.isUserGestureRequiredForPlay()) {
+    } else if (element().isUserGestureRequiredForPlay()) {
         unregisterForPositionUpdatesIfNeeded();
     }
 }
@@ -121,7 +121,7 @@
             return;
     }
 
-    if (LayoutObject* layoutObject = m_element.layoutObject()) {
+    if (LayoutObject* layoutObject = element().layoutObject()) {
         LayoutMedia* layoutMedia = toLayoutMedia(layoutObject);
         layoutMedia->setRequestPositionUpdates(true);
     }
@@ -133,7 +133,7 @@
 void AutoplayExperimentHelper::unregisterForPositionUpdatesIfNeeded()
 {
     if (m_registeredWithLayoutObject) {
-        if (LayoutObject* obj = m_element.layoutObject()) {
+        if (LayoutObject* obj = element().layoutObject()) {
             LayoutMedia* layoutMedia = toLayoutMedia(obj);
             layoutMedia->setRequestPositionUpdates(false);
         }
@@ -155,10 +155,10 @@
 
     m_lastVisibleRect = visibleRect;
 
-    if (!m_element.layoutObject())
+    if (!element().layoutObject())
         return;
 
-    IntRect currentLocation = m_element.layoutObject()->absoluteBoundingBoxRect();
+    IntRect currentLocation = element().layoutObject()->absoluteBoundingBoxRect();
     bool inViewport = meetsVisibilityRequirements();
 
     if (m_lastLocation != currentLocation) {
@@ -177,7 +177,7 @@
 void AutoplayExperimentHelper::updatePositionNotificationRegistration()
 {
     if (m_registeredWithLayoutObject) {
-        LayoutMedia* layoutMedia = toLayoutMedia(m_element.layoutObject());
+        LayoutMedia* layoutMedia = toLayoutMedia(element().layoutObject());
         layoutMedia->setRequestPositionUpdates(true);
     }
 }
@@ -215,7 +215,7 @@
 bool AutoplayExperimentHelper::meetsVisibilityRequirements() const
 {
     if (enabled(IfPageVisible)
-        && m_element.document().pageVisibilityState() != PageVisibilityStateVisible)
+        && element().document().pageVisibilityState() != PageVisibilityStateVisible)
         return false;
 
     if (!enabled(IfViewport))
@@ -224,7 +224,7 @@
     if (m_lastVisibleRect.isEmpty())
         return false;
 
-    LayoutObject* layoutObject = m_element.layoutObject();
+    LayoutObject* layoutObject = element().layoutObject();
     if (!layoutObject)
         return false;
 
@@ -255,10 +255,10 @@
     }
 
     // Start playing!
-    prepareToPlay(m_element.shouldAutoplay()
+    prepareToPlay(element().shouldAutoplay()
         ? GesturelessPlaybackStartedByAutoplayFlagAfterScroll
         : GesturelessPlaybackStartedByPlayMethodAfterScroll);
-    m_element.playInternal();
+    element().playInternal();
 
     return true;
 }
@@ -272,22 +272,20 @@
     // This is what prevents us from starting playback more than once.
     // Since this flag is never set to true once it's cleared, it will block
     // the autoplay experiment forever.
-    if (!m_element.isUserGestureRequiredForPlay())
+    if (!element().isUserGestureRequiredForPlay())
         return false;
 
     // Make sure that this is an element of the right type.
-    if (!enabled(ForVideo)
-        && isHTMLVideoElement(m_element))
+    if (!enabled(ForVideo) && isHTMLVideoElement(element()))
         return false;
 
-    if (!enabled(ForAudio)
-        && isHTMLAudioElement(m_element))
+    if (!enabled(ForAudio) && isHTMLAudioElement(element()))
         return false;
 
     // If nobody has requested playback, either by the autoplay attribute or
     // a play() call, then do nothing.
 
-    if (!m_playPending && !m_element.shouldAutoplay())
+    if (!m_playPending && !element().shouldAutoplay())
         return false;
 
     // Note that the viewport test always returns false on desktop, which is
@@ -298,7 +296,7 @@
 
     // If we require muted media and this is muted, then it is eligible.
     if (enabled(IfMuted))
-        return m_element.muted();
+        return element().muted();
 
     // Element is eligible for gesture override, maybe muted.
     return true;
@@ -311,17 +309,17 @@
         // If we are actually changing the muted state, then this will call
         // mutedChanged().  If isEligible(), then mutedChanged() will try
         // to start playback, which we should not do here.
-        m_element.setMuted(true);
+        element().setMuted(true);
     }
 }
 
 void AutoplayExperimentHelper::prepareToPlay(AutoplayMetrics metric)
 {
-    m_element.recordAutoplayMetric(metric);
+    element().recordAutoplayMetric(metric);
 
     // This also causes !isEligible, so that we don't allow autoplay more than
     // once.  Be sure to do this before muteIfNeeded().
-    m_element.removeUserGestureRequirement();
+    element().removeUserGestureRequirement();
 
     unregisterForPositionUpdatesIfNeeded();
     muteIfNeeded();
@@ -329,14 +327,20 @@
     // Record that this autoplayed without a user gesture.  This is normally
     // set when we discover an autoplay attribute, but we include all cases
     // where playback started without a user gesture, e.g., play().
-    m_element.setInitialPlayWithoutUserGestures(true);
+    element().setInitialPlayWithoutUserGestures(true);
 
     // Do not actually start playback here.
 }
 
 Document& AutoplayExperimentHelper::document() const
 {
-    return m_element.document();
+    return element().document();
+}
+
+HTMLMediaElement& AutoplayExperimentHelper::element() const
+{
+    ASSERT(m_element);
+    return *m_element;
 }
 
 AutoplayExperimentHelper::Mode AutoplayExperimentHelper::fromString(const String& mode)
diff --git a/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.h b/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.h
index 9b66a911..a354060 100644
--- a/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.h
+++ b/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.h
@@ -67,9 +67,10 @@
     NumberOfAutoplayMetrics,
 };
 
-class AutoplayExperimentHelper {
+class AutoplayExperimentHelper final {
+    DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 public:
-    AutoplayExperimentHelper(HTMLMediaElement&);
+    explicit AutoplayExperimentHelper(HTMLMediaElement&);
     ~AutoplayExperimentHelper();
 
     void becameReadyToPlay();
@@ -103,6 +104,11 @@
         PlayMuted     = 1 << 6,
     };
 
+    DEFINE_INLINE_TRACE()
+    {
+        visitor->trace(m_element);
+    }
+
 private:
     // Register to receive position updates, if we haven't already.  If we
     // have, then this does nothing.
@@ -139,6 +145,8 @@
     // Return our media element's document.
     Document& document() const;
 
+    HTMLMediaElement& element() const;
+
     inline bool enabled(Mode mode) const
     {
         return ((int)m_mode) & ((int)mode);
@@ -146,8 +154,7 @@
 
     Mode fromString(const String& mode);
 
-private:
-    HTMLMediaElement& m_element;
+    RawPtrWillBeMember<HTMLMediaElement> m_element;
 
     Mode m_mode;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp b/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp
index 4e21aad..eba56ca 100644
--- a/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLDialogElement.cpp
@@ -76,7 +76,7 @@
         return;
     }
 
-    dialog->document().setFocusedElement(nullptr);
+    dialog->document().clearFocusedElement();
 }
 
 static void inertSubtreesChanged(Document& document)
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
index a16d398..49cacf9 100644
--- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -350,6 +350,11 @@
         case SelectionBehaviorOnFocus::Restore:
             restoreCachedSelection();
             break;
+        case SelectionBehaviorOnFocus::None:
+            // |None| is used only for FocusController::setFocusedElement and
+            // Document::setFocusedElement, and they don't call
+            // updateFocusAppearance().
+            ASSERT_NOT_REACHED();
         }
         if (document().frame())
             document().frame()->selection().revealSelection();
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.idl b/third_party/WebKit/Source/core/html/HTMLLinkElement.idl
index 91c040e..ea37eb9 100644
--- a/third_party/WebKit/Source/core/html/HTMLLinkElement.idl
+++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.idl
@@ -32,6 +32,7 @@
     [Reflect] attribute DOMString media;
     [Reflect] attribute DOMString hreflang;
     [Reflect] attribute DOMString type;
+    [Reflect, RuntimeEnabled=LinkPreload] attribute DOMString as;
     [PutForwards=value] readonly attribute DOMSettableTokenList sizes;
 
     // obsolete members
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index 177ef5c..f3c4ad3 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -3535,6 +3535,7 @@
     visitor->trace(m_audioSourceProvider);
     visitor->template registerWeakMembers<HTMLMediaElement, &HTMLMediaElement::clearWeakMembers>(this);
 #endif
+    visitor->trace(m_autoplayHelper);
     HeapSupplementable<HTMLMediaElement>::trace(visitor);
 #endif
     HTMLElement::trace(visitor);
diff --git a/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp b/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp
index 6c1aa8c..8c4f7685f 100644
--- a/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLTextAreaElement.cpp
@@ -250,6 +250,11 @@
     case SelectionBehaviorOnFocus::Restore:
         restoreCachedSelection();
         break;
+    case SelectionBehaviorOnFocus::None:
+        // |None| is used only for FocusController::setFocusedElement and
+        // Document::setFocusedElement, and they don't call
+        // updateFocusAppearance().
+        ASSERT_NOT_REACHED();
     }
     if (document().frame())
         document().frame()->selection().revealSelection();
diff --git a/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp b/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp
index 212fcc5..cd00b8f6 100644
--- a/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/RadioInputType.cpp
@@ -118,7 +118,7 @@
     }
     if (inputElement) {
         RefPtrWillBeRawPtr<HTMLInputElement> protector(inputElement);
-        document.setFocusedElement(inputElement);
+        document.setFocusedElement(inputElement, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
         inputElement->dispatchSimulatedClick(event, SendNoEvents);
         event->setDefaultHandled();
         return;
diff --git a/third_party/WebKit/Source/core/input/EventHandler.cpp b/third_party/WebKit/Source/core/input/EventHandler.cpp
index 1f84d71d..fc6b6c8 100644
--- a/third_party/WebKit/Source/core/input/EventHandler.cpp
+++ b/third_party/WebKit/Source/core/input/EventHandler.cpp
@@ -1807,14 +1807,14 @@
         if (element) {
             if (slideFocusOnShadowHostIfNecessary(*element))
                 return true;
-            if (!page->focusController().setFocusedElement(element, m_frame, WebFocusTypeMouse, sourceCapabilities))
+            if (!page->focusController().setFocusedElement(element, m_frame, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeMouse, sourceCapabilities)))
                 return true;
         } else {
             // We call setFocusedElement even with !element in order to blur
             // current focus element when a link is clicked; this is expected by
             // some sites that rely on onChange handlers running from form
             // fields before the button click is processed.
-            if (!page->focusController().setFocusedElement(0, m_frame, WebFocusTypeNone, sourceCapabilities))
+            if (!page->focusController().setFocusedElement(nullptr, m_frame, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, sourceCapabilities)))
                 return true;
         }
     }
diff --git a/third_party/WebKit/Source/core/page/FocusController.cpp b/third_party/WebKit/Source/core/page/FocusController.cpp
index 2679a2bc..dfc0bd0 100644
--- a/third_party/WebKit/Source/core/page/FocusController.cpp
+++ b/third_party/WebKit/Source/core/page/FocusController.cpp
@@ -720,7 +720,7 @@
     if (!element) {
         // We didn't find an element to focus, so we should try to pass focus to Chrome.
         if (!initialFocus && m_page->chromeClient().canTakeFocus(type)) {
-            document->setFocusedElement(nullptr);
+            document->clearFocusedElement();
             setFocusedFrame(nullptr);
             m_page->chromeClient().takeFocus(type);
             return true;
@@ -750,7 +750,7 @@
         if (!owner->contentFrame())
             return false;
 
-        document->setFocusedElement(nullptr);
+        document->clearFocusedElement();
         setFocusedFrame(owner->contentFrame());
         return true;
     }
@@ -762,7 +762,7 @@
 
     if (&newDocument != document) {
         // Focus is going away from this document, so clear the focused node.
-        document->setFocusedElement(nullptr);
+        document->clearFocusedElement();
     }
 
     setFocusedFrame(newDocument.frame());
@@ -820,7 +820,12 @@
     selection.clear();
 }
 
-bool FocusController::setFocusedElement(Element* element, PassRefPtrWillBeRawPtr<Frame> newFocusedFrame, WebFocusType type, InputDeviceCapabilities* sourceCapabilities)
+bool FocusController::setFocusedElement(Element* element, PassRefPtrWillBeRawPtr<Frame> newFocusedFrame)
+{
+    return setFocusedElement(element, newFocusedFrame, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
+}
+
+bool FocusController::setFocusedElement(Element* element, PassRefPtrWillBeRawPtr<Frame> newFocusedFrame, const FocusParams& params)
 {
     RefPtrWillBeRawPtr<LocalFrame> oldFocusedFrame = focusedFrame();
     RefPtrWillBeRawPtr<Document> oldDocument = oldFocusedFrame ? oldFocusedFrame->document() : nullptr;
@@ -848,7 +853,7 @@
         clearSelectionIfNeeded(oldFocusedFrame.get(), toLocalFrame(newFocusedFrame.get()), element);
 
     if (oldDocument && oldDocument != newDocument)
-        oldDocument->setFocusedElement(nullptr);
+        oldDocument->clearFocusedElement();
 
     if (newFocusedFrame && !newFocusedFrame->page()) {
         setFocusedFrame(nullptr);
@@ -860,7 +865,7 @@
     RefPtrWillBeRawPtr<Element> protect = element;
     ALLOW_UNUSED_LOCAL(protect);
     if (newDocument) {
-        bool successfullyFocused = newDocument->setFocusedElement(element, type, sourceCapabilities);
+        bool successfullyFocused = newDocument->setFocusedElement(element, params);
         if (!successfullyFocused)
             return false;
     }
diff --git a/third_party/WebKit/Source/core/page/FocusController.h b/third_party/WebKit/Source/core/page/FocusController.h
index 68e2a9c..6c8c017 100644
--- a/third_party/WebKit/Source/core/page/FocusController.h
+++ b/third_party/WebKit/Source/core/page/FocusController.h
@@ -37,6 +37,7 @@
 namespace blink {
 
 struct FocusCandidate;
+struct FocusParams;
 class Element;
 class Frame;
 class HTMLFrameOwnerElement;
@@ -64,7 +65,10 @@
     bool advanceFocus(WebFocusType type, InputDeviceCapabilities* sourceCapabilities = nullptr) { return advanceFocus(type, false, sourceCapabilities); }
     Element* findFocusableElement(WebFocusType, Node&);
 
-    bool setFocusedElement(Element*, PassRefPtrWillBeRawPtr<Frame>, WebFocusType = WebFocusTypeNone, InputDeviceCapabilities* sourceCapabilities = nullptr);
+    bool setFocusedElement(Element*, PassRefPtrWillBeRawPtr<Frame>, const FocusParams&);
+    // |setFocusedElement| variant with SelectionBehaviorOnFocus::None,
+    // |WebFocusTypeNone, and null InputDeviceCapabilities.
+    bool setFocusedElement(Element*, PassRefPtrWillBeRawPtr<Frame>);
 
     void setActive(bool);
     bool isActive() const { return m_isActive; }
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index 1b704fe..8cc9fc6 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -2367,7 +2367,7 @@
 
 void Internals::setInitialFocus(bool reverse)
 {
-    frame()->document()->setFocusedElement(nullptr);
+    frame()->document()->clearFocusedElement();
     frame()->page()->focusController().setInitialFocus(reverse ? WebFocusTypeBackward : WebFocusTypeForward);
 }
 
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
index 4932473d..cdd3659 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
@@ -790,15 +790,13 @@
 
     if (this.editable) {
         var items = [];
-        if (Runtime.experiments.isEnabled("stylesSidebarRuleToolbar")) {
-            var colorButton = new WebInspector.ToolbarButton(WebInspector.UIString("Add color"), "foreground-color-toolbar-item");
-            colorButton.addEventListener("click", this._onInsertColorPropertyClick.bind(this));
-            items.push(colorButton);
+        var colorButton = new WebInspector.ToolbarButton(WebInspector.UIString("Add color"), "foreground-color-toolbar-item");
+        colorButton.addEventListener("click", this._onInsertColorPropertyClick.bind(this));
+        items.push(colorButton);
 
-            var backgroundButton = new WebInspector.ToolbarButton(WebInspector.UIString("Add background-color"), "background-color-toolbar-item");
-            backgroundButton.addEventListener("click", this._onInsertBackgroundColorPropertyClick.bind(this));
-            items.push(backgroundButton);
-        }
+        var backgroundButton = new WebInspector.ToolbarButton(WebInspector.UIString("Add background-color"), "background-color-toolbar-item");
+        backgroundButton.addEventListener("click", this._onInsertBackgroundColorPropertyClick.bind(this));
+        items.push(backgroundButton);
 
         if (rule) {
             var newRuleButton = new WebInspector.ToolbarButton(WebInspector.UIString("Insert Style Rule"), "add-toolbar-item");
@@ -806,6 +804,9 @@
             items.push(newRuleButton);
         }
 
+        var menuButton = new WebInspector.ToolbarButton(WebInspector.UIString("More tools\u2026"), "menu-toolbar-item");
+        items.push(menuButton);
+
         if (items.length) {
             var sectionToolbar = new WebInspector.Toolbar();
             sectionToolbar.element.classList.add("sidebar-pane-section-toolbar");
@@ -824,6 +825,7 @@
             {
                 for (var i = 0; i < items.length; ++i)
                     items[i].setVisible(value);
+                menuButton.setVisible(!value);
             }
             setItemsVisibility(items, false);
             sectionToolbar.element.addEventListener("mouseenter", setItemsVisibility.bind(null, items, true));
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css b/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css
index e838bc2a..f8a7c9e 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css
@@ -748,11 +748,10 @@
 
 .sidebar-pane-section-toolbar {
     position: absolute;
-    right: 2px;
-    bottom: 2px;
+    right: 0;
+    bottom: 0;
     visibility: hidden;
-    background-color: rgba(255, 255, 255, 0.8);
-    border: 1px solid #e5e5e5;
+    background-color: rgba(255, 255, 255, 0.9);
 }
 
 .styles-pane:not(.is-editing-style) .styles-section.matched-styles:not(.read-only):hover .sidebar-pane-section-toolbar {
diff --git a/third_party/WebKit/Source/devtools/front_end/main/Main.js b/third_party/WebKit/Source/devtools/front_end/main/Main.js
index 2c7918e..f2109dc 100644
--- a/third_party/WebKit/Source/devtools/front_end/main/Main.js
+++ b/third_party/WebKit/Source/devtools/front_end/main/Main.js
@@ -144,7 +144,6 @@
         Runtime.experiments.register("securityPanel", "Security panel");
         Runtime.experiments.register("showPrimaryLoadWaterfallInNetworkTimeline", "Show primary load waterfall in Network timeline", true);
         Runtime.experiments.register("stepIntoAsync", "Step into async");
-        Runtime.experiments.register("stylesSidebarRuleToolbar", "Styles sidebar rule toolbar");
         Runtime.experiments.register("timelineInvalidationTracking", "Timeline invalidation tracking", true);
         Runtime.experiments.register("timelineTracingJSProfile", "Timeline tracing based JS profiler", true);
         Runtime.experiments.register("timelineEventsTreeView", "Timeline events tree view", true);
diff --git a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
index e2103b1..dd38c52 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXNodeObject.cpp
@@ -2385,7 +2385,7 @@
 
     Document* document = this->document();
     if (!on) {
-        document->setFocusedElement(nullptr);
+        document->clearFocusedElement();
     } else {
         Node* node = this->node();
         if (node && node->isElementNode()) {
@@ -2393,11 +2393,11 @@
             // That is a problem when focus is removed from the webpage to chrome, and then returns.
             // In these cases, we need to do what keyboard and mouse focus do, which is reset focus first.
             if (document->focusedElement() == node)
-                document->setFocusedElement(nullptr);
+                document->clearFocusedElement();
 
             toElement(node)->focus();
         } else {
-            document->setFocusedElement(nullptr);
+            document->clearFocusedElement();
         }
     }
 }
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn
index d904269..878d8fe5d3b 100644
--- a/third_party/WebKit/Source/platform/BUILD.gn
+++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -358,10 +358,9 @@
   if (is_android) {
     apk_deps = [
       "//base:base_java",
-      "//content/shell/android:copy_content_shell_assets",
+      "//content/shell/android:content_shell_assets",
       "//net/android:net_java",
     ]
-    apk_asset_location = "$root_build_dir/content_shell/assets"
   }
 }
 
diff --git a/third_party/WebKit/Source/web/BUILD.gn b/third_party/WebKit/Source/web/BUILD.gn
index 02da39f..8eb1f1a 100644
--- a/third_party/WebKit/Source/web/BUILD.gn
+++ b/third_party/WebKit/Source/web/BUILD.gn
@@ -143,9 +143,8 @@
   if (is_android) {
     apk_deps = [
       "//base:base_java",
+      "//content/shell/android:content_shell_assets",
       "//net/android:net_java",
-      "//content/shell/android:copy_content_shell_assets",
     ]
-    apk_asset_location = "$root_build_dir/content_shell/assets"
   }
 }
diff --git a/third_party/WebKit/Source/web/TextFinder.cpp b/third_party/WebKit/Source/web/TextFinder.cpp
index c7bf5df7..3bef0a9 100644
--- a/third_party/WebKit/Source/web/TextFinder.cpp
+++ b/third_party/WebKit/Source/web/TextFinder.cpp
@@ -169,7 +169,7 @@
     mainFrameImpl->ensureTextFinder().m_currentActiveMatchFrame = &ownerFrame();
 
     // Make sure no node is focused. See http://crbug.com/38700.
-    ownerFrame().frame()->document()->setFocusedElement(nullptr);
+    ownerFrame().frame()->document()->clearFocusedElement();
 
     if (!options.findNext || activeSelection) {
         // This is either a Find operation or a Find-next from a new start point
@@ -630,7 +630,7 @@
         ownerFrame().frame()->selection().clear();
 
         // Make sure no node is focused. See http://crbug.com/38700.
-        ownerFrame().frame()->document()->setFocusedElement(nullptr);
+        ownerFrame().frame()->document()->clearFocusedElement();
     }
 
     IntRect activeMatchRect;
diff --git a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
index 926efa6..1beab73 100644
--- a/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebLocalFrameImpl.cpp
@@ -1876,7 +1876,7 @@
                 // Found a focusable parent node. Set the active match as the
                 // selection and focus to the focusable node.
                 frame()->selection().setSelection(VisibleSelection(EphemeralRange(activeMatch)));
-                frame()->document()->setFocusedElement(element);
+                frame()->document()->setFocusedElement(element, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
                 return;
             }
         }
@@ -1890,7 +1890,7 @@
                 continue;
             Element* element = toElement(node);
             if (element->isFocusable()) {
-                frame()->document()->setFocusedElement(element);
+                frame()->document()->setFocusedElement(element, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
                 return;
             }
         }
@@ -1901,7 +1901,7 @@
         // we have nothing focused (otherwise you might have text selected but
         // a link focused, which is weird).
         frame()->selection().setSelection(VisibleSelection(EphemeralRange(activeMatch)));
-        frame()->document()->setFocusedElement(nullptr);
+        frame()->document()->clearFocusedElement();
 
         // Finally clear the active match, for two reasons:
         // We just finished the find 'session' and we don't want future (potentially
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
index 5c9b8a4..72629f3 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -928,7 +928,7 @@
     if (Page* currentPage = containingFrame.page())
         currentPage->focusController().setFocusedElement(m_element, &containingFrame);
     else
-        containingFrame.document()->setFocusedElement(m_element);
+        containingFrame.document()->setFocusedElement(m_element, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
 }
 
 void WebPluginContainerImpl::issuePaintInvalidations()
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index bc80f45..bc4fb6b 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -2818,7 +2818,7 @@
     Frame* frame = page()->focusController().focusedOrMainFrame();
     if (frame->isLocalFrame()) {
         if (Document* document = toLocalFrame(frame)->document())
-            document->setFocusedElement(nullptr);
+            document->clearFocusedElement();
     }
     page()->focusController().setInitialFocus(reverse ? WebFocusTypeBackward : WebFocusTypeForward);
 }
@@ -2836,10 +2836,7 @@
         return;
 
     RefPtrWillBeRawPtr<Element> oldFocusedElement = document->focusedElement();
-
-    // Clear the focused node.
-    document->setFocusedElement(nullptr);
-
+    document->clearFocusedElement();
     if (!oldFocusedElement)
         return;
 
diff --git a/third_party/WebKit/Source/web/tests/WebViewTest.cpp b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
index 74fae38..0d1b595 100644
--- a/third_party/WebKit/Source/web/tests/WebViewTest.cpp
+++ b/third_party/WebKit/Source/web/tests/WebViewTest.cpp
@@ -2438,7 +2438,7 @@
     // (A.1) Verifies autocorrect/autocomplete/spellcheck flags are Off and
     // autocapitalize is set to none.
     HTMLInputElement* inputElement = toHTMLInputElement(document->getElementById("input"));
-    document->setFocusedElement(inputElement);
+    document->setFocusedElement(inputElement, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
     webViewImpl->setFocus(true);
     WebTextInputInfo info = webViewImpl->textInputInfo();
     EXPECT_EQ(
@@ -2448,7 +2448,7 @@
     // (A.2) Verifies autocorrect/autocomplete/spellcheck flags are On and
     // autocapitalize is set to sentences.
     inputElement = toHTMLInputElement(document->getElementById("input2"));
-    document->setFocusedElement(inputElement);
+    document->setFocusedElement(inputElement, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
     webViewImpl->setFocus(true);
     info = webViewImpl->textInputInfo();
     EXPECT_EQ(
@@ -2458,7 +2458,7 @@
     // (B) <textarea> Verifies the default text input flags are
     // WebTextInputFlagAutocapitalizeSentences.
     HTMLTextAreaElement* textAreaElement = toHTMLTextAreaElement(document->getElementById("textarea"));
-    document->setFocusedElement(textAreaElement);
+    document->setFocusedElement(textAreaElement, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
     webViewImpl->setFocus(true);
     info = webViewImpl->textInputInfo();
     EXPECT_EQ(WebTextInputFlagAutocapitalizeSentences, info.flags);
@@ -2486,7 +2486,7 @@
     EXPECT_FALSE(client.textIsUpdated());
 
     HTMLInputElement* inputElement = toHTMLInputElement(document->getElementById("input"));
-    document->setFocusedElement(inputElement);
+    document->setFocusedElement(inputElement, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
     webViewImpl->setFocus(true);
     EXPECT_EQ(document->focusedElement(), static_cast<Element*>(inputElement));
 
@@ -2510,7 +2510,7 @@
     // (A.3) Unfocused and value is changed by script.
     client.reset();
     EXPECT_FALSE(client.textIsUpdated());
-    document->setFocusedElement(nullptr);
+    document->clearFocusedElement();
     webViewImpl->setFocus(false);
     EXPECT_NE(document->focusedElement(), static_cast<Element*>(inputElement));
     inputElement->setValue("testA3");
@@ -2521,7 +2521,7 @@
     client.reset();
     EXPECT_FALSE(client.textIsUpdated());
     HTMLTextAreaElement* textAreaElement = toHTMLTextAreaElement(document->getElementById("textarea"));
-    document->setFocusedElement(textAreaElement);
+    document->setFocusedElement(textAreaElement, FocusParams(SelectionBehaviorOnFocus::None, WebFocusTypeNone, nullptr));
     webViewImpl->setFocus(true);
     EXPECT_EQ(document->focusedElement(), static_cast<Element*>(textAreaElement));
     textAreaElement->setValue("testB");
@@ -2540,7 +2540,7 @@
     // (B.3) Unfocused and value is changed by script.
     client.reset();
     EXPECT_FALSE(client.textIsUpdated());
-    document->setFocusedElement(nullptr);
+    document->clearFocusedElement();
     webViewImpl->setFocus(false);
     EXPECT_NE(document->focusedElement(), static_cast<Element*>(textAreaElement));
     inputElement->setValue("testB3");
diff --git a/tools/cfi/blacklist.txt b/tools/cfi/blacklist.txt
index 59f91701..4fb904a 100644
--- a/tools/cfi/blacklist.txt
+++ b/tools/cfi/blacklist.txt
@@ -1,16 +1,5 @@
-# STL allocators (T *allocator<T *>::allocate(size_type, const void*)).
-# The type signature mandates a cast from uninitialized void* to T*.
-# size_type can either be unsigned int (j) or unsigned long (m).
-fun:*8allocateEjPKv
-fun:*8allocateEmPKv
-
-# std::get_temporary_buffer, likewise.
-fun:_ZSt20get_temporary_buffer*
-fun:_ZNSt3__120get_temporary_buffer*
-
-# STL address-of magic (libstdc++, libc++).
-fun:*__addressof*
-fun:_ZNSt3__19addressof*
+# e.g. RolloverProtectedTickClock
+fun:*MutableInstance*
 
 # WTF allocators.
 fun:*allocate*Backing*
@@ -22,16 +11,13 @@
 src:*third_party/mesa*
 
 # Deliberate bad cast to derived class to hide functions.
+type:*BlockIUnknownMethods*
 type:*BlockRefType*
 type:*SkAutoTUnref*
+type:*SkBlockComRef*
 # https://crbug.com/517959
 type:*NoAddRefRelease*
 
-# All std:: types
-# This should be possible to remove, if/when we build against
-# a statically linked libc++.
-type:std::*
-
 # All mojo::test:: types.
 # They are loaded from libmojo_public_test_support.so
 # https://crbug.com/515347
@@ -41,6 +27,19 @@
 # https://crbug.com/520760
 fun:*MessageScannerImpl*MessageScannerImpl*
 
+# src/base/win/event_trace_provider_unittest.cc
+type:*EtwTraceProvider*
+
+# These classes are used to communicate between chrome.exe and
+# chrome_child.dll (see src/sandbox/win/src/sandbox.h,
+# src/chrome/app/chrome_main.cc).
+type:sandbox::BrokerServices
+type:sandbox::TargetPolicy
+type:sandbox::TargetServices
+
+# Likewise (base/win/scoped_handle.cc).
+type:*ActiveVerifier*
+
 #############################################################################
 # Base class's constructor accesses a derived class.
 
diff --git a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp
index 0ed953f..558637c 100644
--- a/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp
+++ b/tools/clang/blink_gc_plugin/CheckFieldsVisitor.cpp
@@ -107,7 +107,13 @@
     return;
   }
 
-  if (Parent()->IsRawPtr() || Parent()->IsRefPtr() || Parent()->IsOwnPtr()) {
+  if (Parent()->IsRawPtr() || Parent()->IsOwnPtr()) {
+    invalid_fields_.push_back(std::make_pair(
+        current_, InvalidSmartPtr(Parent())));
+    return;
+  }
+
+  if (Parent()->IsRefPtr() && !edge->value()->IsGCRefCounted()) {
     invalid_fields_.push_back(std::make_pair(
         current_, InvalidSmartPtr(Parent())));
     return;
diff --git a/tools/clang/blink_gc_plugin/Config.h b/tools/clang/blink_gc_plugin/Config.h
index c62de05..7ca8ea4c 100644
--- a/tools/clang/blink_gc_plugin/Config.h
+++ b/tools/clang/blink_gc_plugin/Config.h
@@ -138,6 +138,11 @@
            name == "ThreadSafeRefCountedGarbageCollected";
   }
 
+  static bool IsGCRefCountedBase(const std::string& name) {
+    return name == "RefCountedGarbageCollected" ||
+           name == "ThreadSafeRefCountedGarbageCollected";
+  }
+
   static bool IsGCBase(const std::string& name) {
     return name == "GarbageCollected" ||
            IsGCFinalizedBase(name) ||
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.cpp b/tools/clang/blink_gc_plugin/RecordInfo.cpp
index 516a40a0..cf7fb8c 100644
--- a/tools/clang/blink_gc_plugin/RecordInfo.cpp
+++ b/tools/clang/blink_gc_plugin/RecordInfo.cpp
@@ -186,6 +186,16 @@
   return is_eagerly_finalized_;
 }
 
+bool RecordInfo::IsGCRefCounted() {
+  if (!IsGCDerived())
+    return false;
+  for (const auto& gc_base : gc_base_names_) {
+    if (Config::IsGCRefCountedBase(gc_base))
+      return true;
+  }
+  return false;
+}
+
 bool RecordInfo::HasDefinition() {
   return record_->hasDefinition();
 }
diff --git a/tools/clang/blink_gc_plugin/RecordInfo.h b/tools/clang/blink_gc_plugin/RecordInfo.h
index e59c0b70..a274ae13 100644
--- a/tools/clang/blink_gc_plugin/RecordInfo.h
+++ b/tools/clang/blink_gc_plugin/RecordInfo.h
@@ -95,6 +95,7 @@
   bool IsOnlyPlacementNewable();
   bool IsGCMixinInstance();
   bool IsEagerlyFinalized();
+  bool IsGCRefCounted();
 
   bool HasDefinition();
 
diff --git a/tools/clang/blink_gc_plugin/tests/heap/stubs.h b/tools/clang/blink_gc_plugin/tests/heap/stubs.h
index 5e07c23..a31ef3a 100644
--- a/tools/clang/blink_gc_plugin/tests/heap/stubs.h
+++ b/tools/clang/blink_gc_plugin/tests/heap/stubs.h
@@ -154,6 +154,9 @@
 template<typename T>
 class GarbageCollectedFinalized : public GarbageCollected<T> { };
 
+template<typename T>
+class RefCountedGarbageCollected : public GarbageCollectedFinalized<T> { };
+
 template<typename T> class Member {
 public:
     operator T*() const { return 0; }
diff --git a/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.cpp b/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.cpp
index e0a200f..22e59d5 100644
--- a/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.cpp
+++ b/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.cpp
@@ -8,4 +8,6 @@
 
 void HeapObject::trace(Visitor*) { }
 
+void RefHeapObject::trace(Visitor*) { }
+
 }
diff --git a/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.h b/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.h
index 0dba311..405732e 100644
--- a/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.h
+++ b/tools/clang/blink_gc_plugin/tests/ref_ptr_to_gc_managed_class.h
@@ -25,6 +25,14 @@
     Vector<RefPtr<HeapObject> > m_objs;
 };
 
+class RefHeapObject : public RefCountedGarbageCollected<HeapObject> {
+public:
+    void trace(Visitor*);
+private:
+    PartObject m_part;
+    Vector<RefPtr<RefHeapObject> > m_objs;
+};
+
 }
 
 #endif
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index cc85b8f6..7ba8957 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -40849,6 +40849,35 @@
   </summary>
 </histogram>
 
+<histogram name="Scheduling.BeginMainFrameQueueDurationCritical"
+    units="microseconds">
+  <owner>brianderson@chromium.org</owner>
+  <summary>
+    How long it takes for the main side to start the BeginMainFrame in response
+    to the compositor's SendBeginMainFrame when the on_critical_path flag is
+    set.
+  </summary>
+</histogram>
+
+<histogram name="Scheduling.BeginMainFrameQueueDurationNotCritical"
+    units="microseconds">
+  <owner>brianderson@chromium.org</owner>
+  <summary>
+    How long it takes for the main side to start the BeginMainFrame in response
+    to the compositor's SendBeginMainFrame when the on_critical_path flag is not
+    set.
+  </summary>
+</histogram>
+
+<histogram name="Scheduling.BeginMainFrameStartToCommitDuration"
+    units="microseconds">
+  <owner>brianderson@chromium.org</owner>
+  <summary>
+    The time from when the main side actually starts the BeginMainFrame to when
+    the commit completes on the impl side.
+  </summary>
+</histogram>
+
 <histogram name="Scheduling.BeginMainFrameToCommitDuration"
     units="microseconds">
   <owner>brianderson@chromium.org</owner>
@@ -77025,6 +77054,15 @@
   <affected-histogram name="Scheduling.PrepareTilesDuration"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="CompositorTimingHistoryProcess2" separator="."
+    ordering="prefix">
+  <suffix name="Browser"/>
+  <suffix name="Renderer"/>
+  <affected-histogram name="Scheduling.BeginMainFrameQueueDurationCritical"/>
+  <affected-histogram name="Scheduling.BeginMainFrameQueueDurationNotCritical"/>
+  <affected-histogram name="Scheduling.BeginMainFrameStartToCommitDuration"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="CompositorTimingHistorySubcategory" separator=".">
   <suffix name="NotUsedForEstimate"
       label="Samples that don't affect estimates. For example, because we are
@@ -77050,6 +77088,24 @@
   <affected-histogram name="Scheduling.Renderer.PrepareTilesDuration"/>
 </histogram_suffixes>
 
+<histogram_suffixes name="CompositorTimingHistorySubcategory2" separator=".">
+  <suffix name="NotUsedForEstimate"
+      label="Samples that don't affect estimates. For example, because we are
+             coming out of idle."/>
+  <affected-histogram
+      name="Scheduling.Browser.BeginMainFrameQueueDurationCritical"/>
+  <affected-histogram
+      name="Scheduling.Browser.BeginMainFrameQueueDurationNotCritical"/>
+  <affected-histogram
+      name="Scheduling.Browser.BeginMainFrameStartToCommitDuration"/>
+  <affected-histogram
+      name="Scheduling.Renderer.BeginMainFrameQueueDurationCritical"/>
+  <affected-histogram
+      name="Scheduling.Renderer.BeginMainFrameQueueDurationNotCritical"/>
+  <affected-histogram
+      name="Scheduling.Renderer.BeginMainFrameStartToCommitDuration"/>
+</histogram_suffixes>
+
 <histogram_suffixes name="ConnCountImpact">
   <suffix name="conn_count_16" label="with 16 persistent connections per host"/>
   <suffix name="conn_count_4" label="with 4 persistent connections per host"/>
diff --git a/tools/perf/page_sets/story_set_unittest.py b/tools/perf/page_sets/story_set_unittest.py
index faedbdf..9f41389 100644
--- a/tools/perf/page_sets/story_set_unittest.py
+++ b/tools/perf/page_sets/story_set_unittest.py
@@ -1,4 +1,4 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2014 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.
 
@@ -18,12 +18,14 @@
     self.top_level_dir = os.path.dirname(self.story_sets_dir)
 
   # TODO(tbarzic): crbug.com/386416.
-  @decorators.Disabled('chromeos')
+  # http://crbug.com/513086
+  @decorators.Disabled('all')
   def testSmoke(self):
     self.RunSmokeTest(self.story_sets_dir, self.top_level_dir)
 
   # TODO(nednguyen): Remove this test once crbug.com/508538 is fixed.
-  @decorators.Disabled('chromeos')
+  # http://crbug.com/513086
+  @decorators.Disabled('all')
   def testNoPageDefinedSyntheticDelay(self):
     for story_set_class in self.GetAllStorySetClasses(self.story_sets_dir,
                                                       self.top_level_dir):
diff --git a/ui/file_manager/OWNERS b/ui/file_manager/OWNERS
index 29adc89..85ce43d 100644
--- a/ui/file_manager/OWNERS
+++ b/ui/file_manager/OWNERS
@@ -1,4 +1,5 @@
 fukino@chromium.org
 hirono@chromium.org
 mtomasz@chromium.org
+yawano@chromium.org
 yoshiki@chromium.org
diff --git a/ui/file_manager/audio_player/elements/audio_player.html b/ui/file_manager/audio_player/elements/audio_player.html
index 9caf15a2..1a68e14 100644
--- a/ui/file_manager/audio_player/elements/audio_player.html
+++ b/ui/file_manager/audio_player/elements/audio_player.html
@@ -26,6 +26,7 @@
         volume="{{volume}}"
         expanded="{{expanded}}"
         volume-slider-shown="{{volumeSliderShown}}"
+        aria-labels="[[ariaLabels]]"
         on-next-clicked="onControllerNextClicked"
         on-previous-clicked="onControllerPreviousClicked"></control-panel>
     <audio id="audio"
diff --git a/ui/file_manager/audio_player/elements/audio_player.js b/ui/file_manager/audio_player/elements/audio_player.js
index a6b51e9..7fd0866 100644
--- a/ui/file_manager/audio_player/elements/audio_player.js
+++ b/ui/file_manager/audio_player/elements/audio_player.js
@@ -98,6 +98,10 @@
       type: Number,
       value: 0,
       reflectToAttribute: true
+    },
+
+    ariaLabels: {
+      type: Object
     }
   },
 
diff --git a/ui/file_manager/audio_player/elements/control_panel.css b/ui/file_manager/audio_player/elements/control_panel.css
index 9a2b198..de868107 100644
--- a/ui/file_manager/audio_player/elements/control_panel.css
+++ b/ui/file_manager/audio_player/elements/control_panel.css
@@ -62,13 +62,6 @@
   top: 0;
 }
 
-.media-button[state='default']:not(.disabled) > .default,
-.media-button[state='ended']:not(.disabled) > .ended,
-.media-button[state='playing']:not(.disabled) > .playing,
-.media-button.disabled > .disabled {
-  opacity: 1;
-}
-
 /* Custom sliders for progress and volume. */
 
 /* Customize the standard input[type='range']. */
@@ -134,7 +127,7 @@
   visibility: hidden;
 }
 
-.media-button.shuffle-mode > label > .icon {
+.media-button.shuffle-mode {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_shuffle.png) 1x,
       url(../assets/200/player_button_shuffle.png) 2x);
@@ -146,7 +139,7 @@
   margin-right: 0;
 }
 
-.media-button.repeat > label > .icon {
+.media-button.repeat {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_repeat.png) 1x,
       url(../assets/200/player_button_repeat.png) 2x);
@@ -158,78 +151,50 @@
   margin-right: 4px;
 }
 
-.media-button.play > .ended {
+.media-button.play {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_play.png) 1x,
       url(../assets/200/player_button_play.png) 2x);
 }
 
-.media-button.play > .playing {
+:host([playing]) .media-button.play {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_pause.png) 1x,
       url(../assets/200/player_button_pause.png) 2x);
 }
 
 .media-button.previous {
+  background-image: -webkit-image-set(
+      url(../assets/100/player_button_previous.png) 1x,
+      url(../assets/200/player_button_previous.png) 2x);
   margin-left: 8px;
   margin-right: 0;
 }
 
-.media-button.previous > .normal {
-  background-image: -webkit-image-set(
-      url(../assets/100/player_button_previous.png) 1x,
-      url(../assets/200/player_button_previous.png) 2x);
-}
-
 .media-button.next {
-  margin-left: 0;
-  margin-right: 8px;
-}
-
-.media-button.next > .normal {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_next.png) 1x,
       url(../assets/200/player_button_next.png) 2x);
-}
-
-.media-button.volume {
   margin-left: 0;
   margin-right: 8px;
 }
 
-.media-button.volume > .normal {
+.media-button.volume {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_volume.png) 1x,
       url(../assets/200/player_button_volume.png) 2x);
-}
-
-.media-button.volume > label > .icon {
-  background-image: -webkit-image-set(
-      url(../assets/100/player_button_volume.png) 1x,
-      url(../assets/200/player_button_volume.png) 2x);
+  margin-left: 0;
+  margin-right: 8px;
   pointer-events: auto;
 }
 
-.media-button.playlist > label > .icon {
+.media-button.playlist {
   background-image: -webkit-image-set(
       url(../assets/100/player_button_playlist.png) 1x,
       url(../assets/200/player_button_playlist.png) 2x);
   pointer-events: auto;
 }
 
-.media-button files-toggle-ripple {
-  position: absolute;
-  height: 28px;
-  left: 2px;
-  top: 2px;
-  width: 28px;
-  pointer-events: none;
-}
-
-.media-button files-toggle-ripple::shadow .ripple.activated {
-  opacity: 0.1;
-}
-
 /* Invisible div used to compute the width required for the elapsed time. */
 .time-controls > .time > .current {
   align-items: center;
diff --git a/ui/file_manager/audio_player/elements/control_panel.html b/ui/file_manager/audio_player/elements/control_panel.html
index e8fdb283..ee8b518 100644
--- a/ui/file_manager/audio_player/elements/control_panel.html
+++ b/ui/file_manager/audio_player/elements/control_panel.html
@@ -7,8 +7,7 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/font-roboto/roboto.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-slider/paper-slider.html">
-<link rel="import" href="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_ripple.html">
-<link rel="import" href="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_toggle_ripple.html">
+<link rel="import" href="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_icon_button.html">
 
 <dom-module id="control-panel">
   <link rel="import" type="css" href="control_panel.css">
@@ -19,77 +18,54 @@
       </div>
       <div class="control-row audio-controls">
         <!-- Shuffle toggle button in the bottom line. -->
-        <button class="shuffle-mode media-button toggle" state="default">
-          <label>
-            <input id="shuffleCheckbox"
-                   type="checkbox"
-                   checked="{{shuffle::change}}">
-            <span class="icon"></span>
-          </label>
-          <files-toggle-ripple activated="[[shuffle]]"></files-toggle-ripple>
-        </button>
+        <files-icon-button toggles
+            id="shuffle"
+            class="shuffle-mode media-button toggle"
+            active="{{shuffle}}">
+        </files-icon-button>
 
         <!-- Repeat toggle button in the bottom line. -->
-        <button class="repeat media-button toggle" state="default">
-          <label>
-            <input id="repeatCheckbox"
-                   type="checkbox"
-                   checked="{{repeat::change}}">
-            <span class="icon"></span>
-          </label>
-          <files-toggle-ripple activated="[[repeat]]"></files-toggle-ripple>
-        </button>
+        <files-icon-button toggles
+            id="repeat"
+            class="repeat media-button toggle"
+            active="{{repeat}}">
+        </files-icon-button>
 
         <!-- Prev button in the bottom line. -->
-        <button class="previous media-button"
-               state="default"
-               on-click="previousClick">
-          <div class="normal default"></div>
-          <div class="disabled"></div>
-          <files-ripple></files-ripple>
-        </button>
+        <files-icon-button
+            id="previous"
+            class="previous media-button"
+            on-click="previousClick">
+        </files-icon-button>
 
         <!-- Play button in the bottom line. -->
-        <button class="play media-button"
-                state$="[[computePlayState_(playing)]]"
-                on-click="playClick">
-          <div class="normal playing"></div>
-          <div class="normal ended"></div>
-          <div class="disabled"></div>
-          <files-ripple></files-ripple>
-        </button>
+        <files-icon-button
+            id="play"
+            class="play media-button"
+            on-click="playClick">
+        </files-icon-button>
 
         <!-- Next button in the bottom line. -->
-        <button class="next media-button"
-                state="default"
-                on-click="nextClick">
-          <div class="normal default"></div>
-          <div class="disabled"></div>
-          <files-ripple></files-ripple>
-        </button>
+        <files-icon-button
+            id="next"
+            class="next media-button"
+            on-click="nextClick">
+        </files-icon-button>
 
         <!-- Volume button in the bottom line. -->
-        <button id="volumeButton"
-                class="volume media-button toggle"
-                state="default"
-                anchor-point="bottom center">
-          <label>
-            <input type="checkbox" checked="{{volumeSliderShown::change}}">
-            <span class="icon"></span>
-          </label>
-          <files-toggle-ripple activated="[[volumeSliderShown]]"></files-toggle-ripple>
-        </button>
+        <files-icon-button toggles
+            id="volume"
+            class="volume media-button toggle"
+            anchor-point="bottom center"
+            active="{{volumeSliderShown}}">
+        </files-icon-button>
 
         <!-- Playlist button in the bottom line. -->
-        <button id="playlistButton"
-                class="playlist media-button toggle"
-                state="default">
-          <label>
-            <input type="checkbox" checked="{{expanded::change}}">
-            <span class="icon"></span>
-          </label>
-          <files-toggle-ripple activated="[[expanded]]"></files-toggle-ripple>
-        </button>
+        <files-icon-button toggles
+            id="playList"
+            class="playlist media-button toggle"
+            active="{{expanded}}">
+        </files-toggle-ripple>
       </div>
       <div class="control-row time-controls">
         <div class="time-container">
diff --git a/ui/file_manager/audio_player/elements/control_panel.js b/ui/file_manager/audio_player/elements/control_panel.js
index 8956287..d67253c 100644
--- a/ui/file_manager/audio_player/elements/control_panel.js
+++ b/ui/file_manager/audio_player/elements/control_panel.js
@@ -16,7 +16,9 @@
       playing: {
         type: Boolean,
         value: false,
-        notify: true
+        notify: true,
+        reflectToAttribute: true,
+        observer: 'playingChanged_'
       },
 
       /**
@@ -88,6 +90,14 @@
         type: Boolean,
         value: false,
         notify: true
+      },
+
+      /**
+       * Dictionary which contains aria-labels for each controls.
+       */
+      ariaLabels: {
+        type: Object,
+        observer: 'ariaLabelsChanged_'
       }
     },
 
@@ -147,19 +157,35 @@
     },
 
     /**
-     * Computes state for play button based on 'playing' property.
-     * @return {string}
+     * Invoked when the playing property is changed.
+     * @param {boolean} playing
+     * @private
      */
-    computePlayState_: function(playing) {
-      return playing ? "playing" : "ended";
+    playingChanged_: function(playing) {
+      if (this.ariaLabels) {
+        this.$.play.setAttribute('aria-label',
+            playing ? this.ariaLabels.pause : this.ariaLabels.play);
+      }
     },
 
     /**
-     * Computes style for '.filled' element of progress bar.
-     * @return {string}
+     * Invoked when the ariaLabels property is changed.
+     * @param {Object} ariaLabels
+     * @private
      */
-    computeProgressBarStyle_: function(time, duration) {
-      return 'width: ' + (time / duration * 100) + '%;';
+    ariaLabelsChanged_: function(ariaLabels) {
+      assert(ariaLabels);
+      // TODO(fukino): Use data bindings.
+      this.$.volumeSlider.setAttribute('aria-label', ariaLabels.volumeSlider);
+      this.$.shuffle.setAttribute('aria-label', ariaLabels.shuffle);
+      this.$.repeat.setAttribute('aria-label', ariaLabels.repeat);
+      this.$.previous.setAttribute('aria-label', ariaLabels.previous);
+      this.$.play.setAttribute('aria-label',
+          this.playing ? ariaLabels.pause : ariaLabels.play);
+      this.$.next.setAttribute('aria-label', ariaLabels.next);
+      this.$.volume.setAttribute('aria-label', ariaLabels.volume);
+      this.$.playList.setAttribute('aria-label', ariaLabels.playList);
+      this.$.timeSlider.setAttribute('aria-label', ariaLabels.seekSlider);
     }
   });
 })();  // Anonymous closure
diff --git a/ui/file_manager/audio_player/js/audio_player.js b/ui/file_manager/audio_player/js/audio_player.js
index ea5fd26..fb09c33 100644
--- a/ui/file_manager/audio_player/js/audio_player.js
+++ b/ui/file_manager/audio_player/js/audio_player.js
@@ -68,6 +68,19 @@
       this.offlineString_ = strings['AUDIO_OFFLINE'];
       AudioPlayer.TrackInfo.DEFAULT_ARTIST =
           strings['AUDIO_PLAYER_DEFAULT_ARTIST'];
+      // Pass translated labels to the AudioPlayerElement.
+      this.player_.ariaLabels = {
+        volumeSlider: strings['AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL'],
+        shuffle: strings['AUDIO_PLAYER_SHUFFLE_BUTTON_LABEL'],
+        repeat: strings['AUDIO_PLAYER_REPEAT_BUTTON_LABEL'],
+        previous: strings['MEDIA_PLAYER_PREVIOUS_BUTTON_LABEL'],
+        play: strings['MEDIA_PLAYER_PLAY_BUTTON_LABEL'],
+        pause: strings['MEDIA_PLAYER_PAUSE_BUTTON_LABEL'],
+        next: strings['MEDIA_PLAYER_NEXT_BUTTON_LABEL'],
+        volume: strings['AUDIO_PLAYER_OPEN_VOLUME_SLIDER_BUTTON_LABEL'],
+        playList: strings['AUDIO_PLAYER_OPEN_PLAY_LIST_BUTTON_LABEL'],
+        seekSlider: strings['MEDIA_PLAYER_SEEK_SLIDER_LABEL']
+      };
     }.bind(this));
 
     this.volumeManager_.addEventListener('externally-unmounted',
diff --git a/ui/file_manager/file_manager/foreground/css/file_manager.css b/ui/file_manager/file_manager/foreground/css/file_manager.css
index 2b462c5..6d73e59 100644
--- a/ui/file_manager/file_manager/foreground/css/file_manager.css
+++ b/ui/file_manager/file_manager/foreground/css/file_manager.css
@@ -60,7 +60,7 @@
   opacity: 0.8;
 }
 
-::-webkit-scrollbar {
+.dialog-container ::-webkit-scrollbar {
   height: 0;
   width: 0;
 }
diff --git a/ui/file_manager/file_manager/foreground/css/share_dialog.css b/ui/file_manager/file_manager/foreground/css/share_dialog.css
index 29a2d32..ab48261 100644
--- a/ui/file_manager/file_manager/foreground/css/share_dialog.css
+++ b/ui/file_manager/file_manager/foreground/css/share_dialog.css
@@ -5,6 +5,10 @@
 .cr-dialog-frame.share-dialog-frame {
   -webkit-app-region: no-drag;
   background-color: white;
+  box-sizing: border-box;
+  max-height: 100%;
+  overflow-x: hidden;
+  overflow-y: auto;
   width: auto;
 }
 
@@ -12,7 +16,6 @@
   height: 100px;
   margin-top: 10px;
   min-width: 300px;
-  overflow: hidden;
   transition: height 200ms ease-out;
 }
 
diff --git a/ui/file_manager/file_manager/foreground/elements/files_icon_button.html b/ui/file_manager/file_manager/foreground/elements/files_icon_button.html
new file mode 100644
index 0000000..f6113e3
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/elements/files_icon_button.html
@@ -0,0 +1,61 @@
+<!-- Copyright 2015 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.
+  -->
+
+<!--
+  `files-icon-button` implements common behaviors among icon buttons in file
+  manager, video player, and audio player.
+  If the button has |toggles| attributes, this element uses files-toggle-ripple
+  to indicate the active state. Otherwise, this element uses files-ripple to
+  show circle burst on click.
+  In addition, this element shows outline only when it is focused by keyboard
+  operation.
+-->
+
+<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-behaviors/iron-button-state.html">
+<link rel="import" href="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_ripple.html">
+<link rel="import" href="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_toggle_ripple.html">
+
+<dom-module id="files-icon-button">
+  <template>
+    <style>
+      :host {
+        background-position: center;
+        background-repeat: no-repeat;
+        border-radius: 2px;
+        cursor: pointer;
+        display: inline-block;
+        height: 32px;
+        outline: none;  /* We use original outline for focused state. */
+        position: relative;
+        width: 32px;
+      }
+
+      :host(.keyboard-focus) {
+        /* We use box-shadow rather than outline to make it rounded. */
+        box-shadow: 0 0 0 1px rgba(66, 133, 244, 0.5);
+      }
+
+      files-toggle-ripple {
+        height: 28px;
+        left: 2px;
+        pointer-events: none;
+        position: absolute;
+        top: 2px;
+        width: 28px;
+      }
+
+      files-toggle-ripple::shadow .ripple.activated {
+        opacity: 0.1;
+      }
+    </style>
+
+    <files-ripple hidden="[[toggles]]"></files-ripple>
+    <files-toggle-ripple activated="[[active]]"></files-toggle-ripple>
+    <!-- TODO(fukino): Make it possible to insert user-defined element to show them on top of ripple effect. -->
+  </template>
+
+  <script src="files_icon_button.js"></script>
+</dom-module>
diff --git a/ui/file_manager/file_manager/foreground/elements/files_icon_button.js b/ui/file_manager/file_manager/foreground/elements/files_icon_button.js
new file mode 100644
index 0000000..63039f3c
--- /dev/null
+++ b/ui/file_manager/file_manager/foreground/elements/files_icon_button.js
@@ -0,0 +1,29 @@
+// Copyright 2015 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.
+
+Polymer({
+  is: 'files-icon-button',
+
+  hostAttributes: {
+    role: 'button',
+    tabindex: 0
+  },
+
+  behaviors: [
+    Polymer.IronButtonState,
+    Polymer.IronControlState
+  ],
+
+  observers: [
+    '_focusedChanged(receivedFocusFromKeyboard)'
+  ],
+
+  _focusedChanged: function(receivedFocusFromKeyboard) {
+    if (receivedFocusFromKeyboard) {
+      this.classList.add('keyboard-focus');
+    } else {
+      this.classList.remove('keyboard-focus');
+    }
+  }
+});
diff --git a/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js b/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js
index e9a8351..25cb653 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/share_dialog.js
@@ -150,8 +150,6 @@
 
   this.webViewWrapper_.style.width = width + 'px';
   this.webViewWrapper_.style.height = height + 'px';
-  this.webView_.style.width = width + 'px';
-  this.webView_.style.height = height + 'px';
 
   // Wait sending 'resizeComplete' event until the latest size can be obtained
   // in the WebView.
@@ -160,8 +158,7 @@
       code: "[document.documentElement.clientWidth," +
             " document.documentElement.clientHeight];"
     }, function(results) {
-      if (results[0][0] === parseInt(this.webView_.style.width, 10) &&
-          results[0][1] === parseInt(this.webView_.style.height, 10)) {
+      if (results[0][0] === width && results[0][1] === height) {
         callback();
       } else {
         setTimeout(checkSize, 50);
diff --git a/ui/file_manager/file_manager/manifest.json b/ui/file_manager/file_manager/manifest.json
index 33a2ee83..0424b7041 100644
--- a/ui/file_manager/file_manager/manifest.json
+++ b/ui/file_manager/file_manager/manifest.json
@@ -158,6 +158,8 @@
     "common/js/path_util.js",
     "common/js/util.js",
     "common/js/volume_manager_common.js",
+    "foreground/elements/files_icon_button.html",
+    "foreground/elements/files_icon_button.js",
     "foreground/elements/files_ripple.html",
     "foreground/elements/files_ripple.js",
     "foreground/elements/files_toast.html",
diff --git a/ui/file_manager/file_manager_resources.grd b/ui/file_manager/file_manager_resources.grd
index a0aa1e6..8826ebc 100644
--- a/ui/file_manager/file_manager_resources.grd
+++ b/ui/file_manager/file_manager_resources.grd
@@ -50,6 +50,8 @@
       <include name="IDR_FILE_MANAGER_VOLUME_MANAGER_JS" file="file_manager/background/js/volume_manager.js" flattenhtml="false" type="BINDATA" />
 
       <!-- Polymer elements -->
+      <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_ICON_BUTTON_HTML" file="file_manager/foreground/elements/files_icon_button.html" type="BINDATA" />
+      <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_ICON_BUTTON_JS" file="file_manager/foreground/elements/files_icon_button.js" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_RIPPLE_HTML" file="file_manager/foreground/elements/files_ripple.html" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_RIPPLE_JS" file="file_manager/foreground/elements/files_ripple.js" type="BINDATA" />
       <include name="IDR_FILE_MANAGER_ELEMENTS_FILES_TOAST_HTML" file="file_manager/foreground/elements/files_toast.html" type="BINDATA" />
diff --git a/ui/file_manager/gallery/js/dimmable_ui_controller.js b/ui/file_manager/gallery/js/dimmable_ui_controller.js
index 840e17e0..3837374 100644
--- a/ui/file_manager/gallery/js/dimmable_ui_controller.js
+++ b/ui/file_manager/gallery/js/dimmable_ui_controller.js
@@ -53,6 +53,11 @@
   /**
    * @private {boolean}
    */
+  this.renaming_ = false;
+
+  /**
+   * @private {boolean}
+   */
   this.disabled_ = false;
 
   /**
@@ -97,17 +102,18 @@
  * @param {Gallery.SubMode|undefined} subMode
  * @param {boolean} loading
  * @param {boolean} spokenFeedbackEnabled
+ * @param {boolean} renaming
  * @return {boolean}
  */
 DimmableUIController.shouldBeDisabled = function(
-    mode, subMode, loading, spokenFeedbackEnabled) {
+    mode, subMode, loading, spokenFeedbackEnabled, renaming) {
   return spokenFeedbackEnabled ||
       mode === undefined ||
       subMode === undefined ||
       mode === Gallery.Mode.THUMBNAIL ||
       (mode === Gallery.Mode.SLIDE && subMode === Gallery.SubMode.EDIT) ||
       (mode === Gallery.Mode.SLIDE && subMode === Gallery.SubMode.BROWSE &&
-       loading);
+       (loading || renaming));
 };
 
 /**
@@ -125,6 +131,18 @@
 };
 
 /**
+ * Sets whether user is renaming an image or not.
+ * @param {boolean} renaming
+ */
+DimmableUIController.prototype.setRenaming = function(renaming) {
+  if (this.renaming_ === renaming)
+    return;
+
+  this.renaming_ = renaming;
+  this.updateAvailability_();
+};
+
+/**
  * Sets whether gallery is currently loading an image or not.
  * @param {boolean} loading
  */
@@ -335,7 +353,8 @@
  */
 DimmableUIController.prototype.updateAvailability_ = function() {
   var disabled = DimmableUIController.shouldBeDisabled(
-      this.mode_, this.subMode_, this.loading_, this.spokenFeedbackEnabled_);
+      this.mode_, this.subMode_, this.loading_, this.spokenFeedbackEnabled_,
+      this.renaming_);
 
   if (this.disabled_ === disabled)
     return;
diff --git a/ui/file_manager/gallery/js/dimmable_ui_controller_unittest.js b/ui/file_manager/gallery/js/dimmable_ui_controller_unittest.js
index 5390a26..c695f7a2 100644
--- a/ui/file_manager/gallery/js/dimmable_ui_controller_unittest.js
+++ b/ui/file_manager/gallery/js/dimmable_ui_controller_unittest.js
@@ -6,30 +6,35 @@
   // Disabled when mode is not set.
   assertTrue(DimmableUIController.shouldBeDisabled(
       undefined /* mode */, undefined /* subMode */, false /* loading */,
-      false /* spokenFeedbackEnabled */));
+      false /* spokenFeedbackEnabled */, false /* renaming */));
 
   // Disabled in thumbnail mode.
   assertTrue(DimmableUIController.shouldBeDisabled(
       Gallery.Mode.THUMBNAIL, Gallery.SubMode.BROWSE, false /* loading */,
-      false /* spokenFeedbackEnabled */));
+      false /* spokenFeedbackEnabled */, false /* renaming */));
 
   // Disabled in edit mode.
   assertTrue(DimmableUIController.shouldBeDisabled(
       Gallery.Mode.SLIDE, Gallery.SubMode.EDIT, false /* loading*/,
-      false /* spokenFeedbackEnabled */));
+      false /* spokenFeedbackEnabled */, false /* renaming */));
 
   // Shouldn't be disabled while browsing in slide mode.
   assertFalse(DimmableUIController.shouldBeDisabled(
       Gallery.Mode.SLIDE, Gallery.SubMode.BROWSE, false /* loading */,
-      false /* spokenFeedbackEnabled */));
+      false /* spokenFeedbackEnabled */, false /* renaming */));
 
   // Disabled while loading an image in slide mode.
   assertTrue(DimmableUIController.shouldBeDisabled(
       Gallery.Mode.SLIDE, Gallery.SubMode.BROWSE, true /* loading */,
-      false /* spokenFeedbackEnabled */));
+      false /* spokenFeedbackEnabled */, false /* renaming */));
 
   // Disabled when spoken feedback is enabled.
   assertTrue(DimmableUIController.shouldBeDisabled(
       Gallery.Mode.SLIDE, Gallery.SubMode.BROWSE, false /* loading */,
-      true /* spokenFeedbackEnabled */));
+      true /* spokenFeedbackEnabled */, false /* renaming */));
+
+  // Disabled when user is renaming an image.
+  assertTrue(DimmableUIController.shouldBeDisabled(
+      Gallery.Mode.SLIDE, Gallery.SubMode.BROWSE, false /* loading */,
+      false /* spokenFeedbackEnabled */, true /* renaming */))
 }
diff --git a/ui/file_manager/gallery/js/gallery.js b/ui/file_manager/gallery/js/gallery.js
index d062397..7a19a7d 100644
--- a/ui/file_manager/gallery/js/gallery.js
+++ b/ui/file_manager/gallery/js/gallery.js
@@ -897,6 +897,8 @@
  */
 Gallery.prototype.onFilenameFocus_ = function() {
   ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', true);
+  this.dimmableUIController_.setRenaming(true);
+
   this.filenameEdit_.originalValue = this.filenameEdit_.value;
   setTimeout(this.filenameEdit_.select.bind(this.filenameEdit_), 0);
   this.onUserAction_();
@@ -936,6 +938,7 @@
   }
 
   ImageUtil.setAttribute(this.filenameSpacer_, 'renaming', false);
+  this.dimmableUIController_.setRenaming(false);
   this.onUserAction_();
 };
 
diff --git a/ui/file_manager/integration_tests/file_manager/open_audio_files.js b/ui/file_manager/integration_tests/file_manager/open_audio_files.js
index 3a3c4c69..f75cbf8 100644
--- a/ui/file_manager/integration_tests/file_manager/open_audio_files.js
+++ b/ui/file_manager/integration_tests/file_manager/open_audio_files.js
@@ -268,7 +268,7 @@
       audioPlayerApp.callRemoteTestUtil(
           'fakeMouseClick',
           audioAppId,
-          ['audio-player /deep/ button.repeat input'],
+          ['audio-player /deep/ files-icon-button.repeat'],
           this.next);
     },
     function(result) {
@@ -404,7 +404,7 @@
       audioPlayerApp.callRemoteTestUtil(
           'fakeMouseClick',
           audioAppId,
-          ['audio-player /deep/ button.repeat input'],
+          ['audio-player /deep/ files-icon-button.repeat'],
           this.next);
     },
     function(result) {
diff --git a/ui/file_manager/video_player/css/media_controls.css b/ui/file_manager/video_player/css/media_controls.css
index f43dfba..f0e3b9d32 100644
--- a/ui/file_manager/video_player/css/media_controls.css
+++ b/ui/file_manager/video_player/css/media_controls.css
@@ -13,14 +13,6 @@
   width: 32px;
 }
 
-.media-button:hover {
-  background-color: rgba(153, 153, 153, 0.2);
-}
-
-.media-button:active {
-  background-color: rgba(153, 153, 153, 0.4);
-}
-
 .media-button.disabled {
   background-color: transparent;
   opacity: 0.26;
@@ -142,6 +134,15 @@
     url(../images/media/media_chromecast.png) 1x,
     url(../images/media/2x/media_chromecast.png) 2x);
   display: none;
+  border-radius: 2px;
+}
+
+/* Reset browser's button style. */
+.media-button.cast {
+  background-color: transparent;
+  border: none;
+  cursor: pointer;
+  outline: none;
 }
 
 #video-player[cast-available][castable] .media-button.cast {
@@ -154,6 +155,10 @@
     url(../images/media/2x/media_chromecast_casting.png) 2x);
 }
 
+.media-button.cast:focus:not(.using-mouse) {
+  box-shadow: 0 0 0 1px rgba(66, 133, 244, 0.5);
+}
+
 /* Fullscreen button. */
 /* There is no final decision whether we need a separate icon when toggled. */
 
@@ -163,7 +168,7 @@
     url(../images/media/2x/media_fullscreen.png) 2x);
 }
 
-#video-player[fullscreen] .media-button.fullscreen {
+#controls[fullscreen] .media-button.fullscreen {
   background-image: -webkit-image-set(
     url(../images/media/media_fullscreen_exit.png) 1x,
     url(../images/media/2x/media_fullscreen_exit.png) 2x);
diff --git a/ui/file_manager/video_player/js/media_controls.js b/ui/file_manager/video_player/js/media_controls.js
index e68ea95..fe9b7ba 100644
--- a/ui/file_manager/video_player/js/media_controls.js
+++ b/ui/file_manager/video_player/js/media_controls.js
@@ -120,12 +120,14 @@
  *
  * @param {string} className Class name.
  * @param {HTMLElement=} opt_parent Parent element or container if undefined.
+ * @param {string=} opt_tagName Tag name of the control. 'div' if undefined.
  * @return {!HTMLElement} The new control element.
  */
-MediaControls.prototype.createControl = function(className, opt_parent) {
+MediaControls.prototype.createControl =
+    function(className, opt_parent, opt_tagName) {
   var parent = opt_parent || this.container_;
-  var control = assertInstanceof(this.document_.createElement('div'),
-      HTMLDivElement);
+  var control = /** @type {!HTMLElement} */
+      (this.document_.createElement(opt_tagName || 'div'));
   control.className = className;
   parent.appendChild(control);
   return control;
@@ -144,7 +146,7 @@
     className, opt_handler, opt_parent, opt_numStates) {
   opt_numStates = opt_numStates || 1;
 
-  var button = this.createControl(className, opt_parent);
+  var button = this.createControl(className, opt_parent, 'files-icon-button');
   button.classList.add('media-button');
 
   button.setAttribute('state', MediaControls.ButtonStateType.DEFAULT);
@@ -230,6 +232,8 @@
 MediaControls.prototype.initPlayButton = function(opt_parent) {
   this.playButton_ = this.createButton('play media-control',
       this.onPlayButtonClicked.bind(this), opt_parent, 3 /* States. */);
+  this.playButton_.setAttribute('aria-label',
+      str('MEDIA_PLAYER_PLAY_BUTTON_LABEL'));
 };
 
 /*
@@ -258,6 +262,8 @@
       document.createElement('paper-slider'));
   this.progressSlider_.classList.add('progress', 'media-control');
   this.progressSlider_.max = MediaControls.PROGRESS_RANGE;
+  this.progressSlider_.setAttribute('aria-label',
+      str('MEDIA_PLAYER_SEEK_SLIDER_LABEL'));
   this.progressSlider_.addEventListener('change', function(event) {
     this.onProgressChange_(this.progressSlider_.ratio);
   }.bind(this));
@@ -385,10 +391,14 @@
   this.soundButton_ = this.createButton('sound media-control',
       this.onSoundButtonClick_.bind(this), volumeControls);
   this.soundButton_.setAttribute('level', 3);  // max level.
+  this.soundButton_.setAttribute('aria-label',
+      str('MEDIA_PLAYER_MUTE_BUTTON_LABEL'));
 
   this.volume_ = /** @type {!PaperSliderElement} */ (
       document.createElement('paper-slider'));
   this.volume_.classList.add('volume', 'media-control');
+  this.volume_.setAttribute('aria-label',
+      str('MEDIA_PLAYER_VOLUME_SLIDER_LABEL'));
   this.volume_.addEventListener('change', function(event) {
     this.onVolumeChange_(this.volume_.ratio);
   }.bind(this));
@@ -406,9 +416,13 @@
 MediaControls.prototype.onSoundButtonClick_ = function() {
   if (this.media_.volume == 0) {
     this.volume_.value = (this.savedVolume_ || 1) * this.volume_.max;
+    this.soundButton_.setAttribute('aria-label',
+        str('MEDIA_PLAYER_MUTE_BUTTON_LABEL'));
   } else {
     this.savedVolume_ = this.media_.volume;
     this.volume_.value = 0;
+    this.soundButton_.setAttribute('aria-label',
+        str('MEDIA_PLAYER_UNMUTE_BUTTON_LABEL'));
   }
   this.onVolumeChange_(this.volume_.ratio);
 };
@@ -435,6 +449,9 @@
 
   this.media_.volume = value;
   this.soundButton_.setAttribute('level', MediaControls.getVolumeLevel_(value));
+  this.soundButton_.setAttribute('aria-label',
+      value === 0 ? str('MEDIA_PLAYER_UNMUTE_BUTTON_LABEL')
+                  : str('MEDIA_PLAYER_MUTE_BUTTON_LABEL'));
 };
 
 /**
@@ -589,12 +606,18 @@
       this.progressSlider_.value === this.progressSlider_.max) {
     this.playButton_.setAttribute('state',
                                   MediaControls.ButtonStateType.ENDED);
+    this.playButton_.setAttribute('aria-label',
+        str('MEDIA_PLAYER_PLAY_BUTTON_LABEL'));
   } else if (playing) {
     this.playButton_.setAttribute('state',
                                   MediaControls.ButtonStateType.PLAYING);
+    this.playButton_.setAttribute('aria-label',
+        str('MEDIA_PLAYER_PAUSE_BUTTON_LABEL'));
   } else {
     this.playButton_.setAttribute('state',
                                   MediaControls.ButtonStateType.DEFAULT);
+    this.playButton_.setAttribute('aria-label',
+        str('MEDIA_PLAYER_PLAY_BUTTON_LABEL'));
   }
 };
 
@@ -649,8 +672,6 @@
  *
  * @param {!HTMLElement} containerElement The container for the controls.
  * @param {function(Event)} onMediaError Function to display an error message.
- * @param {function(string):string} stringFunction Function providing localized
- *     strings.
  * @param {function(Event)=} opt_fullScreenToggle Function to toggle fullscreen
  *     mode.
  * @param {HTMLElement=} opt_stateIconParent The parent for the icon that
@@ -659,10 +680,9 @@
  * @struct
  * @extends {MediaControls}
  */
-function VideoControls(containerElement, onMediaError, stringFunction,
-    opt_fullScreenToggle, opt_stateIconParent) {
+function VideoControls(
+    containerElement, onMediaError, opt_fullScreenToggle, opt_stateIconParent) {
   MediaControls.call(this, containerElement, onMediaError);
-  this.stringFunction_ = stringFunction;
 
   this.container_.classList.add('video-controls');
   this.initPlayButton();
@@ -670,15 +690,22 @@
   this.initVolumeControls();
 
   // Create the cast button.
-  this.castButton_ = this.createButton('cast menubutton');
+  // We need to use <button> since cr.ui.MenuButton.decorate modifies prototype
+  // chain, by which <files-icon-button> will not work correctly.
+  // TODO(fukino): Find a way to use files-icon-button consistently.
+  this.castButton_ = this.createControl(
+      'cast media-button', undefined, 'button');
   this.castButton_.setAttribute('menu', '#cast-menu');
-  this.castButton_.setAttribute(
-      'label', this.stringFunction_('VIDEO_PLAYER_PLAY_ON'));
+  this.castButton_.setAttribute('aria-label', str('VIDEO_PLAYER_PLAY_ON'));
+  this.castButton_.setAttribute('state', MediaControls.ButtonStateType.DEFAULT);
+  this.castButton_.appendChild(document.createElement('files-ripple'));
   cr.ui.decorate(this.castButton_, cr.ui.MenuButton);
 
   if (opt_fullScreenToggle) {
     this.fullscreenButton_ =
         this.createButton('fullscreen', opt_fullScreenToggle);
+    this.fullscreenButton_.setAttribute('aria-label',
+        str('VIDEO_PLAYER_FULL_SCREEN_BUTTON_LABEL'));
   }
 
   if (opt_stateIconParent) {
@@ -744,7 +771,7 @@
  */
 VideoControls.prototype.showTextBanner_ = function(identifier) {
   this.textBanner_.removeAttribute('visible');
-  this.textBanner_.textContent = this.stringFunction_(identifier);
+  this.textBanner_.textContent = str(identifier);
 
   setTimeout(function() {
     var onAnimationEnd = function(event) {
@@ -889,3 +916,21 @@
   hideBelow('.volume-controls', 210);
   hideBelow('.fullscreen', 150);
 };
+
+/**
+ * Updates video control when the window is fullscreened or restored.
+ * @param {boolean} fullscreen True if the window gets fullscreened.
+ */
+VideoControls.prototype.onFullScreenChanged = function(fullscreen) {
+  if (fullscreen) {
+    this.container_.setAttribute('fullscreen', '');
+  } else {
+    this.container_.removeAttribute('fullscreen');
+  }
+
+  if (this.fullscreenButton_) {
+    this.fullscreenButton_.setAttribute('aria-label',
+        fullscreen ? str('VIDEO_PLAYER_EXIT_FULL_SCREEN_BUTTON_LABEL')
+                   : str('VIDEO_PLAYER_FULL_SCREEN_BUTTON_LABEL'));;
+  }
+};
diff --git a/ui/file_manager/video_player/js/video_player.js b/ui/file_manager/video_player/js/video_player.js
index eaa6f31..6420f6c0 100644
--- a/ui/file_manager/video_player/js/video_player.js
+++ b/ui/file_manager/video_player/js/video_player.js
@@ -15,7 +15,6 @@
   VideoControls.call(this,
       controlsContainer,
       this.onPlaybackError_.wrap(this),
-      loadTimeData.getString.wrap(loadTimeData),
       this.toggleFullScreen_.wrap(this),
       videoContainer);
 
@@ -28,9 +27,9 @@
   window.addEventListener('resize', this.updateStyle.wrap(this));
   var currentWindow = chrome.app.window.current();
   currentWindow.onFullscreened.addListener(
-      this.onFullScreenChanged_.bind(this, true));
+      this.onFullScreenChanged.bind(this, true));
   currentWindow.onRestored.addListener(
-      this.onFullScreenChanged_.bind(this, false));
+      this.onFullScreenChanged.bind(this, false));
   document.addEventListener('keydown', function(e) {
     switch (util.getKeyModifiers(e) + e.keyIdentifier) {
       // Handle debug shortcut keys.
@@ -49,7 +48,8 @@
 
       case 'U+0020': // Space
       case 'MediaPlayPause':
-        this.togglePlayStateWithFeedback();
+        if (!e.target.classList.contains('menu-button'))
+          this.togglePlayStateWithFeedback();
         break;
       case 'U+001B': // Escape
         util.toggleFullScreen(
@@ -120,7 +120,7 @@
  */
 FullWindowVideoControls.prototype.showErrorMessage = function(message) {
   var errorBanner = getRequiredElement('error');
-  errorBanner.textContent = loadTimeData.getString(message);
+  errorBanner.textContent = str(message);
   errorBanner.setAttribute('visible', 'true');
 
   // The window is hidden if the video has not loaded yet.
@@ -168,19 +168,6 @@
 };
 
 /**
- * Updates video control when the window is fullscreened or restored.
- * @param {boolean} fullscreen True if the window gets fullscreened.
- * @private
- */
-FullWindowVideoControls.prototype.onFullScreenChanged_ = function(fullscreen) {
-  if (fullscreen) {
-    this.playerContainer_.setAttribute('fullscreen', '');
-  } else {
-    this.playerContainer_.removeAttribute('fullscreen');
-  }
-};
-
-/**
  * Media completion handler.
  */
 FullWindowVideoControls.prototype.onMediaComplete = function() {
@@ -581,7 +568,7 @@
   }
 
   var item = new cr.ui.MenuItem();
-  item.label = loadTimeData.getString('VIDEO_PLAYER_PLAY_THIS_COMPUTER');
+  item.label = str('VIDEO_PLAYER_PLAY_THIS_COMPUTER');
   item.setAttribute('aria-label', item.label);
   item.castLabel = '';
   item.addEventListener('activate', this.onCastSelected_.wrap(this, null));
diff --git a/ui/file_manager/video_player/video_player.html b/ui/file_manager/video_player/video_player.html
index 47f66a1..c9dff59 100644
--- a/ui/file_manager/video_player/video_player.html
+++ b/ui/file_manager/video_player/video_player.html
@@ -16,6 +16,7 @@
   <link rel="stylesheet" type="text/css" href="css/cast_menu.css">
 
   <link rel="import" href="chrome://resources/polymer/v1_0/paper-slider/paper-slider.html">
+  <link rel="import" href="chrome-extension://hhaomjibdihmijegdhdafkllkbggdgoj/foreground/elements/files_icon_button.html">
 
   <style is="custom-style">
     paper-slider {
diff --git a/ui/webui/resources/js/cr/ui/context_menu_handler.js b/ui/webui/resources/js/cr/ui/context_menu_handler.js
index 10cb77c..0c9bb7ad 100644
--- a/ui/webui/resources/js/cr/ui/context_menu_handler.js
+++ b/ui/webui/resources/js/cr/ui/context_menu_handler.js
@@ -152,8 +152,13 @@
 
       switch (e.type) {
         case 'mousedown':
-          if (!this.menu.contains(e.target))
+          if (!this.menu.contains(e.target)) {
             this.hideMenu();
+            if(e.button == 0 /* Left click */) {
+              e.preventDefault();
+              e.stopPropagation();
+            }
+          }
           else
             e.preventDefault();
           break;