diff --git a/chrome/app/mash/mash_runner.cc b/chrome/app/mash/mash_runner.cc
index 9c14e73..d5086ec61 100644
--- a/chrome/app/mash/mash_runner.cc
+++ b/chrome/app/mash/mash_runner.cc
@@ -237,8 +237,8 @@
   service_manager::ServiceContext context(
       base::MakeUnique<mash::MashPackagedService>(),
       std::move(service_request));
-  // Quit the child process if it loses its connection to service manager.
-  context.SetConnectionLostClosure(run_loop.QuitClosure());
+  // Quit the child process when the service quits.
+  context.SetQuitClosure(run_loop.QuitClosure());
   run_loop.Run();
   // |context| must be destroyed before |message_loop|.
 }
diff --git a/chrome/browser/DEPS b/chrome/browser/DEPS
index c491cf46..b5c99f9 100644
--- a/chrome/browser/DEPS
+++ b/chrome/browser/DEPS
@@ -48,6 +48,7 @@
   "+sandbox/win/src",  # The path doesn't say it, but this is the Windows sandbox.
   "+services/image_decoder/public/cpp",
   "+services/image_decoder/public/interfaces",
+  "+services/preferences/public/cpp",
   "+services/preferences/public/interfaces",
   "+services/service_manager",
   "+services/shape_detection/public/interfaces",
diff --git a/chrome/browser/chromeos/preferences_chromeos_browsertest.cc b/chrome/browser/chromeos/preferences_chromeos_browsertest.cc
index 93812b0..aa3234bf 100644
--- a/chrome/browser/chromeos/preferences_chromeos_browsertest.cc
+++ b/chrome/browser/chromeos/preferences_chromeos_browsertest.cc
@@ -5,10 +5,16 @@
 #include <stddef.h>
 #include <sys/types.h>
 
+#include <set>
+#include <string>
+
 #include "ash/shell.h"
 #include "base/command_line.h"
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/run_loop.h"
+#include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/input_method/input_method_manager_impl.h"
 #include "chrome/browser/chromeos/login/login_manager_test.h"
@@ -20,12 +26,20 @@
 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
 #include "chrome/browser/chromeos/system/fake_input_device_settings.h"
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos.h"
+#include "chrome/browser/ui/browser.h"
 #include "chrome/common/pref_names.h"
+#include "chrome/test/base/in_process_browser_test.h"
 #include "chromeos/chromeos_switches.h"
 #include "components/feedback/tracing_manager.h"
 #include "components/prefs/pref_service.h"
+#include "components/prefs/pref_store.h"
+#include "components/prefs/writeable_pref_store.h"
 #include "components/user_manager/user_manager.h"
+#include "content/public/common/service_manager_connection.h"
 #include "content/public/test/test_utils.h"
+#include "services/preferences/public/cpp/pref_client_store.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/base/ime/chromeos/fake_ime_keyboard.h"
 #include "ui/events/event_utils.h"
@@ -141,6 +155,61 @@
   DISALLOW_COPY_AND_ASSIGN(PreferencesTest);
 };
 
+class PreferencesServiceBrowserTest : public InProcessBrowserTest {
+ public:
+  PreferencesServiceBrowserTest() {}
+
+ protected:
+  static service_manager::Connector* connector() {
+    return content::ServiceManagerConnection::GetForProcess()->GetConnector();
+  }
+
+  void WaitForPrefChange(PrefStore* store, const std::string& key) {
+    base::RunLoop run_loop;
+    TestPrefObserver observer(key, run_loop.QuitClosure());
+    store->AddObserver(&observer);
+    run_loop.Run();
+    store->RemoveObserver(&observer);
+  }
+
+  bool GetIntegerPrefValue(PrefStore* store,
+                           const std::string& key,
+                           int* out_value) {
+    const base::Value* value = nullptr;
+    if (!store->GetValue(key, &value))
+      return false;
+    return value->GetAsInteger(out_value);
+  }
+
+ private:
+  class TestPrefObserver : public PrefStore::Observer {
+   public:
+    TestPrefObserver(const std::string& pref_name,
+                     const base::Closure& callback)
+        : pref_name_(pref_name), callback_(callback) {}
+
+    ~TestPrefObserver() override {}
+
+    // PrefStore::Observer:
+    void OnPrefValueChanged(const std::string& key) override {
+      if (key == pref_name_)
+        callback_.Run();
+    }
+
+    void OnInitializationCompleted(bool success) override {
+      ASSERT_TRUE(success);
+    }
+
+   private:
+    const std::string pref_name_;
+    const base::Closure callback_;
+
+    DISALLOW_COPY_AND_ASSIGN(TestPrefObserver);
+  };
+
+  DISALLOW_COPY_AND_ASSIGN(PreferencesServiceBrowserTest);
+};
+
 IN_PROC_BROWSER_TEST_F(PreferencesTest, PRE_MultiProfiles) {
   RegisterUser(test_users_[0].GetUserEmail());
   RegisterUser(test_users_[1].GetUserEmail());
@@ -214,4 +283,43 @@
   CheckLocalStateCorrespondsToPrefs(prefs1);
 }
 
+IN_PROC_BROWSER_TEST_F(PreferencesServiceBrowserTest, Basic) {
+  constexpr int kInitialValue = 1;
+  PrefService* pref_service = browser()->profile()->GetPrefs();
+  pref_service->SetInteger(prefs::kMouseSensitivity, kInitialValue);
+
+  prefs::mojom::PreferencesServiceFactoryPtr factory_a;
+  connector()->BindInterface(prefs::mojom::kServiceName, &factory_a);
+  scoped_refptr<preferences::PrefClientStore> pref_store_a =
+      new preferences::PrefClientStore(std::move(factory_a));
+  pref_store_a->Subscribe({prefs::kMouseSensitivity});
+  WaitForPrefChange(pref_store_a.get(), prefs::kMouseSensitivity);
+
+  prefs::mojom::PreferencesServiceFactoryPtr factory_b;
+  connector()->BindInterface(prefs::mojom::kServiceName, &factory_b);
+  scoped_refptr<preferences::PrefClientStore> pref_store_b =
+      new preferences::PrefClientStore(std::move(factory_b));
+  pref_store_b->Subscribe({prefs::kMouseSensitivity});
+  WaitForPrefChange(pref_store_b.get(), prefs::kMouseSensitivity);
+
+  int value_a = 0;
+  ASSERT_TRUE(GetIntegerPrefValue(pref_store_a.get(), prefs::kMouseSensitivity,
+                                  &value_a));
+  EXPECT_EQ(kInitialValue, value_a);
+
+  int value_b = 0;
+  ASSERT_TRUE(GetIntegerPrefValue(pref_store_b.get(), prefs::kMouseSensitivity,
+                                  &value_b));
+  EXPECT_EQ(kInitialValue, value_b);
+
+  const int kTestValue = 42;
+  pref_store_a->SetValue(prefs::kMouseSensitivity,
+                         base::MakeUnique<base::FundamentalValue>(kTestValue),
+                         WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+  WaitForPrefChange(pref_store_b.get(), prefs::kMouseSensitivity);
+  ASSERT_TRUE(GetIntegerPrefValue(pref_store_b.get(), prefs::kMouseSensitivity,
+                                  &value_b));
+  EXPECT_EQ(kTestValue, value_b);
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc
index 4c619e38..0ea2aea2 100644
--- a/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc
+++ b/chrome/browser/extensions/api/image_writer_private/write_from_url_operation.cc
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h"
 #include "base/files/file_util.h"
 #include "chrome/browser/extensions/api/image_writer_private/error_messages.h"
 #include "chrome/browser/extensions/api/image_writer_private/operation_manager.h"
-#include "chrome/browser/extensions/api/image_writer_private/write_from_url_operation.h"
 #include "content/public/browser/browser_thread.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_fetcher.h"
 
 namespace extensions {
@@ -83,9 +84,37 @@
 
   SetStage(image_writer_api::STAGE_DOWNLOAD);
 
+  // Create traffic annotation tag.
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("cros_recovery_image_download", R"(
+        semantics {
+          sender: "Chrome OS Recovery Utility"
+          description:
+            "The Google Chrome OS recovery utility downloads the recovery "
+            "image from Google Download Server."
+          trigger:
+            "User uses the Chrome OS Recovery Utility app/extension, selects "
+            "a Chrome OS recovery image, and clicks the Create button to write "
+            "the image to a USB or SD card."
+          data:
+            "URL of the image file to be downloaded. No other data or user "
+            "identifier is sent."
+          destination: GOOGLE_OWNED_SERVICE
+        }
+        policy {
+          cookies_allowed: true
+          cookies_store: "user"
+          setting:
+            "This feature cannot be disabled by settings, it can only be used "
+            "by whitelisted apps/extension."
+          policy_exception_justification:
+            "Not implemented, considered not useful."
+        })");
+
   // Store the URL fetcher on this object so that it is destroyed before this
   // object is.
-  url_fetcher_ = net::URLFetcher::Create(url_, net::URLFetcher::GET, this);
+  url_fetcher_ = net::URLFetcher::Create(url_, net::URLFetcher::GET, this,
+                                         traffic_annotation);
 
   url_fetcher_->SetRequestContext(request_context_);
   url_fetcher_->SaveResponseToFileAtPath(
diff --git a/chrome/browser/prefs/preferences_manifest.json b/chrome/browser/prefs/preferences_manifest.json
index 0ce32ca..bb498c20 100644
--- a/chrome/browser/prefs/preferences_manifest.json
+++ b/chrome/browser/prefs/preferences_manifest.json
@@ -4,7 +4,7 @@
   "interface_provider_specs": {
     "service_manager:connector": {
       "provides": {
-        "preferences_manager": [ "prefs::mojom::PreferencesFactory" ]
+        "preferences_manager": [ "prefs::mojom::PreferencesServiceFactory" ]
       },
       "requires": {
       }
diff --git a/chrome/browser/prefs/preferences_service.cc b/chrome/browser/prefs/preferences_service.cc
index 5494965..85b9c2a 100644
--- a/chrome/browser/prefs/preferences_service.cc
+++ b/chrome/browser/prefs/preferences_service.cc
@@ -33,7 +33,8 @@
       service_->FindPreference(preference_name);
   std::unique_ptr<base::DictionaryValue> dictionary =
       base::MakeUnique<base::DictionaryValue>();
-  dictionary->Set(preference_name, pref->GetValue()->CreateDeepCopy());
+  dictionary->SetWithoutPathExpansion(preference_name,
+                                      pref->GetValue()->CreateDeepCopy());
   client_->OnPreferencesChanged(std::move(dictionary));
 }
 
@@ -73,7 +74,7 @@
     preferences_change_registrar_->Add(
         it, base::Bind(&PreferencesService::PreferenceChanged,
                        base::Unretained(this)));
-    dictionary->Set(it, pref->GetValue()->CreateDeepCopy());
+    dictionary->SetWithoutPathExpansion(it, pref->GetValue()->CreateDeepCopy());
   }
 
   if (dictionary->empty())
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 4bab94b..849eb3a 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -2384,7 +2384,11 @@
         "//chrome/browser/chromeos:arc_test_support",
         "//chromeos/ime:gencode",
         "//components/arc:arc_test_support",
+        "//components/prefs",
         "//components/user_manager:test_support",
+        "//services/preferences/public/cpp",
+        "//services/preferences/public/interfaces",
+        "//services/service_manager/public/cpp",
         "//ui/login:resources",
       ]
 
diff --git a/chrome/test/base/mash_browser_tests_main.cc b/chrome/test/base/mash_browser_tests_main.cc
index 5f44d7fc..7e011882 100644
--- a/chrome/test/base/mash_browser_tests_main.cc
+++ b/chrome/test/base/mash_browser_tests_main.cc
@@ -162,7 +162,7 @@
   service_manager::ServiceContext context(
       base::MakeUnique<mash::MashPackagedService>(),
       std::move(service_request));
-  context.SetConnectionLostClosure(run_loop.QuitClosure());
+  context.SetQuitClosure(run_loop.QuitClosure());
   run_loop.Run();
 }
 
diff --git a/content/browser/renderer_host/render_view_host_delegate.cc b/content/browser/renderer_host/render_view_host_delegate.cc
index 3d5853c..dfd91f0 100644
--- a/content/browser/renderer_host/render_view_host_delegate.cc
+++ b/content/browser/renderer_host/render_view_host_delegate.cc
@@ -61,4 +61,8 @@
   return false;
 }
 
+bool RenderViewHostDelegate::HasPersistentVideo() const {
+  return false;
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_view_host_delegate.h b/content/browser/renderer_host/render_view_host_delegate.h
index 7dc40c3..3059773 100644
--- a/content/browser/renderer_host/render_view_host_delegate.h
+++ b/content/browser/renderer_host/render_view_host_delegate.h
@@ -185,6 +185,9 @@
   // Whether download UI should be hidden.
   virtual bool HideDownloadUI() const;
 
+  // Whether the WebContents as a persistent video.
+  virtual bool HasPersistentVideo() const;
+
  protected:
   virtual ~RenderViewHostDelegate() {}
 };
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index e16766a..8388af1b 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -532,6 +532,10 @@
   if (delegate_ && delegate_->HideDownloadUI())
     prefs.hide_download_ui = true;
 
+  // `media_controls_enabled` is `true` by default.
+  if (delegate_ && delegate_->HasPersistentVideo())
+    prefs.media_controls_enabled = false;
+
   prefs.background_video_track_optimization_enabled =
       base::FeatureList::IsEnabled(media::kBackgroundVideoTrackOptimization);
 
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 52c4520..f8225d5 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -703,6 +703,13 @@
     view->DismissTextHandles();
 }
 
+void WebContentsAndroid::SetHasPersistentVideo(
+    JNIEnv* env,
+    const base::android::JavaParamRef<jobject>& obj,
+    jboolean value) {
+  web_contents_->SetHasPersistentVideo(value);
+}
+
 void WebContentsAndroid::OnFinishGetContentBitmap(
     const JavaRef<jobject>& obj,
     const JavaRef<jobject>& callback,
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h
index d31ba28..93fc028 100644
--- a/content/browser/web_contents/web_contents_android.h
+++ b/content/browser/web_contents/web_contents_android.h
@@ -193,6 +193,9 @@
                     const base::android::JavaParamRef<jobject>& jcallback);
   void DismissTextHandles(JNIEnv* env,
                           const base::android::JavaParamRef<jobject>& obj);
+  void SetHasPersistentVideo(JNIEnv* env,
+                             const base::android::JavaParamRef<jobject>& obj,
+                             jboolean value);
 
   void SetMediaSession(
       const base::android::ScopedJavaLocalRef<jobject>& j_media_session);
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 7b92187..87b9b7b 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -4252,6 +4252,10 @@
   return is_overlay_content_;
 }
 
+bool WebContentsImpl::HasPersistentVideo() const {
+  return has_persistent_video_;
+}
+
 bool WebContentsImpl::IsFocusedElementEditable() {
   RenderFrameHostImpl* frame = GetFocusedFrame();
   return frame && frame->has_focused_editable_element();
@@ -5280,6 +5284,14 @@
   }
 }
 
+void WebContentsImpl::SetHasPersistentVideo(bool value) {
+  if (has_persistent_video_ == value)
+    return;
+
+  has_persistent_video_ = value;
+  NotifyPreferencesChanged();
+}
+
 #if defined(OS_ANDROID)
 void WebContentsImpl::NotifyFindMatchRectsReply(
     int version,
@@ -5344,19 +5356,7 @@
 }
 
 void WebContentsImpl::UpdateOverridingUserAgent() {
-  std::set<RenderViewHost*> render_view_host_set;
-  for (FrameTreeNode* node : frame_tree_.Nodes()) {
-    RenderWidgetHost* render_widget_host =
-        node->current_frame_host()->GetRenderWidgetHost();
-    if (!render_widget_host)
-      continue;
-    RenderViewHost* render_view_host = RenderViewHost::From(render_widget_host);
-    if (!render_view_host)
-      continue;
-    render_view_host_set.insert(render_view_host);
-  }
-  for (RenderViewHost* render_view_host : render_view_host_set)
-    render_view_host->OnWebkitPreferencesChanged();
+  NotifyPreferencesChanged();
 }
 
 void WebContentsImpl::SetJavaScriptDialogManagerForTesting(
@@ -5417,4 +5417,20 @@
                          " releasing your website to the public."));
 }
 
+void WebContentsImpl::NotifyPreferencesChanged() {
+  std::set<RenderViewHost*> render_view_host_set;
+  for (FrameTreeNode* node : frame_tree_.Nodes()) {
+    RenderWidgetHost* render_widget_host =
+        node->current_frame_host()->GetRenderWidgetHost();
+    if (!render_widget_host)
+      continue;
+    RenderViewHost* render_view_host = RenderViewHost::From(render_widget_host);
+    if (!render_view_host)
+      continue;
+    render_view_host_set.insert(render_view_host);
+  }
+  for (RenderViewHost* render_view_host : render_view_host_set)
+    render_view_host->OnWebkitPreferencesChanged();
+}
+
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index cf9f25f..c325f5a 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -572,6 +572,7 @@
   bool IsOverridingUserAgent() override;
   bool IsJavaScriptDialogShowing() const override;
   bool HideDownloadUI() const override;
+  bool HasPersistentVideo() const override;
 
   // NavigatorDelegate ---------------------------------------------------------
 
@@ -791,6 +792,9 @@
   void IncrementBluetoothConnectedDeviceCount();
   void DecrementBluetoothConnectedDeviceCount();
 
+  // Called when the WebContents gains or loses a persistent video.
+  void SetHasPersistentVideo(bool value);
+
 #if defined(OS_ANDROID)
   // Called by FindRequestManager when all of the find match rects are in.
   void NotifyFindMatchRectsReply(int version,
@@ -1172,6 +1176,10 @@
   // certificate via --allow-insecure-localhost.
   void ShowInsecureLocalhostWarningIfNeeded();
 
+  // Notify this WebContents that the preferences have changed. This will send
+  // an IPC to all the renderer process associated with this WebContents.
+  void NotifyPreferencesChanged();
+
   // Data for core operation ---------------------------------------------------
 
   // Delegate for notifying our owner about stuff. Not owned by us.
@@ -1502,6 +1510,8 @@
 
   int currently_playing_video_count_ = 0;
 
+  bool has_persistent_video_ = false;
+
   base::WeakPtrFactory<WebContentsImpl> loading_weak_factory_;
   base::WeakPtrFactory<WebContentsImpl> weak_factory_;
 
diff --git a/content/common/service_manager/embedded_service_runner.cc b/content/common/service_manager/embedded_service_runner.cc
index 0c7c4589..665a6e3 100644
--- a/content/common/service_manager/embedded_service_runner.cc
+++ b/content/common/service_manager/embedded_service_runner.cc
@@ -87,7 +87,7 @@
             factory_callback_.Run(), std::move(request));
 
     service_manager::ServiceContext* raw_context = context.get();
-    context->SetConnectionLostClosure(
+    context->SetQuitClosure(
         base::Bind(&InstanceManager::OnInstanceLost, this, instance_id));
     contexts_.insert(std::make_pair(raw_context, std::move(context)));
     id_to_context_map_.insert(std::make_pair(instance_id, raw_context));
diff --git a/content/common/service_manager/service_manager_connection_impl.cc b/content/common/service_manager/service_manager_connection_impl.cc
index 8be6e76b..83a4d11 100644
--- a/content/common/service_manager/service_manager_connection_impl.cc
+++ b/content/common/service_manager/service_manager_connection_impl.cc
@@ -273,7 +273,7 @@
     return accept;
   }
 
-  bool OnStop() override {
+  bool OnServiceManagerConnectionLost() override {
     ClearConnectionFiltersOnIOThread();
     callback_task_runner_->PostTask(FROM_HERE, stop_callback_);
     return true;
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index 657c9a0..322d072 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -517,6 +517,11 @@
         nativeDismissTextHandles(mNativeWebContentsAndroid);
     }
 
+    @Override
+    public void setHasPersistentVideo(boolean value) {
+        nativeSetHasPersistentVideo(mNativeWebContentsAndroid, value);
+    }
+
     @CalledByNative
     private final void setMediaSession(MediaSessionImpl mediaSession) {
         mMediaSession = mediaSession;
@@ -604,4 +609,5 @@
             String url, boolean isFavicon, int maxBitmapSize,
             boolean bypassCache, ImageDownloadCallback callback);
     private native void nativeDismissTextHandles(long nativeWebContentsAndroid);
+    private native void nativeSetHasPersistentVideo(long nativeWebContentsAndroid, boolean value);
 }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index 3e5332e..dd74c514 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -372,4 +372,12 @@
      *                        (e.g. renderer for the currently selected tab)
      */
     public void simulateRendererKilledForTesting(boolean wasOomProtected);
+
+    /**
+     * Notifies the WebContents about the new persistent video status. It should be called whenever
+     * the value changes.
+     *
+     * @param value Whether there is a persistent video associated with this WebContents.
+     */
+    public void setHasPersistentVideo(boolean value);
 }
diff --git a/content/public/common/common_param_traits_macros.h b/content/public/common/common_param_traits_macros.h
index 8d53c17..bf638a5 100644
--- a/content/public/common/common_param_traits_macros.h
+++ b/content/public/common/common_param_traits_macros.h
@@ -251,6 +251,7 @@
   IPC_STRUCT_TRAITS_MEMBER(max_keyframe_distance_to_disable_background_video)
   IPC_STRUCT_TRAITS_MEMBER(enable_instant_source_buffer_gc)
   IPC_STRUCT_TRAITS_MEMBER(presentation_receiver)
+  IPC_STRUCT_TRAITS_MEMBER(media_controls_enabled)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(blink::mojom::WindowFeatures)
diff --git a/content/public/common/web_preferences.cc b/content/public/common/web_preferences.cc
index 2034641d..ba85d1b0 100644
--- a/content/public/common/web_preferences.cc
+++ b/content/public/common/web_preferences.cc
@@ -227,7 +227,8 @@
       max_keyframe_distance_to_disable_background_video(
           base::TimeDelta::FromSeconds(10)),
       enable_instant_source_buffer_gc(false),
-      presentation_receiver(false) {
+      presentation_receiver(false),
+      media_controls_enabled(true) {
   standard_font_family_map[kCommonScript] =
       base::ASCIIToUTF16("Times New Roman");
   fixed_font_family_map[kCommonScript] = base::ASCIIToUTF16("Courier New");
diff --git a/content/public/common/web_preferences.h b/content/public/common/web_preferences.h
index ccabaec..71ea3098 100644
--- a/content/public/common/web_preferences.h
+++ b/content/public/common/web_preferences.h
@@ -284,6 +284,9 @@
   // Whether it is a presentation receiver.
   bool presentation_receiver;
 
+  // If disabled, media controls should never be used.
+  bool media_controls_enabled;
+
   // We try to keep the default values the same as the default values in
   // chrome, except for the cases where it would require lots of extra work for
   // the embedder to use the same default value.
diff --git a/content/public/test/test_download_request_handler.cc b/content/public/test/test_download_request_handler.cc
index c0f9525..180f37f 100644
--- a/content/public/test/test_download_request_handler.cc
+++ b/content/public/test/test_download_request_handler.cc
@@ -24,6 +24,7 @@
 #include "net/base/io_buffer.h"
 #include "net/http/http_request_headers.h"
 #include "net/http/http_response_headers.h"
+#include "net/http/http_util.h"
 #include "net/url_request/url_request_filter.h"
 #include "net/url_request/url_request_interceptor.h"
 
@@ -477,8 +478,9 @@
 
 void TestDownloadRequestHandler::PartialResponseJob::
     NotifyHeadersCompleteAndPrepareToRead() {
-  std::string normalized_headers;
-  response_info_.headers->GetNormalizedHeaders(&normalized_headers);
+  std::string normalized_headers =
+      net::HttpUtil::ConvertHeadersBackToHTTPResponse(
+          response_info_.headers->raw_headers());
   DVLOG(1) << "Notify ready with headers:\n" << normalized_headers;
 
   offset_of_next_read_ = requested_range_begin_;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index e3ea8995..65b2fdc5 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1101,6 +1101,8 @@
 
   settings->setPresentationReceiver(prefs.presentation_receiver);
 
+  settings->setMediaControlsEnabled(prefs.media_controls_enabled);
+
 #if defined(OS_MACOSX)
   settings->setDoubleTapToZoomEnabled(true);
   web_view->setMaximumLegibleScale(prefs.default_maximum_page_scale_factor);
diff --git a/google_apis/drive/base_requests.cc b/google_apis/drive/base_requests.cc
index d1aa60d..39492d0 100644
--- a/google_apis/drive/base_requests.cc
+++ b/google_apis/drive/base_requests.cc
@@ -95,18 +95,14 @@
 // Returns response headers as a string. Returns a warning message if
 // |url_fetcher| does not contain a valid response. Used only for debugging.
 std::string GetResponseHeadersAsString(const URLFetcher* url_fetcher) {
-  // net::HttpResponseHeaders::raw_headers(), as the name implies, stores
-  // all headers in their raw format, i.e each header is null-terminated.
-  // So logging raw_headers() only shows the first header, which is probably
-  // the status line.  GetNormalizedHeaders, on the other hand, will show all
-  // the headers, one per line, which is probably what we want.
   std::string headers;
   // Check that response code indicates response headers are valid (i.e. not
   // malformed) before we retrieve the headers.
   if (url_fetcher->GetResponseCode() == URLFetcher::RESPONSE_CODE_INVALID) {
     headers.assign("Response headers are malformed!!");
   } else {
-    url_fetcher->GetResponseHeaders()->GetNormalizedHeaders(&headers);
+    headers = net::HttpUtil::ConvertHeadersBackToHTTPResponse(
+        url_fetcher->GetResponseHeaders()->raw_headers());
   }
   return headers;
 }
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index 789fa47..03bd8a45 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -25,6 +25,7 @@
 #include "net/base/load_flags.h"
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
+#include "net/http/http_util.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "net/url_request/url_request_status.h"
@@ -953,7 +954,8 @@
 #ifndef NDEBUG
   std::string headers;
   if (source->GetResponseHeaders())
-    source->GetResponseHeaders()->GetNormalizedHeaders(&headers);
+    headers = net::HttpUtil::ConvertHeadersBackToHTTPResponse(
+        source->GetResponseHeaders()->raw_headers());
   DVLOG(2) << "Response " << url.spec() << ", code = " << response_code << "\n"
            << headers << "\n";
   DVLOG(2) << "data: " << data << "\n";
diff --git a/media/mojo/services/media_service.cc b/media/mojo/services/media_service.cc
index 72df120..43eace8 100644
--- a/media/mojo/services/media_service.cc
+++ b/media/mojo/services/media_service.cc
@@ -39,7 +39,7 @@
   return true;
 }
 
-bool MediaService::OnStop() {
+bool MediaService::OnServiceManagerConnectionLost() {
   mojo_media_client_.reset();
   return true;
 }
diff --git a/media/mojo/services/media_service.h b/media/mojo/services/media_service.h
index de2b0da..08c4885 100644
--- a/media/mojo/services/media_service.h
+++ b/media/mojo/services/media_service.h
@@ -41,7 +41,7 @@
   void OnStart() final;
   bool OnConnect(const service_manager::ServiceInfo& remote_info,
                  service_manager::InterfaceRegistry* registry) final;
-  bool OnStop() final;
+  bool OnServiceManagerConnectionLost() final;
 
   // service_manager::InterfaceFactory<mojom::MediaService> implementation.
   void Create(const service_manager::Identity& remote_identity,
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index 635c15ca..868570b0 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -70,6 +70,34 @@
 
 namespace {
 
+// Returns a simple text serialization of the given
+// |HttpResponseHeaders|. This is used by tests to verify that an
+// |HttpResponseHeaders| matches an expectation string.
+//
+//  * One line per header, written as:
+//        HEADER_NAME: HEADER_VALUE\n
+//  * The original case of header names is preserved.
+//  * Whitespace around head names/values is stripped.
+//  * Repeated headers are not aggregated.
+//  * Headers are listed in their original order.
+// TODO(tfarina): this is a duplicate function from
+// http_response_headers_unittest.cc:ToSimpleString(). Figure out how to merge
+// them. crbug.com/488593
+std::string ToSimpleString(const scoped_refptr<HttpResponseHeaders>& parsed) {
+  std::string result = parsed->GetStatusLine() + "\n";
+
+  size_t iter = 0;
+  std::string name;
+  std::string value;
+  while (parsed->EnumerateHeaderLines(&iter, &name, &value)) {
+    std::string new_line = name + ": " + value + "\n";
+
+    result += new_line;
+  }
+
+  return result;
+}
+
 // Tests the load timing values of a request that goes through a
 // MockNetworkTransaction.
 void TestLoadTimingNetworkRequest(const LoadTimingInfo& load_timing_info) {
@@ -262,7 +290,7 @@
                                     std::string* response_headers) {
   HttpResponseInfo response;
   RunTransactionTestWithResponseInfo(cache, trans_info, &response);
-  response.headers->GetNormalizedHeaders(response_headers);
+  *response_headers = ToSimpleString(response.headers);
 }
 
 void RunTransactionTestWithResponseAndGetTiming(
@@ -275,7 +303,7 @@
   RunTransactionTestBase(cache, trans_info, MockHttpRequest(trans_info),
                          &response, log, load_timing_info, nullptr, nullptr,
                          nullptr);
-  response.headers->GetNormalizedHeaders(response_headers);
+  *response_headers = ToSimpleString(response.headers);
 }
 
 // This class provides a handler for kFastNoStoreGET_Transaction so that the
@@ -6734,13 +6762,10 @@
   EXPECT_EQ(response_time.ToInternalValue(),
             response.response_time.ToInternalValue());
 
-  std::string headers;
-  response.headers->GetNormalizedHeaders(&headers);
-
   EXPECT_EQ("HTTP/1.1 200 OK\n"
             "Date: Wed, 22 Jul 2009 03:15:26 GMT\n"
             "Last-Modified: Wed, 06 Feb 2008 22:38:21 GMT\n",
-            headers);
+            ToSimpleString(response.headers));
 
   RemoveMockTransaction(&mock_network_response);
 }
diff --git a/net/http/http_response_headers.cc b/net/http/http_response_headers.cc
index d5ab1e8..d0b2fc1 100644
--- a/net/http/http_response_headers.cc
+++ b/net/http/http_response_headers.cc
@@ -460,60 +460,6 @@
   DCHECK_EQ('\0', raw_headers_[raw_headers_.size() - 1]);
 }
 
-// Append all of our headers to the final output string.
-void HttpResponseHeaders::GetNormalizedHeaders(std::string* output) const {
-  // copy up to the null byte.  this just copies the status line.
-  output->assign(raw_headers_.c_str());
-
-  // headers may appear multiple times (not necessarily in succession) in the
-  // header data, so we build a map from header name to generated header lines.
-  // to preserve the order of the original headers, the actual values are kept
-  // in a separate list.  finally, the list of headers is flattened to form
-  // the normalized block of headers.
-  //
-  // NOTE: We take special care to preserve the whitespace around any commas
-  // that may occur in the original response headers.  Because our consumer may
-  // be a web app, we cannot be certain of the semantics of commas despite the
-  // fact that RFC 2616 says that they should be regarded as value separators.
-  //
-  using HeadersMap = std::unordered_map<std::string, size_t>;
-  HeadersMap headers_map;
-  HeadersMap::iterator iter = headers_map.end();
-
-  std::vector<std::string> headers;
-
-  for (size_t i = 0; i < parsed_.size(); ++i) {
-    DCHECK(!parsed_[i].is_continuation());
-
-    std::string name(parsed_[i].name_begin, parsed_[i].name_end);
-    std::string lower_name = base::ToLowerASCII(name);
-
-    iter = headers_map.find(lower_name);
-    if (iter == headers_map.end()) {
-      iter = headers_map.insert(
-          HeadersMap::value_type(lower_name, headers.size())).first;
-      headers.push_back(name + ": ");
-    } else {
-      headers[iter->second].append(", ");
-    }
-
-    std::string::const_iterator value_begin = parsed_[i].value_begin;
-    std::string::const_iterator value_end = parsed_[i].value_end;
-    while (++i < parsed_.size() && parsed_[i].is_continuation())
-      value_end = parsed_[i].value_end;
-    --i;
-
-    headers[iter->second].append(value_begin, value_end);
-  }
-
-  for (size_t i = 0; i < headers.size(); ++i) {
-    output->push_back('\n');
-    output->append(headers[i]);
-  }
-
-  output->push_back('\n');
-}
-
 bool HttpResponseHeaders::GetNormalizedHeader(const std::string& name,
                                               std::string* value) const {
   // If you hit this assertion, please use EnumerateHeader instead!
diff --git a/net/http/http_response_headers.h b/net/http/http_response_headers.h
index e45fe05..167980d 100644
--- a/net/http/http_response_headers.h
+++ b/net/http/http_response_headers.h
@@ -119,30 +119,6 @@
                           int64_t resource_size,
                           bool replace_status_line);
 
-  // Creates a normalized header string.  The output will be formatted exactly
-  // like so:
-  //     HTTP/<version> <status_code>[ <status_text>]\n
-  //     [<header-name>: <header-values>\n]*
-  // meaning, each line is \n-terminated, and there is no extra whitespace
-  // beyond the single space separators shown (of course, values can contain
-  // whitespace within them).  If a given header-name appears more than once
-  // in the set of headers, they are combined into a single line like so:
-  //     <header-name>: <header-value1>, <header-value2>, ...<header-valueN>\n
-  //
-  // DANGER: For some headers (e.g., "Set-Cookie"), the normalized form can be
-  // a lossy format.  This is due to the fact that some servers generate
-  // Set-Cookie headers that contain unquoted commas (usually as part of the
-  // value of an "expires" attribute).  So, use this function with caution.  Do
-  // not expect to be able to re-parse Set-Cookie headers from this output.
-  //
-  // NOTE: Do not make any assumptions about the encoding of this output
-  // string.  It may be non-ASCII, and the encoding used by the server is not
-  // necessarily known to us.  Do not assume that this output is UTF-8!
-  //
-  // TODO(darin): remove this method
-  //
-  void GetNormalizedHeaders(std::string* output) const;
-
   // Fetch the "normalized" value of a single header, where all values for the
   // header name are separated by commas.  See the GetNormalizedHeaders for
   // format details.  Returns false if this header wasn't found.
diff --git a/services/image_decoder/image_decoder_service.cc b/services/image_decoder/image_decoder_service.cc
index 4226e9fe..4ad2a0b 100644
--- a/services/image_decoder/image_decoder_service.cc
+++ b/services/image_decoder/image_decoder_service.cc
@@ -62,10 +62,6 @@
   return true;
 }
 
-bool ImageDecoderService::OnStop() {
-  return true;
-}
-
 void ImageDecoderService::MaybeRequestQuitDelayed() {
   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
       FROM_HERE,
diff --git a/services/image_decoder/image_decoder_service.h b/services/image_decoder/image_decoder_service.h
index 643a130..a41006e 100644
--- a/services/image_decoder/image_decoder_service.h
+++ b/services/image_decoder/image_decoder_service.h
@@ -27,7 +27,6 @@
   void OnStart() override;
   bool OnConnect(const service_manager::ServiceInfo& remote_info,
                  service_manager::InterfaceRegistry* registry) override;
-  bool OnStop() override;
 
  private:
   void MaybeRequestQuitDelayed();
diff --git a/services/preferences/public/cpp/pref_client_store.cc b/services/preferences/public/cpp/pref_client_store.cc
index 2ca8134..289aaaa 100644
--- a/services/preferences/public/cpp/pref_client_store.cc
+++ b/services/preferences/public/cpp/pref_client_store.cc
@@ -82,7 +82,7 @@
     return;
 
   auto prefs = base::MakeUnique<base::DictionaryValue>();
-  prefs->Set(key, value.CreateDeepCopy());
+  prefs->SetWithoutPathExpansion(key, value.CreateDeepCopy());
   prefs_service_ptr_->SetPreferences(std::move(prefs));
 }
 
diff --git a/services/service_manager/background/tests/test_service.cc b/services/service_manager/background/tests/test_service.cc
index 18de6bd..96fd1522 100644
--- a/services/service_manager/background/tests/test_service.cc
+++ b/services/service_manager/background/tests/test_service.cc
@@ -28,9 +28,6 @@
     registry->AddInterface(this);
     return true;
   }
-  bool OnStop() override {
-    return true;
-  }
 
   // InterfaceFactory<mojom::TestService>:
   void Create(const Identity& remote_identity,
diff --git a/services/service_manager/public/cpp/lib/service.cc b/services/service_manager/public/cpp/lib/service.cc
index 72222ef..2b40a6c 100644
--- a/services/service_manager/public/cpp/lib/service.cc
+++ b/services/service_manager/public/cpp/lib/service.cc
@@ -42,20 +42,25 @@
   interface_provider->GetInterface(interface_name, std::move(interface_pipe));
 }
 
-bool Service::OnStop() { return true; }
+bool Service::OnServiceManagerConnectionLost() {
+  return true;
+}
 
 ServiceContext* Service::context() const {
   DCHECK(service_context_)
-      << "Service::context() may only be called during or after OnStart().";
+      << "Service::context() may only be called after the Service constructor.";
   return service_context_;
 }
 
+void Service::SetContext(ServiceContext* context) {
+  service_context_ = context;
+}
+
 ForwardingService::ForwardingService(Service* target) : target_(target) {}
 
 ForwardingService::~ForwardingService() {}
 
 void ForwardingService::OnStart() {
-  target_->set_context(context());
   target_->OnStart();
 }
 
@@ -64,6 +69,20 @@
   return target_->OnConnect(remote_info, registry);
 }
 
-bool ForwardingService::OnStop() { return target_->OnStop(); }
+void ForwardingService::OnBindInterface(
+    const ServiceInfo& remote_info,
+    const std::string& interface_name,
+    mojo::ScopedMessagePipeHandle interface_pipe) {
+  target_->OnBindInterface(remote_info, interface_name,
+                           std::move(interface_pipe));
+}
+
+bool ForwardingService::OnServiceManagerConnectionLost() {
+  return target_->OnServiceManagerConnectionLost();
+}
+
+void ForwardingService::SetContext(ServiceContext* context) {
+  target_->SetContext(context);
+}
 
 }  // namespace service_manager
diff --git a/services/service_manager/public/cpp/lib/service_context.cc b/services/service_manager/public/cpp/lib/service_context.cc
index f45202e..6459459 100644
--- a/services/service_manager/public/cpp/lib/service_context.cc
+++ b/services/service_manager/public/cpp/lib/service_context.cc
@@ -42,14 +42,18 @@
   } else {
     DCHECK(pending_connector_request_.is_pending());
   }
+  service_->SetContext(this);
 }
 
 ServiceContext::~ServiceContext() {}
 
-void ServiceContext::SetConnectionLostClosure(const base::Closure& closure) {
-  connection_lost_closure_ = closure;
-  if (service_quit_)
-    QuitNow();
+void ServiceContext::SetQuitClosure(const base::Closure& closure) {
+  if (service_quit_) {
+    // CAUTION: May delete |this|.
+    closure.Run();
+  } else {
+    quit_closure_ = closure;
+  }
 }
 
 void ServiceContext::RequestQuit() {
@@ -64,15 +68,13 @@
 }
 
 void ServiceContext::QuitNow() {
+  service_quit_ = true;
   if (binding_.is_bound())
     binding_.Close();
-  if (!connection_lost_closure_.is_null())
-    base::ResetAndReturn(&connection_lost_closure_).Run();
-}
-
-void ServiceContext::DestroyService() {
-  QuitNow();
-  service_.reset();
+  if (!quit_closure_.is_null()) {
+    // CAUTION: May delete |this|.
+    base::ResetAndReturn(&quit_closure_).Run();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -83,8 +85,6 @@
   local_info_ = info;
   callback.Run(std::move(pending_connector_request_),
                mojo::MakeRequest(&service_control_));
-
-  service_->set_context(this);
   service_->OnStart();
 }
 
@@ -140,19 +140,10 @@
 }
 
 void ServiceContext::OnConnectionError() {
-  // Note that the Service doesn't technically have to quit now, it may live
-  // on to service existing connections. All existing Connectors however are
-  // invalid.
-  service_quit_ = service_->OnStop();
-  if (service_quit_) {
+  if (service_->OnServiceManagerConnectionLost()) {
+    // CAUTION: May delete |this|.
     QuitNow();
-    // NOTE: This call may delete |this|, so don't access any ServiceContext
-    // state beyond this point.
-    return;
   }
-
-  // We don't reset the connector as clients may have taken a raw pointer to it.
-  // Connect() will return nullptr if they try to connect to anything.
 }
 
 void ServiceContext::OnRegistryConnectionError(InterfaceRegistry* registry) {
diff --git a/services/service_manager/public/cpp/lib/service_runner.cc b/services/service_manager/public/cpp/lib/service_runner.cc
index 374a948..4ba2f58 100644
--- a/services/service_manager/public/cpp/lib/service_runner.cc
+++ b/services/service_manager/public/cpp/lib/service_runner.cc
@@ -57,7 +57,7 @@
         mojo::MakeRequest<mojom::Service>(mojo::MakeScopedHandle(
             mojo::MessagePipeHandle(service_request_handle)))));
     base::RunLoop run_loop;
-    context_->SetConnectionLostClosure(run_loop.QuitClosure());
+    context_->SetQuitClosure(run_loop.QuitClosure());
     run_loop.Run();
     context_.reset();
   }
diff --git a/services/service_manager/public/cpp/service.h b/services/service_manager/public/cpp/service.h
index 250b8ab..db5ad50 100644
--- a/services/service_manager/public/cpp/service.h
+++ b/services/service_manager/public/cpp/service.h
@@ -23,9 +23,9 @@
   Service();
   virtual ~Service();
 
-  // Called exactly once, when a bidirectional connection with the Service
-  // Manager has been established. No calls to OnConnect() will be received
-  // before this.
+  // Called exactly once when a bidirectional connection with the Service
+  // Manager has been established. No calls to OnConnect() or OnBindInterface()
+  // will be made before this.
   virtual void OnStart();
 
   // Called each time a connection to this service is brokered by the Service
@@ -51,32 +51,28 @@
   // service should use this as a signal to shut down, and in fact its process
   // may be reaped shortly afterward if applicable.
   //
-  // Return true from this method to tell the ServiceContext to signal its
-  // shutdown externally (i.e. to invoke its "connection lost" closure if set),
-  // or return false to defer the signal. If deferred, the Service should
-  // explicitly call QuitNow() on the ServiceContext when it's ready to be
-  // torn down.
+  // If this returns |true| then QuitNow() will be invoked immediately upon
+  // return to the ServiceContext. Otherwise the Service is responsible for
+  // eventually calling QuitNow().
   //
-  // The default implementation returns true.
+  // The default implementation returns |true|.
   //
-  // While it's possible for this to be invoked before either OnStart() or
-  // OnConnect() is invoked, neither will be invoked at any point after this
-  // OnStop().
-  virtual bool OnStop();
+  // NOTE: This may be called at any time, and once it's been called, none of
+  // the other public Service methods will be invoked by the ServiceContext.
+  virtual bool OnServiceManagerConnectionLost();
 
  protected:
-  // Access the ServiceContext associated with this Service. Note that this is
-  // only valid to call during or after OnStart(), but never before! As such,
-  // it's always safe to call in OnStart() and OnConnect(), but should generally
-  // be avoided in OnStop().
+  // Accesses the ServiceContext associated with this Service. Note that this is
+  // only valid AFTER the Service's constructor has run.
   ServiceContext* context() const;
 
  private:
   friend class ForwardingService;
   friend class ServiceContext;
 
-  // NOTE: This is guaranteed to be called before OnStart().
-  void set_context(ServiceContext* context) { service_context_ = context; }
+  // NOTE: This MUST be called before any public Service methods. ServiceContext
+  // satisfies this guarantee for any Service instance it owns.
+  virtual void SetContext(ServiceContext* context);
 
   ServiceContext* service_context_ = nullptr;
 
@@ -95,9 +91,14 @@
   void OnStart() override;
   bool OnConnect(const ServiceInfo& remote_info,
                  InterfaceRegistry* registry) override;
-  bool OnStop() override;
+  void OnBindInterface(const ServiceInfo& remote_info,
+                       const std::string& interface_name,
+                       mojo::ScopedMessagePipeHandle interface_pipe) override;
+  bool OnServiceManagerConnectionLost() override;
 
  private:
+  void SetContext(ServiceContext* context) override;
+
   Service* const target_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(ForwardingService);
diff --git a/services/service_manager/public/cpp/service_context.h b/services/service_manager/public/cpp/service_context.h
index a1af32c..f843462 100644
--- a/services/service_manager/public/cpp/service_context.h
+++ b/services/service_manager/public/cpp/service_context.h
@@ -22,9 +22,11 @@
 namespace service_manager {
 
 // Encapsulates a connection to the Service Manager in two parts:
+//
 // - a bound InterfacePtr to mojom::Connector, the primary mechanism
 //   by which the instantiating service connects to other services,
 //   brokered by the Service Manager.
+//
 // - a bound InterfaceRequest of mojom::Service, an interface used by the
 //   Service Manager to inform this service of lifecycle events and
 //   inbound connections brokered by it.
@@ -62,12 +64,14 @@
   const ServiceInfo& local_info() const { return local_info_; }
   const Identity& identity() const { return local_info_.identity; }
 
-  // Specify a function to be called when the connection to the service manager
-  // is lost. Note that if connection has already been lost, then |closure| is
-  // called immediately.
+  // Specify a closure to be run when the Service calls QuitNow(), typically
+  // in response to Service::OnServiceManagerConnectionLost().
   //
-  // It is acceptable for |closure| to delete this ServiceContext.
-  void SetConnectionLostClosure(const base::Closure& closure);
+  // Note that if the Service has already called QuitNow(), |closure| is run
+  // immediately from this method.
+  //
+  // NOTE: It is acceptable for |closure| to delete this ServiceContext.
+  void SetQuitClosure(const base::Closure& closure);
 
   // Informs the Service Manager that this instance is ready to terminate. If
   // the Service Manager has any outstanding connection requests for this
@@ -75,33 +79,32 @@
   // the pending request(s) and can then appropriately decide whether or not
   // it still wants to quit.
   //
-  // If the request is granted, the Service Manager will service the connection
-  // to this ServiceContext and Service::OnStop() will eventually be invoked.
+  // If the request is granted, the Service Manager will soon sever the
+  // connection to this ServiceContext, and
+  // Service::OnServiceManagerConnectionLost() will be invoked at that time.
   void RequestQuit();
 
   // Immediately severs the connection to the Service Manager.
   //
-  // Note that calling this before the Service receives OnStop() can lead to
-  // unpredictable behavior, specifically because clients may have inbound
-  // connections in transit which may have already been brokered by the Service
-  // Manager and thus will be irreparably broken on the client side.
+  // Note that calling this before the Service receives
+  // OnServiceManagerConnectionLost() can lead to unpredictable behavior, as the
+  // Service Manager may have already brokered new inbound connections from
+  // other services to this Service instance, and those connections will be
+  // abruptly terminated as they can no longer result in OnConnect() or
+  // OnBindInterface() calls on the Service.
   //
-  // Use of this call before OnStop() should be reserved for exceptional cases.
+  // To put it another way: unless you want flaky connections to be a normal
+  // experience for consumers of your service, avoid calling this before
+  // receiving Service::OnServiceManagerConnectionLost().
   void DisconnectFromServiceManager();
 
-  // Immediately severs the connection to the Service Manager.
-  //
-  // If a connection-lost closure was set, it is immediately invoked. Note that
-  // it is never necessary or meaningful to call this after the Service
-  // has received OnStop().
+  // Immediately severs the connection to the Service Manager and invokes the
+  // quit closure (see SetQuitClosure() above) if one has been set.
   //
   // See comments on DisconnectFromServiceManager() regarding abrupt
   // disconnection from the Service Manager.
   void QuitNow();
 
-  // Simliar to QuitNow() above but also destroys the Service instance.
-  void DestroyService();
-
  private:
   friend class service_manager::Service;
 
@@ -146,9 +149,16 @@
   // is unbound and therefore invalid until OnStart() is called.
   mojom::ServiceControlAssociatedPtr service_control_;
 
+  // The Service may call QuitNow() before SetConnectionLostClosure(), and the
+  // latter is expected to invoke the closure immediately in that case. This is
+  // used to track that condition.
+  //
+  // TODO(rockot): Figure out who depends on this behavior and make them stop.
+  // It's weird and shouldn't be necessary.
   bool service_quit_ = false;
 
-  base::Closure connection_lost_closure_;
+  // The closure to run when QuitNow() is invoked. May delete |this|.
+  base::Closure quit_closure_;
 
   base::WeakPtrFactory<ServiceContext> weak_factory_;
 
diff --git a/services/service_manager/tests/connect/connect_test_package.cc b/services/service_manager/tests/connect/connect_test_package.cc
index 596774e1..974e387 100644
--- a/services/service_manager/tests/connect/connect_test_package.cc
+++ b/services/service_manager/tests/connect/connect_test_package.cc
@@ -181,7 +181,7 @@
     return true;
   }
 
-  bool OnStop() override {
+  bool OnServiceManagerConnectionLost() override {
     provided_services_.clear();
     return true;
   }
diff --git a/services/service_manager/tests/lifecycle/app_client.cc b/services/service_manager/tests/lifecycle/app_client.cc
index 9ada68b..5e9467e 100644
--- a/services/service_manager/tests/lifecycle/app_client.cc
+++ b/services/service_manager/tests/lifecycle/app_client.cc
@@ -21,7 +21,7 @@
   return true;
 }
 
-bool AppClient::OnStop() {
+bool AppClient::OnServiceManagerConnectionLost() {
   base::MessageLoop::current()->QuitWhenIdle();
   return true;
 }
@@ -54,7 +54,7 @@
 
 void AppClient::BindingLost() {
   if (bindings_.empty())
-    OnStop();
+    OnServiceManagerConnectionLost();
 }
 
 }  // namespace test
diff --git a/services/service_manager/tests/lifecycle/app_client.h b/services/service_manager/tests/lifecycle/app_client.h
index 2c31a3f..9d8baad 100644
--- a/services/service_manager/tests/lifecycle/app_client.h
+++ b/services/service_manager/tests/lifecycle/app_client.h
@@ -31,7 +31,7 @@
   // Service:
   bool OnConnect(const ServiceInfo& remote_info,
                  InterfaceRegistry* registry) override;
-  bool OnStop() override;
+  bool OnServiceManagerConnectionLost() override;
 
   // InterfaceFactory<LifecycleControl>:
   void Create(const Identity& remote_identity,
diff --git a/services/service_manager/tests/service_manager/embedder.cc b/services/service_manager/tests/service_manager/embedder.cc
index 9cabede..dceb8f3 100644
--- a/services/service_manager/tests/service_manager/embedder.cc
+++ b/services/service_manager/tests/service_manager/embedder.cc
@@ -52,7 +52,7 @@
     return true;
   }
 
-  bool OnStop() override {
+  bool OnServiceManagerConnectionLost() override {
     base::MessageLoop::current()->QuitWhenIdle();
     return true;
   }
diff --git a/services/shape_detection/shape_detection_service.cc b/services/shape_detection/shape_detection_service.cc
index e0105629..c2375168 100644
--- a/services/shape_detection/shape_detection_service.cc
+++ b/services/shape_detection/shape_detection_service.cc
@@ -48,8 +48,4 @@
   return true;
 }
 
-bool ShapeDetectionService::OnStop() {
-  return true;
-}
-
 }  // namespace shape_detection
diff --git a/services/shape_detection/shape_detection_service.h b/services/shape_detection/shape_detection_service.h
index b84125f..ab79456 100644
--- a/services/shape_detection/shape_detection_service.h
+++ b/services/shape_detection/shape_detection_service.h
@@ -25,7 +25,6 @@
   void OnStart() override;
   bool OnConnect(const service_manager::ServiceInfo& remote_info,
                  service_manager::InterfaceRegistry* registry) override;
-  bool OnStop() override;
 
  private:
   std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
diff --git a/services/tracing/service.cc b/services/tracing/service.cc
index 31cfcde..f2a6c3b 100644
--- a/services/tracing/service.cc
+++ b/services/tracing/service.cc
@@ -28,7 +28,7 @@
   return true;
 }
 
-bool Service::OnStop() {
+bool Service::OnServiceManagerConnectionLost() {
   // TODO(beng): This is only required because Service isn't run by
   // ServiceRunner - instead it's launched automatically by the standalone
   // service manager. It shouldn't be.
diff --git a/services/tracing/service.h b/services/tracing/service.h
index 5938b07f..b45d54c 100644
--- a/services/tracing/service.h
+++ b/services/tracing/service.h
@@ -38,7 +38,7 @@
   // service_manager::Service implementation.
   bool OnConnect(const service_manager::ServiceInfo& remote_info,
                  service_manager::InterfaceRegistry* registry) override;
-  bool OnStop() override;
+  bool OnServiceManagerConnectionLost() override;
 
   // service_manager::InterfaceFactory<mojom::Factory>:
   void Create(const service_manager::Identity& remote_identity,
diff --git a/third_party/WebKit/LayoutTests/fast/css-intrinsic-dimensions/height-css-tables-expected.html b/third_party/WebKit/LayoutTests/fast/css-intrinsic-dimensions/height-css-tables-expected.html
index 1e3c7f2..5f4d437 100644
--- a/third_party/WebKit/LayoutTests/fast/css-intrinsic-dimensions/height-css-tables-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/css-intrinsic-dimensions/height-css-tables-expected.html
@@ -28,10 +28,9 @@
   </div>
 </div>
 
-<!-- crbug.com/690087: We use 99px instead of 100px because we end up discarding 1px when trying
-     to allocate the spare pixels to the table. -->
-<div class="table container" style="display: block; float: left; height: 99px;">
-  <div class="td" style="height: 91px;" style="display: block;">
+
+<div class="table container" style="display: block; float: left; height: 98px;">
+  <div class="td" style="height: 90px;" style="display: block;">
     <div class="item"></div>
   </div>
 </div>
diff --git a/third_party/WebKit/LayoutTests/media/controls/settings-disable-controls.html b/third_party/WebKit/LayoutTests/media/controls/settings-disable-controls.html
new file mode 100644
index 0000000..5bd7c115
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/media/controls/settings-disable-controls.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<title>Test that 'mediaControlsEnabled' properly toggles the native controls</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../media-file.js"></script>
+<script src="../media-controls.js"></script>
+<video controls></video>
+<script>
+async_test(t => {
+  var video = document.querySelector('video');
+
+  internals.mediaPlayerRemoteRouteAvailabilityChanged(video, true);
+  t.add_cleanup(() => {
+    internals.mediaPlayerRemoteRouteAvailabilityChanged(video, false);
+  });
+
+  video.addEventListener('canplaythrough', t.step_func(e => {
+    assert_equals(overlayCastButton(video).style.display, "none");
+    assert_not_equals(mediaControlsButton(video, "panel").style.display, "none");
+
+    internals.settings.setMediaControlsEnabled(false);
+    testRunner.layoutAndPaintAsyncThen(t.step_func(() => {
+      assert_equals(mediaControlsButton(video, "panel").style.display, "none");
+      assert_equals(overlayCastButton(video).style.display, "none");
+
+      internals.settings.setMediaControlsEnabled(true);
+      testRunner.layoutAndPaintAsyncThen(t.step_func_done(() => {
+        assert_not_equals(mediaControlsButton(video, "panel").style.display, "none");
+        assert_equals(overlayCastButton(video).style.display, "none");
+      }));
+    }));
+  }));
+
+  video.src = findMediaFile('video', '../content/test');
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table-two-pass-layout-overpaint-expected.html b/third_party/WebKit/LayoutTests/paint/invalidation/table-two-pass-layout-overpaint-expected.html
index 6c8da19..013c379 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table-two-pass-layout-overpaint-expected.html
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table-two-pass-layout-overpaint-expected.html
@@ -11,14 +11,8 @@
     <tr>
         <td>
             <div id="target"></div>
-            <div id="dummy"></div>
         </td>
     </tr>
 </table>
 </body>
 </html>
-<!-- crbug.com/690087: We do this to force a two-pass layout so that we get the same height on the table as the reference. -->
-<script>
-  document.body.offsetTop;
-  document.getElementById("dummy").style.display = "none";
-</script>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/table-two-pass-layout-overpaint-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/table-two-pass-layout-overpaint-expected.txt
index f4575e4d..a3de9dc 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/table-two-pass-layout-overpaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/table-two-pass-layout-overpaint-expected.txt
@@ -7,40 +7,17 @@
       "drawsContent": true,
       "paintInvalidations": [
         {
-          "object": "LayoutTable TABLE",
-          "rect": [8, 106, 106, 1],
-          "reason": "incremental"
-        },
-        {
-          "object": "LayoutTableCell TD",
-          "rect": [10, 104, 102, 1],
-          "reason": "incremental"
-        },
-        {
           "object": "LayoutBlockFlow DIV id='target'",
-          "rect": [11, 45, 100, 25],
-          "reason": "bounds change"
-        },
-        {
-          "object": "LayoutBlockFlow DIV id='target'",
-          "rect": [11, 44, 50, 25],
-          "reason": "bounds change"
+          "rect": [61, 44, 50, 25],
+          "reason": "incremental"
         }
       ]
     }
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTable TABLE",
-      "reason": "incremental"
-    },
-    {
-      "object": "LayoutTableCell TD",
-      "reason": "incremental"
-    },
-    {
       "object": "LayoutBlockFlow DIV id='target'",
-      "reason": "bounds change"
+      "reason": "incremental"
     }
   ]
 }
diff --git a/third_party/WebKit/PerformanceTests/Layout/nested-percent-height-tables.html b/third_party/WebKit/PerformanceTests/Layout/nested-percent-height-tables.html
deleted file mode 100644
index 934ed15..0000000
--- a/third_party/WebKit/PerformanceTests/Layout/nested-percent-height-tables.html
+++ /dev/null
@@ -1,94 +0,0 @@
-<!DOCTYPE HTML>
-<style>
-.body { margin:0; }
-.maxHeight { width:100%; height:100%; }
-.overflowDiv { overflow:hidden; display:inline-block }
-.overflowAuto { overflow:auto; }
-</style>
-<html id="top">
-  <body class="body" style="height:100%;">
-    <table class="maxHeight">
-      <tr>
-        <td style="height:100%;">
-          <div class="maxHeight">
-            <table class="maxHeight">
-              <tr>
-                <td class="maxHeight">
-                  <table class="maxHeight">
-                    <tr>
-                      <td style="height:100%;">
-                        <div class="maxHeight">
-                          <table id="top" class="maxHeight">
-                            <colgroup>
-                              <col/>
-                              <col />
-                              <col  style="width:100%;"/>
-                            </colgroup>
-                            <tr  style="height:100%;">
-                              <td style="height:100%;">
-                                <div class="overflowAuto maxHeight" style="position:relative;">
-                              </td>
-                              <td rowspan="1">
-                                <div class="overflowDiv" >
-                                </div>
-                              </td>
-                              <td style="height:100%;">
-                                <div class="overflowAuto maxHeight" style="position:relative;">
-                                  <div class="maxHeight">
-                                    <table class="maxHeight">
-                                      <tr>
-                                        <td class="maxHeight">
-                                          <table class="maxHeight">
-                                            <tr>
-                                              <td  style="height:100%;">
-                                                <table  class="maxHeight">
-                                                  <tr>
-                                                    <td colspan="2" class="maxHeight">
-                                                      <div class=" maxHeight">
-                                                        <table class="maxHeight">
-                                                          <tr>
-                                                            <td class="maxHeight">
-                                                              <table class="maxHeight">
-                                                                <tr>
-                                                                  <td  style="height:100%;">
-                                                                    <table class="maxHeight">
-                                                                      <tr>
-                                                                        <td class="maxHeight">
-                                                                          <table class="maxHeight">
-                                                                            <tr>
-                                                                              <td class="maxHeight">
-                                                                                <div class="maxHeight">
-                                                                                  <table class="maxHeight">
-                                                                                    <tr>
-                                                                                      <td class="maxHeight">
-                                                                                        <table class="maxHeight">
-                                                                                          <tr>
-                                                                                            <td  class="maxHeight">
-                                                                                              <table class="maxHeight">
-                                                                                                <tr>
-                                                                                                  <td class="maxHeight">
-                                                                                                    <table class="maxHeight">
-                                                                                                      <tr>
-                                                                                                        <td class="maxHeight">
-                                                                                                          <table class="maxHeight">
-                                                                                                            <tr>
-                                                                                                              <td class="maxHeight">
-                                                                                                                <table class="maxHeight">
-                                                                                                                  <tr>
-                                                                                                                    <td class="maxHeight">
-                                                                                                                      <table class="maxHeight">
-                                                                                                                        <tr>
-                                                                                                                          <td class="maxHeight">
-<script src="../resources/runner.js"></script>
-<script>
-function test() {
-  PerfTestRunner.forceLayout();
-  document.getElementById("top").style.height = "100%";
-  PerfTestRunner.forceLayout();
-  document.getElementById("top").style.height = "auto";
-}
-PerfTestRunner.measureRunsPerSecond({
-  description: "Measures performance of nested tables with percent height.",
-  run: test,
-});
-</script>
diff --git a/third_party/WebKit/Source/core/frame/Settings.json5 b/third_party/WebKit/Source/core/frame/Settings.json5
index e5c0b05..f72c8b4 100644
--- a/third_party/WebKit/Source/core/frame/Settings.json5
+++ b/third_party/WebKit/Source/core/frame/Settings.json5
@@ -916,5 +916,12 @@
       name: "presentationReceiver",
       initial: false,
     },
+
+    // Whether Blink should show media controls when `controls` attribute is used.
+    {
+      name: "mediaControlsEnabled",
+      initial: true,
+      invalidate: "MediaControls",
+    },
   ],
 }
diff --git a/third_party/WebKit/Source/core/frame/SettingsDelegate.h b/third_party/WebKit/Source/core/frame/SettingsDelegate.h
index 37edc88db..72041f8 100644
--- a/third_party/WebKit/Source/core/frame/SettingsDelegate.h
+++ b/third_party/WebKit/Source/core/frame/SettingsDelegate.h
@@ -63,6 +63,7 @@
     AccessibilityStateChange,
     TextTrackKindUserPreferenceChange,
     DOMWorldsChange,
+    MediaControlsChange,
   };
 
   virtual void settingsChanged(ChangeType) = 0;
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index dbbcdb2a..a3a195c2 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -134,6 +134,7 @@
   MediaControlsShowFullscreen,
   MediaControlsShowNoScript,
   MediaControlsShowNotShown,
+  MediaControlsShowDisabledSettings,
   MediaControlsShowMax
 };
 
@@ -372,6 +373,18 @@
          RuntimeEnabledFeatures::backgroundVideoTrackOptimizationEnabled();
 }
 
+void HTMLMediaElement::onMediaControlsEnabledChange(Document* document) {
+  auto it = documentToElementSetMap().find(document);
+  if (it == documentToElementSetMap().end())
+    return;
+  DCHECK(it->value);
+  WeakMediaElementSet& elements = *it->value;
+  for (const auto& element : elements) {
+    element->updateControlsVisibility();
+    element->mediaControls()->onMediaControlsEnabledChange();
+  }
+}
+
 HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName,
                                    Document& document)
     : HTMLElement(tagName, document),
@@ -2386,6 +2399,13 @@
 
 bool HTMLMediaElement::shouldShowControls(
     const RecordMetricsBehavior recordMetrics) const {
+  Settings* settings = document().settings();
+  if (settings && !settings->getMediaControlsEnabled()) {
+    if (recordMetrics == RecordMetricsBehavior::DoRecord)
+      showControlsHistogram().count(MediaControlsShowDisabledSettings);
+    return false;
+  }
+
   if (fastHasAttribute(controlsAttr)) {
     if (recordMetrics == RecordMetricsBehavior::DoRecord)
       showControlsHistogram().count(MediaControlsShowAttribute);
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.h b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
index 1b3a7d9..fa05bccdfa 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
@@ -98,6 +98,10 @@
   // by the page).
   static bool mediaTracksEnabledInternally();
 
+  // Notify the HTMLMediaElement that the media controls settings have changed
+  // for the given document.
+  static void onMediaControlsEnabledChange(Document*);
+
   DECLARE_VIRTUAL_TRACE();
 
   DECLARE_VIRTUAL_TRACE_WRAPPERS();
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
index ad9607ac..cefa6bb 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
@@ -71,8 +71,16 @@
 }
 
 static bool shouldShowCastButton(HTMLMediaElement& mediaElement) {
-  return !mediaElement.fastHasAttribute(HTMLNames::disableremoteplaybackAttr) &&
-         mediaElement.hasRemoteRoutes();
+  if (mediaElement.fastHasAttribute(HTMLNames::disableremoteplaybackAttr))
+    return false;
+
+  // Explicitly do not show cast button when the mediaControlsEnabled setting is
+  // false to make sure the overlay does not appear.
+  Document& document = mediaElement.document();
+  if (document.settings() && !document.settings()->getMediaControlsEnabled())
+    return false;
+
+  return mediaElement.hasRemoteRoutes();
 }
 
 static bool preferHiddenVolumeControls(const Document& document) {
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControls.h b/third_party/WebKit/Source/core/html/shadow/MediaControls.h
index b2046b6..7480531 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControls.h
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControls.h
@@ -110,6 +110,13 @@
     refreshCastButtonVisibility();
   }
 
+  // TODO(mlamouri): this method is needed in order to notify the controls that
+  // the `mediaControlsEnabled` setting has changed.
+  void onMediaControlsEnabledChange() {
+    // There is no update because only the overlay is expected to change.
+    refreshCastButtonVisibilityWithoutUpdate();
+  }
+
   DECLARE_VIRTUAL_TRACE();
 
  private:
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
index 685b14c..7084123c 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
@@ -293,6 +293,22 @@
   ASSERT_TRUE(isElementVisible(*castOverlayButton));
 }
 
+TEST_F(MediaControlsTest, CastOverlayMediaControlsDisabled) {
+  Element* castOverlayButton = getElementByShadowPseudoId(
+      mediaControls(), "-internal-media-controls-overlay-cast-button");
+  ASSERT_NE(nullptr, castOverlayButton);
+
+  EXPECT_FALSE(isElementVisible(*castOverlayButton));
+  simulateRouteAvailabe();
+  EXPECT_TRUE(isElementVisible(*castOverlayButton));
+
+  document().settings()->setMediaControlsEnabled(false);
+  EXPECT_FALSE(isElementVisible(*castOverlayButton));
+
+  document().settings()->setMediaControlsEnabled(true);
+  EXPECT_TRUE(isElementVisible(*castOverlayButton));
+}
+
 TEST_F(MediaControlsTest, KeepControlsVisibleIfOverflowListVisible) {
   Element* overflowList = getElementByShadowPseudoId(
       mediaControls(), "-internal-media-controls-overflow-menu-list");
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.cpp b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
index 8fe7915e..c497b9f0 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTable.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
@@ -451,13 +451,12 @@
     layouter.setChildNeedsLayout(&section);
   if (!section.needsLayout())
     markChildForPaginationRelayoutIfNeeded(section, layouter);
-  if (section.needsLayout()) {
-    section.layout();
-    section.setLogicalHeight(LayoutUnit(section.calcRowLogicalHeight()));
-  }
+  section.layoutIfNeeded();
+  int sectionLogicalHeight = section.calcRowLogicalHeight();
+  section.setLogicalHeight(LayoutUnit(sectionLogicalHeight));
   if (view()->layoutState()->isPaginated())
     updateFragmentationInfoForChild(section);
-  setLogicalHeight(logicalHeight() + section.logicalHeight());
+  setLogicalHeight(logicalHeight() + sectionLogicalHeight);
 }
 
 LayoutUnit LayoutTable::logicalHeightFromStyle() const {
@@ -502,8 +501,8 @@
     extraLogicalHeight -=
         section->distributeExtraLogicalHeightToRows(extraLogicalHeight);
 
-  // crbug.com/690087: We really would like to enable this ASSERT to ensure that
-  // all the extra space has been distributed.
+  // FIXME: We really would like to enable this ASSERT to ensure that all the
+  // extra space has been distributed.
   // However our current distribution algorithm does not round properly and thus
   // we can have some remaining height.
   // ASSERT(!topSection() || !extraLogicalHeight);
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableSection.h b/third_party/WebKit/Source/core/layout/LayoutTableSection.h
index 0254244..f7d6d1d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableSection.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTableSection.h
@@ -329,8 +329,6 @@
 
   bool isRepeatingHeaderGroup() const;
 
-  void layout() override;
-
  protected:
   void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override;
   bool nodeAtPoint(HitTestResult&,
@@ -345,6 +343,8 @@
 
   void willBeRemovedFromTree() override;
 
+  void layout() override;
+
   int borderSpacingForRow(unsigned row) const {
     return m_grid[row].rowLayoutObject ? table()->vBorderSpacing() : 0;
   }
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp
index d5771fbc..6f484137 100644
--- a/third_party/WebKit/Source/core/page/Page.cpp
+++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -437,6 +437,16 @@
         }
       }
     } break;
+    case SettingsDelegate::MediaControlsChange:
+      for (Frame* frame = mainFrame(); frame;
+           frame = frame->tree().traverseNext()) {
+        if (!frame->isLocalFrame())
+          continue;
+        Document* doc = toLocalFrame(frame)->document();
+        if (doc)
+          HTMLMediaElement::onMediaControlsEnabledChange(doc);
+      }
+      break;
   }
 }
 
diff --git a/third_party/WebKit/Source/platform/heap/Heap.cpp b/third_party/WebKit/Source/platform/heap/Heap.cpp
index 97ce826..e0b5cb8 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.cpp
+++ b/third_party/WebKit/Source/platform/heap/Heap.cpp
@@ -145,8 +145,9 @@
   ProcessHeap::decreaseTotalAllocatedSpace(delta);
 }
 
-ThreadHeap::ThreadHeap()
-    : m_regionTree(WTF::makeUnique<RegionTree>()),
+ThreadHeap::ThreadHeap(ThreadState* threadState)
+    : m_threadState(threadState),
+      m_regionTree(WTF::makeUnique<RegionTree>()),
       m_heapDoesNotContainCache(WTF::wrapUnique(new HeapDoesNotContainCache)),
       m_freePagePool(WTF::wrapUnique(new PagePool)),
       m_markingStack(CallbackStack::create()),
@@ -160,41 +161,9 @@
 ThreadHeap::~ThreadHeap() {
 }
 
-void ThreadHeap::attach(ThreadState* thread) {
-  MutexLocker locker(m_threadAttachMutex);
-  m_threads.insert(thread);
-}
-
-void ThreadHeap::detach(ThreadState* thread) {
-  ASSERT(ThreadState::current() == thread);
-  bool isLastThread = false;
-  {
-    // Grab the threadAttachMutex to ensure only one thread can shutdown at
-    // a time and that no other thread can do a global GC. It also allows
-    // safe iteration of the m_threads set which happens as part of
-    // thread local GC asserts. We enter a safepoint while waiting for the
-    // lock to avoid a dead-lock where another thread has already requested
-    // GC.
-    MutexLocker locker(m_threadAttachMutex);
-    thread->runTerminationGC();
-    ASSERT(m_threads.contains(thread));
-    m_threads.erase(thread);
-    isLastThread = m_threads.isEmpty();
-  }
-  if (thread->isMainThread())
-    DCHECK_EQ(heapStats().allocatedSpace(), 0u);
-  if (isLastThread)
-    delete this;
-}
-
 #if DCHECK_IS_ON()
 BasePage* ThreadHeap::findPageFromAddress(Address address) {
-  MutexLocker locker(m_threadAttachMutex);
-  for (ThreadState* state : m_threads) {
-    if (BasePage* page = state->findPageFromAddress(address))
-      return page;
-  }
-  return nullptr;
+  return m_threadState->findPageFromAddress(address);
 }
 #endif
 
@@ -346,19 +315,16 @@
 
 void ThreadHeap::preGC() {
   ASSERT(!ThreadState::current()->isInGC());
-  for (ThreadState* state : m_threads)
-    state->preGC();
+  m_threadState->preGC();
 }
 
 void ThreadHeap::postGC(BlinkGC::GCType gcType) {
   ASSERT(ThreadState::current()->isInGC());
-  for (ThreadState* state : m_threads)
-    state->postGC(gcType);
+  m_threadState->postGC(gcType);
 }
 
 void ThreadHeap::preSweep(BlinkGC::GCType gcType) {
-  for (ThreadState* state : m_threads)
-    state->preSweep(gcType);
+  m_threadState->preSweep(gcType);
 }
 
 void ThreadHeap::processMarkingStack(Visitor* visitor) {
@@ -510,15 +476,12 @@
 }
 
 size_t ThreadHeap::objectPayloadSizeForTesting() {
-  // MEMO: is threadAttachMutex locked?
   size_t objectPayloadSize = 0;
-  for (ThreadState* state : m_threads) {
-    state->setGCState(ThreadState::GCRunning);
-    state->makeConsistentForGC();
-    objectPayloadSize += state->objectPayloadSizeForTesting();
-    state->setGCState(ThreadState::Sweeping);
-    state->setGCState(ThreadState::NoGCScheduled);
-  }
+  m_threadState->setGCState(ThreadState::GCRunning);
+  m_threadState->makeConsistentForGC();
+  objectPayloadSize += m_threadState->objectPayloadSizeForTesting();
+  m_threadState->setGCState(ThreadState::Sweeping);
+  m_threadState->setGCState(ThreadState::NoGCScheduled);
   return objectPayloadSize;
 }
 
@@ -527,15 +490,13 @@
   TRACE_EVENT0("blink_gc", "ThreadHeap::visitPersistentRoots");
   ProcessHeap::crossThreadPersistentRegion().tracePersistentNodes(visitor);
 
-  for (ThreadState* state : m_threads)
-    state->visitPersistents(visitor);
+  m_threadState->visitPersistents(visitor);
 }
 
 void ThreadHeap::visitStackRoots(Visitor* visitor) {
   ASSERT(ThreadState::current()->isInGC());
   TRACE_EVENT0("blink_gc", "ThreadHeap::visitStackRoots");
-  for (ThreadState* state : m_threads)
-    state->visitStack(visitor);
+  m_threadState->visitStack(visitor);
 }
 
 BasePage* ThreadHeap::lookupPageForAddress(Address address) {
@@ -555,8 +516,7 @@
   ProcessHeap::decreaseTotalMarkedObjectSize(m_stats.markedObjectSize());
 
   m_stats.reset();
-  for (ThreadState* state : m_threads)
-    state->resetHeapCounters();
+  m_threadState->resetHeapCounters();
 }
 
 ThreadHeap* ThreadHeap::s_mainThreadHeap = nullptr;
diff --git a/third_party/WebKit/Source/platform/heap/Heap.h b/third_party/WebKit/Source/platform/heap/Heap.h
index e9b3b880..bf5ebe7 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.h
+++ b/third_party/WebKit/Source/platform/heap/Heap.h
@@ -220,11 +220,9 @@
   double m_estimatedMarkingTimePerByte;
 };
 
-using ThreadStateSet = HashSet<ThreadState*>;
-
 class PLATFORM_EXPORT ThreadHeap {
  public:
-  ThreadHeap();
+  explicit ThreadHeap(ThreadState*);
   ~ThreadHeap();
 
   // Returns true for main thread's heap.
@@ -270,8 +268,6 @@
 
   StackFrameDepth& stackFrameDepth() { return m_stackFrameDepth; }
 
-  RecursiveMutex& threadAttachMutex() { return m_threadAttachMutex; }
-  const ThreadStateSet& threads() const { return m_threads; }
   ThreadHeapStats& heapStats() { return m_stats; }
   CallbackStack* markingStack() const { return m_markingStack.get(); }
   CallbackStack* postMarkingCallbackStack() const {
@@ -282,11 +278,6 @@
   }
   CallbackStack* ephemeronStack() const { return m_ephemeronStack.get(); }
 
-  void attach(ThreadState*);
-  void detach(ThreadState*);
-  void lockThreadAttachMutex();
-  void unlockThreadAttachMutex();
-
   void visitPersistentRoots(Visitor*);
   void visitStackRoots(Visitor*);
   void enterSafePoint(ThreadState*);
@@ -454,8 +445,7 @@
   void commitCallbackStacks();
   void decommitCallbackStacks();
 
-  RecursiveMutex m_threadAttachMutex;
-  ThreadStateSet m_threads;
+  ThreadState* m_threadState;
   ThreadHeapStats m_stats;
   std::unique_ptr<RegionTree> m_regionTree;
   std::unique_ptr<HeapDoesNotContainCache> m_heapDoesNotContainCache;
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 0dfd5f4..9b8d8098 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -131,9 +131,7 @@
   ASSERT(!**s_threadSpecific);
   **s_threadSpecific = this;
 
-  m_heap = new ThreadHeap();
-  ASSERT(m_heap);
-  m_heap->attach(this);
+  m_heap = WTF::wrapUnique(new ThreadHeap(this));
 
   for (int arenaIndex = 0; arenaIndex < BlinkGC::LargeObjectArenaIndex;
        arenaIndex++)
@@ -148,6 +146,10 @@
 
 ThreadState::~ThreadState() {
   ASSERT(checkThread());
+  if (isMainThread())
+    DCHECK_EQ(heap().heapStats().allocatedSpace(), 0u);
+  CHECK(gcState() == ThreadState::NoGCScheduled);
+
   for (int i = 0; i < BlinkGC::NumberOfArenas; ++i)
     delete m_arenas[i];
 
@@ -163,6 +165,12 @@
   new ThreadState();
 }
 
+void ThreadState::detachCurrentThread() {
+  ThreadState* state = current();
+  state->runTerminationGC();
+  delete state;
+}
+
 void ThreadState::removeAllPages() {
   ASSERT(checkThread());
   for (int i = 0; i < BlinkGC::NumberOfArenas; ++i)
@@ -208,13 +216,6 @@
   removeAllPages();
 }
 
-void ThreadState::detachCurrentThread() {
-  ThreadState* state = current();
-  state->heap().detach(state);
-  RELEASE_ASSERT(state->gcState() == ThreadState::NoGCScheduled);
-  delete state;
-}
-
 NO_SANITIZE_ADDRESS
 void ThreadState::visitAsanFakeStackForPointer(Visitor* visitor, Address ptr) {
 #if defined(ADDRESS_SANITIZER)
@@ -1256,14 +1257,6 @@
 }
 #endif
 
-void ThreadState::lockThreadAttachMutex() {
-  m_heap->threadAttachMutex().lock();
-}
-
-void ThreadState::unlockThreadAttachMutex() {
-  m_heap->threadAttachMutex().unlock();
-}
-
 void ThreadState::invokePreFinalizers() {
   ASSERT(checkThread());
   ASSERT(!sweepForbidden());
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.h b/third_party/WebKit/Source/platform/heap/ThreadState.h
index 69b00073..522977f 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.h
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.h
@@ -158,9 +158,6 @@
     ThreadState* m_state;
   };
 
-  void lockThreadAttachMutex();
-  void unlockThreadAttachMutex();
-
   static void attachMainThread();
 
   // Associate ThreadState object with the current thread. After this
@@ -613,7 +610,7 @@
   // and lazily construct ThreadState in it using placement new.
   static uint8_t s_mainThreadStateStorage[];
 
-  ThreadHeap* m_heap;
+  std::unique_ptr<ThreadHeap> m_heap;
   ThreadIdentifier m_thread;
   std::unique_ptr<PersistentRegion> m_persistentRegion;
   BlinkGC::StackState m_stackState;
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.cpp b/third_party/WebKit/Source/web/WebSettingsImpl.cpp
index 0d18192e..8843e8c 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.cpp
+++ b/third_party/WebKit/Source/web/WebSettingsImpl.cpp
@@ -724,4 +724,8 @@
   m_expensiveBackgroundThrottlingMaxDelay = maxDelay;
 }
 
+void WebSettingsImpl::setMediaControlsEnabled(bool enabled) {
+  m_settings->setMediaControlsEnabled(enabled);
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/web/WebSettingsImpl.h b/third_party/WebKit/Source/web/WebSettingsImpl.h
index a6eae28f..0c4ec8c0 100644
--- a/third_party/WebKit/Source/web/WebSettingsImpl.h
+++ b/third_party/WebKit/Source/web/WebSettingsImpl.h
@@ -208,6 +208,7 @@
   void setExpensiveBackgroundThrottlingInitialBudget(float) override;
   void setExpensiveBackgroundThrottlingMaxBudget(float) override;
   void setExpensiveBackgroundThrottlingMaxDelay(float) override;
+  void setMediaControlsEnabled(bool) override;
 
   bool showFPSCounter() const { return m_showFPSCounter; }
   bool showPaintRects() const { return m_showPaintRects; }
diff --git a/third_party/WebKit/public/web/WebSettings.h b/third_party/WebKit/public/web/WebSettings.h
index 64a661a..ef8014e4 100644
--- a/third_party/WebKit/public/web/WebSettings.h
+++ b/third_party/WebKit/public/web/WebSettings.h
@@ -295,6 +295,7 @@
   virtual void setExpensiveBackgroundThrottlingInitialBudget(float) = 0;
   virtual void setExpensiveBackgroundThrottlingMaxBudget(float) = 0;
   virtual void setExpensiveBackgroundThrottlingMaxDelay(float) = 0;
+  virtual void setMediaControlsEnabled(bool) = 0;
 
  protected:
   ~WebSettings() {}
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 9c9f420..2026b258 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -10301,15 +10301,13 @@
 </histogram>
 
 <histogram name="DevTools.ActionTaken" enum="DevToolsAction">
-  <owner>sergeyv@chromium.org</owner>
-  <owner>vsevik@chromium.org</owner>
+  <owner>alph@chromium.org</owner>
   <owner>pfeldman@chromium.org</owner>
   <summary>Specified DevTools action has been taken.</summary>
 </histogram>
 
 <histogram name="DevTools.InspectElement" units="ms">
-  <owner>sergeyv@chromium.org</owner>
-  <owner>vsevik@chromium.org</owner>
+  <owner>alph@chromium.org</owner>
   <owner>pfeldman@chromium.org</owner>
   <summary>
     Time to load Developer Tools when user clicks Inspect Element in the context
@@ -10318,15 +10316,13 @@
 </histogram>
 
 <histogram name="DevTools.PanelShown" enum="DevToolsPanel">
-  <owner>sergeyv@chromium.org</owner>
-  <owner>vsevik@chromium.org</owner>
+  <owner>alph@chromium.org</owner>
   <owner>pfeldman@chromium.org</owner>
   <summary>Specified DevTools panel was shown.</summary>
 </histogram>
 
 <histogram name="DevTools.SettingChanged" enum="DevToolsSetting">
-  <owner>sergeyv@chromium.org</owner>
-  <owner>vsevik@chromium.org</owner>
+  <owner>alph@chromium.org</owner>
   <owner>pfeldman@chromium.org</owner>
   <summary>Specified DevTools setting was changed.</summary>
 </histogram>
@@ -98927,6 +98923,7 @@
   <int value="1" label="Fullscreen"/>
   <int value="2" label="No scripts allowed"/>
   <int value="3" label="Not shown"/>
+  <int value="4" label="Disabled by settings"/>
 </enum>
 
 <enum name="MediaDocumentDownloadButtonType" type="int">