diff --git a/DEPS b/DEPS
index 762c7e5..308a11b 100644
--- a/DEPS
+++ b/DEPS
@@ -40,11 +40,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '5ad721e94682b51b9f773d95704f11990468fef6',
+  'skia_revision': '875218ebd816eb8931c64c5018ce2dc9bc8fd695',
   # 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': '00805bbf75fb604986fb77d223060d97f3b03ad1',
+  'v8_revision': '1539c3a15a256290a6a2f1afcb6afc9d226ceda3',
   # 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.
@@ -232,7 +232,7 @@
     Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067',
 
   'src/third_party/webrtc':
-    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '3ceef5c9c324cd6cd3090e1ce0d53ccd33763681', # commit position 16807
+    Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '44c51851dbdaeb2cab8be7348ecf89cb72c13510', # commit position 16820
 
   'src/third_party/openmax_dl':
     Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' +  Var('openmax_dl_revision'),
diff --git a/android_webview/common/crash_reporter/OWNERS b/android_webview/common/crash_reporter/OWNERS
new file mode 100644
index 0000000..38324cc
--- /dev/null
+++ b/android_webview/common/crash_reporter/OWNERS
@@ -0,0 +1 @@
+per-file crash_keys*=rsesek@chromium.org
diff --git a/android_webview/common/crash_reporter/aw_microdump_crash_reporter.cc b/android_webview/common/crash_reporter/aw_microdump_crash_reporter.cc
index 6d5e33d9..44c3b7c 100644
--- a/android_webview/common/crash_reporter/aw_microdump_crash_reporter.cc
+++ b/android_webview/common/crash_reporter/aw_microdump_crash_reporter.cc
@@ -168,20 +168,23 @@
     client->set_crash_signal_fd(crash_signal_fd);
   }
   ::crash_reporter::SetCrashReporterClient(client);
-  breakpad::SetShouldSanitizeDumps(true);
+  breakpad::SanitizationInfo sanitization_info;
+  sanitization_info.should_sanitize_dumps = true;
 #if !defined(COMPONENT_BUILD)
-  breakpad::SetSkipDumpIfPrincipalMappingNotReferenced(
-        reinterpret_cast<uintptr_t>(&EnableCrashReporter));
-#endif
+  sanitization_info.skip_dump_if_principal_mapping_not_referenced = true;
+  sanitization_info.address_within_principal_mapping =
+      reinterpret_cast<uintptr_t>(&EnableCrashReporter);
+#endif  // defined(COMPONENT_BUILD)
 
   bool is_browser_process =
       process_type.empty() ||
       process_type == breakpad::kWebViewSingleProcessType ||
       process_type == breakpad::kBrowserProcessType;
   if (is_browser_process) {
-    breakpad::InitCrashReporter("");
+    breakpad::InitCrashReporter("", sanitization_info);
   } else {
-    breakpad::InitNonBrowserCrashReporterForAndroid(process_type);
+    breakpad::InitNonBrowserCrashReporterForAndroid(process_type,
+                                                    sanitization_info);
   }
   g_enabled = true;
 }
diff --git a/android_webview/native/aw_metrics_service_client_impl.cc b/android_webview/native/aw_metrics_service_client_impl.cc
index 7566b51..d1ab432a 100644
--- a/android_webview/native/aw_metrics_service_client_impl.cc
+++ b/android_webview/native/aw_metrics_service_client_impl.cc
@@ -14,6 +14,7 @@
 #include "components/metrics/call_stack_profile_metrics_provider.h"
 #include "components/metrics/enabled_state_provider.h"
 #include "components/metrics/gpu/gpu_metrics_provider.h"
+#include "components/metrics/metrics_log_uploader.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_service.h"
 #include "components/metrics/metrics_state_manager.h"
@@ -204,10 +205,12 @@
 AwMetricsServiceClientImpl::CreateUploader(
     const std::string& server_url,
     const std::string& mime_type,
+    metrics::MetricsLogUploader::MetricServiceType service_type,
     const base::Callback<void(int)>& on_upload_complete) {
   return std::unique_ptr<::metrics::MetricsLogUploader>(
-      new metrics::NetMetricsLogUploader(
-          request_context_, server_url, mime_type, on_upload_complete));
+      new metrics::NetMetricsLogUploader(request_context_, server_url,
+                                         mime_type, service_type,
+                                         on_upload_complete));
 }
 
 base::TimeDelta AwMetricsServiceClientImpl::GetStandardUploadInterval() {
diff --git a/android_webview/native/aw_metrics_service_client_impl.h b/android_webview/native/aw_metrics_service_client_impl.h
index 75242ad..1d5ca2f 100644
--- a/android_webview/native/aw_metrics_service_client_impl.h
+++ b/android_webview/native/aw_metrics_service_client_impl.h
@@ -12,6 +12,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/macros.h"
+#include "components/metrics/metrics_log_uploader.h"
 
 namespace metrics {
 class MetricsStateManager;
@@ -55,6 +56,7 @@
   std::unique_ptr<metrics::MetricsLogUploader> CreateUploader(
       const std::string& server_url,
       const std::string& mime_type,
+      metrics::MetricsLogUploader::MetricServiceType service_type,
       const base::Callback<void(int)>& on_upload_complete) override;
   base::TimeDelta GetStandardUploadInterval() override;
 
diff --git a/base/trace_event/memory_infra_background_whitelist.cc b/base/trace_event/memory_infra_background_whitelist.cc
index 9230fe5..b45eec6 100644
--- a/base/trace_event/memory_infra_background_whitelist.cc
+++ b/base/trace_event/memory_infra_background_whitelist.cc
@@ -32,6 +32,7 @@
     "ProcessMemoryMetrics",
     "Skia",
     "Sql",
+    "URLRequestContext",
     "V8Isolate",
     "WinHeap",
     "SyncDirectory",
@@ -61,6 +62,17 @@
     "malloc",
     "malloc/allocated_objects",
     "malloc/metadata_fragmentation_caches",
+    "net/http_network_session_0x?",
+    "net/http_network_session_0x?/quic_stream_factory",
+    "net/http_network_session_0x?/socket_pool",
+    "net/http_network_session_0x?/spdy_session_pool",
+    "net/http_network_session_0x?/stream_factory",
+    "net/sdch_manager_0x?",
+    "net/ssl_session_cache",
+    "net/url_request_context_0x?",
+    "net/url_request_context_0x?/http_cache",
+    "net/url_request_context_0x?/http_network_session",
+    "net/url_request_context_0x?/sdch_manager",
     "web_cache/Image_resources",
     "web_cache/CSS stylesheet_resources",
     "web_cache/Script_resources",
diff --git a/chrome/BUILD.gn b/chrome/BUILD.gn
index 3a95db3..6f50b97 100644
--- a/chrome/BUILD.gn
+++ b/chrome/BUILD.gn
@@ -649,13 +649,6 @@
       # non-component builds, will ensure the export symbol table is correct.
       ":verify_chrome_framework_order",
     ]
-
-    # Only official builds that include Widevine need the widevine
-    # signature file.
-    if (is_chrome_branded && enable_pepper_cdms) {
-      sources += [ "$root_out_dir/$chrome_framework_name.sig" ]
-      public_deps += [ ":sign_chrome_framework_for_widevine" ]
-    }
   }
 
   action("clean_up_old_versions") {
@@ -869,25 +862,12 @@
         ":widevine_cdm_library_copy",
         "//third_party/widevine/cdm:widevinecdmadapter",
       ]
-
-      # Signatures are only generated for official chrome.
-      if (is_chrome_branded) {
-        sources += [
-          "$root_out_dir/$widevine_cdm_path/widevinecdmadapter.plugin.sig",
-          "$root_out_dir/libwidevinecdm.dylib.sig",
-        ]
-        public_deps += [ ":sign_cdm_adapter_for_widevine" ]
-      }
     }
 
     copy("widevine_cdm_library_copy") {
       sources = [
         "$root_out_dir/$widevine_cdm_path/libwidevinecdm.dylib",
       ]
-      if (is_chrome_branded) {
-        sources +=
-            [ "$root_out_dir/$widevine_cdm_path/libwidevinecdm.dylib.sig" ]
-      }
       outputs = [
         "$root_out_dir/{{source_file_part}}",
       ]
@@ -907,25 +887,6 @@
         "//third_party/widevine/cdm:widevine_cdm_manifest",
       ]
     }
-
-    widevine_sign_file("sign_cdm_adapter_for_widevine") {
-      file = "$root_out_dir/$widevine_cdm_path/widevinecdmadapter.plugin"
-      deps = [
-        "//third_party/widevine/cdm:widevinecdmadapter",
-      ]
-    }
-
-    widevine_sign_file("sign_chrome_framework_for_widevine") {
-      file = "$root_out_dir/$chrome_framework_name.framework/"
-      if (defined(chrome_framework_version)) {
-        file += "Versions/$chrome_framework_version/"
-      }
-      file += "$chrome_framework_name"
-      signature_file = "$root_out_dir/$chrome_framework_name.sig"
-      deps = [
-        ":chrome_framework",
-      ]
-    }
   }
 
   group("widevine_cdm_library") {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContextMenuManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContextMenuManager.java
index 101a74c..4078a2c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContextMenuManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/ContextMenuManager.java
@@ -185,7 +185,7 @@
                     mDelegate.openItem(WindowOpenDisposition.NEW_WINDOW);
                     return true;
                 case ID_OPEN_IN_NEW_TAB:
-                    mDelegate.openItem(WindowOpenDisposition.NEW_FOREGROUND_TAB);
+                    mDelegate.openItem(WindowOpenDisposition.NEW_BACKGROUND_TAB);
                     return true;
                 case ID_OPEN_IN_INCOGNITO_TAB:
                     mDelegate.openItem(WindowOpenDisposition.OFF_THE_RECORD);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index ebbbd514..7e0fe007 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -137,13 +137,6 @@
     }
 
     /**
-     * Object that registered through the {@link NewTabPageManager}, and that will be notified when
-     * the {@link NewTabPage} is destroyed.
-     * @see NewTabPageManager#addDestructionObserver(DestructionObserver)
-     */
-    public interface DestructionObserver { void onDestroy(); }
-
-    /**
      * Handles user interaction with the fakebox (the URL bar in the NTP).
      */
     public interface FakeboxDelegate {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index f584026..53d8d2f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -35,13 +35,13 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ntp.LogoBridge.Logo;
 import org.chromium.chrome.browser.ntp.LogoBridge.LogoObserver;
-import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
 import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener;
 import org.chromium.chrome.browser.ntp.cards.CardsVariationParameters;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 import org.chromium.chrome.browser.suggestions.Tile;
 import org.chromium.chrome.browser.suggestions.TileGridLayout;
@@ -229,10 +229,13 @@
             }
         });
 
+        OfflinePageBridge offlinePageBridge =
+                OfflinePageBridge.getForProfile(Profile.getLastUsedProfile());
+
         mTileGridLayout = (TileGridLayout) mNewTabPageLayout.findViewById(R.id.tile_grid_layout);
         mTileGridLayout.setMaxRows(getMaxTileRows(searchProviderHasLogo));
         mTileGroup = new TileGroup(mActivity, mManager, mContextMenuManager, mTileGroupDelegate,
-                /* observer = */ this, getTileTitleLines());
+                /* observer = */ this, offlinePageBridge, getTileTitleLines());
 
         mSearchProviderLogoView =
                 (LogoView) mNewTabPageLayout.findViewById(R.id.search_provider_logo);
@@ -249,8 +252,7 @@
 
         // Set up snippets
         NewTabPageAdapter newTabPageAdapter = new NewTabPageAdapter(mManager, mNewTabPageLayout,
-                mUiConfig, OfflinePageBridge.getForProfile(Profile.getLastUsedProfile()),
-                mContextMenuManager, /* tileGroupDelegate = */ null);
+                mUiConfig, offlinePageBridge, mContextMenuManager, /* tileGroupDelegate = */ null);
         mRecyclerView.setAdapter(newTabPageAdapter);
 
         int scrollOffset;
@@ -879,6 +881,12 @@
     }
 
     @Override
+    public void onTileOfflineBadgeVisibilityChanged(Tile tile) {
+        mTileGridLayout.updateOfflineBadge(tile);
+        mSnapshotTileGridChanged = true;
+    }
+
+    @Override
     public void onLoadTaskAdded() {
         mPendingLoadTasks++;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
index aad8ce4..676f009c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -85,7 +85,8 @@
             mRoot.addChild(mAboveTheFold);
         }
         if (tileGroupDelegate != null) {
-            mRoot.addChild(new TileGrid(uiDelegate, mContextMenuManager, tileGroupDelegate));
+            mRoot.addChild(new TileGrid(
+                    uiDelegate, mContextMenuManager, tileGroupDelegate, offlinePageBridge));
         }
         mRoot.addChildren(mSections, mSigninPromo, mAllDismissed, mFooter);
         if (mAboveTheFoldView == null
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
index 24bc8c0..2f3fe25 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SectionList.java
@@ -6,7 +6,6 @@
 
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
-import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
 import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnum;
@@ -15,6 +14,7 @@
 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
+import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsRanker;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
index b4777bc..9b858c98 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SignInPromo.java
@@ -15,13 +15,13 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
-import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
 import org.chromium.chrome.browser.preferences.ChromePreferenceManager;
 import org.chromium.chrome.browser.signin.AccountSigninActivity;
 import org.chromium.chrome.browser.signin.SigninAccessPoint;
 import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.signin.SigninManager.SignInAllowedObserver;
 import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
+import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 import org.chromium.chrome.browser.widget.displaystyle.UiConfig;
 
@@ -64,7 +64,7 @@
     }
 
     /**
-     * @returns a {@link DestructionObserver} observer that updates the visibility of the signin
+     * @return a {@link DestructionObserver} observer that updates the visibility of the signin
      * promo and unregisters itself when the New Tab Page is destroyed.
      */
     @Nullable
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
index 0581597..6675201 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.ntp.cards;
 
 import android.support.annotation.CallSuper;
+import android.support.annotation.Nullable;
 
 import org.chromium.base.Callback;
 import org.chromium.base.Log;
@@ -16,9 +17,8 @@
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticleViewHolder;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
-import org.chromium.chrome.browser.offlinepages.ClientId;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
-import org.chromium.chrome.browser.offlinepages.OfflinePageItem;
+import org.chromium.chrome.browser.suggestions.SuggestionsOfflineModelObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsRanker;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 
@@ -39,8 +39,7 @@
 
     private final Delegate mDelegate;
     private final SuggestionsCategoryInfo mCategoryInfo;
-    private final OfflinePageBridge mOfflinePageBridge;
-    private final OfflinePageBridge.OfflinePageModelObserver mOfflinePageObserver;
+    private final OfflineModelObserver mOfflineModelObserver;
 
     // Children
     private final SectionHeader mHeader;
@@ -75,7 +74,6 @@
             SuggestionsCategoryInfo info) {
         mDelegate = delegate;
         mCategoryInfo = info;
-        mOfflinePageBridge = offlinePageBridge;
 
         mHeader = new SectionHeader(info.getTitle());
         mSuggestionsList = new SuggestionsList(uiDelegate, ranker, info);
@@ -84,33 +82,8 @@
         mProgressIndicator = new ProgressItem();
         addChildren(mHeader, mSuggestionsList, mStatus, mMoreButton, mProgressIndicator);
 
-        mOfflinePageObserver =
-                new OfflinePageBridge.OfflinePageModelObserver() {
-                    @Override
-                    public void offlinePageModelLoaded() {
-                        updateAllSnippetOfflineAvailability();
-                    }
-
-                    @Override
-                    public void offlinePageAdded(OfflinePageItem addedPage) {
-                        updateAllSnippetOfflineAvailability();
-                    }
-
-                    @Override
-                    public void offlinePageDeleted(long offlineId, ClientId clientId) {
-                        for (SnippetArticle article : mSuggestionsList) {
-                            if (article.requiresExactOfflinePage()) continue;
-                            Long articleOfflineId = article.getOfflinePageOfflineId();
-                            if (articleOfflineId == null) continue;
-                            if (articleOfflineId.longValue() != offlineId) continue;
-                            // The old value cannot be simply removed without a request to the
-                            // model, because there may be an older offline page for the same
-                            // URL.
-                            updateSnippetOfflineAvailability(article);
-                        }
-                    }
-                };
-        mOfflinePageBridge.addObserver(mOfflinePageObserver);
+        mOfflineModelObserver = new OfflineModelObserver(offlinePageBridge);
+        uiDelegate.addDestructionObserver(mOfflineModelObserver);
 
         mStatus.setVisible(!hasSuggestions());
     }
@@ -234,7 +207,7 @@
     @Override
     @CallSuper
     public void detach() {
-        mOfflinePageBridge.removeObserver(mOfflinePageObserver);
+        mOfflineModelObserver.onDestroy();
         super.detach();
     }
 
@@ -417,37 +390,12 @@
 
         for (SnippetArticle article : suggestions) {
             if (!article.requiresExactOfflinePage()) {
-                updateSnippetOfflineAvailability(article);
+                mOfflineModelObserver.updateOfflinableSuggestionAvailability(article);
             }
         }
     }
 
-    private void updateSnippetOfflineAvailability(final SnippetArticle article) {
-        // This method is not applicable to articles for which the exact offline id must specified.
-        assert !article.requiresExactOfflinePage();
-        if (!mOfflinePageBridge.isOfflinePageModelLoaded()) return;
-        // TabId is relevant only for recent tab offline pages, which we do not handle here, so we
-        // do not care about tab id.
-        mOfflinePageBridge.selectPageForOnlineUrl(
-                article.mUrl, /*tabId=*/0, new Callback<OfflinePageItem>() {
-                    @Override
-                    public void onResult(OfflinePageItem item) {
-                        mSuggestionsList.updateSuggestionOfflineId(
-                                article, item == null ? null : item.getOfflineId());
-                    }
-                });
-    }
 
-    /**
-     * Checks which SnippetArticles are available offline and updates them with offline id of the
-     * matched offline page.
-     */
-    private void updateAllSnippetOfflineAvailability() {
-        for (final SnippetArticle article : mSuggestionsList) {
-            if (article.requiresExactOfflinePage()) continue;
-            updateSnippetOfflineAvailability(article);
-        }
-    }
 
     /** Lets the {@link SuggestionsSection} know when a suggestion fetch has been started. */
     public void onFetchStarted() {
@@ -513,4 +461,20 @@
     SectionHeader getHeaderItemForTesting() {
         return mHeader;
     }
+
+    private class OfflineModelObserver extends SuggestionsOfflineModelObserver<SnippetArticle> {
+        public OfflineModelObserver(OfflinePageBridge bridge) {
+            super(bridge);
+        }
+
+        @Override
+        public void onSuggestionOfflineIdChanged(SnippetArticle suggestion, @Nullable Long id) {
+            mSuggestionsList.updateSuggestionOfflineId(suggestion, id);
+        }
+
+        @Override
+        public Iterable<SnippetArticle> getOfflinableSuggestions() {
+            return mSuggestionsList;
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
index 7c9db0e06..96409080 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
@@ -6,12 +6,14 @@
 import android.graphics.Bitmap;
 import android.support.annotation.Nullable;
 
+import org.chromium.chrome.browser.suggestions.OfflinableSuggestion;
+
 import java.io.File;
 
 /**
  * Represents the data for an article card on the NTP.
  */
-public class SnippetArticle {
+public class SnippetArticle implements OfflinableSuggestion {
     /** The category of this article. */
     public final int mCategory;
 
@@ -170,10 +172,7 @@
         setOfflinePageOfflineId(offlinePageId);
     }
 
-    /**
-    * @return whether a snippet has to be matched with the exact offline page or with the most
-    * recent offline page found by the snippet's URL.
-    */
+    @Override
     public boolean requiresExactOfflinePage() {
         return isDownload() || isRecentTab();
     }
@@ -201,15 +200,17 @@
         setOfflinePageOfflineId(offlinePageId);
     }
 
-    /** Sets offline id of the corresponding to the snippet offline page. Null to clear.*/
+    @Override
+    public String getUrl() {
+        return mUrl;
+    }
+
+    @Override
     public void setOfflinePageOfflineId(@Nullable Long offlineId) {
         mOfflinePageOfflineId = offlineId;
     }
 
-    /**
-     * Gets offline id of the corresponding to the snippet offline page.
-     * Null if there is no corresponding offline page.
-     */
+    @Override
     @Nullable
     public Long getOfflinePageOfflineId() {
         return mOfflinePageOfflineId;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
index 87dee41..68f0ca8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -8,12 +8,12 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.annotations.CalledByNative;
-import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
 import org.chromium.chrome.browser.ntp.NewTabPageUma;
 import org.chromium.chrome.browser.ntp.cards.ActionItem;
 import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo;
 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus.CategoryStatusEnum;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsMetricsReporter;
 import org.chromium.chrome.browser.suggestions.SuggestionsRanker;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
index f2f42ff6..48065c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -426,6 +426,7 @@
      * Returns via callback any urls in <code>urls</code> for which there exist offline pages.
      *
      * TODO(http://crbug.com/598006): Add metrics for preventing UI jank.
+     * TODO(http://crbug.com/693514): Now unused in production code. Can be removed.
      */
     public void checkPagesExistOffline(Set<String> urls, Callback<Set<String>> callback) {
         String[] urlArray = urls.toArray(new String[urls.size()]);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 328686f..946645c5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -236,8 +236,9 @@
 
     private final Handler mHandler = new Handler();
     private final WebContents mWebContents;
+    private final String mSchemelessOriginForPaymentApp;
+    private final String mOriginForDisplay;
     private final String mMerchantName;
-    private final String mOrigin;
     private final byte[][] mCertificateChain;
     private final AddressEditor mAddressEditor;
     private final CardEditor mCardEditor;
@@ -334,9 +335,13 @@
 
         mWebContents = webContents;
 
+        mSchemelessOriginForPaymentApp = UrlFormatter.formatUrlForSecurityDisplay(
+                mWebContents.getLastCommittedUrl(), false /* omit scheme for payment apps. */);
+
+        mOriginForDisplay = UrlFormatter.formatUrlForSecurityDisplay(
+                mWebContents.getLastCommittedUrl(), true /* include scheme in display */);
+
         mMerchantName = webContents.getTitle();
-        mOrigin =
-                UrlFormatter.formatUrlForSecurityDisplay(mWebContents.getLastCommittedUrl(), true);
         mCertificateChain = CertificateChainHelper.getCertificateChain(mWebContents);
 
         mApps = new ArrayList<>();
@@ -433,7 +438,7 @@
         mUI = new PaymentRequestUI(activity, this, mRequestShipping,
                 mRequestPayerName || mRequestPayerPhone || mRequestPayerEmail,
                 mMerchantSupportsAutofillPaymentInstruments,
-                !PaymentPreferencesUtil.isPaymentCompleteOnce(), mMerchantName, mOrigin,
+                !PaymentPreferencesUtil.isPaymentCompleteOnce(), mMerchantName, mOriginForDisplay,
                 new ShippingStrings(mShippingType));
 
         final FaviconHelper faviconHelper = new FaviconHelper();
@@ -615,7 +620,8 @@
         // so a fast response from a non-autofill payment app at the front of the app list does not
         // cause NOT_SUPPORTED payment rejection.
         for (Map.Entry<PaymentApp, Map<String, PaymentMethodData>> q : queryApps.entrySet()) {
-            q.getKey().getInstruments(q.getValue(), mOrigin, mCertificateChain, this);
+            q.getKey().getInstruments(
+                    q.getValue(), mSchemelessOriginForPaymentApp, mCertificateChain, this);
         }
     }
 
@@ -1133,9 +1139,9 @@
             }
         }
 
-        instrument.invokePaymentApp(mMerchantName, mOrigin, mCertificateChain,
-                Collections.unmodifiableMap(methodData), mRawTotal, mRawLineItems,
-                Collections.unmodifiableMap(modifiers), this);
+        instrument.invokePaymentApp(mMerchantName, mSchemelessOriginForPaymentApp,
+                mCertificateChain, Collections.unmodifiableMap(methodData), mRawTotal,
+                mRawLineItems, Collections.unmodifiableMap(modifiers), this);
 
         recordSuccessFunnelHistograms("PayClicked");
         return !(instrument instanceof AutofillPaymentInstrument);
@@ -1221,14 +1227,14 @@
     public void canMakePayment() {
         if (mClient == null) return;
 
-        CanMakePaymentQuery query = sCanMakePaymentQueries.get(mOrigin);
+        CanMakePaymentQuery query = sCanMakePaymentQueries.get(mSchemelessOriginForPaymentApp);
         if (query == null) {
             query = new CanMakePaymentQuery(mMethodData.keySet());
-            sCanMakePaymentQueries.put(mOrigin, query);
+            sCanMakePaymentQueries.put(mSchemelessOriginForPaymentApp, query);
             mHandler.postDelayed(new Runnable() {
                 @Override
                 public void run() {
-                    sCanMakePaymentQueries.remove(mOrigin);
+                    sCanMakePaymentQueries.remove(mSchemelessOriginForPaymentApp);
                 }
             }, CAN_MAKE_PAYMENT_QUERY_PERIOD_MS);
         }
@@ -1369,7 +1375,7 @@
             }
         }
 
-        CanMakePaymentQuery query = sCanMakePaymentQueries.get(mOrigin);
+        CanMakePaymentQuery query = sCanMakePaymentQueries.get(mSchemelessOriginForPaymentApp);
         if (query != null) query.setResponse(mCanMakePayment);
 
         // The list of payment instruments is ready to display.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/DestructionObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/DestructionObserver.java
new file mode 100644
index 0000000..2b95775c
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/DestructionObserver.java
@@ -0,0 +1,12 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.suggestions;
+
+/**
+ * Object that is registered through the {@link SuggestionsUiDelegate}, and that will be notified
+ * when its owner is destroyed.
+ * @see SuggestionsUiDelegate#addDestructionObserver(DestructionObserver)
+ */
+public interface DestructionObserver { void onDestroy(); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/OfflinableSuggestion.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/OfflinableSuggestion.java
new file mode 100644
index 0000000..732608e
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/OfflinableSuggestion.java
@@ -0,0 +1,28 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.suggestions;
+
+import android.support.annotation.Nullable;
+
+/**
+ * Exposes the data of a suggestion that can be saved offline.
+ */
+public interface OfflinableSuggestion {
+    /** @return The URL of this suggestion. */
+    String getUrl();
+
+    /** Assigns an offline page id to the suggestion. Set to {@code null} to clear. */
+    void setOfflinePageOfflineId(@Nullable Long offlineId);
+
+    /** @return current offline id assigned to the suggestion, or {@code null} if there is none. */
+    @Nullable
+    Long getOfflinePageOfflineId();
+
+    /**
+     * @return whether a suggestion has to be matched with the exact offline page or with the most
+     * recent offline page found by the suggestion's URL.
+     */
+    boolean requiresExactOfflinePage();
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
index e6dfb124..ad72913 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java
@@ -12,7 +12,6 @@
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.NativePageHost;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
-import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsBridge;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
index 6969148..2fff2de 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsNavigationDelegateImpl.java
@@ -96,7 +96,7 @@
         if (article.isAssetDownload()) {
             assert windowOpenDisposition == WindowOpenDisposition.CURRENT_TAB
                     || windowOpenDisposition == WindowOpenDisposition.NEW_WINDOW
-                    || windowOpenDisposition == WindowOpenDisposition.NEW_FOREGROUND_TAB;
+                    || windowOpenDisposition == WindowOpenDisposition.NEW_BACKGROUND_TAB;
             DownloadUtils.openFile(
                     article.getAssetDownloadFile(), article.getAssetDownloadMimeType(), false);
             return;
@@ -123,7 +123,7 @@
             assert article.getOfflinePageOfflineId() != null;
             assert windowOpenDisposition == WindowOpenDisposition.CURRENT_TAB
                     || windowOpenDisposition == WindowOpenDisposition.NEW_WINDOW
-                    || windowOpenDisposition == WindowOpenDisposition.NEW_FOREGROUND_TAB;
+                    || windowOpenDisposition == WindowOpenDisposition.NEW_BACKGROUND_TAB;
             loadUrlParams = OfflinePageUtils.getLoadUrlParamsForOpeningOfflineVersion(
                     article.mUrl, article.getOfflinePageOfflineId());
             // Extra headers are not read in loadUrl, but verbatim headers are.
@@ -149,7 +149,7 @@
             case WindowOpenDisposition.CURRENT_TAB:
                 mHost.loadUrl(loadUrlParams);
                 break;
-            case WindowOpenDisposition.NEW_FOREGROUND_TAB:
+            case WindowOpenDisposition.NEW_BACKGROUND_TAB:
                 openUrlInNewTab(loadUrlParams, false);
                 break;
             case WindowOpenDisposition.OFF_THE_RECORD:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsOfflineModelObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsOfflineModelObserver.java
new file mode 100644
index 0000000..9cfb5bf
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsOfflineModelObserver.java
@@ -0,0 +1,97 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.suggestions;
+
+import android.support.annotation.Nullable;
+
+import org.chromium.base.Callback;
+import org.chromium.chrome.browser.offlinepages.ClientId;
+import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
+import org.chromium.chrome.browser.offlinepages.OfflinePageItem;
+
+/**
+ * Handles checking the offline state of suggestions and notifications about related changes.
+ * @param <T> type of suggestion to handle. Mostly a convenience parameter to avoid casts.
+ */
+public abstract class SuggestionsOfflineModelObserver<T extends OfflinableSuggestion>
+        extends OfflinePageBridge.OfflinePageModelObserver implements DestructionObserver {
+    private final OfflinePageBridge mOfflinePageBridge;
+
+    /**
+     * Constructor for an offline model observer. It registers itself with the bridge, but the
+     * unregistration will have to be done by the caller, either directly or by registering the
+     * created observer as {@link DestructionObserver}.
+     * @param bridge source of the offline state data.
+     */
+    public SuggestionsOfflineModelObserver(OfflinePageBridge bridge) {
+        mOfflinePageBridge = bridge;
+        mOfflinePageBridge.addObserver(this);
+    }
+
+    @Override
+    public void onDestroy() {
+        mOfflinePageBridge.removeObserver(this);
+    }
+
+    @Override
+    public void offlinePageModelLoaded() {
+        updateOfflinableSuggestionsAvailability();
+    }
+
+    @Override
+    public void offlinePageAdded(OfflinePageItem addedPage) {
+        updateOfflinableSuggestionsAvailability();
+    }
+
+    @Override
+    public void offlinePageDeleted(long offlineId, ClientId clientId) {
+        for (T suggestion : getOfflinableSuggestions()) {
+            if (suggestion.requiresExactOfflinePage()) continue;
+
+            Long suggestionOfflineId = suggestion.getOfflinePageOfflineId();
+            if (suggestionOfflineId == null) continue;
+            if (suggestionOfflineId != offlineId) continue;
+
+            // The old value cannot be simply removed without a request to the
+            // model, because there may be an older offline page for the same
+            // URL.
+            updateOfflinableSuggestionAvailability(suggestion);
+        }
+    }
+
+    public void updateOfflinableSuggestionsAvailability() {
+        for (T suggestion : getOfflinableSuggestions()) {
+            if (suggestion.requiresExactOfflinePage()) continue;
+            updateOfflinableSuggestionAvailability(suggestion);
+        }
+    }
+
+    public void updateOfflinableSuggestionAvailability(final T suggestion) {
+        // This method is not applicable to articles for which the exact offline id must specified.
+        assert !suggestion.requiresExactOfflinePage();
+        if (!mOfflinePageBridge.isOfflinePageModelLoaded()) return;
+
+        // TabId is relevant only for recent tab offline pages, which we do not handle here, so we
+        // do not care about tab id.
+        mOfflinePageBridge.selectPageForOnlineUrl(
+                suggestion.getUrl(), /*tabId=*/0, new Callback<OfflinePageItem>() {
+                    @Override
+                    public void onResult(OfflinePageItem item) {
+                        onSuggestionOfflineIdChanged(
+                                suggestion, item == null ? null : item.getOfflineId());
+                    }
+                });
+    }
+
+    /**
+     * Called when the offline state of a suggestion is retrieved.
+     * @param suggestion the suggestion for which the offline state was checked.
+     * @param id the new offline id of the suggestion.
+     */
+    public abstract void onSuggestionOfflineIdChanged(T suggestion, @Nullable Long id);
+
+    /** Handle to the suggestions for which to observe changes. */
+    public abstract Iterable<T> getOfflinableSuggestions();
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java
index 64a68505a..0d6fbccd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegate.java
@@ -4,15 +4,11 @@
 
 package org.chromium.chrome.browser.suggestions;
 
-import org.chromium.base.Callback;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
 import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallback;
 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
-import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 
-import java.util.Set;
-
 /**
  * Interface between the suggestion surface and the rest of the browser.
  */
@@ -65,13 +61,4 @@
      * Registers a {@link DestructionObserver}, notified when the New Tab Page goes away.
      */
     void addDestructionObserver(DestructionObserver destructionObserver);
-
-    // Offline
-
-    /**
-     * Checks if the pages with the given URLs are available offline.
-     * @param pageUrls The URLs of the sites whose offline availability is requested.
-     * @param callback Fired when the results are available.
-     */
-    void getUrlsAvailableOffline(Set<String> pageUrls, Callback<Set<String>> callback);
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java
index e5b5c47..02741c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsUiDelegateImpl.java
@@ -4,31 +4,19 @@
 
 package org.chromium.chrome.browser.suggestions;
 
-import android.net.Uri;
-import android.os.SystemClock;
 import android.support.annotation.Nullable;
 
-import org.chromium.base.Callback;
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.NativePageHost;
-import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
 import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallback;
 import org.chromium.chrome.browser.favicon.LargeIconBridge;
 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
-import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
-import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.profiles.Profile;
 
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
 
 /**
  * {@link SuggestionsUiDelegate} implementation.
@@ -85,55 +73,6 @@
     }
 
     @Override
-    public void getUrlsAvailableOffline(
-            Set<String> pageUrls, final Callback<Set<String>> callback) {
-        final Set<String> urlsAvailableOffline = new HashSet<>();
-        if (mIsDestroyed || !isNtpOfflinePagesEnabled()) {
-            callback.onResult(urlsAvailableOffline);
-            return;
-        }
-
-        HashSet<String> urlsToCheckForOfflinePage = new HashSet<>();
-
-        for (String pageUrl : pageUrls) {
-            if (isLocalUrl(pageUrl)) {
-                urlsAvailableOffline.add(pageUrl);
-            } else {
-                urlsToCheckForOfflinePage.add(pageUrl);
-            }
-        }
-
-        final long offlineQueryStartTime = SystemClock.elapsedRealtime();
-
-        OfflinePageBridge offlinePageBridge = OfflinePageBridge.getForProfile(mProfile);
-
-        // TODO(dewittj): Remove this code by making the NTP badging available after the NTP is
-        // fully loaded.
-        if (offlinePageBridge == null || !offlinePageBridge.isOfflinePageModelLoaded()) {
-            // Posting a task to avoid potential re-entrancy issues.
-            ThreadUtils.postOnUiThread(new Runnable() {
-                @Override
-                public void run() {
-                    callback.onResult(urlsAvailableOffline);
-                }
-            });
-            return;
-        }
-
-        offlinePageBridge.checkPagesExistOffline(
-                urlsToCheckForOfflinePage, new Callback<Set<String>>() {
-                    @Override
-                    public void onResult(Set<String> urlsWithOfflinePages) {
-                        urlsAvailableOffline.addAll(urlsWithOfflinePages);
-                        callback.onResult(urlsAvailableOffline);
-                        RecordHistogram.recordTimesHistogram("NewTabPage.OfflineUrlsLoadTime",
-                                SystemClock.elapsedRealtime() - offlineQueryStartTime,
-                                TimeUnit.MILLISECONDS);
-                    }
-                });
-    }
-
-    @Override
     public SuggestionsSource getSuggestionsSource() {
         return mSuggestionsSource;
     }
@@ -191,12 +130,4 @@
         if (mLargeIconBridge == null) mLargeIconBridge = new LargeIconBridge(mProfile);
         return mLargeIconBridge;
     }
-
-    private boolean isNtpOfflinePagesEnabled() {
-        return ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_OFFLINE_PAGES_FEATURE_NAME);
-    }
-
-    private boolean isLocalUrl(String url) {
-        return UrlConstants.FILE_SCHEME.equals(Uri.parse(url).getScheme());
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java
index 6b9e3bf..067927d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/Tile.java
@@ -14,11 +14,10 @@
 /**
  * Holds the details to populate a site suggestion tile.
  */
-public class Tile {
+public class Tile implements OfflinableSuggestion {
     private final String mTitle;
     private final String mUrl;
     private final String mWhitelistIconPath;
-    private final boolean mOfflineAvailable;
     private final int mIndex;
 
     @NTPTileSourceEnum
@@ -30,21 +29,22 @@
     @Nullable
     private Drawable mIcon;
 
+    @Nullable
+    private Long mOfflinePageOfflineId;
+
     /**
      * @param title The tile title.
      * @param url The site URL.
      * @param whitelistIconPath The path to the icon image file, if this is a whitelisted tile.
      * Empty otherwise.
-     * @param offlineAvailable Whether there is an offline copy of the URL available.
      * @param index The index of this tile in the list of tiles.
      * @param source The {@code NTPTileSource} that generated this tile.
      */
-    public Tile(String title, String url, String whitelistIconPath, boolean offlineAvailable,
-            int index, @NTPTileSourceEnum int source) {
+    public Tile(String title, String url, String whitelistIconPath, int index,
+            @NTPTileSourceEnum int source) {
         mTitle = title;
         mUrl = url;
         mWhitelistIconPath = whitelistIconPath;
-        mOfflineAvailable = offlineAvailable;
         mIndex = index;
         mSource = source;
     }
@@ -62,9 +62,9 @@
 
         mType = tile.getType();
         mIcon = tile.getIcon();
+        mOfflinePageOfflineId = tile.mOfflinePageOfflineId;
 
         if (!tile.getTitle().equals(mTitle)) return true;
-        if (tile.isOfflineAvailable() != mOfflineAvailable) return true;
         if (tile.getIndex() != mIndex) return true;
 
         // Ignore the whitelist changes when we already have an icon, since we won't need to reload
@@ -74,13 +74,27 @@
         return false;
     }
 
-    /**
-     * @return The site URL of this tile.
-     */
+    @Override
     public String getUrl() {
         return mUrl;
     }
 
+    @Override
+    public void setOfflinePageOfflineId(@Nullable Long offlineId) {
+        mOfflinePageOfflineId = offlineId;
+    }
+
+    @Nullable
+    @Override
+    public Long getOfflinePageOfflineId() {
+        return mOfflinePageOfflineId;
+    }
+
+    @Override
+    public boolean requiresExactOfflinePage() {
+        return false;
+    }
+
     /**
      * @return The title of this tile.
      */
@@ -99,7 +113,7 @@
      * @return Whether this tile is available offline.
      */
     public boolean isOfflineAvailable() {
-        return mOfflineAvailable;
+        return getOfflinePageOfflineId() != null;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
index f282287..11f5d1e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGrid.java
@@ -14,6 +14,7 @@
 import org.chromium.chrome.browser.ntp.cards.ItemViewType;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageViewHolder;
 import org.chromium.chrome.browser.ntp.cards.OptionalLeaf;
+import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 
 /**
  * The model and controller for a group of site suggestion tiles that will be rendered in a grid.
@@ -38,10 +39,10 @@
     private final TileGroup mTileGroup;
 
     public TileGrid(SuggestionsUiDelegate uiDelegate, ContextMenuManager contextMenuManager,
-            TileGroup.Delegate tileGroupDelegate) {
+            TileGroup.Delegate tileGroupDelegate, OfflinePageBridge offlinePageBridge) {
         mTileGroup = new TileGroup(ContextUtils.getApplicationContext(), uiDelegate,
                 contextMenuManager, tileGroupDelegate,
-                /* observer = */ this, getTileTitleLines());
+                /* observer = */ this, offlinePageBridge, getTileTitleLines());
         mTileGroup.startObserving(getMaxTileRows() * MAX_TILE_COLUMNS);
     }
 
@@ -74,6 +75,11 @@
     }
 
     @Override
+    public void onTileOfflineBadgeVisibilityChanged(Tile tile) {
+        if (isVisible()) notifyItemChanged(0, new ViewHolder.UpdateOfflineBadgeCallback(tile));
+    }
+
+    @Override
     public void onLoadTaskAdded() {}
 
     @Override
@@ -112,6 +118,10 @@
             mLayout.updateIconView(tile);
         }
 
+        public void updateOfflineBadge(Tile tile) {
+            mLayout.updateOfflineBadge(tile);
+        }
+
         /**
          * Callback to update the icon view for the view holder.
          */
@@ -128,5 +138,22 @@
                 ((ViewHolder) holder).updateIconView(mTile);
             }
         }
+
+        /**
+         * Callback to update the offline badge for the view holder.
+         */
+        public static class UpdateOfflineBadgeCallback extends PartialBindCallback {
+            private final Tile mTile;
+
+            public UpdateOfflineBadgeCallback(Tile tile) {
+                mTile = tile;
+            }
+
+            @Override
+            public void onResult(NewTabPageViewHolder holder) {
+                assert holder instanceof ViewHolder;
+                ((ViewHolder) holder).updateOfflineBadge(mTile);
+            }
+        }
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java
index 6a37c4ce..31d13d5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java
@@ -71,14 +71,17 @@
      * @param tile The tile that holds the data to populate the tile view.
      */
     public void updateIconView(Tile tile) {
-        int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            TileView tileView = (TileView) getChildAt(i);
-            if (TextUtils.equals(tile.getUrl(), tileView.getUrl())) {
-                tileView.renderIcon(tile);
-                break;
-            }
-        }
+        TileView tileView = getTileView(tile.getUrl());
+        if (tileView != null) tileView.renderIcon(tile);
+    }
+
+    /**
+     * Updates the visibility of the offline badge on the child view with a matching URL.
+     * @param tile The tile that holds the data to populate the tile view.
+     */
+    public void updateOfflineBadge(Tile tile) {
+        TileView tileView = getTileView(tile.getUrl());
+        if (tileView != null) tileView.renderOfflineBadge(tile);
     }
 
     @Override
@@ -148,4 +151,14 @@
 
         setMeasuredDimension(totalWidth, resolveSize(totalHeight, heightMeasureSpec));
     }
+
+    /** @return A tile view associated to the provided URL, or {@code null} if none is found. */
+    private TileView getTileView(String url) {
+        int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            TileView tileView = (TileView) getChildAt(i);
+            if (TextUtils.equals(url, tileView.getUrl())) return tileView;
+        }
+        return null;
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
index 15a6e8f..ceaa781 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileGroup.java
@@ -22,13 +22,14 @@
 import android.view.ViewGroup;
 
 import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.base.Callback;
 import org.chromium.base.Log;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
 import org.chromium.chrome.browser.ntp.ContextMenuManager.ContextMenuItemId;
 import org.chromium.chrome.browser.ntp.MostVisitedTileType;
+import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.widget.RoundedIconGenerator;
 import org.chromium.ui.mojom.WindowOpenDisposition;
 
@@ -93,6 +94,12 @@
         void onTileIconChanged(Tile tile);
 
         /**
+         * Called when the visibility of a tile's offline badge has changed.
+         * @param tile The tile for which the visibility of the offline badge has changed.
+         */
+        void onTileOfflineBadgeVisibilityChanged(Tile tile);
+
+        /**
          * Called when an asynchronous loading task has started.
          */
         void onLoadTaskAdded();
@@ -120,6 +127,13 @@
     private final RoundedIconGenerator mIconGenerator;
 
     /**
+     * Access point to offline related features. Will be {@code null} when the badges are disabled.
+     * @see ChromeFeatureList#NTP_OFFLINE_PAGES_FEATURE_NAME
+     */
+    @Nullable
+    private final OfflineModelObserver mOfflineModelObserver;
+
+    /**
      * Source of truth for the tile data. Since the objects can change when the data is updated,
      * other objects should not hold references to them but keep track of the URL instead, and use
      * it to retrieve a {@link Tile}.
@@ -138,7 +152,7 @@
      */
     public TileGroup(Context context, SuggestionsUiDelegate uiDelegate,
             ContextMenuManager contextMenuManager, Delegate tileGroupDelegate, Observer observer,
-            int titleLines) {
+            OfflinePageBridge offlinePageBridge, int titleLines) {
         mContext = context;
         mUiDelegate = uiDelegate;
         mContextMenuManager = contextMenuManager;
@@ -156,29 +170,51 @@
                 ApiCompatibilityUtils.getColor(resources, R.color.default_favicon_background_color);
         mIconGenerator = new RoundedIconGenerator(mContext, desiredIconSizeDp, desiredIconSizeDp,
                 ICON_CORNER_RADIUS_DP, iconColor, ICON_TEXT_SIZE_DP);
+
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.NTP_OFFLINE_PAGES_FEATURE_NAME)) {
+            mOfflineModelObserver = new OfflineModelObserver(offlinePageBridge);
+            mUiDelegate.addDestructionObserver(mOfflineModelObserver);
+        } else {
+            mOfflineModelObserver = null;
+        }
     }
 
     @Override
     public void onMostVisitedURLsAvailable(final String[] titles, final String[] urls,
             final String[] whitelistIconPaths, final int[] sources) {
-        // If no tiles have been built yet, this is the initial load. Build the tiles immediately so
-        // the layout is stable during initial rendering. They can be
-        // replaced later if there are offline urls, but that will not affect the layout widths and
-        // heights. A stable layout enables reliable scroll position initialization.
-        if (!mHasReceivedData) {
-            buildTiles(titles, urls, whitelistIconPaths, null, sources);
+        boolean isInitialLoad = !mHasReceivedData;
+        mHasReceivedData = true;
+
+        Tile[] newTiles = new Tile[titles.length];
+        Set<String> addedUrls = new HashSet<>();
+        boolean countChanged = isInitialLoad || mTiles.length != titles.length;
+        boolean dataChanged = countChanged;
+        for (int i = 0; i < titles.length; i++) {
+            assert urls[i] != null; // We assume everywhere that the url is not null.
+
+            // TODO(dgn): Add UMA to track the cause of https://crbug.com/690926. Checking this
+            // should not even be necessary as the backend is supposed to send non dupes URLs.
+            if (addedUrls.contains(urls[i])) {
+                assert false : "Incoming NTP Tiles are not unique. Dupe on " + urls[i];
+                continue;
+            }
+
+            newTiles[i] = new Tile(titles[i], urls[i], whitelistIconPaths[i], i, sources[i]);
+            if (newTiles[i].importData(getTile(urls[i]))) dataChanged = true;
+            addedUrls.add(urls[i]);
         }
 
-        // TODO(https://crbug.com/607573): We should show offline-available content in a nonblocking
-        // way so that responsiveness of the NTP does not depend on ready availability of offline
-        // pages.
-        Set<String> urlSet = new HashSet<>(Arrays.asList(urls));
-        mUiDelegate.getUrlsAvailableOffline(urlSet, new Callback<Set<String>>() {
-            @Override
-            public void onResult(Set<String> offlineUrls) {
-                buildTiles(titles, urls, whitelistIconPaths, offlineUrls, sources);
-            }
-        });
+        if (!dataChanged) return;
+
+        mTiles = newTiles;
+
+        if (mOfflineModelObserver != null) {
+            mOfflineModelObserver.updateOfflinableSuggestionsAvailability();
+        }
+
+        if (countChanged) mObserver.onTileCountChanged();
+        if (isInitialLoad) mObserver.onLoadTaskCompleted();
+        mObserver.onTileDataChanged();
     }
 
     @Override
@@ -240,40 +276,6 @@
         return mHasReceivedData;
     }
 
-    private void buildTiles(String[] titles, String[] urls, String[] whitelistIconPaths,
-            @Nullable Set<String> offlineUrls, int[] sources) {
-        boolean isInitialLoad = !mHasReceivedData;
-        mHasReceivedData = true;
-
-        Tile[] newTiles = new Tile[titles.length];
-        Set<String> addedUrls = new HashSet<>();
-        boolean countChanged = isInitialLoad || mTiles.length != titles.length;
-        boolean dataChanged = countChanged;
-        for (int i = 0; i < titles.length; i++) {
-            assert urls[i] != null; // We assume everywhere that the url is not null.
-
-            // TODO(dgn): Add UMA to track the cause of https://crbug.com/690926. Checking this
-            // should not even be necessary as the backend is supposed to send non dupes URLs.
-            if (addedUrls.contains(urls[i])) {
-                assert false : "Incoming NTP Tiles are not unique. Dupe on " + urls[i];
-                continue;
-            }
-
-            boolean offlineAvailable = offlineUrls != null && offlineUrls.contains(urls[i]);
-            newTiles[i] = new Tile(
-                    titles[i], urls[i], whitelistIconPaths[i], offlineAvailable, i, sources[i]);
-            if (newTiles[i].importData(getTile(urls[i]))) dataChanged = true;
-            addedUrls.add(urls[i]);
-        }
-
-        if (!dataChanged) return;
-
-        mTiles = newTiles;
-        if (countChanged) mObserver.onTileCountChanged();
-        if (isInitialLoad) mObserver.onLoadTaskCompleted();
-        mObserver.onTileDataChanged();
-    }
-
     /**
      * Inflates a new tile view, initializes it, and loads an icon for it.
      * @param tile The tile that holds the data to populate the new tile view.
@@ -417,4 +419,29 @@
             mContextMenuManager.createContextMenu(contextMenu, view, this);
         }
     }
+
+    private class OfflineModelObserver extends SuggestionsOfflineModelObserver<Tile> {
+        public OfflineModelObserver(OfflinePageBridge bridge) {
+            super(bridge);
+        }
+
+        @Override
+        public void onSuggestionOfflineIdChanged(Tile suggestion, @Nullable Long id) {
+            // Retrieve a tile from the internal data, to make sure we don't update a stale object.
+            Tile tile = getTile(suggestion.getUrl());
+            if (tile == null) return;
+
+            boolean oldOfflineAvailable = tile.isOfflineAvailable();
+            tile.setOfflinePageOfflineId(id);
+
+            // Only notify to update the view if there will be a visible change.
+            if (oldOfflineAvailable == tile.isOfflineAvailable()) return;
+            mObserver.onTileOfflineBadgeVisibilityChanged(tile);
+        }
+
+        @Override
+        public Iterable<Tile> getOfflinableSuggestions() {
+            return Arrays.asList(mTiles);
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java
index 0b498239..0c36d8e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/TileView.java
@@ -65,6 +65,11 @@
         mIconView.setImageDrawable(tile.getIcon());
     }
 
+    /** Shows or hides the offline badge to reflect the offline availability of the {@link Tile}. */
+    public void renderOfflineBadge(Tile tile) {
+        mBadgeView.setVisibility(tile.isOfflineAvailable() ? VISIBLE : GONE);
+    }
+
     /** Updates the view if there have been changes since the last time. */
     public void updateIfDataChanged(Tile tile) {
         if (!isUpToDate(tile)) renderTile(tile);
@@ -84,7 +89,7 @@
         // callbacks and handlers use it to look up the data and notify the rest of the system.
         assert mUrl.equals(tile.getUrl());
         mTitleView.setText(TitleUtil.getTitleForDisplay(tile.getTitle(), tile.getUrl()));
-        mBadgeView.setVisibility(tile.isOfflineAvailable() ? VISIBLE : GONE);
+        renderOfflineBadge(tile);
         renderIcon(tile);
     }
 }
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 73e6102..482ef77 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -926,11 +926,14 @@
   "java/src/org/chromium/chrome/browser/snackbar/undo/UndoBarController.java",
   "java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java",
   "java/src/org/chromium/chrome/browser/suggestions/ContentSuggestionsActivity.java",
+  "java/src/org/chromium/chrome/browser/suggestions/DestructionObserver.java",
   "java/src/org/chromium/chrome/browser/suggestions/MostVisitedSites.java",
   "java/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetContent.java",
   "java/src/org/chromium/chrome/browser/suggestions/Tile.java",
   "java/src/org/chromium/chrome/browser/suggestions/TileGrid.java",
   "java/src/org/chromium/chrome/browser/suggestions/TileGridLayout.java",
+  "java/src/org/chromium/chrome/browser/suggestions/OfflinableSuggestion.java",
+  "java/src/org/chromium/chrome/browser/suggestions/SuggestionsOfflineModelObserver.java",
   "java/src/org/chromium/chrome/browser/suggestions/TileGroup.java",
   "java/src/org/chromium/chrome/browser/suggestions/TileGroupDelegateImpl.java",
   "java/src/org/chromium/chrome/browser/suggestions/TileView.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
index cc7666e..6ec28c3 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -11,7 +11,6 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
-import org.chromium.base.Callback;
 import org.chromium.base.ThreadUtils;
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.RetryOnFailure;
@@ -20,12 +19,12 @@
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
 import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallback;
 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
-import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView;
 import org.chromium.chrome.browser.ntp.cards.SuggestionsCategoryInfo;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsMetricsReporter;
 import org.chromium.chrome.browser.suggestions.SuggestionsNavigationDelegate;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
@@ -39,7 +38,6 @@
 
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.Set;
 
 /**
  * Tests for the appearance of Article Snippets.
@@ -231,11 +229,6 @@
         }
 
         @Override
-        public void getUrlsAvailableOffline(Set<String> pageUrls, Callback<Set<String>> callback) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
         public SuggestionsSource getSuggestionsSource() {
             return mSnippetsSource;
         }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/OWNERS b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/OWNERS
new file mode 100644
index 0000000..78c3488
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/OWNERS
@@ -0,0 +1 @@
+file://chrome/android/java/src/org/chromium/chrome/browser/ntp/OWNERS
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTest.java
index 29e05233..19025322 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/suggestions/SuggestionsBottomSheetTest.java
@@ -11,6 +11,7 @@
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.view.MotionEvent;
 
+import org.chromium.base.test.util.RetryOnFailure;
 import org.chromium.chrome.browser.ntp.cards.ItemViewType;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView;
 import org.chromium.chrome.test.BottomSheetTestCaseBase;
@@ -42,6 +43,7 @@
         super.tearDown();
     }
 
+    @RetryOnFailure
     @MediumTest
     public void testContextMenu() throws InterruptedException {
         NewTabPageRecyclerView recyclerView =
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
index f63ea83..3ce31b2 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -54,7 +54,6 @@
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.DisableHistogramsRule;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
-import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
 import org.chromium.chrome.browser.ntp.cards.SignInPromo.SigninObserver;
 import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
 import org.chromium.chrome.browser.ntp.snippets.CategoryStatus;
@@ -64,6 +63,7 @@
 import org.chromium.chrome.browser.signin.SigninManager;
 import org.chromium.chrome.browser.signin.SigninManager.SignInAllowedObserver;
 import org.chromium.chrome.browser.signin.SigninManager.SignInStateObserver;
+import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsMetricsReporter;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 import org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils.CategoryInfoBuilder;
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java
index f9e2a34b..5227ae5 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/SectionListTest.java
@@ -9,6 +9,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -29,11 +30,11 @@
 import org.chromium.base.Callback;
 import org.chromium.base.test.util.Feature;
 import org.chromium.chrome.browser.DisableHistogramsRule;
-import org.chromium.chrome.browser.ntp.NewTabPage.DestructionObserver;
 import org.chromium.chrome.browser.ntp.snippets.CategoryInt;
 import org.chromium.chrome.browser.ntp.snippets.KnownCategories;
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
+import org.chromium.chrome.browser.suggestions.DestructionObserver;
 import org.chromium.chrome.browser.suggestions.SuggestionsMetricsReporter;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 import org.chromium.chrome.test.util.browser.suggestions.ContentSuggestionsTestUtils.CategoryInfoBuilder;
@@ -243,19 +244,20 @@
         registerCategory(mSuggestionSource, CATEGORY1, 1);
         registerCategory(mSuggestionSource,
                 new CategoryInfoBuilder(CATEGORY2).withViewAllAction().build(), 3);
+
         SectionList sectionList = new SectionList(mUiDelegate, mOfflinePageBridge);
         bindViewHolders(sectionList);
 
         ArgumentCaptor<DestructionObserver> argument =
                 ArgumentCaptor.forClass(DestructionObserver.class);
-        verify(mUiDelegate).addDestructionObserver(argument.capture());
+        verify(mUiDelegate, atLeastOnce()).addDestructionObserver(argument.capture());
 
         assertFalse(sectionList.isEmpty());
         SuggestionsSection section = sectionList.getSectionForTesting(CATEGORY1);
         assertNotNull(section);
 
         // Now destroy the UI and thus notify the SectionList.
-        argument.getValue().onDestroy();
+        for (DestructionObserver observer : argument.getAllValues()) observer.onDestroy();
         // The section should be removed.
         assertTrue(sectionList.isEmpty());
         // Verify that the section has been detached by notifying its parent about changes. If not
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java
index 34e27df6..fc193a7 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/TileGroupTest.java
@@ -6,7 +6,6 @@
 
 import static junit.framework.TestCase.assertNotNull;
 
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -16,30 +15,27 @@
 import android.support.annotation.DimenRes;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.ArgumentMatchers;
 import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
 import org.robolectric.annotation.Implements;
 import org.robolectric.annotation.RealObject;
 import org.robolectric.shadows.ShadowResources;
 
-import org.chromium.base.Callback;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.EnableFeatures;
 import org.chromium.chrome.browser.ntp.ContextMenuManager;
 import org.chromium.chrome.browser.ntp.cards.NodeParent;
 import org.chromium.chrome.browser.ntp.cards.SuggestionsSection;
+import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 
-import java.util.Collections;
-import java.util.Set;
-
 /**
  * Unit tests for {@link TileGroup}.
  */
@@ -50,6 +46,9 @@
     private static final int TILE_TITLE_LINES = 1;
     private static final String[] URLS = {"https://www.google.com", "https://tellmedadjokes.com"};
 
+    @Rule
+    public EnableFeatures.Processor mEnableFeatureProcessor = new EnableFeatures.Processor();
+
     @Mock
     private SuggestionsSection.Delegate mDelegate;
     @Mock
@@ -58,6 +57,8 @@
     private SuggestionsUiDelegate mUiDelegate;
     @Mock
     private TileGroup.Observer mTileGroupObserver;
+    @Mock
+    private OfflinePageBridge mOfflinePageBridge;
 
     private FakeTileGroupDelegate mTileGroupDelegate;
 
@@ -69,10 +70,11 @@
     }
 
     @Test
+    @EnableFeatures({ChromeFeatureList.NTP_OFFLINE_PAGES_FEATURE_NAME})
     public void testInitialiseWithEmptyTileList() {
         TileGroup tileGroup = new TileGroup(RuntimeEnvironment.application, mUiDelegate,
                 mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
-                TILE_TITLE_LINES);
+                mOfflinePageBridge, TILE_TITLE_LINES);
         tileGroup.startObserving(MAX_TILES_TO_FETCH);
         notifyTileUrlsAvailable();
 
@@ -82,55 +84,19 @@
     }
 
     @Test
-    public void testInitialiseWithOfflineUrl() {
+    @EnableFeatures({ChromeFeatureList.NTP_OFFLINE_PAGES_FEATURE_NAME})
+    public void testInitialiseWithTileList() {
         TileGroup tileGroup = new TileGroup(RuntimeEnvironment.application, mUiDelegate,
                 mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
-                TILE_TITLE_LINES);
+                mOfflinePageBridge, TILE_TITLE_LINES);
         tileGroup.startObserving(MAX_TILES_TO_FETCH);
 
-        OfflineUrlsCallbackHandler callbackHandler = new OfflineUrlsCallbackHandler();
-        doAnswer(callbackHandler)
-                .when(mUiDelegate)
-                .getUrlsAvailableOffline(ArgumentMatchers.<Set<String>>any(),
-                        ArgumentMatchers.<Callback<Set<String>>>any());
-
         notifyTileUrlsAvailable(URLS);
 
         InOrder inOrder = inOrder(mTileGroupObserver);
         inOrder.verify(mTileGroupObserver).onTileCountChanged();
         inOrder.verify(mTileGroupObserver).onLoadTaskCompleted();
         inOrder.verify(mTileGroupObserver).onTileDataChanged();
-
-        callbackHandler.engage(Collections.singleton(URLS[1]));
-
-        // Notification about the url that should be marked as offline.
-        inOrder.verify(mTileGroupObserver).onTileDataChanged();
-        inOrder.verifyNoMoreInteractions();
-    }
-
-    @Test
-    public void testInitialiseNoOfflineUrl() {
-        TileGroup tileGroup = new TileGroup(RuntimeEnvironment.application, mUiDelegate,
-                mock(ContextMenuManager.class), mTileGroupDelegate, mTileGroupObserver,
-                TILE_TITLE_LINES);
-        tileGroup.startObserving(MAX_TILES_TO_FETCH);
-
-        OfflineUrlsCallbackHandler callbackHandler = new OfflineUrlsCallbackHandler();
-        doAnswer(callbackHandler)
-                .when(mUiDelegate)
-                .getUrlsAvailableOffline(ArgumentMatchers.<Set<String>>any(),
-                        ArgumentMatchers.<Callback<Set<String>>>any());
-
-        notifyTileUrlsAvailable(URLS);
-
-        InOrder inOrder = inOrder(mTileGroupObserver);
-        inOrder.verify(mTileGroupObserver).onTileCountChanged();
-        inOrder.verify(mTileGroupObserver).onLoadTaskCompleted();
-        inOrder.verify(mTileGroupObserver).onTileDataChanged();
-
-        callbackHandler.engage(Collections.<String>emptySet());
-
-        // Triggering the offline callback does not cause updates because the data has not changed.
         inOrder.verifyNoMoreInteractions();
     }
 
@@ -145,29 +111,6 @@
                 titles, urls, whitelistIconPaths, sources);
     }
 
-    private static class OfflineUrlsCallbackHandler implements Answer<Void> {
-        private Callback<Set<String>> mCallback;
-        private Set<String> mCallbackArgument;
-
-        @Override
-        public Void answer(InvocationOnMock invocation) throws Throwable {
-            mCallback = invocation.getArgument(1);
-            if (mCallbackArgument != null) invokeCallback();
-            return null;
-        }
-
-        public void engage(Set<String> callbackArgument) {
-            mCallbackArgument = callbackArgument;
-            if (mCallbackArgument != null && mCallback != null) invokeCallback();
-        }
-
-        private void invokeCallback() {
-            mCallback.onResult(mCallbackArgument);
-            mCallback = null;
-            mCallbackArgument = null;
-        }
-    }
-
     private class FakeTileGroupDelegate implements TileGroup.Delegate {
         public MostVisitedSites.Observer mObserver;
 
diff --git a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
index 1f9269c..05bc04c 100644
--- a/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
+++ b/chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.cc
@@ -16,6 +16,7 @@
 #include "content/public/browser/web_contents.h"
 #include "jni/ContextualSearchSceneLayer_jni.h"
 #include "net/base/load_flags.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "ui/android/resources/resource_manager_impl.h"
 #include "ui/android/view_android.h"
@@ -232,7 +233,8 @@
 
   GURL gurl(thumbnail_url_);
   Profile* profile = ProfileAndroid::FromProfileAndroid(j_profile);
-  fetcher_ = base::MakeUnique<chrome::BitmapFetcher>(gurl, this);
+  fetcher_ = base::MakeUnique<chrome::BitmapFetcher>(gurl, this,
+                                                     NO_TRAFFIC_ANNOTATION_YET);
   fetcher_->Init(
       profile->GetRequestContext(),
       std::string(),
diff --git a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc
index 8d53c9b..9538cfc 100644
--- a/chrome/browser/android/ntp/content_suggestions_notifier_service.cc
+++ b/chrome/browser/android/ntp/content_suggestions_notifier_service.cc
@@ -35,6 +35,7 @@
 using params::ntp_snippets::kNotificationsFeature;
 using params::ntp_snippets::kNotificationsKeepWhenFrontmostParam;
 using params::ntp_snippets::kNotificationsUseSnippetAsTextParam;
+using params::ntp_snippets::kNotificationsOpenToNTPParam;
 
 namespace {
 
@@ -131,11 +132,14 @@
                                 : base::Time::Max();
     bool use_snippet = variations::GetVariationParamByFeatureAsBool(
         kNotificationsFeature, kNotificationsUseSnippetAsTextParam, false);
+    bool open_to_ntp = variations::GetVariationParamByFeatureAsBool(
+        kNotificationsFeature, kNotificationsOpenToNTPParam, false);
     service_->FetchSuggestionImage(
         suggestion->id(),
         base::Bind(&NotifyingObserver::ImageFetched,
                    weak_ptr_factory_.GetWeakPtr(), suggestion->id(),
-                   suggestion->url(), suggestion->title(),
+                   open_to_ntp ? GURL("chrome://newtab") : suggestion->url(),
+                   suggestion->title(),
                    use_snippet ? suggestion->snippet_text()
                                : suggestion->publisher_name(),
                    timeout_at));
diff --git a/chrome/browser/android/offline_pages/background_loader_offliner.cc b/chrome/browser/android/offline_pages/background_loader_offliner.cc
index 732a4eca..2bf511a6 100644
--- a/chrome/browser/android/offline_pages/background_loader_offliner.cc
+++ b/chrome/browser/android/offline_pages/background_loader_offliner.cc
@@ -153,6 +153,12 @@
   params.client_id = request.client_id();
   params.proposed_offline_id = request.request_id();
   params.is_background = true;
+
+  // Pass in the original URL if it's different from last committed
+  // when redirects occur.
+  if (params.url != request.url())
+    params.original_url = request.url();
+
   offline_page_model_->SavePage(
       params, std::move(archiver),
       base::Bind(&BackgroundLoaderOffliner::OnPageSaved,
diff --git a/chrome/browser/android/omnibox/answers_image_bridge.cc b/chrome/browser/android/omnibox/answers_image_bridge.cc
index e21164e..fa08f54 100644
--- a/chrome/browser/android/omnibox/answers_image_bridge.cc
+++ b/chrome/browser/android/omnibox/answers_image_bridge.cc
@@ -15,6 +15,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_android.h"
 #include "jni/AnswersImage_jni.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "url/gurl.h"
@@ -75,7 +76,8 @@
   std::string url;
   base::android::ConvertJavaStringToUTF8(env, java_url, &url);
   return bitmap_fetcher_service->RequestImage(
-      GURL(url), new AnswersImageObserverAndroid(env, java_callback));
+      GURL(url), new AnswersImageObserverAndroid(env, java_callback),
+      NO_TRAFFIC_ANNOTATION_YET);
 }
 
 // static
diff --git a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
index bc890bf..8dcfd51 100644
--- a/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
+++ b/chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
@@ -34,6 +34,7 @@
 #include "components/sync/driver/sync_service_utils.h"
 #include "content/public/browser/notification_service.h"
 #include "extensions/features/features.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "chrome/browser/autocomplete/keyword_extensions_delegate_impl.h"
@@ -249,7 +250,47 @@
   BitmapFetcherService* image_service =
       BitmapFetcherServiceFactory::GetForBrowserContext(profile_);
   DCHECK(image_service);
-  image_service->Prefetch(url);
+
+  // TODO(jdonnelly, rhalavati): Create a helper function with Callback to
+  // create annotation and pass it to image_service, merging this annotation and
+  // chrome/browser/ui/omnibox/chrome_omnibox_client.cc
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("omnibox_prefetch_image", R"(
+        semantics {
+          sender: "Omnibox"
+          description:
+            "Chromium provides answers in the suggestion list for certain "
+            "queries that the user types in the omnibox. This request "
+            "retrieves a small image (for example, an icon illustrating the "
+            "current weather conditions) when this can add information to an "
+            "answer."
+          trigger:
+            "Change of results for the query typed by the user in the "
+            "omnibox."
+          data:
+            "The only data sent is the path to an image. No user data is "
+            "included, although some might be inferrable (e.g. whether the "
+            "weather is sunny or rainy in the user's current location) from "
+            "the name of the image in the path."
+          destination: WEBSITE
+        }
+        policy {
+          cookies_allowed: true
+          cookies_store: "user"
+          setting:
+            "You can enable or disable this feature via 'Use a prediction "
+            "service to help complete searches and URLs typed in the "
+            "address bar.' in Chromium's settings under Advanced. The "
+            "feature is enabled by default."
+          policy {
+            SearchSuggestEnabled {
+                policy_options {mode: MANDATORY}
+                value: false
+            }
+          }
+        })");
+
+  image_service->Prefetch(url, traffic_annotation);
 }
 
 void ChromeAutocompleteProviderClient::OnAutocompleteControllerResultReady(
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc
index 35c5ab9..af9447a2 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher.cc
@@ -11,10 +11,11 @@
 
 namespace chrome {
 
-BitmapFetcher::BitmapFetcher(const GURL& url, BitmapFetcherDelegate* delegate)
-    : url_(url),
-      delegate_(delegate) {
-}
+BitmapFetcher::BitmapFetcher(
+    const GURL& url,
+    BitmapFetcherDelegate* delegate,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation)
+    : url_(url), delegate_(delegate), traffic_annotation_(traffic_annotation) {}
 
 BitmapFetcher::~BitmapFetcher() {
 }
@@ -26,7 +27,8 @@
   if (url_fetcher_ != NULL)
     return;
 
-  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_->SetReferrer(referrer);
   url_fetcher_->SetReferrerPolicy(referrer_policy);
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher.h b/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
index f6058cf0..a34ef5ab 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_delegate.h"
 #include "chrome/browser/image_decoder.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_fetcher_delegate.h"
 #include "net/url_request/url_request.h"
 #include "url/gurl.h"
@@ -28,7 +29,9 @@
 class BitmapFetcher : public net::URLFetcherDelegate,
                       public ImageDecoder::ImageRequest {
  public:
-  BitmapFetcher(const GURL& url, BitmapFetcherDelegate* delegate);
+  BitmapFetcher(const GURL& url,
+                BitmapFetcherDelegate* delegate,
+                const net::NetworkTrafficAnnotationTag& traffic_annotation);
   ~BitmapFetcher() override;
 
   const GURL& url() const { return url_; }
@@ -74,6 +77,7 @@
   std::unique_ptr<net::URLFetcher> url_fetcher_;
   const GURL url_;
   BitmapFetcherDelegate* const delegate_;
+  const net::NetworkTrafficAnnotationTag traffic_annotation_;
 
   DISALLOW_COPY_AND_ASSIGN(BitmapFetcher);
 };
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc
index d4f1211..458a755f 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_browsertest.cc
@@ -12,6 +12,7 @@
 #include "content/public/test/test_utils.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_status_code.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "net/url_request/test_url_fetcher_factory.h"
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_status.h"
@@ -107,7 +108,7 @@
   // Set up a delegate to wait for the callback.
   BitmapFetcherTestDelegate delegate(kAsyncCall);
 
-  BitmapFetcher fetcher(url, &delegate);
+  BitmapFetcher fetcher(url, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   url_fetcher_factory_->SetFakeResponse(
       url, image_string, net::HTTP_OK, net::URLRequestStatus::SUCCESS);
@@ -141,7 +142,7 @@
 
   BitmapFetcherTestDelegate delegate(kSyncCall);
 
-  BitmapFetcher fetcher(url, &delegate);
+  BitmapFetcher fetcher(url, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   fetcher.OnImageDecoded(image);
 
@@ -160,7 +161,7 @@
   // Set up a delegate to wait for the callback.
   BitmapFetcherTestDelegate delegate(kAsyncCall);
 
-  BitmapFetcher fetcher(url, &delegate);
+  BitmapFetcher fetcher(url, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
 
   url_fetcher_factory_->SetFakeResponse(url,
                                         std::string(),
@@ -183,7 +184,7 @@
 IN_PROC_BROWSER_TEST_F(BitmapFetcherBrowserTest, HandleImageFailedTest) {
   GURL url("http://example.com/this-should-be-a-decode-failure");
   BitmapFetcherTestDelegate delegate(kAsyncCall);
-  BitmapFetcher fetcher(url, &delegate);
+  BitmapFetcher fetcher(url, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
   url_fetcher_factory_->SetFakeResponse(url,
                                         std::string("Not a real bitmap"),
                                         net::HTTP_OK,
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
index f1a2f9a..fcca01f 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.cc
@@ -83,7 +83,8 @@
 
 BitmapFetcherService::RequestId BitmapFetcherService::RequestImage(
     const GURL& url,
-    Observer* observer) {
+    Observer* observer,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   // Create a new request, assigning next available request ID.
   ++current_request_id_;
   if (current_request_id_ == REQUEST_ID_INVALID)
@@ -111,22 +112,26 @@
     return REQUEST_ID_INVALID;
 
   // Make sure there's a fetcher for this URL and attach to request.
-  const chrome::BitmapFetcher* fetcher = EnsureFetcherForUrl(url);
+  const chrome::BitmapFetcher* fetcher =
+      EnsureFetcherForUrl(url, traffic_annotation);
   request->set_fetcher(fetcher);
 
   requests_.push_back(request.release());
   return requests_.back()->request_id();
 }
 
-void BitmapFetcherService::Prefetch(const GURL& url) {
+void BitmapFetcherService::Prefetch(
+    const GURL& url,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   if (url.is_valid())
-    EnsureFetcherForUrl(url);
+    EnsureFetcherForUrl(url, traffic_annotation);
 }
 
 std::unique_ptr<chrome::BitmapFetcher> BitmapFetcherService::CreateFetcher(
-    const GURL& url) {
+    const GURL& url,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   std::unique_ptr<chrome::BitmapFetcher> new_fetcher(
-      new chrome::BitmapFetcher(url, this));
+      new chrome::BitmapFetcher(url, this, traffic_annotation));
 
   new_fetcher->Init(
       content::BrowserContext::GetDefaultStoragePartition(context_)->
@@ -139,12 +144,14 @@
 }
 
 const chrome::BitmapFetcher* BitmapFetcherService::EnsureFetcherForUrl(
-    const GURL& url) {
+    const GURL& url,
+    const net::NetworkTrafficAnnotationTag& traffic_annotation) {
   const chrome::BitmapFetcher* fetcher = FindFetcherForUrl(url);
   if (fetcher)
     return fetcher;
 
-  std::unique_ptr<chrome::BitmapFetcher> new_fetcher = CreateFetcher(url);
+  std::unique_ptr<chrome::BitmapFetcher> new_fetcher =
+      CreateFetcher(url, traffic_annotation);
   active_fetchers_.push_back(std::move(new_fetcher));
   return active_fetchers_.back().get();
 }
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h
index b3bdcf2..8c8e355 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service.h
@@ -12,6 +12,7 @@
 #include "base/memory/scoped_vector.h"
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_delegate.h"
 #include "components/keyed_service/core/keyed_service.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 
 namespace content {
 class BrowserContext;
@@ -56,22 +57,30 @@
   // downloaded one.
   // NOTE: The observer might be called back synchronously from RequestImage if
   // the image is already in the cache.
-  RequestId RequestImage(const GURL& url, Observer* observer);
+  RequestId RequestImage(
+      const GURL& url,
+      Observer* observer,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
   // Start fetching the image at the given |url|.
-  void Prefetch(const GURL& url);
+  void Prefetch(const GURL& url,
+                const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
  protected:
   // Create a bitmap fetcher for the given |url| and start it. Virtual method
   // so tests can override this for different behavior.
-  virtual std::unique_ptr<chrome::BitmapFetcher> CreateFetcher(const GURL& url);
+  virtual std::unique_ptr<chrome::BitmapFetcher> CreateFetcher(
+      const GURL& url,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
  private:
   friend class BitmapFetcherServiceTest;
 
   // Gets the existing fetcher for |url| or constructs a new one if it doesn't
   // exist.
-  const chrome::BitmapFetcher* EnsureFetcherForUrl(const GURL& url);
+  const chrome::BitmapFetcher* EnsureFetcherForUrl(
+      const GURL& url,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation);
 
   // Find a fetcher with a given |url|. Return NULL if none is found.
   const chrome::BitmapFetcher* FindFetcherForUrl(const GURL& url);
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service_unittest.cc b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service_unittest.cc
index 5c1bf07..b33b227 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher_service_unittest.cc
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher_service_unittest.cc
@@ -11,6 +11,7 @@
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
@@ -48,8 +49,10 @@
   // Create a fetcher, but don't start downloading. That allows side-stepping
   // the decode step, which requires a utility process.
   std::unique_ptr<chrome::BitmapFetcher> CreateFetcher(
-      const GURL& url) override {
-    return base::MakeUnique<chrome::BitmapFetcher>(url, this);
+      const GURL& url,
+      const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
+    return base::MakeUnique<chrome::BitmapFetcher>(url, this,
+                                                   traffic_annotation);
   }
 };
 
@@ -128,8 +131,8 @@
   GURL invalid_url;
   ASSERT_FALSE(invalid_url.is_valid());
 
-  BitmapFetcherService::RequestId request_id =
-      service_->RequestImage(invalid_url, new TestObserver(this));
+  BitmapFetcherService::RequestId request_id = service_->RequestImage(
+      invalid_url, new TestObserver(this), TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(invalid_request_id, request_id);
 }
 
@@ -141,18 +144,24 @@
 TEST_F(BitmapFetcherServiceTest, OnlyFirstRequestCreatesFetcher) {
   EXPECT_EQ(0U, active_fetchers().size());
 
-  service_->RequestImage(url1_, new TestObserver(this));
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(1U, active_fetchers().size());
 
-  service_->RequestImage(url1_, new TestObserver(this));
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(1U, active_fetchers().size());
 }
 
 TEST_F(BitmapFetcherServiceTest, CompletedFetchNotifiesAllObservers) {
-  service_->RequestImage(url1_, new TestObserver(this));
-  service_->RequestImage(url1_, new TestObserver(this));
-  service_->RequestImage(url1_, new TestObserver(this));
-  service_->RequestImage(url1_, new TestObserver(this));
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(1U, active_fetchers().size());
   EXPECT_EQ(4U, requests().size());
 
@@ -162,12 +171,16 @@
 }
 
 TEST_F(BitmapFetcherServiceTest, CancelRequest) {
-  service_->RequestImage(url1_, new TestObserver(this));
-  service_->RequestImage(url1_, new TestObserver(this));
-  BitmapFetcherService::RequestId requestId =
-      service_->RequestImage(url2_, new TestObserver(this));
-  service_->RequestImage(url1_, new TestObserver(this));
-  service_->RequestImage(url1_, new TestObserver(this));
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
+  BitmapFetcherService::RequestId requestId = service_->RequestImage(
+      url2_, new TestObserver(this), TRAFFIC_ANNOTATION_FOR_TESTS);
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(5U, requests().size());
 
   service_->CancelRequest(requestId);
@@ -181,8 +194,10 @@
 }
 
 TEST_F(BitmapFetcherServiceTest, FailedNullRequestsAreHandled) {
-  service_->RequestImage(url1_, new TestObserver(this));
-  service_->RequestImage(url2_, new TestObserver(this));
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
+  service_->RequestImage(url2_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(0U, cache_size());
 
   CompleteFetch(url1_);
@@ -192,8 +207,10 @@
   EXPECT_EQ(1U, cache_size());
 }
 TEST_F(BitmapFetcherServiceTest, FailedRequestsDontEnterCache) {
-  service_->RequestImage(url1_, new TestObserver(this));
-  service_->RequestImage(url2_, new TestObserver(this));
+  service_->RequestImage(url1_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
+  service_->RequestImage(url2_, new TestObserver(this),
+                         TRAFFIC_ANNOTATION_FOR_TESTS);
   EXPECT_EQ(0U, cache_size());
 
   CompleteFetch(url1_);
diff --git a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc
index 3ef7fddce..4c2aa11 100644
--- a/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc
+++ b/chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_service.cc
@@ -141,11 +141,6 @@
   app_manager_->AddObserver(this);
   pref_change_registrar_.reset(new PrefChangeRegistrar());
   pref_change_registrar_->Init(profile_->GetPrefs());
-  // Try to start/stop kiosk app on policy compliance state change.
-  pref_change_registrar_->Add(
-      prefs::kArcPolicyCompliant,
-      base::Bind(&ArcKioskAppService::PreconditionsChanged,
-                 base::Unretained(this)));
   notification_blocker_.reset(new ArcKioskNotificationBlocker());
   PreconditionsChanged();
 }
@@ -159,9 +154,7 @@
   if (app_id_.empty())
     return;
   app_info_ = ArcAppListPrefs::Get(profile_)->GetApp(app_id_);
-  if (app_info_ && app_info_->ready &&
-      profile_->GetPrefs()->GetBoolean(prefs::kArcPolicyCompliant) &&
-      !maintenance_session_running_) {
+  if (app_info_ && app_info_->ready && !maintenance_session_running_) {
     if (!app_launcher_)
       app_launcher_ = base::MakeUnique<ArcKioskAppLauncher>(
           profile_, ArcAppListPrefs::Get(profile_), app_id_, this);
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
index df090969..9c9a8d0 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.cc
@@ -41,43 +41,7 @@
 
 constexpr char kArcGlobalAppRestrictions[] = "globalAppRestrictions";
 constexpr char kArcCaCerts[] = "caCerts";
-constexpr char kNonComplianceDetails[] = "nonComplianceDetails";
-constexpr char kNonComplianceReason[] = "nonComplianceReason";
 constexpr char kPolicyCompliantJson[] = "{ \"policyCompliant\": true }";
-constexpr char kPolicyNonCompliantJson[] = "{ \"policyCompliant\": false }";
-
-// Value from CloudDPS NonComplianceDetail.NonComplianceReason enum.
-// Used to figure out whether to ignore non-compliance.
-enum NonComplianceReason : int {
-  UNKNOWN = 0,
-
-  // The API level of the device does not support the setting.
-  API_LEVEL = 1,
-
-  // The admin type (profile owner, device owner, etc.) does not support the
-  // setting.
-  ADMIN_TYPE = 2,
-
-  // The user has not taken required action to comply with the setting.
-  USER_ACTION = 3,
-
-  // The setting has an invalid value.
-  INVALID_VALUE = 4,
-
-  // A required application has not been (or cannot be) installed.
-  APP_NOT_INSTALLED = 5,
-
-  // The policy is not supported by the version of CloudDPC on the device.
-  UNSUPPORTED = 6,
-};
-
-// ChromeOS should ignore some non-critical CloudDPC non-compliance reasons
-// and proceed with starting ARC apps.
-bool IgnoreNonComplianceReason(int reason) {
-  return reason == NonComplianceReason::API_LEVEL ||
-         reason == NonComplianceReason::APP_NOT_INSTALLED ||
-         reason == NonComplianceReason::UNSUPPORTED;
-}
 
 // invert_bool_value: If the Chrome policy and the ARC policy with boolean value
 // have opposite semantics, set this to true so the bool is inverted before
@@ -315,7 +279,9 @@
 void OnReportComplianceParseFailure(
     const ArcPolicyBridge::ReportComplianceCallback& callback,
     const std::string& error) {
-  callback.Run(kPolicyNonCompliantJson);
+  // TODO(poromov@): Report to histogram.
+  DLOG(ERROR) << "Can't parse policy compliance report";
+  callback.Run(kPolicyCompliantJson);
 }
 
 void UpdateFirstComplianceSinceSignInTiming(
@@ -372,12 +338,6 @@
   arc_bridge_service()->policy()->RemoveObserver(this);
 }
 
-// static
-void ArcPolicyBridge::RegisterProfilePrefs(
-    user_prefs::PrefRegistrySyncable* registry) {
-  registry->RegisterBooleanPref(prefs::kArcPolicyCompliant, false);
-}
-
 void ArcPolicyBridge::OverrideIsManagedForTesting(bool is_managed) {
   is_managed_ = is_managed;
 }
@@ -457,37 +417,12 @@
 void ArcPolicyBridge::OnReportComplianceParseSuccess(
     const ArcPolicyBridge::ReportComplianceCallback& callback,
     std::unique_ptr<base::Value> parsed_json) {
-  const base::DictionaryValue* dict;
-  Profile* const profile = GetProfile();
-  if (!profile || !parsed_json || !parsed_json->GetAsDictionary(&dict) ||
-      !dict) {
-    callback.Run(kPolicyNonCompliantJson);
-    return;
-  }
+  // Always returns "compliant".
+  callback.Run(kPolicyCompliantJson);
 
-  // ChromeOS is 'compliant' with the report if all "nonComplianceDetails"
-  // entries have API_LEVEL, APP_NOT_INSTALLED or UNSUPPORTED reason.
-  bool compliant = true;
-  const base::ListValue* value = nullptr;
-  dict->GetList(kNonComplianceDetails, &value);
-  if (!dict->empty() && value && !value->empty()) {
-    for (const auto& entry : *value) {
-      const base::DictionaryValue* entry_dict;
-      int reason = 0;
-      // Get NonComplianceDetails.NonComplianceReason int enum value and check
-      // whether it shouldn't be ignored.
-      if (entry->GetAsDictionary(&entry_dict) &&
-          entry_dict->GetInteger(kNonComplianceReason, &reason) &&
-          !IgnoreNonComplianceReason(reason)) {
-        compliant = false;
-        break;
-      }
-    }
-  }
-  profile->GetPrefs()->SetBoolean(prefs::kArcPolicyCompliant, compliant);
-  callback.Run(compliant ? kPolicyCompliantJson : kPolicyNonCompliantJson);
-
-  UpdateComplianceReportMetrics(dict);
+  const base::DictionaryValue* dict = nullptr;
+  if (parsed_json->GetAsDictionary(&dict))
+    UpdateComplianceReportMetrics(dict);
 }
 
 void ArcPolicyBridge::UpdateComplianceReportMetrics(
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h
index 4966c0a..51fa6d7 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge.h
@@ -46,8 +46,6 @@
                   policy::PolicyService* policy_service);
   ~ArcPolicyBridge() override;
 
-  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
-
   void OverrideIsManagedForTesting(bool is_managed);
 
   // InstanceHolder<mojom::PolicyInstance>::Observer overrides.
diff --git a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
index d2c2acf..59fc751 100644
--- a/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
+++ b/chrome/browser/chromeos/arc/policy/arc_policy_bridge_unittest.cc
@@ -57,7 +57,6 @@
     "]}";
 
 constexpr char kPolicyCompliantResponse[] = "{ \"policyCompliant\": true }";
-constexpr char kPolicyNonCompliantResponse[] = "{ \"policyCompliant\": false }";
 
 // Helper class to define callbacks that verify that they were run.
 // Wraps a bool initially set to |false| and verifies that it's been set to
@@ -416,26 +415,16 @@
   policy_bridge()->ReportCompliance(
       "\"nonComplianceDetails\" : [}",
       PolicyComplianceCallback(run_loop().QuitClosure(),
-                               kPolicyNonCompliantResponse));
+                               kPolicyCompliantResponse));
   run_loop().Run();
 }
 
-TEST_F(ArcPolicyBridgeTest, ReportComplianceTest_NonCompliantReasons) {
+TEST_F(ArcPolicyBridgeTest, ReportComplianceTest_WithNonCompliantDetails) {
   policy_bridge()->ReportCompliance(
       "{\"nonComplianceDetails\" : "
       "[{\"fieldPath\":\"\",\"nonComplianceReason\":0,\"packageName\":\"\","
       "\"settingName\":\"someSetting\",\"cachedSize\":-1}]}",
       PolicyComplianceCallback(run_loop().QuitClosure(),
-                               kPolicyNonCompliantResponse));
-  run_loop().Run();
-}
-
-TEST_F(ArcPolicyBridgeTest, ReportComplianceTest_CompliantReasons) {
-  policy_bridge()->ReportCompliance(
-      "{\"nonComplianceDetails\" : "
-      "[{\"fieldPath\":\"\",\"nonComplianceReason\":1,\"packageName\":\"\","
-      "\"settingName\":\"someSetting\",\"cachedSize\":-1}]}",
-      PolicyComplianceCallback(run_loop().QuitClosure(),
                                kPolicyCompliantResponse));
   run_loop().Run();
 }
diff --git a/chrome/browser/chromeos/login/login_manager_test.cc b/chrome/browser/chromeos/login/login_manager_test.cc
index 5e9bcdb..354f2dc 100644
--- a/chrome/browser/chromeos/login/login_manager_test.cc
+++ b/chrome/browser/chromeos/login/login_manager_test.cc
@@ -201,8 +201,6 @@
   const UserContext user_context = CreateUserContext(user_id);
   SetExpectedCredentials(user_context);
   EXPECT_TRUE(TryToLogin(user_context));
-  // Let LoginDisplayHostImpl delete itself.
-  content::RunAllPendingInMessageLoop();
 }
 
 void LoginManagerTest::AddUser(const std::string& user_id) {
diff --git a/chrome/browser/extensions/webstore_install_helper.cc b/chrome/browser/extensions/webstore_install_helper.cc
index 691ec849..cd21e66 100644
--- a/chrome/browser/extensions/webstore_install_helper.cc
+++ b/chrome/browser/extensions/webstore_install_helper.cc
@@ -10,6 +10,7 @@
 #include "components/safe_json/safe_json_parser.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/base/load_flags.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request.h"
 
 using content::BrowserThread;
@@ -53,7 +54,36 @@
     // No existing |icon_fetcher_| to avoid unbalanced AddRef().
     CHECK(!icon_fetcher_.get());
     AddRef();  // Balanced in OnFetchComplete().
-    icon_fetcher_.reset(new chrome::BitmapFetcher(icon_url_, this));
+
+    net::NetworkTrafficAnnotationTag traffic_annotation =
+        net::DefineNetworkTrafficAnnotation("webstore_install_helper", R"(
+          semantics {
+            sender: "Webstore Install Helper"
+            description:
+              "Fetches the bitmap corresponding to an extension icon."
+            trigger:
+              "This can happen in a few different circumstances: "
+              "1-User initiated an install from the Chrome Web Store."
+              "2-User initiated an inline installation from another website."
+              "3-Loading of kiosk app data on Chrome OS (provided that the "
+              "kiosk app is a Web Store app)."
+            data:
+              "The url of the icon for the extension, which includes the "
+              "extension id."
+            destination: GOOGLE_OWNED_SERVICE
+          }
+          policy {
+            cookies_allowed: false
+            setting:
+              "There's no direct Chromium's setting to disable this, but you "
+              "could uninstall all extensions and not install (or begin the "
+              "installation flow for) any more."
+            policy_exception_justification:
+              "Not implemented, considered not useful."
+          })");
+
+    icon_fetcher_.reset(
+        new chrome::BitmapFetcher(icon_url_, this, traffic_annotation));
     icon_fetcher_->Init(
         context_getter_, std::string(),
         net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE,
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.cc b/chrome/browser/metrics/chrome_metrics_service_client.cc
index f63623c..965168fe 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.cc
+++ b/chrome/browser/metrics/chrome_metrics_service_client.cc
@@ -59,6 +59,7 @@
 #include "components/metrics/drive_metrics_provider.h"
 #include "components/metrics/file_metrics_provider.h"
 #include "components/metrics/gpu/gpu_metrics_provider.h"
+#include "components/metrics/metrics_log_uploader.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_reporting_default_state.h"
 #include "components/metrics/metrics_service.h"
@@ -515,11 +516,12 @@
 ChromeMetricsServiceClient::CreateUploader(
     const std::string& server_url,
     const std::string& mime_type,
+    metrics::MetricsLogUploader::MetricServiceType service_type,
     const base::Callback<void(int)>& on_upload_complete) {
   return std::unique_ptr<metrics::MetricsLogUploader>(
       new metrics::NetMetricsLogUploader(
-          g_browser_process->system_request_context(),
-          server_url, mime_type, on_upload_complete));
+          g_browser_process->system_request_context(), server_url, mime_type,
+          service_type, on_upload_complete));
 }
 
 base::TimeDelta ChromeMetricsServiceClient::GetStandardUploadInterval() {
diff --git a/chrome/browser/metrics/chrome_metrics_service_client.h b/chrome/browser/metrics/chrome_metrics_service_client.h
index 24e87b3..dad283c 100644
--- a/chrome/browser/metrics/chrome_metrics_service_client.h
+++ b/chrome/browser/metrics/chrome_metrics_service_client.h
@@ -18,6 +18,7 @@
 #include "base/threading/thread_checker.h"
 #include "build/build_config.h"
 #include "chrome/browser/metrics/metrics_memory_details.h"
+#include "components/metrics/metrics_log_uploader.h"
 #include "components/metrics/metrics_service_client.h"
 #include "components/metrics/profiler/tracking_synchronizer_observer.h"
 #include "components/metrics/proto/system_profile.pb.h"
@@ -80,6 +81,7 @@
   std::unique_ptr<metrics::MetricsLogUploader> CreateUploader(
       const std::string& server_url,
       const std::string& mime_type,
+      metrics::MetricsLogUploader::MetricServiceType service_type,
       const base::Callback<void(int)>& on_upload_complete) override;
   base::TimeDelta GetStandardUploadInterval() override;
   base::string16 GetRegistryBackupKey() override;
diff --git a/chrome/browser/ntp_snippets/ntp_snippets_features.cc b/chrome/browser/ntp_snippets/ntp_snippets_features.cc
index 5af0a6f..6d5a891 100644
--- a/chrome/browser/ntp_snippets/ntp_snippets_features.cc
+++ b/chrome/browser/ntp_snippets/ntp_snippets_features.cc
@@ -14,6 +14,7 @@
 const char kNotificationsUseSnippetAsTextParam[] = "use_snippet_as_text";
 const char kNotificationsKeepWhenFrontmostParam[] =
     "keep_notification_when_frontmost";
+const char kNotificationsOpenToNTPParam[] = "open_to_ntp";
 const char kNotificationsDailyLimit[] = "daily_limit";
 const char kNotificationsIgnoredLimitParam[] = "ignored_limit";
 
diff --git a/chrome/browser/ntp_snippets/ntp_snippets_features.h b/chrome/browser/ntp_snippets/ntp_snippets_features.h
index 867077b7..a254064 100644
--- a/chrome/browser/ntp_snippets/ntp_snippets_features.h
+++ b/chrome/browser/ntp_snippets/ntp_snippets_features.h
@@ -25,6 +25,10 @@
 // "false": automatically dismiss notification when Chrome becomes frontmost.
 extern const char kNotificationsKeepWhenFrontmostParam[];
 
+// "true": notifications link to chrome://newtab, with appropriate text.
+// "false": notifications link to URL of notifying article.
+extern const char kNotificationsOpenToNTPParam[];
+
 // An integer. The maximum number of notifications that will be shown in 1 day.
 extern const char kNotificationsDailyLimit[];
 constexpr int kNotificationsDefaultDailyLimit = 1;
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index cef77d3..75ca0ce 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -575,7 +575,6 @@
 
 #if defined(OS_CHROMEOS)
   arc::ArcSessionManager::RegisterProfilePrefs(registry);
-  arc::ArcPolicyBridge::RegisterProfilePrefs(registry);
   chromeos::first_run::RegisterProfilePrefs(registry);
   chromeos::file_system_provider::RegisterProfilePrefs(registry);
   chromeos::KeyPermissions::RegisterProfilePrefs(registry);
diff --git a/chrome/browser/profiles/profile_avatar_downloader.cc b/chrome/browser/profiles/profile_avatar_downloader.cc
index 6bfb7a88..e3647a0 100644
--- a/chrome/browser/profiles/profile_avatar_downloader.cc
+++ b/chrome/browser/profiles/profile_avatar_downloader.cc
@@ -12,6 +12,7 @@
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_avatar_icon_util.h"
 #include "net/base/load_flags.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "ui/gfx/image/image.h"
 
 namespace {
@@ -27,7 +28,28 @@
   DCHECK(!callback_.is_null());
   GURL url(std::string(kHighResAvatarDownloadUrlPrefix) +
            profiles::GetDefaultAvatarIconFileNameAtIndex(icon_index));
-  fetcher_.reset(new chrome::BitmapFetcher(url, this));
+  net::NetworkTrafficAnnotationTag traffic_annotation =
+      net::DefineNetworkTrafficAnnotation("profile_avatar", R"(
+        semantics {
+          sender: "Profile Avatar Downloader"
+          description:
+            "The Chromium binary comes with a bundle of low-resolution "
+            "versions of avatar images. When the user selects an avatar in "
+            "chrome://settings, Chromium will download a high-resolution "
+            "version from Google's static content servers for use in the "
+            "people manager UI."
+          trigger:
+            "User selects a new avatar in chrome://settings for their profile"
+          data: "None, only the filename of the png to download."
+          destination: GOOGLE_OWNED_SERVICE
+        }
+        policy {
+          cookies_allowed: false
+          policy_exception_justification:
+            "No content is being uploaded or saved; this request merely "
+            "downloads a publicly available PNG file."
+        })");
+  fetcher_.reset(new chrome::BitmapFetcher(url, this, traffic_annotation));
 }
 
 ProfileAvatarDownloader::~ProfileAvatarDownloader() {
diff --git a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
index e4eac62b..c9da53c 100644
--- a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
+++ b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
@@ -525,21 +525,21 @@
 class WindowDestroyer : public content::WebContentsObserver {
  public:
   WindowDestroyer(content::WebContents* web_contents, TabStripModel* model)
-      : content::WebContentsObserver(web_contents),
-        tab_strip_model_(model),
-        browser_closed_observer_(chrome::NOTIFICATION_BROWSER_CLOSED,
-                                 content::NotificationService::AllSources()) {}
-
-  // Wait for the browser window to be destroyed.
-  void Wait() { browser_closed_observer_.Wait(); }
+      : content::WebContentsObserver(web_contents), tab_strip_model_(model) {}
 
   void RenderProcessGone(base::TerminationStatus status) override {
+    // Wait for the window to be destroyed, which will ensure all other
+    // RenderViewHost objects are deleted before we return and proceed with
+    // the next iteration of notifications.
+    content::WindowedNotificationObserver observer(
+        chrome::NOTIFICATION_BROWSER_CLOSED,
+        content::NotificationService::AllSources());
     tab_strip_model_->CloseAllTabs();
+    observer.Wait();
   }
 
  private:
   TabStripModel* tab_strip_model_;
-  content::WindowedNotificationObserver browser_closed_observer_;
 
   DISALLOW_COPY_AND_ASSIGN(WindowDestroyer);
 };
@@ -572,12 +572,16 @@
   // Create an object that will close the window on a process crash.
   WindowDestroyer destroyer(wc1, browser()->tab_strip_model());
 
+  content::WindowedNotificationObserver observer(
+      chrome::NOTIFICATION_BROWSER_CLOSED,
+      content::NotificationService::AllSources());
+
   // Kill the renderer process, simulating a crash. This should the ProcessDied
   // method to be called. Alternatively, RenderProcessHost::OnChannelError can
   // be called to directly force a call to ProcessDied.
   wc1->GetRenderProcessHost()->Shutdown(-1, true);
 
-  destroyer.Wait();
+  observer.Wait();
 }
 
 // Sets up the browser in order to start the tests with two tabs open: one
diff --git a/chrome/browser/sessions/session_restore_stats_collector.cc b/chrome/browser/sessions/session_restore_stats_collector.cc
index abc35130..b8459f9 100644
--- a/chrome/browser/sessions/session_restore_stats_collector.cc
+++ b/chrome/browser/sessions/session_restore_stats_collector.cc
@@ -98,9 +98,7 @@
     : tab_count(0u),
       tabs_deferred(0u),
       tabs_load_started(0u),
-      tabs_loaded(0u),
-      parallel_tab_loads(0u) {
-}
+      tabs_loaded(0u) {}
 
 SessionRestoreStatsCollector::TabState::TabState(
     NavigationController* controller)
@@ -397,11 +395,8 @@
   tab_state->loading_state = TAB_IS_LOADING;
   ++loading_tab_count_;
 
-  if (!done_tracking_non_deferred_tabs_) {
+  if (!done_tracking_non_deferred_tabs_)
     ++tab_loader_stats_.tabs_load_started;
-    tab_loader_stats_.parallel_tab_loads =
-        std::max(tab_loader_stats_.parallel_tab_loads, loading_tab_count_);
-  }
 }
 
 void SessionRestoreStatsCollector::ReleaseIfDoneTracking() {
@@ -516,9 +511,6 @@
         base::Histogram::kUmaTargetedHistogramFlag);
     counter_for_count->AddTime(tab_loader_stats.non_deferred_tabs_loaded);
   }
-
-  UMA_HISTOGRAM_COUNTS_100("SessionRestore.ParallelTabLoads",
-                           tab_loader_stats.parallel_tab_loads);
 }
 
 void SessionRestoreStatsCollector::UmaStatsReportingDelegate::
diff --git a/chrome/browser/sessions/session_restore_stats_collector.h b/chrome/browser/sessions/session_restore_stats_collector.h
index e7e3a883..ee52c3a 100644
--- a/chrome/browser/sessions/session_restore_stats_collector.h
+++ b/chrome/browser/sessions/session_restore_stats_collector.h
@@ -103,10 +103,6 @@
     // (vaguely named for historical reasons, as it predates the concept of
     // deferred tabs).
     base::TimeDelta non_deferred_tabs_loaded;
-
-    // The maximum number of tabs loading in parallel. This corresponds to the
-    // "SessionRestore.ParallelTabLoads" metric.
-    size_t parallel_tab_loads;
   };
 
   // The StatsReportingDelegate is responsible for delivering statistics
diff --git a/chrome/browser/sessions/session_restore_stats_collector_unittest.cc b/chrome/browser/sessions/session_restore_stats_collector_unittest.cc
index ea2a8e0c..10082a60 100644
--- a/chrome/browser/sessions/session_restore_stats_collector_unittest.cc
+++ b/chrome/browser/sessions/session_restore_stats_collector_unittest.cc
@@ -63,8 +63,7 @@
                                         size_t tabs_loaded,
                                         int foreground_tab_first_loaded_ms,
                                         int foreground_tab_first_paint_ms,
-                                        int non_deferred_tabs_loaded_ms,
-                                        size_t parallel_tab_loads) {
+                                        int non_deferred_tabs_loaded_ms) {
     EXPECT_LT(0u, report_tab_loader_stats_call_count_);
     report_tab_loader_stats_call_count_--;
 
@@ -78,7 +77,6 @@
               tab_loader_stats_.foreground_tab_first_paint);
     EXPECT_EQ(base::TimeDelta::FromMilliseconds(non_deferred_tabs_loaded_ms),
               tab_loader_stats_.non_deferred_tabs_loaded);
-    EXPECT_EQ(parallel_tab_loads, tab_loader_stats_.parallel_tab_loads);
   }
 
   void ExpectReportTabDeferredCalled() {
@@ -324,8 +322,7 @@
 
   Tick();  // 2ms.
   GenerateLoadStop(0);
-  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 2, 1, 2,
-                                                           1);
+  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 2, 1, 2);
   mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
 }
 
@@ -343,8 +340,7 @@
 
   Tick();  // 2ms.
   GenerateRenderWidgetHostDidUpdateBackingStore(0);
-  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 1, 2, 1,
-                                                           1);
+  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 1, 2, 1);
   mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
 }
 
@@ -385,8 +381,7 @@
 
   Tick();  // 7ms.
   GenerateLoadStop(2);
-  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(3, 0, 3, 3, 2, 1, 7,
-                                                           1);
+  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(3, 0, 3, 3, 2, 1, 7);
   mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
   mock_reporting_delegate.EnsureNoUnexpectedCalls();
 }
@@ -426,8 +421,7 @@
   mock_reporting_delegate.EnsureNoUnexpectedCalls();
   Tick();  // 6ms.
   GenerateLoadStop(2);
-  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(3, 0, 3, 3, 2, 1, 6,
-                                                           2);
+  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(3, 0, 3, 3, 2, 1, 6);
   mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
   mock_reporting_delegate.EnsureNoUnexpectedCalls();
 }
@@ -453,8 +447,7 @@
   // Foreground tab finishes loading and stats get reported.
   Tick();  // 2ms.
   GenerateLoadStop(0);
-  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(2, 1, 1, 1, 2, 1, 2,
-                                                           1);
+  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(2, 1, 1, 1, 2, 1, 2);
   mock_reporting_delegate.EnsureNoUnexpectedCalls();
 
   // Background tab starts loading, paints and stops loading. This fires off a
@@ -501,8 +494,7 @@
   // stats to be emitted, but with empty foreground paint and load values.
   Tick();  // 3ms.
   GenerateRenderWidgetHostDidUpdateBackingStore(1);
-  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 0, 0, 2,
-                                                           1);
+  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 0, 0, 2);
   mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
   mock_reporting_delegate.EnsureNoUnexpectedCalls();
 }
@@ -538,8 +530,7 @@
   // stats to be emitted, but with an empty foreground paint value.
   Tick();  // 3ms.
   GenerateRenderWidgetHostDidUpdateBackingStore(1);
-  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 1, 0, 1,
-                                                           1);
+  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 1, 0, 1);
   mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
   mock_reporting_delegate.EnsureNoUnexpectedCalls();
 }
@@ -555,8 +546,7 @@
 
   // Destroy the tab. Expect all timings to be zero.
   GenerateWebContentsDestroyed(0);
-  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 0, 0, 0, 0,
-                                                           1);
+  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 0, 0, 0, 0);
   mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
   mock_reporting_delegate.EnsureNoUnexpectedCalls();
 }
@@ -576,8 +566,7 @@
 
   // Destroy the tab. Expect both load timings to be zero.
   GenerateWebContentsDestroyed(0);
-  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 0, 0, 1, 0,
-                                                           1);
+  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 0, 0, 1, 0);
   mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
   mock_reporting_delegate.EnsureNoUnexpectedCalls();
 }
@@ -599,8 +588,7 @@
   // Reload the tab. Expect the paint timing to be zero.
   Tick();  // 2 ms.
   GenerateLoadStart(0);
-  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 1, 0, 1,
-                                                           1);
+  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(1, 0, 1, 1, 1, 0, 1);
   mock_reporting_delegate.ExpectReportStatsCollectorDeathCalled();
   mock_reporting_delegate.EnsureNoUnexpectedCalls();
 }
@@ -625,8 +613,7 @@
   // with all zero timings.
   Tick();  // 2 ms.
   GenerateWebContentsDestroyed(0);
-  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(2, 1, 1, 0, 0, 0, 0,
-                                                           1);
+  mock_reporting_delegate.ExpectReportTabLoaderStatsCalled(2, 1, 1, 0, 0, 0, 0);
   mock_reporting_delegate.EnsureNoUnexpectedCalls();
 
   // Destroy the background tab. The collector should release itself.
diff --git a/chrome/browser/sessions/session_service.cc b/chrome/browser/sessions/session_service.cc
index 185ad29..2cc27dc 100644
--- a/chrome/browser/sessions/session_service.cc
+++ b/chrome/browser/sessions/session_service.cc
@@ -77,9 +77,6 @@
           this)),
       has_open_trackable_browsers_(false),
       move_on_new_browser_(false),
-      save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
-      save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
-      save_delay_in_hrs_(base::TimeDelta::FromHours(8)),
       force_browser_not_alive_with_no_windows_(false),
       weak_factory_(this) {
   // We should never be created when incognito.
@@ -96,9 +93,6 @@
           this)),
       has_open_trackable_browsers_(false),
       move_on_new_browser_(false),
-      save_delay_in_millis_(base::TimeDelta::FromMilliseconds(2500)),
-      save_delay_in_mins_(base::TimeDelta::FromMinutes(10)),
-      save_delay_in_hrs_(base::TimeDelta::FromHours(8)),
       force_browser_not_alive_with_no_windows_(false),
       weak_factory_(this) {
   Init();
@@ -354,8 +348,6 @@
   TabClosed(session_tab_helper->window_id(),
             session_tab_helper->session_id(),
             contents->GetClosedByUserGesture());
-  RecordSessionUpdateHistogramData(content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
-                                   &last_updated_tab_closed_time_);
 }
 
 void SessionService::SetWindowType(const SessionID& window_id,
@@ -526,8 +518,6 @@
 }
 
 void SessionService::OnSavedCommands() {
-  RecordSessionUpdateHistogramData(chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
-                                   &last_updated_save_time_);
   content::NotificationService::current()->Notify(
       chrome::NOTIFICATION_SESSION_SERVICE_SAVED,
       content::Source<Profile>(profile()),
@@ -628,8 +618,6 @@
             session_tab_helper->session_id(),
             web_contents->GetController().GetEntryCount());
       }
-      RecordSessionUpdateHistogramData(type,
-                                       &last_updated_nav_list_pruned_time_);
       break;
     }
 
@@ -675,11 +663,6 @@
           session_tab_helper->session_id(),
           navigation);
       content::Details<content::LoadCommittedDetails> changed(details);
-      if (changed->type == content::NAVIGATION_TYPE_NEW_PAGE ||
-        changed->type == content::NAVIGATION_TYPE_EXISTING_PAGE) {
-        RecordSessionUpdateHistogramData(type,
-                                         &last_updated_nav_entry_commit_time_);
-      }
       break;
     }
 
@@ -974,113 +957,6 @@
                                    browser->is_app() ? TYPE_APP : TYPE_NORMAL);
 }
 
-void SessionService::RecordSessionUpdateHistogramData(int type,
-    base::TimeTicks* last_updated_time) {
-  if (!last_updated_time->is_null()) {
-    base::TimeDelta delta = base::TimeTicks::Now() - *last_updated_time;
-    // We're interested in frequent updates periods longer than
-    // 10 minutes.
-    bool use_long_period = false;
-    if (delta >= save_delay_in_mins_) {
-      use_long_period = true;
-    }
-    switch (type) {
-      case chrome::NOTIFICATION_SESSION_SERVICE_SAVED :
-        RecordUpdatedSaveTime(delta, use_long_period);
-        break;
-      case content::NOTIFICATION_WEB_CONTENTS_DESTROYED:
-        RecordUpdatedTabClosed(delta, use_long_period);
-        break;
-      case content::NOTIFICATION_NAV_LIST_PRUNED:
-        RecordUpdatedNavListPruned(delta, use_long_period);
-        break;
-      case content::NOTIFICATION_NAV_ENTRY_COMMITTED:
-        RecordUpdatedNavEntryCommit(delta, use_long_period);
-        break;
-      default:
-        NOTREACHED() << "Bad type sent to RecordSessionUpdateHistogramData";
-        break;
-    }
-  }
-  (*last_updated_time) = base::TimeTicks::Now();
-}
-
-void SessionService::RecordUpdatedTabClosed(base::TimeDelta delta,
-                                            bool use_long_period) {
-  std::string name("SessionRestore.TabClosedPeriod");
-  UMA_HISTOGRAM_CUSTOM_TIMES(name,
-      delta,
-      // 2500ms is the default save delay.
-      save_delay_in_millis_,
-      save_delay_in_mins_,
-      50);
-  if (use_long_period) {
-    std::string long_name_("SessionRestore.TabClosedLongPeriod");
-    UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
-        delta,
-        save_delay_in_mins_,
-        save_delay_in_hrs_,
-        50);
-  }
-}
-
-void SessionService::RecordUpdatedNavListPruned(base::TimeDelta delta,
-                                                bool use_long_period) {
-  std::string name("SessionRestore.NavigationListPrunedPeriod");
-  UMA_HISTOGRAM_CUSTOM_TIMES(name,
-      delta,
-      // 2500ms is the default save delay.
-      save_delay_in_millis_,
-      save_delay_in_mins_,
-      50);
-  if (use_long_period) {
-    std::string long_name_("SessionRestore.NavigationListPrunedLongPeriod");
-    UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
-        delta,
-        save_delay_in_mins_,
-        save_delay_in_hrs_,
-        50);
-  }
-}
-
-void SessionService::RecordUpdatedNavEntryCommit(base::TimeDelta delta,
-                                                 bool use_long_period) {
-  std::string name("SessionRestore.NavEntryCommittedPeriod");
-  UMA_HISTOGRAM_CUSTOM_TIMES(name,
-      delta,
-      // 2500ms is the default save delay.
-      save_delay_in_millis_,
-      save_delay_in_mins_,
-      50);
-  if (use_long_period) {
-    std::string long_name_("SessionRestore.NavEntryCommittedLongPeriod");
-    UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
-        delta,
-        save_delay_in_mins_,
-        save_delay_in_hrs_,
-        50);
-  }
-}
-
-void SessionService::RecordUpdatedSaveTime(base::TimeDelta delta,
-                                           bool use_long_period) {
-  std::string name("SessionRestore.SavePeriod");
-  UMA_HISTOGRAM_CUSTOM_TIMES(name,
-      delta,
-      // 2500ms is the default save delay.
-      save_delay_in_millis_,
-      save_delay_in_mins_,
-      50);
-  if (use_long_period) {
-    std::string long_name_("SessionRestore.SaveLongPeriod");
-    UMA_HISTOGRAM_CUSTOM_TIMES(long_name_,
-        delta,
-        save_delay_in_mins_,
-        save_delay_in_hrs_,
-        50);
-  }
-}
-
 void SessionService::MaybeDeleteSessionOnlyData() {
   // Don't try anything if we're testing.  The browser_process is not fully
   // created and DeleteSession will crash if we actually attempt it.
diff --git a/chrome/browser/sessions/session_service.h b/chrome/browser/sessions/session_service.h
index 15ec48c..e11a7f2 100644
--- a/chrome/browser/sessions/session_service.h
+++ b/chrome/browser/sessions/session_service.h
@@ -325,12 +325,6 @@
   void RecordSessionUpdateHistogramData(int type,
     base::TimeTicks* last_updated_time);
 
-  // Helper methods to record the histogram data
-  void RecordUpdatedTabClosed(base::TimeDelta delta, bool use_long_period);
-  void RecordUpdatedNavListPruned(base::TimeDelta delta, bool use_long_period);
-  void RecordUpdatedNavEntryCommit(base::TimeDelta delta, bool use_long_period);
-  void RecordUpdatedSaveTime(base::TimeDelta delta, bool use_long_period);
-
   // Deletes session data if no windows are open for the current profile.
   void MaybeDeleteSessionOnlyData();
 
@@ -387,17 +381,6 @@
   // current/last session.
   bool move_on_new_browser_;
 
-  // Used for reporting frequency of session altering operations.
-  base::TimeTicks last_updated_tab_closed_time_;
-  base::TimeTicks last_updated_nav_list_pruned_time_;
-  base::TimeTicks last_updated_nav_entry_commit_time_;
-  base::TimeTicks last_updated_save_time_;
-
-  // Constants used in calculating histogram data.
-  const base::TimeDelta save_delay_in_millis_;
-  const base::TimeDelta save_delay_in_mins_;
-  const base::TimeDelta save_delay_in_hrs_;
-
   // For browser_tests, since we want to simulate the browser shutting down
   // without quitting.
   bool force_browser_not_alive_with_no_windows_;
diff --git a/chrome/browser/ui/login/login_handler_browsertest.cc b/chrome/browser/ui/login/login_handler_browsertest.cc
index 63cd691..d3e1ca5 100644
--- a/chrome/browser/ui/login/login_handler_browsertest.cc
+++ b/chrome/browser/ui/login/login_handler_browsertest.cc
@@ -98,7 +98,6 @@
 
 const char kMultiRealmTestPage[] = "/login/multi_realm.html";
 const int  kMultiRealmTestRealmCount = 2;
-const int kMultiRealmTestAuthRequestsCount = 4;
 
 const char kSingleRealmTestPage[] = "/login/single_realm.html";
 
@@ -461,102 +460,104 @@
 // Test handling of resources that require authentication even though
 // the page they are included on doesn't.  In this case we should only
 // present the minimal number of prompts necessary for successfully
-// displaying the page.
-class MultiRealmLoginPromptBrowserTest : public LoginPromptBrowserTest {
- public:
-  void TearDownOnMainThread() override {
-    login_prompt_observer_.UnregisterAll();
-    LoginPromptBrowserTest::TearDownOnMainThread();
-  }
-
-  // Load the multi-realm test page, waits for LoginHandlers to be created, then
-  // calls |for_each_realm_func| once for each authentication realm, passing a
-  // LoginHandler for the realm as an argument. The page should stop loading
-  // after that.
-  template <class F>
-  void RunTest(const F& for_each_realm_func);
-
-  NavigationController* GetNavigationController() {
-    return &browser()
-                ->tab_strip_model()
-                ->GetActiveWebContents()
-                ->GetController();
-  }
-
-  LoginPromptBrowserTestObserver* login_prompt_observer() {
-    return &login_prompt_observer_;
-  }
-
- private:
-  LoginPromptBrowserTestObserver login_prompt_observer_;
-};
-
-template <class F>
-void MultiRealmLoginPromptBrowserTest::RunTest(const F& for_each_realm_func) {
+// displaying the page.  First we check whether cancelling works as
+// expected.
+IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmCancellation) {
   ASSERT_TRUE(embedded_test_server()->Start());
   GURL test_page = embedded_test_server()->GetURL(kMultiRealmTestPage);
 
-  NavigationController* controller = GetNavigationController();
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  NavigationController* controller = &contents->GetController();
+  LoginPromptBrowserTestObserver observer;
 
-  login_prompt_observer_.Register(
-      content::Source<NavigationController>(controller));
+  observer.Register(content::Source<NavigationController>(controller));
 
   WindowedLoadStopObserver load_stop_waiter(controller, 1);
 
-  browser()->OpenURL(OpenURLParams(test_page, Referrer(),
-                                   WindowOpenDisposition::CURRENT_TAB,
-                                   ui::PAGE_TRANSITION_TYPED, false));
+  {
+    WindowedAuthNeededObserver auth_needed_waiter(controller);
+    browser()->OpenURL(OpenURLParams(test_page, Referrer(),
+                                     WindowOpenDisposition::CURRENT_TAB,
+                                     ui::PAGE_TRANSITION_TYPED, false));
+    auth_needed_waiter.Wait();
+  }
 
-  // Need to have LoginHandlers created for all requests that need
-  // authentication.
-  while (login_prompt_observer_.handlers().size() <
-         kMultiRealmTestAuthRequestsCount)
-    WindowedAuthNeededObserver(controller).Wait();
+  int n_handlers = 0;
 
-  // Now confirm or cancel auth once per realm.
-  std::set<std::string> seen_realms;
-  for (int i = 0; i < kMultiRealmTestRealmCount; ++i) {
-    auto it = std::find_if(
-        login_prompt_observer_.handlers().begin(),
-        login_prompt_observer_.handlers().end(),
-        [&seen_realms](LoginHandler* handler) {
-          return seen_realms.count(handler->auth_info()->realm) == 0;
-        });
-    ASSERT_TRUE(it != login_prompt_observer_.handlers().end());
-    seen_realms.insert((*it)->auth_info()->realm);
+  while (n_handlers < kMultiRealmTestRealmCount) {
+    WindowedAuthNeededObserver auth_needed_waiter(controller);
 
-    for_each_realm_func(*it);
+    while (!observer.handlers().empty()) {
+      WindowedAuthCancelledObserver auth_cancelled_waiter(controller);
+      LoginHandler* handler = *observer.handlers().begin();
+
+      ASSERT_TRUE(handler);
+      n_handlers++;
+      handler->CancelAuth();
+      auth_cancelled_waiter.Wait();
+    }
+
+    if (n_handlers < kMultiRealmTestRealmCount)
+      auth_needed_waiter.Wait();
   }
 
   load_stop_waiter.Wait();
+
+  EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers);
+  EXPECT_EQ(0, observer.auth_supplied_count());
+  EXPECT_LT(0, observer.auth_needed_count());
+  EXPECT_LT(0, observer.auth_cancelled_count());
 }
 
-// Checks that cancelling works as expected.
-IN_PROC_BROWSER_TEST_F(MultiRealmLoginPromptBrowserTest,
-                       MultipleRealmCancellation) {
-  RunTest([this](LoginHandler* handler) {
-    WindowedAuthCancelledObserver waiter(GetNavigationController());
-    handler->CancelAuth();
-    waiter.Wait();
-  });
+// Similar to the MultipleRealmCancellation test above, but tests
+// whether supplying credentials work as exepcted.
+IN_PROC_BROWSER_TEST_F(LoginPromptBrowserTest, MultipleRealmConfirmation) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  GURL test_page = embedded_test_server()->GetURL(kMultiRealmTestPage);
 
-  EXPECT_EQ(0, login_prompt_observer()->auth_supplied_count());
-  EXPECT_LT(0, login_prompt_observer()->auth_needed_count());
-  EXPECT_LT(0, login_prompt_observer()->auth_cancelled_count());
-}
+  content::WebContents* contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  NavigationController* controller = &contents->GetController();
+  LoginPromptBrowserTestObserver observer;
 
-// Checks that supplying credentials works as exepcted.
-IN_PROC_BROWSER_TEST_F(MultiRealmLoginPromptBrowserTest,
-                       MultipleRealmConfirmation) {
-  RunTest([this](LoginHandler* handler) {
-    WindowedAuthSuppliedObserver waiter(GetNavigationController());
-    SetAuthFor(handler);
-    waiter.Wait();
-  });
+  observer.Register(content::Source<NavigationController>(controller));
 
-  EXPECT_LT(0, login_prompt_observer()->auth_needed_count());
-  EXPECT_LT(0, login_prompt_observer()->auth_supplied_count());
-  EXPECT_EQ(0, login_prompt_observer()->auth_cancelled_count());
+  WindowedLoadStopObserver load_stop_waiter(controller, 1);
+  int n_handlers = 0;
+
+  {
+    WindowedAuthNeededObserver auth_needed_waiter(controller);
+
+    browser()->OpenURL(OpenURLParams(test_page, Referrer(),
+                                     WindowOpenDisposition::CURRENT_TAB,
+                                     ui::PAGE_TRANSITION_TYPED, false));
+    auth_needed_waiter.Wait();
+  }
+
+  while (n_handlers < kMultiRealmTestRealmCount) {
+    WindowedAuthNeededObserver auth_needed_waiter(controller);
+
+    while (!observer.handlers().empty()) {
+      WindowedAuthSuppliedObserver auth_supplied_waiter(controller);
+      LoginHandler* handler = *observer.handlers().begin();
+
+      ASSERT_TRUE(handler);
+      n_handlers++;
+      SetAuthFor(handler);
+      auth_supplied_waiter.Wait();
+    }
+
+    if (n_handlers < kMultiRealmTestRealmCount)
+      auth_needed_waiter.Wait();
+  }
+
+  load_stop_waiter.Wait();
+
+  EXPECT_EQ(kMultiRealmTestRealmCount, n_handlers);
+  EXPECT_LT(0, observer.auth_needed_count());
+  EXPECT_LT(0, observer.auth_supplied_count());
+  EXPECT_EQ(0, observer.auth_cancelled_count());
 }
 
 // Testing for recovery from an incorrect password for the case where
diff --git a/chrome/browser/ui/login/login_handler_test_utils.cc b/chrome/browser/ui/login/login_handler_test_utils.cc
index d1c419d7..a0814c6b 100644
--- a/chrome/browser/ui/login/login_handler_test_utils.cc
+++ b/chrome/browser/ui/login/login_handler_test_utils.cc
@@ -57,10 +57,6 @@
   registrar_.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED, source);
 }
 
-void LoginPromptBrowserTestObserver::UnregisterAll() {
-  registrar_.RemoveAll();
-}
-
 WindowedLoadStopObserver::WindowedLoadStopObserver(
     content::NavigationController* controller,
     int notification_count)
diff --git a/chrome/browser/ui/login/login_handler_test_utils.h b/chrome/browser/ui/login/login_handler_test_utils.h
index bf277a0..8f32a54f 100644
--- a/chrome/browser/ui/login/login_handler_test_utils.h
+++ b/chrome/browser/ui/login/login_handler_test_utils.h
@@ -31,7 +31,6 @@
   void RemoveHandler(LoginHandler* handler);
 
   void Register(const content::NotificationSource& source);
-  void UnregisterAll();
 
   const std::list<LoginHandler*>& handlers() const { return handlers_; }
 
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
index 3e12199..19b3da3 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -48,6 +48,7 @@
 #include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
 #include "extensions/common/constants.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/window_open_disposition.h"
 #include "url/gurl.h"
@@ -289,11 +290,53 @@
         BitmapFetcherServiceFactory::GetForBrowserContext(profile_);
     if (image_service) {
       image_service->CancelRequest(request_id_);
+
+      // TODO(jdonnelly, rhalavati): Create a helper function with Callback to
+      // create annotation and pass it to image_service, merging this annotation
+      // and the one in
+      // chrome/browser/autocomplete/chrome_autocomplete_provider_client.cc
+      net::NetworkTrafficAnnotationTag traffic_annotation =
+          net::DefineNetworkTrafficAnnotation("omnibox_result_change", R"(
+            semantics {
+              sender: "Omnibox"
+              description:
+                "Chromium provides answers in the suggestion list for "
+                "certain queries that user types in the omnibox. This request "
+                "retrieves a small image (for example, an icon illustrating "
+                "the current weather conditions) when this can add information "
+                "to an answer."
+              trigger:
+                "Change of results for the query typed by the user in the "
+                "omnibox."
+              data:
+                "The only data sent is the path to an image. No user data is "
+                "included, although some might be inferrable (e.g. whether the "
+                "weather is sunny or rainy in the user's current location) "
+                "from the name of the image in the path."
+              destination: WEBSITE
+            }
+            policy {
+              cookies_allowed: true
+              cookies_store: "user"
+              setting:
+                "You can enable or disable this feature via 'Use a prediction "
+                "service to help complete searches and URLs typed in the "
+                "address bar.' in Chromium's settings under Advanced. The "
+                "feature is enabled by default."
+              policy {
+                SearchSuggestEnabled {
+                    policy_options {mode: MANDATORY}
+                    value: false
+                }
+              }
+            })");
+
       request_id_ = image_service->RequestImage(
           match->answer->second_line().image_url(),
           new AnswerImageObserver(
               base::Bind(&ChromeOmniboxClient::OnBitmapFetched,
-                         base::Unretained(this), on_bitmap_fetched)));
+                         base::Unretained(this), on_bitmap_fetched)),
+          traffic_annotation);
     }
   }
 }
diff --git a/chrome/browser/ui/passwords/account_avatar_fetcher.cc b/chrome/browser/ui/passwords/account_avatar_fetcher.cc
index b12c625..c842cc0 100644
--- a/chrome/browser/ui/passwords/account_avatar_fetcher.cc
+++ b/chrome/browser/ui/passwords/account_avatar_fetcher.cc
@@ -5,15 +5,49 @@
 #include "chrome/browser/ui/passwords/account_avatar_fetcher.h"
 
 #include "net/base/load_flags.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_operations.h"
 
+namespace {
+
+constexpr net::NetworkTrafficAnnotationTag kTrafficAnnotation =
+    net::DefineNetworkTrafficAnnotation("credenential_avatar", R"(
+        semantics {
+          sender: "Chrome Password Manager"
+          description:
+            "Every credential saved in Chromium via the Credential Management "
+            "API can have an avatar URL. The URL is essentially provided by "
+            "the site calling the API. The avatar is used in the account "
+            "chooser UI and auto signin toast which appear when a site calls "
+            "navigator.credentials.get(). The avatar is retrieved before "
+            "showing the UI."
+          trigger:
+            "User visits a site that calls navigator.credentials.get(). "
+            "Assuming there are matching credentials in the Chromium password "
+            "store, the avatars are retrieved."
+          destination: WEBSITE
+        }
+        policy {
+          cookies_allowed: false
+          setting:
+            "One can disable saving new credentials in the settings (see "
+            "'Passwords and forms'). There is no setting to disable the API."
+          policy {
+            PasswordManagerEnabled {
+                policy_options {mode: MANDATORY}
+                value: false
+            }
+          }
+        })");
+
+}  // namespace
+
 AccountAvatarFetcher::AccountAvatarFetcher(
     const GURL& url,
     const base::WeakPtr<AccountAvatarFetcherDelegate>& delegate)
-    : fetcher_(url, this), delegate_(delegate) {
-}
+    : fetcher_(url, this, kTrafficAnnotation), delegate_(delegate) {}
 
 AccountAvatarFetcher::~AccountAvatarFetcher() = default;
 
diff --git a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
index aa13796b..497aa60f 100644
--- a/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
+++ b/chrome/browser/ui/views/find_bar_views_interactive_uitest.cc
@@ -85,14 +85,6 @@
     return details;
   }
 
-  FindNotificationDetails WaitForFinalFindResult() {
-    while (true) {
-      auto details = WaitForFindResult();
-      if (details.final_update())
-        return details;
-    }
-  }
-
  private:
   DISALLOW_COPY_AND_ASSIGN(FindInPageTest);
 };
@@ -191,28 +183,28 @@
 
   // Clicking the next and previous buttons should not alter the focused view.
   ClickOnView(next_button);
-  EXPECT_EQ(2, WaitForFinalFindResult().active_match_ordinal());
+  EXPECT_EQ(2, WaitForFindResult().active_match_ordinal());
   EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
   ClickOnView(previous_button);
-  EXPECT_EQ(1, WaitForFinalFindResult().active_match_ordinal());
+  EXPECT_EQ(1, WaitForFindResult().active_match_ordinal());
   EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
 
   // Tapping the next and previous buttons should not alter the focused view.
   TapOnView(next_button);
-  EXPECT_EQ(2, WaitForFinalFindResult().active_match_ordinal());
+  EXPECT_EQ(2, WaitForFindResult().active_match_ordinal());
   EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
   TapOnView(previous_button);
-  EXPECT_EQ(1, WaitForFinalFindResult().active_match_ordinal());
+  EXPECT_EQ(1, WaitForFindResult().active_match_ordinal());
   EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_TEXT_FIELD));
 
   // The same should be true even when the previous button is focused.
   previous_button->RequestFocus();
   EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_PREVIOUS_BUTTON));
   ClickOnView(next_button);
-  EXPECT_EQ(2, WaitForFinalFindResult().active_match_ordinal());
+  EXPECT_EQ(2, WaitForFindResult().active_match_ordinal());
   EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_PREVIOUS_BUTTON));
   TapOnView(next_button);
-  EXPECT_EQ(3, WaitForFinalFindResult().active_match_ordinal());
+  EXPECT_EQ(3, WaitForFindResult().active_match_ordinal());
   EXPECT_TRUE(IsViewFocused(browser(), VIEW_ID_FIND_IN_PAGE_PREVIOUS_BUTTON));
 }
 
diff --git a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
index 19bdcb64..c5853e0 100644
--- a/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
+++ b/chrome/browser/ui/webui/net_internals/net_internals_ui_browsertest.cc
@@ -103,12 +103,6 @@
  private:
   void RegisterMessages() override;
 
-  void RegisterMessage(const std::string& message,
-                       const content::WebUI::MessageCallback& handler);
-
-  void HandleMessage(const content::WebUI::MessageCallback& handler,
-                     const base::ListValue* data);
-
   // Runs NetInternalsTest.callback with the given value.
   void RunJavascriptCallback(base::Value* value);
 
@@ -164,56 +158,35 @@
 }
 
 void NetInternalsTest::MessageHandler::RegisterMessages() {
-  RegisterMessage(
-      "getTestServerURL",
+  web_ui()->RegisterMessageCallback("getTestServerURL",
       base::Bind(&NetInternalsTest::MessageHandler::GetTestServerURL,
                  base::Unretained(this)));
-  RegisterMessage("addCacheEntry",
-                  base::Bind(&NetInternalsTest::MessageHandler::AddCacheEntry,
-                             base::Unretained(this)));
-  RegisterMessage("loadPage",
-                  base::Bind(&NetInternalsTest::MessageHandler::LoadPage,
-                             base::Unretained(this)));
-  RegisterMessage("prerenderPage",
-                  base::Bind(&NetInternalsTest::MessageHandler::PrerenderPage,
-                             base::Unretained(this)));
-  RegisterMessage(
-      "navigateToPrerender",
+  web_ui()->RegisterMessageCallback("addCacheEntry",
+      base::Bind(&NetInternalsTest::MessageHandler::AddCacheEntry,
+                 base::Unretained(this)));
+  web_ui()->RegisterMessageCallback("loadPage",
+      base::Bind(&NetInternalsTest::MessageHandler::LoadPage,
+                  base::Unretained(this)));
+  web_ui()->RegisterMessageCallback("prerenderPage",
+      base::Bind(&NetInternalsTest::MessageHandler::PrerenderPage,
+                  base::Unretained(this)));
+  web_ui()->RegisterMessageCallback("navigateToPrerender",
       base::Bind(&NetInternalsTest::MessageHandler::NavigateToPrerender,
                  base::Unretained(this)));
-  RegisterMessage(
-      "createIncognitoBrowser",
+  web_ui()->RegisterMessageCallback("createIncognitoBrowser",
       base::Bind(&NetInternalsTest::MessageHandler::CreateIncognitoBrowser,
                  base::Unretained(this)));
-  RegisterMessage(
-      "closeIncognitoBrowser",
+  web_ui()->RegisterMessageCallback("closeIncognitoBrowser",
       base::Bind(&NetInternalsTest::MessageHandler::CloseIncognitoBrowser,
                  base::Unretained(this)));
-  RegisterMessage(
-      "getNetLogFileContents",
-      base::Bind(&NetInternalsTest::MessageHandler::GetNetLogFileContents,
-                 base::Unretained(this)));
-  RegisterMessage(
-      "enableDataReductionProxy",
-      base::Bind(&NetInternalsTest::MessageHandler::EnableDataReductionProxy,
-                 base::Unretained(this)));
-}
-
-void NetInternalsTest::MessageHandler::RegisterMessage(
-    const std::string& message,
-    const content::WebUI::MessageCallback& handler) {
-  web_ui()->RegisterMessageCallback(
-      message, base::Bind(&NetInternalsTest::MessageHandler::HandleMessage,
-                          base::Unretained(this), handler));
-}
-
-void NetInternalsTest::MessageHandler::HandleMessage(
-    const content::WebUI::MessageCallback& handler,
-    const base::ListValue* data) {
-  // The handler might run a nested loop to wait for something.
-  base::MessageLoop::ScopedNestableTaskAllower nestable_task_allower(
-      base::MessageLoop::current());
-  handler.Run(data);
+  web_ui()->RegisterMessageCallback("getNetLogFileContents",
+      base::Bind(
+          &NetInternalsTest::MessageHandler::GetNetLogFileContents,
+          base::Unretained(this)));
+  web_ui()->RegisterMessageCallback("enableDataReductionProxy",
+      base::Bind(
+          &NetInternalsTest::MessageHandler::EnableDataReductionProxy,
+          base::Unretained(this)));
 }
 
 void NetInternalsTest::MessageHandler::RunJavascriptCallback(
diff --git a/chrome/browser/win/enumerate_modules_model.cc b/chrome/browser/win/enumerate_modules_model.cc
index c9349cf..47eae22 100644
--- a/chrome/browser/win/enumerate_modules_model.cc
+++ b/chrome/browser/win/enumerate_modules_model.cc
@@ -28,7 +28,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
-#include "base/threading/sequenced_worker_pool.h"
+#include "base/task_scheduler/post_task.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "base/version.h"
@@ -163,10 +163,15 @@
 }
 
 ModuleEnumerator::ModuleEnumerator(EnumerateModulesModel* observer)
-    : enumerated_modules_(nullptr),
+    : background_task_runner_(base::CreateTaskRunnerWithTraits(
+          base::TaskTraits()
+              .MayBlock()
+              .WithPriority(base::TaskPriority::BACKGROUND)
+              .WithShutdownBehavior(
+                  base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN))),
+      enumerated_modules_(nullptr),
       observer_(observer),
-      per_module_delay_(kDefaultPerModuleDelay) {
-}
+      per_module_delay_(kDefaultPerModuleDelay) {}
 
 ModuleEnumerator::~ModuleEnumerator() {
 }
@@ -178,11 +183,9 @@
   // This object can't be reaped until it has finished scanning, so its safe
   // to post a raw pointer to another thread. It will simply be leaked if the
   // scanning has not been finished before shutdown.
-  BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior(
+  background_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&ModuleEnumerator::ScanImplStart,
-                 base::Unretained(this)),
-      base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
+      base::Bind(&ModuleEnumerator::ScanImplStart, base::Unretained(this)));
 }
 
 void ModuleEnumerator::SetPerModuleDelayToZero() {
@@ -225,25 +228,12 @@
 
   // Post a delayed task to scan the first module. This forwards directly to
   // ScanImplFinish if there are no modules to scan.
-  BrowserThread::GetBlockingPool()->PostDelayedWorkerTask(
+  background_task_runner_->PostDelayedTask(
       FROM_HERE,
-      base::Bind(&ModuleEnumerator::ScanImplModule,
-                 base::Unretained(this),
-                 0),
+      base::Bind(&ModuleEnumerator::ScanImplModule, base::Unretained(this), 0),
       per_module_delay_);
 }
 
-void ModuleEnumerator::ScanImplDelay(size_t index) {
-  // Bounce this over to a CONTINUE_ON_SHUTDOWN task in the same pool. This is
-  // necessary to prevent shutdown hangs while inspecting a module.
-  BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior(
-      FROM_HERE,
-      base::Bind(&ModuleEnumerator::ScanImplModule,
-                 base::Unretained(this),
-                 index),
-      base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
-}
-
 void ModuleEnumerator::ScanImplModule(size_t index) {
   while (index < enumerated_modules_->size()) {
     base::TimeTicks start_time = base::TimeTicks::Now();
@@ -255,14 +245,12 @@
     enumeration_inspection_time_ += elapsed;
     enumeration_total_time_ += elapsed;
 
-    // With a non-zero delay, bounce back over to ScanImplDelay, which will
-    // bounce back to this function and inspect the next module.
+    // If |per_module_delay_| is non-zero, post a task to scan the next module
+    // when the delay expires.
     if (!per_module_delay_.is_zero()) {
-      BrowserThread::GetBlockingPool()->PostDelayedWorkerTask(
-          FROM_HERE,
-          base::Bind(&ModuleEnumerator::ScanImplDelay,
-                     base::Unretained(this),
-                     index + 1),
+      background_task_runner_->PostDelayedTask(
+          FROM_HERE, base::Bind(&ModuleEnumerator::ScanImplModule,
+                                base::Unretained(this), index + 1),
           per_module_delay_);
       return;
     }
@@ -613,9 +601,9 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // |module_enumerator_| is used as a lock to know whether or not there are
-  // active/pending blocking pool tasks. If a module enumerator exists then a
-  // scan is already underway. Otherwise, either no scan has been completed or
-  // a scan has terminated.
+  // active/pending background tasks. If a module enumerator exists then a scan
+  // is already underway. Otherwise, either no scan has been completed or a scan
+  // has terminated.
   if (module_enumerator_) {
     // If a scan is in progress and this request is for immediate results, then
     // inform the background scan. This is done without any locks because the
@@ -628,7 +616,7 @@
 
   // Only allow a single scan per process lifetime. Immediately notify any
   // observers that the scan is complete. At this point |enumerated_modules_| is
-  // safe to access as no potentially racing blocking pool task can exist.
+  // safe to access as no potentially racing background task can exist.
   if (!enumerated_modules_.empty()) {
     for (Observer& observer : observers_)
       observer.OnScanCompleted();
diff --git a/chrome/browser/win/enumerate_modules_model.h b/chrome/browser/win/enumerate_modules_model.h
index 76ce022..7eb192f 100644
--- a/chrome/browser/win/enumerate_modules_model.h
+++ b/chrome/browser/win/enumerate_modules_model.h
@@ -141,18 +141,11 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(EnumerateModulesTest, CollapsePath);
 
-  // This function enumerates all modules in the blocking pool. Once the list of
-  // module filenames is populated it posts a delayed task to call
-  // ScanImplDelay for the first module.
+  // This function posts a task to enumerate all modules asynchronously. Once
+  // the list of module filenames is populated, a delayed task is posted to scan
+  // the first module.
   void ScanImplStart();
 
-  // Immediately posts a CONTINUE_ON_SHUTDOWN task to ScanImplModule for the
-  // given module. This ping-ponging is because the blocking pool does not
-  // offer a delayed CONTINUE_ON_SHUTDOWN task.
-  // TODO(chrisha): When the new scheduler enables delayed CONTINUE_ON_SHUTDOWN
-  // tasks, simplify this logic.
-  void ScanImplDelay(size_t index);
-
   // Inspects the module in |enumerated_modules_| at the given |index|. Gets
   // module information, normalizes it, and collapses the path. This is an
   // expensive operation and non-critical. Posts a delayed task to ScanImplDelay
@@ -210,6 +203,9 @@
   // The typedef for the vector that maps a regular file path to %env_var%.
   typedef std::vector<std::pair<base::string16, base::string16>> PathMapping;
 
+  // The TaskRunner to perform work in the background.
+  const scoped_refptr<base::TaskRunner> background_task_runner_;
+
   // The vector of paths to %env_var%, used to account for differences in
   // where people keep there files, c:\windows vs. d:\windows, etc.
   PathMapping path_mapping_;
@@ -248,7 +244,7 @@
 // ready.
 //
 // The member functions of this class may only be used from the UI thread. The
-// bulk of the work is actually performed in the blocking pool with
+// bulk of the work is actually performed asynchronously in TaskScheduler with
 // CONTINUE_ON_SHUTDOWN semantics, as the WinCrypt functions can effectively
 // block arbitrarily during shutdown.
 //
@@ -341,13 +337,12 @@
   void DoneScanning();
 
   // The vector containing all the modules enumerated. Will be normalized and
-  // any bad modules will be marked. Written to from the blocking pool by the
-  // |module_enumerator_|, read from on the UI thread by this class.
+  // any bad modules will be marked. Written to from the background TaskRunner
+  // by the |module_enumerator_|, read from on the UI thread by this class.
   ModuleEnumerator::ModulesVector enumerated_modules_;
 
-  // The object responsible for enumerating the modules in the blocking pool.
-  // Only used from the UI thread. This ends up internally doing its work in the
-  // blocking pool.
+  // The object responsible for enumerating the modules on a background
+  // TaskRunner. Only accessed from the UI thread.
   std::unique_ptr<ModuleEnumerator> module_enumerator_;
 
   // Whether the conflict notification has been acknowledged by the user. Only
diff --git a/chrome/browser/win/enumerate_modules_model_unittest.cc b/chrome/browser/win/enumerate_modules_model_unittest.cc
index 3b1f3b4..1649ada 100644
--- a/chrome/browser/win/enumerate_modules_model_unittest.cc
+++ b/chrome/browser/win/enumerate_modules_model_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_task_scheduler.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 typedef testing::Test EnumerateModulesTest;
@@ -103,6 +104,7 @@
 };
 
 TEST_F(EnumerateModulesTest, CollapsePath) {
+  base::test::ScopedTaskScheduler scoped_task_scheduler;
   ModuleEnumerator module_enumerator(nullptr);
   module_enumerator.path_mapping_.clear();
   module_enumerator.path_mapping_.push_back(
diff --git a/chrome/common/chrome_paths.cc b/chrome/common/chrome_paths.cc
index 122dd54..d33af32 100644
--- a/chrome/common/chrome_paths.cc
+++ b/chrome/common/chrome_paths.cc
@@ -241,6 +241,13 @@
         return false;
       cur = cur.Append(FILE_PATH_LITERAL("Diagnostics"));
       break;
+    case chrome::DIR_ROAMING_USER_DATA:
+      if (!GetDefaultRoamingUserDataDirectory(&cur)) {
+        NOTREACHED();
+        return false;
+      }
+      create_dir = true;
+      break;
 #endif
     case chrome::DIR_RESOURCES:
 #if defined(OS_MACOSX)
diff --git a/chrome/common/chrome_paths.h b/chrome/common/chrome_paths.h
index dd8c0b5b..0924105 100644
--- a/chrome/common/chrome_paths.h
+++ b/chrome/common/chrome_paths.h
@@ -26,6 +26,8 @@
 #if defined(OS_WIN)
   DIR_WATCHER_DATA,             // Directory where the Chrome watcher stores
                                 // data.
+  DIR_ROAMING_USER_DATA,        // Directory where user data is stored that
+                                // needs to be roamed between computers.
 #endif
   DIR_RESOURCES,                // Directory containing separate file resources
                                 // used by Chrome at runtime.
diff --git a/chrome/common/chrome_paths_internal.h b/chrome/common/chrome_paths_internal.h
index 4b9322a5..ab812935 100644
--- a/chrome/common/chrome_paths_internal.h
+++ b/chrome/common/chrome_paths_internal.h
@@ -27,6 +27,12 @@
 // DIR_USER_DATA has been overridden by a command-line option.
 bool GetDefaultUserDataDirectory(base::FilePath* result);
 
+#if defined(OS_WIN)
+// Get the path to the roaming user's data directory, regardless of whether
+// DIR_ROAMING_USER_DATA has been overridden by a command-line option.
+bool GetDefaultRoamingUserDataDirectory(base::FilePath* result);
+#endif
+
 // Get the path to the user's cache directory.  This is normally the
 // same as the profile directory, but on Linux it can also be
 // $XDG_CACHE_HOME and on Mac it can be under ~/Library/Caches.
diff --git a/chrome/common/chrome_paths_win.cc b/chrome/common/chrome_paths_win.cc
index 597448b..767f967 100644
--- a/chrome/common/chrome_paths_win.cc
+++ b/chrome/common/chrome_paths_win.cc
@@ -51,6 +51,15 @@
   return true;
 }
 
+bool GetDefaultRoamingUserDataDirectory(base::FilePath* result) {
+  if (!PathService::Get(base::DIR_APP_DATA, result))
+    return false;
+  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+  *result = result->Append(dist->GetInstallSubDir());
+  *result = result->Append(chrome::kUserDataDirname);
+  return true;
+}
+
 void GetUserCacheDirectory(const base::FilePath& profile_dir,
                            base::FilePath* result) {
   // This function does more complicated things on Mac/Linux.
diff --git a/chrome/common/crash_keys.cc b/chrome/common/crash_keys.cc
index fe3830b..313ccc9 100644
--- a/chrome/common/crash_keys.cc
+++ b/chrome/common/crash_keys.cc
@@ -101,7 +101,10 @@
   // but ultimately constitute a single key-value pair.
   //
   // If you're adding keys here, please also add them to the following list:
-  // chrome/app/chrome_crash_reporter_client_win.cc::RegisterCrashKeysHelper().
+  // chrome/app/chrome_crash_reporter_client_win.cc::RegisterCrashKeysHelper(),
+  // and consider adding the new keys to the following list as well:
+  // android_webview/common/crash_reporter/crash_keys.cc::
+  //     RegisterWebViewCrashKeys().
   base::debug::CrashKey fixed_keys[] = {
 #if defined(OS_MACOSX) || defined(OS_WIN)
     { kMetricsClientId, kSmallSize },
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 666c385..254cdb9 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -31,9 +31,6 @@
 // utility methods (IsArcPlayStoreEnabledForProfile() and
 // SetArcPlayStoreEnabledForProfile()) in chrome/browser/chromeos/arc/arc_util.
 const char kArcEnabled[] = "arc.enabled";
-// A preference that indicated whether Android reported that it's compliant
-// with provided policies. When it's compliant, Android kiosk app will start.
-const char kArcPolicyCompliant[] = "arc.policy_compliant";
 // A preference that indicates that user accepted PlayStore terms.
 const char kArcTermsAccepted[] = "arc.terms.accepted";
 // A preference to keep user's consent to use location service.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 95181d91..03a07aa 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -23,7 +23,6 @@
 extern const char kArcBackupRestoreEnabled[];
 extern const char kArcDataRemoveRequested[];
 extern const char kArcEnabled[];
-extern const char kArcPolicyCompliant[];
 extern const char kArcTermsAccepted[];
 extern const char kArcLocationServiceEnabled[];
 extern const char kArcPackages[];
diff --git a/chromecast/browser/metrics/cast_metrics_service_client.cc b/chromecast/browser/metrics/cast_metrics_service_client.cc
index a8a4fa8..0d61688 100644
--- a/chromecast/browser/metrics/cast_metrics_service_client.cc
+++ b/chromecast/browser/metrics/cast_metrics_service_client.cc
@@ -24,6 +24,7 @@
 #include "components/metrics/client_info.h"
 #include "components/metrics/enabled_state_provider.h"
 #include "components/metrics/gpu/gpu_metrics_provider.h"
+#include "components/metrics/metrics_log_uploader.h"
 #include "components/metrics/metrics_provider.h"
 #include "components/metrics/metrics_service.h"
 #include "components/metrics/metrics_state_manager.h"
@@ -244,10 +245,12 @@
 CastMetricsServiceClient::CreateUploader(
     const std::string& server_url,
     const std::string& mime_type,
+    ::metrics::MetricsLogUploader::MetricServiceType service_type,
     const base::Callback<void(int)>& on_upload_complete) {
   return std::unique_ptr<::metrics::MetricsLogUploader>(
       new ::metrics::NetMetricsLogUploader(request_context_, server_url,
-                                           mime_type, on_upload_complete));
+                                           mime_type, service_type,
+                                           on_upload_complete));
 }
 
 base::TimeDelta CastMetricsServiceClient::GetStandardUploadInterval() {
diff --git a/chromecast/browser/metrics/cast_metrics_service_client.h b/chromecast/browser/metrics/cast_metrics_service_client.h
index 64d2ad6..a45cee9c 100644
--- a/chromecast/browser/metrics/cast_metrics_service_client.h
+++ b/chromecast/browser/metrics/cast_metrics_service_client.h
@@ -14,6 +14,7 @@
 #include "base/memory/ref_counted.h"
 #include "build/build_config.h"
 #include "components/metrics/enabled_state_provider.h"
+#include "components/metrics/metrics_log_uploader.h"
 #include "components/metrics/metrics_service_client.h"
 
 class PrefRegistrySimple;
@@ -81,6 +82,7 @@
   std::unique_ptr<::metrics::MetricsLogUploader> CreateUploader(
       const std::string& server_url,
       const std::string& mime_type,
+      ::metrics::MetricsLogUploader::MetricServiceType service_type,
       const base::Callback<void(int)>& on_upload_complete) override;
   base::TimeDelta GetStandardUploadInterval() override;
 
diff --git a/components/arc/common/policy.mojom b/components/arc/common/policy.mojom
index 94122bb..742d0e71 100644
--- a/components/arc/common/policy.mojom
+++ b/components/arc/common/policy.mojom
@@ -15,6 +15,7 @@
   // Pass a JSON with policy compliance details that reference fields in
   // CloudDps NonComplianceReason. Should return ChromeOS response to the report
   // in JSON format as in CloudDps PolicyComplianceReportResponse.
+  // ChromeOS always returns that it's compliant with the report.
   [MinVersion=1] ReportCompliance@1(string request) => (string response);
 };
 
diff --git a/components/crash/content/app/breakpad_linux.cc b/components/crash/content/app/breakpad_linux.cc
index 12c55b81..3c31d761 100644
--- a/components/crash/content/app/breakpad_linux.cc
+++ b/components/crash/content/app/breakpad_linux.cc
@@ -110,14 +110,7 @@
 
 class MicrodumpInfo {
  public:
-  MicrodumpInfo()
-      : microdump_build_fingerprint_(nullptr),
-        microdump_product_info_(nullptr),
-        microdump_gpu_fingerprint_(nullptr),
-        microdump_process_type_(nullptr),
-        skip_dump_if_principal_mapping_not_referenced_(false),
-        address_within_principal_mapping_(0ul),
-        should_sanitize_dumps_(false) {}
+  MicrodumpInfo() : microdump_gpu_fingerprint_(nullptr) {}
 
   // The order in which SetGpuFingerprint and Initialize are called
   // may be dependent on the timing of the availability of GPU
@@ -132,28 +125,21 @@
   // SetGpuFingerprint has not been called called at the point at
   // which a microdump is generated, then the GPU fingerprint will be
   // UNKNOWN.
-  void SetGpuFingerprint(const std::string& gpu_fingerprint);
-  void SetSkipDumpIfPrincipalMappingNotReferenced(
-      uintptr_t address_within_principal_mapping);
-  void SetShouldSanitizeDumps(bool should_sanitize_dumps);
-  void UpdateMinidumpDescriptor(MinidumpDescriptor* minidump_descriptor);
-  void UpdateExceptionHandlers();
+  void SetGpuFingerprintForMicrodump(const std::string& gpu_fingerprint);
   void Initialize(const std::string& process_type,
                   const char* product_name,
                   const char* product_version,
-                  const char* android_build_fp);
+                  const char* android_build_fp,
+                  const SanitizationInfo& sanitization_info);
 
  private:
   base::ThreadChecker thread_checker_;
-  const char* microdump_build_fingerprint_;
-  const char* microdump_product_info_;
   const char* microdump_gpu_fingerprint_;
-  const char* microdump_process_type_;
-  bool skip_dump_if_principal_mapping_not_referenced_;
-  uintptr_t address_within_principal_mapping_;
-  bool should_sanitize_dumps_;
 };
 
+void SetMinidumpSanitizationFields(MinidumpDescriptor* minidump_descriptor,
+                                   const SanitizationInfo& sanitization_info);
+
 base::LazyInstance<MicrodumpInfo> g_microdump_info =
     LAZY_INSTANCE_INITIALIZER;
 
@@ -780,7 +766,12 @@
 }
 #endif
 
+#if defined(OS_ANDROID)
+void EnableCrashDumping(bool unattended,
+                        const SanitizationInfo& sanitization_info) {
+#else
 void EnableCrashDumping(bool unattended) {
+#endif  // defined(OS_ANDROID)
   g_is_crash_reporter_enabled = true;
 
   base::FilePath tmp_path("/tmp");
@@ -805,7 +796,7 @@
   }
 #if defined(OS_ANDROID)
   unattended = true;  // Android never uploads directly.
-  g_microdump_info.Get().UpdateMinidumpDescriptor(&minidump_descriptor);
+  SetMinidumpSanitizationFields(&minidump_descriptor, sanitization_info);
 #endif
   if (unattended) {
     g_breakpad = new ExceptionHandler(
@@ -883,7 +874,8 @@
 }
 
 void EnableNonBrowserCrashDumping(const std::string& process_type,
-                                  int minidump_fd) {
+                                  int minidump_fd,
+                                  const SanitizationInfo& sanitization_info) {
   // This will guarantee that the BuildInfo has been initialized and subsequent
   // calls will not require memory allocation.
   base::android::BuildInfo::GetInstance();
@@ -912,71 +904,42 @@
   strncpy(g_process_type, process_type.c_str(), process_type_len);
 
   MinidumpDescriptor descriptor(minidump_fd);
-  g_microdump_info.Get().UpdateMinidumpDescriptor(&descriptor);
+  SetMinidumpSanitizationFields(&descriptor, sanitization_info);
   g_breakpad =
       new ExceptionHandler(descriptor, ShouldGenerateDump,
                            CrashDoneInProcessNoUpload, nullptr, true, -1);
 }
 
-void MicrodumpInfo::SetGpuFingerprint(const std::string& gpu_fingerprint) {
+void MicrodumpInfo::SetGpuFingerprintForMicrodump(
+    const std::string& gpu_fingerprint) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!microdump_gpu_fingerprint_);
   microdump_gpu_fingerprint_ = strdup(gpu_fingerprint.c_str());
   ANNOTATE_LEAKING_OBJECT_PTR(microdump_gpu_fingerprint_);
 
-  UpdateExceptionHandlers();
-}
-
-void MicrodumpInfo::SetSkipDumpIfPrincipalMappingNotReferenced(
-    uintptr_t address_within_principal_mapping) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  skip_dump_if_principal_mapping_not_referenced_ = true;
-  address_within_principal_mapping_ = address_within_principal_mapping;
-
-  UpdateExceptionHandlers();
-}
-
-void MicrodumpInfo::SetShouldSanitizeDumps(bool should_sanitize_dumps) {
-  DCHECK(thread_checker_.CalledOnValidThread());
-  should_sanitize_dumps_ = should_sanitize_dumps;
-
-  UpdateExceptionHandlers();
-}
-
-void MicrodumpInfo::UpdateMinidumpDescriptor(
-    MinidumpDescriptor* minidump_descriptor) {
-  google_breakpad::MicrodumpExtraInfo* microdump_extra_info =
-      minidump_descriptor->microdump_extra_info();
-
-  minidump_descriptor->set_skip_dump_if_principal_mapping_not_referenced(
-      skip_dump_if_principal_mapping_not_referenced_);
-  minidump_descriptor->set_address_within_principal_mapping(
-      address_within_principal_mapping_);
-  minidump_descriptor->set_sanitize_stacks(should_sanitize_dumps_);
-
-  microdump_extra_info->gpu_fingerprint = microdump_gpu_fingerprint_;
-  microdump_extra_info->product_info = microdump_product_info_;
-  microdump_extra_info->process_type = microdump_process_type_;
-  microdump_extra_info->build_fingerprint = microdump_build_fingerprint_;
-}
-
-void MicrodumpInfo::UpdateExceptionHandlers() {
-  if (g_breakpad) {
-    MinidumpDescriptor descriptor(g_breakpad->minidump_descriptor());
-    UpdateMinidumpDescriptor(&descriptor);
-    g_breakpad->set_minidump_descriptor(descriptor);
-  }
   if (g_microdump) {
     MinidumpDescriptor descriptor(g_microdump->minidump_descriptor());
-    UpdateMinidumpDescriptor(&descriptor);
+    descriptor.microdump_extra_info()->gpu_fingerprint =
+        microdump_gpu_fingerprint_;
     g_microdump->set_minidump_descriptor(descriptor);
   }
 }
 
+void SetMinidumpSanitizationFields(MinidumpDescriptor* minidump_descriptor,
+                                   const SanitizationInfo& sanitization_info) {
+  minidump_descriptor->set_skip_dump_if_principal_mapping_not_referenced(
+      sanitization_info.skip_dump_if_principal_mapping_not_referenced);
+  minidump_descriptor->set_address_within_principal_mapping(
+      sanitization_info.address_within_principal_mapping);
+  minidump_descriptor->set_sanitize_stacks(
+      sanitization_info.should_sanitize_dumps);
+}
+
 void MicrodumpInfo::Initialize(const std::string& process_type,
                                const char* product_name,
                                const char* product_version,
-                               const char* android_build_fp) {
+                               const char* android_build_fp,
+                               const SanitizationInfo& sanitization_info) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(!g_microdump);
   // |process_type| for webview's browser process is kBrowserProcessType or
@@ -987,23 +950,26 @@
                             process_type == kBrowserProcessType;
 
   MinidumpDescriptor descriptor(MinidumpDescriptor::kMicrodumpOnConsole);
+  google_breakpad::MicrodumpExtraInfo* microdump_extra_info =
+      descriptor.microdump_extra_info();
 
   if (product_name && product_version) {
-    microdump_product_info_ =
+    microdump_extra_info->product_info =
         strdup((product_name + std::string(":") + product_version).c_str());
-    ANNOTATE_LEAKING_OBJECT_PTR(microdump_product_info_);
+    ANNOTATE_LEAKING_OBJECT_PTR(microdump_extra_info->product_info);
   }
 
-  microdump_process_type_ =
+  microdump_extra_info->process_type =
       strdup(process_type.empty() ? kBrowserProcessType : process_type.c_str());
-  ANNOTATE_LEAKING_OBJECT_PTR(microdump_process_type_);
+  ANNOTATE_LEAKING_OBJECT_PTR(microdump_extra_info->process_type);
 
   if (android_build_fp) {
-    microdump_build_fingerprint_ = strdup(android_build_fp);
-    ANNOTATE_LEAKING_OBJECT_PTR(microdump_build_fingerprint_);
+    microdump_extra_info->build_fingerprint = strdup(android_build_fp);
+    ANNOTATE_LEAKING_OBJECT_PTR(microdump_extra_info->build_fingerprint);
   }
 
-  UpdateMinidumpDescriptor(&descriptor);
+  SetMinidumpSanitizationFields(&descriptor, sanitization_info);
+  microdump_extra_info->gpu_fingerprint = microdump_gpu_fingerprint_;
 
   g_microdump =
       new ExceptionHandler(descriptor, ShouldGenerateDump, MicrodumpCrashDone,
@@ -1930,7 +1896,20 @@
   (void) HANDLE_EINTR(sys_waitpid(child, nullptr, 0));
 }
 
+#if defined(OS_ANDROID)
+// In Android WebView, microdumps are generated conditionally (depending on the
+// cause of the crash) and can be sanitized to prevent exposing unnecessary data
+// from the embedding application.
 void InitCrashReporter(const std::string& process_type) {
+  SanitizationInfo sanitization_info;
+  InitCrashReporter(process_type, sanitization_info);
+}
+
+void InitCrashReporter(const std::string& process_type,
+                       const SanitizationInfo& sanitization_info) {
+#else
+void InitCrashReporter(const std::string& process_type) {
+#endif  // defined(OS_ANDROID)
   // The maximum lengths specified by breakpad include the trailing NULL, so the
   // actual length of the chunk is one less.
   static_assert(crash_keys::kChunkMaxLength == 63, "kChunkMaxLength mismatch");
@@ -1944,7 +1923,7 @@
   // Handler registration is LIFO. Install the microdump handler first, such
   // that if conventional minidump crash reporting is enabled below, it takes
   // precedence (i.e. its handler is run first) over the microdump handler.
-  InitMicrodumpCrashHandlerIfNecessary(process_type);
+  InitMicrodumpCrashHandlerIfNecessary(process_type, sanitization_info);
 #endif
   // Determine the process type and take appropriate action.
   const base::CommandLine& parsed_command_line =
@@ -1967,7 +1946,12 @@
     }
 
     InitCrashKeys();
+#if defined(OS_ANDROID)
+    EnableCrashDumping(GetCrashReporterClient()->IsRunningUnattended(),
+                       sanitization_info);
+#else
     EnableCrashDumping(GetCrashReporterClient()->IsRunningUnattended());
+#endif  // defined(OS_ANDROID)
   } else if (GetCrashReporterClient()->EnableBreakpadForProcess(process_type)) {
 #if defined(OS_ANDROID)
     NOTREACHED() << "Breakpad initialized with InitCrashReporter() instead of "
@@ -1995,13 +1979,22 @@
 
 #if defined(OS_ANDROID)
 void InitNonBrowserCrashReporterForAndroid(const std::string& process_type) {
+  SanitizationInfo sanitization_info;
+  sanitization_info.should_sanitize_dumps = false;
+  sanitization_info.skip_dump_if_principal_mapping_not_referenced = false;
+  InitNonBrowserCrashReporterForAndroid(process_type, sanitization_info);
+}
+
+void InitNonBrowserCrashReporterForAndroid(
+    const std::string& process_type,
+    const SanitizationInfo& sanitization_info) {
   const base::CommandLine* command_line =
       base::CommandLine::ForCurrentProcess();
 
   // Handler registration is LIFO. Install the microdump handler first, such
   // that if conventional minidump crash reporting is enabled below, it takes
   // precedence (i.e. its handler is run first) over the microdump handler.
-  InitMicrodumpCrashHandlerIfNecessary(process_type);
+  InitMicrodumpCrashHandlerIfNecessary(process_type, sanitization_info);
 
   if (command_line->HasSwitch(switches::kEnableCrashReporter)) {
     // On Android we need to provide a FD to the file where the minidump is
@@ -2013,7 +2006,8 @@
       NOTREACHED() << "Could not find minidump FD, crash reporting disabled.";
     } else {
       InitCrashKeys();
-      EnableNonBrowserCrashDumping(process_type, minidump_fd);
+      EnableNonBrowserCrashDumping(process_type, minidump_fd,
+                                   sanitization_info);
       // Note: not installing DumpWithoutCrash handler here because browser
       // is not set up to receive multiple reports from child process.
     }
@@ -2023,7 +2017,9 @@
 // The microdump handler does NOT upload anything. It just dumps out on the
 // system console (logcat) a restricted and serialized variant of a minidump.
 // See crbug.com/410294 for more details.
-void InitMicrodumpCrashHandlerIfNecessary(const std::string& process_type) {
+void InitMicrodumpCrashHandlerIfNecessary(
+    const std::string& process_type,
+    const SanitizationInfo& sanitization_info) {
   if (!GetCrashReporterClient()->ShouldEnableBreakpadMicrodumps())
     return;
 
@@ -2042,12 +2038,12 @@
       base::android::BuildInfo::GetInstance()->android_build_fp();
 
   g_microdump_info.Get().Initialize(process_type, product_name, product_version,
-                                    android_build_fp);
+                                    android_build_fp, sanitization_info);
 }
 
 void AddGpuFingerprintToMicrodumpCrashHandler(
     const std::string& gpu_fingerprint) {
-  g_microdump_info.Get().SetGpuFingerprint(gpu_fingerprint);
+  g_microdump_info.Get().SetGpuFingerprintForMicrodump(gpu_fingerprint);
 }
 
 void GenerateMinidumpOnDemandForAndroid(int dump_fd) {
@@ -2063,16 +2059,6 @@
 void SuppressDumpGeneration() {
   g_dumps_suppressed = G_DUMPS_SUPPRESSED_MAGIC;
 }
-
-void SetSkipDumpIfPrincipalMappingNotReferenced(
-    uintptr_t address_within_principal_mapping) {
-  g_microdump_info.Get().SetSkipDumpIfPrincipalMappingNotReferenced(
-      address_within_principal_mapping);
-}
-
-void SetShouldSanitizeDumps(bool should_sanitize_dumps) {
-  g_microdump_info.Get().SetShouldSanitizeDumps(should_sanitize_dumps);
-}
 #endif  // OS_ANDROID
 
 bool IsCrashReporterEnabled() {
diff --git a/components/crash/content/app/breakpad_linux.h b/components/crash/content/app/breakpad_linux.h
index 2cd1795..3ef4e8a9 100644
--- a/components/crash/content/app/breakpad_linux.h
+++ b/components/crash/content/app/breakpad_linux.h
@@ -17,6 +17,15 @@
 extern void InitCrashReporter(const std::string& process_type);
 
 #if defined(OS_ANDROID)
+struct SanitizationInfo {
+  bool should_sanitize_dumps = false;
+  bool skip_dump_if_principal_mapping_not_referenced = false;
+  uintptr_t address_within_principal_mapping = 0;
+};
+
+// Turns on the crash reporter in any process.
+extern void InitCrashReporter(const std::string& process_type,
+                              const SanitizationInfo& sanitization_info);
 
 const char kWebViewSingleProcessType[] = "webview";
 const char kBrowserProcessType[] = "browser";
@@ -24,10 +33,15 @@
 // Enables the crash reporter in child processes.
 extern void InitNonBrowserCrashReporterForAndroid(
     const std::string& process_type);
+// Enables the crash reporter in child processes.
+extern void InitNonBrowserCrashReporterForAndroid(
+    const std::string& process_type,
+    const SanitizationInfo& sanitization_info);
 
 // Enables *micro*dump only. Can be called from any process.
 extern void InitMicrodumpCrashHandlerIfNecessary(
-    const std::string& process_type);
+    const std::string& process_type,
+    const SanitizationInfo& sanitization_info);
 
 extern void AddGpuFingerprintToMicrodumpCrashHandler(
     const std::string& gpu_fingerprint);
@@ -36,23 +50,7 @@
 // generate dumps. Calling base::debug::DumpWithoutCrashing will still
 // generate a dump.
 extern void SuppressDumpGeneration();
-
-// Calling SetShouldSanitizeDumps determines whether or not subsequent
-// crash dumps should be sanitized. Sanitized dumps still contain
-// enough stack information to unwind crashes, but other stack data is
-// erased.
-extern void SetShouldSanitizeDumps(bool sanitize_dumps);
-
-// Inform breakpad of an address within the text section that is
-// considered interesting for the purpose of crashes so that this can
-// be used to elide microdumps that do not reference interesting
-// code. Minidumps will still be generated, but stacks from threads
-// that do not reference the principal mapping will not be included.
-// The full interesting address range is determined by looking up the
-// memory mapping that contains |addr|.
-extern void SetSkipDumpIfPrincipalMappingNotReferenced(
-    uintptr_t address_within_principal_mapping);
-#endif
+#endif  // defined(OS_ANDROID)
 
 // Checks if crash reporting is enabled. Note that this is not the same as
 // being opted into metrics reporting (and crash reporting), which controls
diff --git a/components/data_use_measurement/core/data_use_user_data.cc b/components/data_use_measurement/core/data_use_user_data.cc
index 4c452e9..de9cf6f 100644
--- a/components/data_use_measurement/core/data_use_user_data.cc
+++ b/components/data_use_measurement/core/data_use_user_data.cc
@@ -124,6 +124,8 @@
       return "NTPSnippetsThumbnails";
     case DOODLE:
       return "Doodle";
+    case UKM:
+      return "UKM";
   }
   return "INVALID";
 }
diff --git a/components/data_use_measurement/core/data_use_user_data.h b/components/data_use_measurement/core/data_use_user_data.h
index b930c3f..4f8b4b9 100644
--- a/components/data_use_measurement/core/data_use_user_data.h
+++ b/components/data_use_measurement/core/data_use_user_data.h
@@ -62,6 +62,7 @@
     NTP_SNIPPETS_SUGGESTIONS,
     NTP_SNIPPETS_THUMBNAILS,
     DOODLE,
+    UKM,
   };
 
   // Data use broken by content type. This enum must remain synchronized
diff --git a/components/metrics/metrics_log_uploader.cc b/components/metrics/metrics_log_uploader.cc
index 41b83ed..0d67ced 100644
--- a/components/metrics/metrics_log_uploader.cc
+++ b/components/metrics/metrics_log_uploader.cc
@@ -9,11 +9,12 @@
 MetricsLogUploader::MetricsLogUploader(
     const std::string& server_url,
     const std::string& mime_type,
+    MetricServiceType service_type,
     const base::Callback<void(int)>& on_upload_complete)
     : server_url_(server_url),
       mime_type_(mime_type),
-      on_upload_complete_(on_upload_complete) {
-}
+      service_type_(service_type),
+      on_upload_complete_(on_upload_complete) {}
 
 MetricsLogUploader::~MetricsLogUploader() {
 }
diff --git a/components/metrics/metrics_log_uploader.h b/components/metrics/metrics_log_uploader.h
index 2ef0cf2..bcc4662 100644
--- a/components/metrics/metrics_log_uploader.h
+++ b/components/metrics/metrics_log_uploader.h
@@ -16,11 +16,20 @@
 // of MetricsService.
 class MetricsLogUploader {
  public:
+  // Possible service types. This should correspond to a type from
+  // DataUseUserData.
+  enum MetricServiceType {
+    UMA,
+    UKM,
+  };
+
   // Constructs the uploader that will upload logs to the specified |server_url|
-  // with the given |mime_type|. The |on_upload_complete| callback will be
-  // called with the HTTP response code of the upload or with -1 on an error.
+  // with the given |mime_type|. The |service_type| marks which service the
+  // data usage should be attributed to. The |on_upload_complete| callback will
+  // be called with the HTTP response code of the upload or with -1 on an error.
   MetricsLogUploader(const std::string& server_url,
                      const std::string& mime_type,
+                     MetricServiceType service_type,
                      const base::Callback<void(int)>& on_upload_complete);
   virtual ~MetricsLogUploader();
 
@@ -33,6 +42,11 @@
  protected:
   const std::string server_url_;
   const std::string mime_type_;
+
+  // Which service type this uploads for. This is used for bandwidth
+  // attribution.
+  const MetricServiceType service_type_;
+
   const base::Callback<void(int)> on_upload_complete_;
 
  private:
diff --git a/components/metrics/metrics_service.cc b/components/metrics/metrics_service.cc
index c8b9e30b..91e7dd23 100644
--- a/components/metrics/metrics_service.cc
+++ b/components/metrics/metrics_service.cc
@@ -1000,8 +1000,8 @@
 
   if (!log_uploader_) {
     log_uploader_ = client_->CreateUploader(
-        client_->GetMetricsServerUrl(),
-        metrics::kDefaultMetricsMimeType,
+        client_->GetMetricsServerUrl(), metrics::kDefaultMetricsMimeType,
+        metrics::MetricsLogUploader::UMA,
         base::Bind(&MetricsService::OnLogUploadComplete,
                    self_ptr_factory_.GetWeakPtr()));
   }
diff --git a/components/metrics/metrics_service_client.h b/components/metrics/metrics_service_client.h
index 2ce2017..0c5f693 100644
--- a/components/metrics/metrics_service_client.h
+++ b/components/metrics/metrics_service_client.h
@@ -13,6 +13,7 @@
 #include "base/callback.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
+#include "components/metrics/metrics_log_uploader.h"
 #include "components/metrics/metrics_reporting_default_state.h"
 #include "components/metrics/proto/system_profile.pb.h"
 
@@ -95,6 +96,7 @@
   virtual std::unique_ptr<MetricsLogUploader> CreateUploader(
       const std::string& server_url,
       const std::string& mime_type,
+      metrics::MetricsLogUploader::MetricServiceType service_type,
       const base::Callback<void(int)>& on_upload_complete) = 0;
 
   // Returns the standard interval between upload attempts.
diff --git a/components/metrics/net/net_metrics_log_uploader.cc b/components/metrics/net/net_metrics_log_uploader.cc
index 5b2c95e..0064177 100644
--- a/components/metrics/net/net_metrics_log_uploader.cc
+++ b/components/metrics/net/net_metrics_log_uploader.cc
@@ -6,6 +6,7 @@
 
 #include "base/metrics/histogram_macros.h"
 #include "components/data_use_measurement/core/data_use_user_data.h"
+#include "components/metrics/metrics_log_uploader.h"
 #include "net/base/load_flags.h"
 #include "net/url_request/url_fetcher.h"
 #include "url/gurl.h"
@@ -16,10 +17,13 @@
     net::URLRequestContextGetter* request_context_getter,
     const std::string& server_url,
     const std::string& mime_type,
+    MetricsLogUploader::MetricServiceType service_type,
     const base::Callback<void(int)>& on_upload_complete)
-    : MetricsLogUploader(server_url, mime_type, on_upload_complete),
-      request_context_getter_(request_context_getter) {
-}
+    : MetricsLogUploader(server_url,
+                         mime_type,
+                         service_type,
+                         on_upload_complete),
+      request_context_getter_(request_context_getter) {}
 
 NetMetricsLogUploader::~NetMetricsLogUploader() {
 }
@@ -28,8 +32,19 @@
                                       const std::string& log_hash) {
   current_fetch_ =
       net::URLFetcher::Create(GURL(server_url_), net::URLFetcher::POST, this);
-  data_use_measurement::DataUseUserData::AttachToFetcher(
-      current_fetch_.get(), data_use_measurement::DataUseUserData::UMA);
+
+  auto service = data_use_measurement::DataUseUserData::UMA;
+
+  switch (service_type_) {
+    case MetricsLogUploader::UMA:
+      service = data_use_measurement::DataUseUserData::UMA;
+      break;
+    case MetricsLogUploader::UKM:
+      service = data_use_measurement::DataUseUserData::UKM;
+      break;
+  }
+  data_use_measurement::DataUseUserData::AttachToFetcher(current_fetch_.get(),
+                                                         service);
   current_fetch_->SetRequestContext(request_context_getter_);
   current_fetch_->SetUploadData(mime_type_, compressed_log_data);
 
diff --git a/components/metrics/net/net_metrics_log_uploader.h b/components/metrics/net/net_metrics_log_uploader.h
index ab44bdbc..b81d166 100644
--- a/components/metrics/net/net_metrics_log_uploader.h
+++ b/components/metrics/net/net_metrics_log_uploader.h
@@ -30,6 +30,7 @@
   NetMetricsLogUploader(net::URLRequestContextGetter* request_context_getter,
                         const std::string& server_url,
                         const std::string& mime_type,
+                        MetricsLogUploader::MetricServiceType service_type,
                         const base::Callback<void(int)>& on_upload_complete);
   ~NetMetricsLogUploader() override;
 
diff --git a/components/metrics/net/net_metrics_log_uploader_unittest.cc b/components/metrics/net/net_metrics_log_uploader_unittest.cc
index 8a8704e..14258f7 100644
--- a/components/metrics/net/net_metrics_log_uploader_unittest.cc
+++ b/components/metrics/net/net_metrics_log_uploader_unittest.cc
@@ -18,7 +18,7 @@
 
   void CreateAndOnUploadCompleteReuseUploader() {
     uploader_.reset(new NetMetricsLogUploader(
-        NULL, "http://dummy_server", "dummy_mime",
+        NULL, "http://dummy_server", "dummy_mime", MetricsLogUploader::UMA,
         base::Bind(&NetMetricsLogUploaderTest::OnUploadCompleteReuseUploader,
                    base::Unretained(this))));
     uploader_->UploadLog("initial_dummy_data", "initial_dummy_hash");
diff --git a/components/metrics/test_metrics_log_uploader.cc b/components/metrics/test_metrics_log_uploader.cc
index f51b663..9c701cc 100644
--- a/components/metrics/test_metrics_log_uploader.cc
+++ b/components/metrics/test_metrics_log_uploader.cc
@@ -3,14 +3,19 @@
 // found in the LICENSE file.
 
 #include "components/metrics/test_metrics_log_uploader.h"
+#include "components/metrics/metrics_log_uploader.h"
 
 namespace metrics {
 
 TestMetricsLogUploader::TestMetricsLogUploader(
     const std::string& server_url,
     const std::string& mime_type,
+    MetricsLogUploader::MetricServiceType service_type,
     const base::Callback<void(int)>& on_upload_complete)
-    : MetricsLogUploader(server_url, mime_type, on_upload_complete),
+    : MetricsLogUploader(server_url,
+                         mime_type,
+                         service_type,
+                         on_upload_complete),
       is_uploading_(false) {}
 
 TestMetricsLogUploader::~TestMetricsLogUploader() = default;
diff --git a/components/metrics/test_metrics_log_uploader.h b/components/metrics/test_metrics_log_uploader.h
index d2b4bdb..196370a 100644
--- a/components/metrics/test_metrics_log_uploader.h
+++ b/components/metrics/test_metrics_log_uploader.h
@@ -13,6 +13,7 @@
  public:
   TestMetricsLogUploader(const std::string& server_url,
                          const std::string& mime_type,
+                         MetricsLogUploader::MetricServiceType service_type,
                          const base::Callback<void(int)>& on_upload_complete);
   ~TestMetricsLogUploader() override;
 
diff --git a/components/metrics/test_metrics_service_client.cc b/components/metrics/test_metrics_service_client.cc
index 60defbc..b68bef8 100644
--- a/components/metrics/test_metrics_service_client.cc
+++ b/components/metrics/test_metrics_service_client.cc
@@ -67,9 +67,10 @@
 std::unique_ptr<MetricsLogUploader> TestMetricsServiceClient::CreateUploader(
     const std::string& server_url,
     const std::string& mime_type,
+    MetricsLogUploader::MetricServiceType service_type,
     const base::Callback<void(int)>& on_upload_complete) {
-  uploader_ =
-      new TestMetricsLogUploader(server_url, mime_type, on_upload_complete);
+  uploader_ = new TestMetricsLogUploader(server_url, mime_type, service_type,
+                                         on_upload_complete);
   return std::unique_ptr<MetricsLogUploader>(uploader_);
 }
 
diff --git a/components/metrics/test_metrics_service_client.h b/components/metrics/test_metrics_service_client.h
index b8ddc6a..8d77e52a 100644
--- a/components/metrics/test_metrics_service_client.h
+++ b/components/metrics/test_metrics_service_client.h
@@ -10,6 +10,7 @@
 #include <string>
 
 #include "base/macros.h"
+#include "components/metrics/metrics_log_uploader.h"
 #include "components/metrics/metrics_service_client.h"
 #include "components/metrics/test_metrics_log_uploader.h"
 
@@ -38,6 +39,7 @@
   std::unique_ptr<MetricsLogUploader> CreateUploader(
       const std::string& server_url,
       const std::string& mime_type,
+      MetricsLogUploader::MetricServiceType service_type,
       const base::Callback<void(int)>& on_upload_complete) override;
   base::TimeDelta GetStandardUploadInterval() override;
   bool IsReportingPolicyManaged() override;
diff --git a/components/ntp_snippets/features.cc b/components/ntp_snippets/features.cc
index 85b325f5f..49c2097 100644
--- a/components/ntp_snippets/features.cc
+++ b/components/ntp_snippets/features.cc
@@ -32,7 +32,7 @@
     "NTPSnippetsIncreasedVisibility", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kPhysicalWebPageSuggestionsFeature{
-    "NTPPhysicalWebPageSuggestions", base::FEATURE_ENABLED_BY_DEFAULT};
+    "NTPPhysicalWebPageSuggestions", base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kContentSuggestionsSource{
     "NTPSnippets", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/omnibox/browser/in_memory_url_index_unittest.cc b/components/omnibox/browser/in_memory_url_index_unittest.cc
index 54119ee..57751d8 100644
--- a/components/omnibox/browser/in_memory_url_index_unittest.cc
+++ b/components/omnibox/browser/in_memory_url_index_unittest.cc
@@ -710,6 +710,108 @@
   EXPECT_EQ(1U, matches.size());
 }
 
+TEST_F(InMemoryURLIndexTest, TrimHistoryIds) {
+  // Constants ---------------------------------------------------------------
+
+  constexpr size_t kItemsToScoreLimit = 500;
+  constexpr size_t kAlmostLimit = kItemsToScoreLimit - 5;
+
+  constexpr int kLowTypedCount = 2;
+  constexpr int kHighTypedCount = 100;
+
+  constexpr int kLowVisitCount = 20;
+  constexpr int kHighVisitCount = 200;
+
+  constexpr base::TimeDelta kOld = base::TimeDelta::FromDays(15);
+  constexpr base::TimeDelta kNew = base::TimeDelta::FromDays(2);
+
+  constexpr int kMinRowId = 5000;
+
+  // Helpers -----------------------------------------------------------------
+
+  struct ItemGroup {
+    history::URLID min_id;
+    history::URLID max_id;
+    int typed_count;
+    int visit_count;
+    base::TimeDelta days_ago;
+  };
+
+  auto GetHistoryIdsUpTo = [&](HistoryID max) {
+    HistoryIDSet res;
+    // All ids are inserted in the end so the implicit hint would work.
+    for (HistoryID id = kMinRowId; id < max; ++id)
+      res.insert(id);
+    return res;
+  };
+
+  auto CountGroupElementsInIds = [](const ItemGroup& group,
+                                    const HistoryIDSet& ids) {
+    return std::count_if(ids.begin(), ids.end(), [&](history::URLID id) {
+      return group.min_id <= id && id < group.max_id;
+    });
+  };
+
+  // Test body --------------------------------------------------------------
+
+  // Groups of items ordered by increasing priority.
+  ItemGroup item_groups[] = {
+      {0, 0, kLowTypedCount, kLowVisitCount, kOld},
+      {0, 0, kLowTypedCount, kLowVisitCount, kNew},
+      {0, 0, kLowTypedCount, kHighVisitCount, kOld},
+      {0, 0, kLowTypedCount, kHighVisitCount, kNew},
+      {0, 0, kHighTypedCount, kLowVisitCount, kOld},
+      {0, 0, kHighTypedCount, kLowVisitCount, kNew},
+      {0, 0, kHighTypedCount, kHighVisitCount, kOld},
+      {0, 0, kHighTypedCount, kHighVisitCount, kNew},
+  };
+
+  // Initialize groups.
+  history::URLID row_id = kMinRowId;
+  for (auto& group : item_groups) {
+    group.min_id = row_id;
+    for (size_t i = 0; i < kAlmostLimit; ++i) {
+      history::URLRow new_row(
+          GURL("http://www.fake_url" + std::to_string(row_id) + ".com"),
+          row_id);
+      new_row.set_typed_count(group.typed_count);
+      new_row.set_visit_count(group.visit_count);
+      new_row.set_last_visit(base::Time::Now() - group.days_ago);
+      UpdateURL(std::move(new_row));
+      ++row_id;
+    }
+    group.max_id = row_id;
+  }
+
+  // First group. Because number of entries is small enough no trimming occurs.
+  {
+    auto ids = GetHistoryIdsUpTo(item_groups[0].max_id);
+    EXPECT_FALSE(GetPrivateData()->TrimHistoryIdsPool(&ids));
+    EXPECT_EQ(kAlmostLimit, ids.size());
+  }
+
+  // Each next group should fill almost everything, while the previous group
+  // should occupy what's left.
+  auto error_position = std::adjacent_find(
+      std::begin(item_groups), std::end(item_groups),
+      [&](const ItemGroup& previous, const ItemGroup& current) {
+        auto ids = GetHistoryIdsUpTo(current.max_id);
+        EXPECT_TRUE(GetPrivateData()->TrimHistoryIdsPool(&ids));
+
+        size_t current_count = CountGroupElementsInIds(current, ids);
+        EXPECT_EQ(kAlmostLimit, current_count);
+        if (current_count != kAlmostLimit)
+          return true;
+
+        size_t previous_count = CountGroupElementsInIds(previous, ids);
+        EXPECT_EQ(kItemsToScoreLimit - kAlmostLimit, previous_count);
+        return previous_count != kItemsToScoreLimit - kAlmostLimit;
+      });
+
+  EXPECT_TRUE(error_position == std::end(item_groups))
+      << "broken after: " << error_position - std::begin(item_groups);
+}
+
 TEST_F(InMemoryURLIndexTest, HugeResultSet) {
   // Create a huge set of qualifying history items.
   for (history::URLID row_id = 5000; row_id < 6000; ++row_id) {
@@ -721,12 +823,7 @@
 
   ScoredHistoryMatches matches = url_index_->HistoryItemsForTerms(
       ASCIIToUTF16("b"), base::string16::npos, kMaxMatches);
-  URLIndexPrivateData& private_data(*GetPrivateData());
   EXPECT_EQ(kMaxMatches, matches.size());
-  // There are 7 matches already in the database.
-  EXPECT_EQ(1008U, private_data.pre_filter_item_count_);
-  EXPECT_EQ(500U, private_data.post_filter_item_count_);
-  EXPECT_EQ(kMaxMatches, private_data.post_scoring_item_count_);
 }
 
 TEST_F(InMemoryURLIndexTest, TitleSearch) {
diff --git a/components/omnibox/browser/url_index_private_data.cc b/components/omnibox/browser/url_index_private_data.cc
index 8088389..6556116 100644
--- a/components/omnibox/browser/url_index_private_data.cc
+++ b/components/omnibox/browser/url_index_private_data.cc
@@ -141,11 +141,7 @@
 
 URLIndexPrivateData::URLIndexPrivateData()
     : restored_cache_version_(0),
-      saved_cache_version_(kCurrentCacheFileVersion),
-      pre_filter_item_count_(0),
-      post_filter_item_count_(0),
-      post_scoring_item_count_(0) {
-}
+      saved_cache_version_(kCurrentCacheFileVersion) {}
 
 ScoredHistoryMatches URLIndexPrivateData::HistoryItemsForTerms(
     base::string16 original_search_string,
@@ -153,10 +149,6 @@
     size_t max_matches,
     bookmarks::BookmarkModel* bookmark_model,
     TemplateURLService* template_url_service) {
-  pre_filter_item_count_ = 0;
-  post_filter_item_count_ = 0;
-  post_scoring_item_count_ = 0;
-
   // This list will contain the original search string and any other string
   // transformations.
   String16Vector search_strings;
@@ -182,6 +174,7 @@
   // approach.
   ResetSearchTermCache();
 
+  bool history_ids_were_trimmed = false;
   for (const base::string16& search_string : search_strings) {
     // The search string we receive may contain escaped characters. For reducing
     // the index we need individual, lower-cased words, ignoring escapings. For
@@ -202,29 +195,8 @@
     if (lower_words.empty())
       continue;
     HistoryIDSet history_id_set = HistoryIDSetFromWords(lower_words);
-    pre_filter_item_count_ += history_id_set.size();
-    // Trim the candidate pool if it is large. Note that we do not filter out
-    // items that do not contain the search terms as proper substrings --
-    // doing so is the performance-costly operation we are trying to avoid in
-    // order to maintain omnibox responsiveness.
-    const size_t kItemsToScoreLimit = 500;
-    if (history_id_set.size() > kItemsToScoreLimit) {
-      HistoryIDVector history_ids;
-      std::copy(history_id_set.begin(), history_id_set.end(),
-                std::back_inserter(history_ids));
-      // Trim down the set by sorting by typed-count, visit-count, and last
-      // visit.
-      HistoryItemFactorGreater item_factor_functor(history_info_map_);
-      std::partial_sort(history_ids.begin(),
-                        history_ids.begin() + kItemsToScoreLimit,
-                        history_ids.end(), item_factor_functor);
-      history_id_set.clear();
-      std::copy(history_ids.begin(), history_ids.begin() + kItemsToScoreLimit,
-                std::inserter(history_id_set, history_id_set.end()));
-      post_filter_item_count_ += history_id_set.size();
-    } else {
-      post_filter_item_count_ += pre_filter_item_count_;
-    }
+    history_ids_were_trimmed |= TrimHistoryIdsPool(&history_id_set);
+
     ScoredHistoryMatches temp_scored_items;
     HistoryIdSetToScoredMatches(history_id_set, lower_raw_string,
                                 template_url_service, bookmark_model,
@@ -242,8 +214,7 @@
     std::sort(scored_items.begin(), scored_items.end(),
               ScoredHistoryMatch::MatchScoreGreater);
   }
-  post_scoring_item_count_ = scored_items.size();
-  if (pre_filter_item_count_ > post_filter_item_count_) {
+  if (history_ids_were_trimmed) {
     // If we trim the results set we do not want to cache the results for next
     // time as the user's ultimately desired result could easily be eliminated
     // in the early rough filter.
@@ -472,9 +443,6 @@
   return data_copy;
   // Not copied:
   //    search_term_cache_
-  //    pre_filter_item_count_
-  //    post_filter_item_count_
-  //    post_scoring_item_count_
 }
 
 bool URLIndexPrivateData::Empty() const {
@@ -528,6 +496,27 @@
   return history_id_set;
 }
 
+bool URLIndexPrivateData::TrimHistoryIdsPool(
+    HistoryIDSet* history_id_set) const {
+  constexpr size_t kItemsToScoreLimit = 500;
+  if (history_id_set->size() <= kItemsToScoreLimit)
+    return false;
+
+  HistoryIDVector history_ids(history_id_set->begin(), history_id_set->end());
+
+  // Trim down the set by sorting by typed-count, visit-count, and last
+  // visit.
+  auto new_end = history_ids.begin() + kItemsToScoreLimit;
+  HistoryItemFactorGreater item_factor_functor(history_info_map_);
+
+  std::nth_element(history_ids.begin(), new_end, history_ids.end(),
+                   item_factor_functor);
+  history_ids.erase(new_end, history_ids.end());
+
+  *history_id_set = {history_ids.begin(), history_ids.end()};
+  return true;
+}
+
 HistoryIDSet URLIndexPrivateData::HistoryIDsForTerm(
     const base::string16& term) {
   if (term.empty())
diff --git a/components/omnibox/browser/url_index_private_data.h b/components/omnibox/browser/url_index_private_data.h
index 50bcf4b7..4eb77e5 100644
--- a/components/omnibox/browser/url_index_private_data.h
+++ b/components/omnibox/browser/url_index_private_data.h
@@ -146,13 +146,14 @@
 
   friend class ::HistoryQuickProviderTest;
   friend class InMemoryURLIndexTest;
-  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, CalculateWordStartsOffsets);
   FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, CacheSaveRestore);
+  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, CalculateWordStartsOffsets);
   FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, HugeResultSet);
   FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, ReadVisitsFromHistory);
   FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, RebuildFromHistoryIfCacheOld);
   FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, Scoring);
   FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, TitleSearch);
+  FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, TrimHistoryIds);
   FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, TypedCharacterCaching);
   FRIEND_TEST_ALL_PREFIXES(InMemoryURLIndexTest, WhitelistedURLs);
   FRIEND_TEST_ALL_PREFIXES(LimitedInMemoryURLIndexTest, Initialization);
@@ -208,6 +209,14 @@
   // in |unsorted_words|.
   HistoryIDSet HistoryIDSetFromWords(const String16Vector& unsorted_words);
 
+  // Trims the candidate pool in advance of doing proper substring searching, to
+  // cap the cost of such searching. Discards the least-relevant items (based on
+  // visit stats), which are least likely to score highly in the end.  To
+  // minimize the risk of discarding a valuable URL, the candidate pool is still
+  // left two orders of magnitude larger than the final number of results
+  // returned from the HQP. Returns whether anything was trimmed.
+  bool TrimHistoryIdsPool(HistoryIDSet* history_id_set) const;
+
   // Helper function to HistoryIDSetFromWords which composes a set of history
   // ids for the given term given in |term|.
   HistoryIDSet HistoryIDsForTerm(const base::string16& term);
@@ -379,12 +388,6 @@
   // Used only for testing upgrading of an older version of the cache upon
   // restore.
   int saved_cache_version_;
-
-  // Used for unit testing only. Records the number of candidate history items
-  // at three stages in the index searching process.
-  size_t pre_filter_item_count_;    // After word index is queried.
-  size_t post_filter_item_count_;   // After trimming large result set.
-  size_t post_scoring_item_count_;  // After performing final filter/scoring.
 };
 
 #endif  // COMPONENTS_OMNIBOX_BROWSER_URL_INDEX_PRIVATE_DATA_H_
diff --git a/components/printing/renderer/print_web_view_helper.cc b/components/printing/renderer/print_web_view_helper.cc
index 173fb4381..e59e372e 100644
--- a/components/printing/renderer/print_web_view_helper.cc
+++ b/components/printing/renderer/print_web_view_helper.cc
@@ -1854,9 +1854,15 @@
 
   double css_scale_factor = 1.0f;
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
-    if (params.params.scale_factor >= kEpsilon)
-      css_scale_factor = params.params.scale_factor;
+  if (params.params.scale_factor >= kEpsilon)
+    css_scale_factor = params.params.scale_factor;
 #endif
+
+  // Save the original page size here to avoid rounding errors incurred by
+  // converting to pixels and back and by scaling the page for reflow and
+  // scaling back. Windows uses |page_size_in_dpi| for the actual page size
+  // so requires an accurate value.
+  gfx::Size original_page_size = params.params.page_size;
   ComputePageLayoutInPointsForCss(frame, params.page_number, params.params,
                                   ignore_css_margins_, &css_scale_factor,
                                   &page_layout_in_points);
@@ -1864,19 +1870,10 @@
   gfx::Rect content_area;
   GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size,
                                           &content_area);
-  int dpi = static_cast<int>(params.params.dpi);
+
   // Calculate the actual page size and content area in dpi.
   if (page_size_in_dpi) {
-    // Windows uses this for the actual page size. We have scaled page size
-    // to get blink to reflow the page, so scale it back to the real size
-    // before returning it.
-    *page_size_in_dpi =
-        gfx::Size(static_cast<int>(ConvertUnitDouble(page_size.width(),
-                                                     kPointsPerInch, dpi) *
-                                   css_scale_factor),
-                  static_cast<int>(ConvertUnitDouble(page_size.height(),
-                                                     kPointsPerInch, dpi) *
-                                   css_scale_factor));
+    *page_size_in_dpi = original_page_size;
   }
 
   if (content_area_in_dpi) {
diff --git a/components/printing/test/mock_printer.cc b/components/printing/test/mock_printer.cc
index 4197dc60..1a38b7a 100644
--- a/components/printing/test/mock_printer.cc
+++ b/components/printing/test/mock_printer.cc
@@ -40,6 +40,13 @@
   }
 }
 
+void UpdatePageSizeAndScaling(const gfx::Size& page_size,
+                              int scale_factor,
+                              PrintMsg_Print_Params* params) {
+  params->page_size = page_size;
+  params->scale_factor = static_cast<double>(scale_factor) / 100.0;
+}
+
 }  // namespace
 
 MockPrinterPage::MockPrinterPage(const void* source_data,
@@ -161,7 +168,9 @@
 void MockPrinter::UpdateSettings(int cookie,
                                  PrintMsg_PrintPages_Params* params,
                                  const std::vector<int>& pages,
-                                 int margins_type) {
+                                 int margins_type,
+                                 const gfx::Size& page_size,
+                                 int scale_factor) {
   if (document_cookie_ == -1) {
     document_cookie_ = CreateDocumentCookie();
   }
@@ -169,6 +178,8 @@
   params->pages = pages;
   SetPrintParams(&(params->params));
   UpdateMargins(margins_type, dpi_, &(params->params));
+  if (!page_size.IsEmpty())
+    UpdatePageSizeAndScaling(page_size, scale_factor, &params->params);
   printer_status_ = PRINTER_PRINTING;
 }
 
diff --git a/components/printing/test/mock_printer.h b/components/printing/test/mock_printer.h
index 5eaba45..9492a6b 100644
--- a/components/printing/test/mock_printer.h
+++ b/components/printing/test/mock_printer.h
@@ -85,7 +85,9 @@
   void UpdateSettings(int cookie,
                       PrintMsg_PrintPages_Params* params,
                       const std::vector<int>& page_range_array,
-                      int margins_type);
+                      int margins_type,
+                      const gfx::Size& page_size,
+                      int scale_factor);
   void SetPrintedPagesCount(int cookie, int number_pages);
   void PrintPage(const PrintHostMsg_DidPrintPage_Params& params);
 
diff --git a/components/printing/test/print_mock_render_thread.cc b/components/printing/test/print_mock_render_thread.cc
index cc8205a..74013e34 100644
--- a/components/printing/test/print_mock_render_thread.cc
+++ b/components/printing/test/print_mock_render_thread.cc
@@ -15,6 +15,7 @@
 #include "printing/features/features.h"
 #include "printing/page_range.h"
 #include "printing/print_job_constants.h"
+#include "printing/units.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if BUILDFLAG(ENABLE_PRINTING)
@@ -162,9 +163,32 @@
       new_ranges.push_back(range);
     }
   }
-  std::vector<int> pages(printing::PageRange::GetPages(new_ranges));
-  printer_->UpdateSettings(document_cookie, params, pages, margins_type);
 
+  // Get media size
+  const base::DictionaryValue* media_size_value = nullptr;
+  gfx::Size page_size;
+  if (job_settings.GetDictionary(printing::kSettingMediaSize,
+                                 &media_size_value)) {
+    int width_microns = 0;
+    int height_microns = 0;
+    if (media_size_value->GetInteger(printing::kSettingMediaSizeWidthMicrons,
+                                     &width_microns) &&
+        media_size_value->GetInteger(printing::kSettingMediaSizeHeightMicrons,
+                                     &height_microns)) {
+      float device_microns_per_unit =
+          (printing::kHundrethsMMPerInch * 10.0f) / printing::kDefaultPdfDpi;
+      page_size = gfx::Size(width_microns / device_microns_per_unit,
+                            height_microns / device_microns_per_unit);
+    }
+  }
+
+  // Get scaling
+  int scale_factor = 100;
+  job_settings.GetInteger(printing::kSettingScaleFactor, &scale_factor);
+
+  std::vector<int> pages(printing::PageRange::GetPages(new_ranges));
+  printer_->UpdateSettings(document_cookie, params, pages, margins_type,
+                           page_size, scale_factor);
   job_settings.GetBoolean(printing::kSettingShouldPrintSelectionOnly,
                           &params->params.selection_only);
   job_settings.GetBoolean(printing::kSettingShouldPrintBackgrounds,
diff --git a/components/printing/test/print_web_view_helper_browsertest.cc b/components/printing/test/print_web_view_helper_browsertest.cc
index 279ae825..ce387743 100644
--- a/components/printing/test/print_web_view_helper_browsertest.cc
+++ b/components/printing/test/print_web_view_helper_browsertest.cc
@@ -24,6 +24,7 @@
 #include "ipc/ipc_listener.h"
 #include "printing/features/features.h"
 #include "printing/print_job_constants.h"
+#include "printing/units.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebMouseEvent.h"
 #include "third_party/WebKit/public/platform/WebString.h"
@@ -210,6 +211,20 @@
   }
 #endif  // BUILDFLAG(ENABLE_PRINT_PREVIEW)
 
+#if defined(OS_WIN)
+  // Verifies that the correct page size was returned.
+  void VerifyPrintedPageSize(const gfx::Size& page_size) {
+    const IPC::Message* print_msg =
+        render_thread_->sink().GetUniqueMessageMatching(
+            PrintHostMsg_DidPrintPage::ID);
+    PrintHostMsg_DidPrintPage::Param post_did_print_page_param;
+    PrintHostMsg_DidPrintPage::Read(print_msg, &post_did_print_page_param);
+    gfx::Size page_size_received =
+        std::get<0>(post_did_print_page_param).page_size;
+    EXPECT_EQ(page_size, page_size_received);
+  }
+#endif
+
   // Verifies whether the pages printed or not.
   void VerifyPagesPrinted(bool printed) {
     const IPC::Message* print_msg =
@@ -971,6 +986,41 @@
   VerifyPagesPrinted(true);
 }
 
+// Tests that when printing non-default scaling values, the page size returned
+// by PrintWebViewHelper is still the real physical page size. See
+// crbug.com/686384
+TEST_F(MAYBE_PrintWebViewHelperPreviewTest, OnPrintForPrintPreviewWithScaling) {
+  LoadHTML(kPrintPreviewHTML);
+
+  // Fill in some dummy values.
+  base::DictionaryValue dict;
+  CreatePrintSettingsDictionary(&dict);
+
+  // Media size
+  gfx::Size page_size_in = gfx::Size(240, 480);
+  float device_microns_per_unit =
+      (printing::kHundrethsMMPerInch * 10.0f) / printing::kDefaultPdfDpi;
+  int height_microns =
+      static_cast<int>(page_size_in.height() * device_microns_per_unit);
+  int width_microns =
+      static_cast<int>(page_size_in.width() * device_microns_per_unit);
+  auto media_size = base::MakeUnique<base::DictionaryValue>();
+  media_size->SetInteger(kSettingMediaSizeHeightMicrons, height_microns);
+  media_size->SetInteger(kSettingMediaSizeWidthMicrons, width_microns);
+
+  // Non default scaling value
+  dict.SetInteger(kSettingScaleFactor, 80);
+  dict.Set(kSettingMediaSize, media_size.release());
+
+  OnPrintForPrintPreview(dict);
+
+  VerifyPrintFailed(false);
+  VerifyPagesPrinted(true);
+#if defined(OS_WIN)
+  VerifyPrintedPageSize(page_size_in);
+#endif
+}
+
 // Tests that printing from print preview fails and receiving error messages
 // through that channel all works.
 TEST_F(MAYBE_PrintWebViewHelperPreviewTest, OnPrintForPrintPreviewFail) {
diff --git a/components/sessions/core/session_backend.cc b/components/sessions/core/session_backend.cc
index 43db0ae..be991f6 100644
--- a/components/sessions/core/session_backend.cc
+++ b/components/sessions/core/session_backend.cc
@@ -56,8 +56,7 @@
   }
   // Reads the contents of the file specified in the constructor, returning
   // true on success, and filling up |commands| with commands.
-  bool Read(sessions::BaseSessionService::SessionType type,
-            std::vector<std::unique_ptr<sessions::SessionCommand>>* commands);
+  bool Read(std::vector<std::unique_ptr<sessions::SessionCommand>>* commands);
 
  private:
   // Reads a single command, returning it. A return value of NULL indicates
@@ -91,13 +90,11 @@
 };
 
 bool SessionFileReader::Read(
-    sessions::BaseSessionService::SessionType type,
     std::vector<std::unique_ptr<sessions::SessionCommand>>* commands) {
   if (!file_->IsValid())
     return false;
   FileHeader header;
   int read_count;
-  TimeTicks start_time = TimeTicks::Now();
   read_count = file_->ReadAtCurrentPos(reinterpret_cast<char*>(&header),
                                        sizeof(header));
   if (read_count != sizeof(header) || header.signature != kFileSignature ||
@@ -110,13 +107,6 @@
     read_commands.push_back(std::move(command));
   if (!errored_)
     read_commands.swap(*commands);
-  if (type == sessions::BaseSessionService::TAB_RESTORE) {
-    UMA_HISTOGRAM_TIMES("TabRestore.read_session_file_time",
-                        TimeTicks::Now() - start_time);
-  } else {
-    UMA_HISTOGRAM_TIMES("SessionRestore.read_session_file_time",
-                        TimeTicks::Now() - start_time);
-  }
   return !errored_;
 }
 
@@ -262,7 +252,7 @@
     std::vector<std::unique_ptr<sessions::SessionCommand>>* commands) {
   Init();
   SessionFileReader file_reader(GetLastSessionPath());
-  return file_reader.Read(type_, commands);
+  return file_reader.Read(commands);
 }
 
 void SessionBackend::DeleteLastSession() {
@@ -278,19 +268,8 @@
   const base::FilePath last_session_path = GetLastSessionPath();
   if (base::PathExists(last_session_path))
     base::DeleteFile(last_session_path, false);
-  if (base::PathExists(current_session_path)) {
-    int64_t file_size;
-    if (base::GetFileSize(current_session_path, &file_size)) {
-      if (type_ == sessions::BaseSessionService::TAB_RESTORE) {
-        UMA_HISTOGRAM_COUNTS("TabRestore.last_session_file_size",
-                             static_cast<int>(file_size / 1024));
-      } else {
-        UMA_HISTOGRAM_COUNTS("SessionRestore.last_session_file_size",
-                             static_cast<int>(file_size / 1024));
-      }
-    }
+  if (base::PathExists(current_session_path))
     last_session_valid_ = base::Move(current_session_path, last_session_path);
-  }
 
   if (base::PathExists(current_session_path))
     base::DeleteFile(current_session_path, false);
@@ -303,7 +282,7 @@
     std::vector<std::unique_ptr<sessions::SessionCommand>>* commands) {
   Init();
   SessionFileReader file_reader(GetCurrentSessionPath());
-  return file_reader.Read(type_, commands);
+  return file_reader.Read(commands);
 }
 
 bool SessionBackend::AppendCommandsToFile(
@@ -313,10 +292,6 @@
     int wrote;
     const size_type content_size = static_cast<size_type>((*i)->size());
     const size_type total_size =  content_size + sizeof(id_type);
-    if (type_ == sessions::BaseSessionService::TAB_RESTORE)
-      UMA_HISTOGRAM_COUNTS("TabRestore.command_size", total_size);
-    else
-      UMA_HISTOGRAM_COUNTS("SessionRestore.command_size", total_size);
     wrote = file->WriteAtCurrentPos(reinterpret_cast<const char*>(&total_size),
                                     sizeof(total_size));
     if (wrote != sizeof(total_size)) {
diff --git a/components/ukm/ukm_service.cc b/components/ukm/ukm_service.cc
index bd9b2c8..c58eef84 100644
--- a/components/ukm/ukm_service.cc
+++ b/components/ukm/ukm_service.cc
@@ -277,8 +277,9 @@
   // TODO(holte): Handle data usage on cellular, etc.
   if (!log_uploader_) {
     log_uploader_ = client_->CreateUploader(
-        GetServerUrl(), kMimeType, base::Bind(&UkmService::OnLogUploadComplete,
-                                              self_ptr_factory_.GetWeakPtr()));
+        GetServerUrl(), kMimeType, metrics::MetricsLogUploader::UKM,
+        base::Bind(&UkmService::OnLogUploadComplete,
+                   self_ptr_factory_.GetWeakPtr()));
   }
   log_upload_in_progress_ = true;
 
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index b39ba86..63e138d 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -572,6 +572,11 @@
   // Select an appropriate renderer to show the error page.
   RenderFrameHostImpl* render_frame_host =
       frame_tree_node_->render_manager()->GetFrameHostForNavigation(*this);
+
+  // Don't ask the renderer to commit an URL if the browser will kill it when
+  // it does.
+  DCHECK(render_frame_host->CanCommitURL(common_params_.url));
+
   NavigatorImpl::CheckWebUIRendererDoesNotDisplayNormalURL(render_frame_host,
                                                            common_params_.url);
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 1448dd8..069f5b5 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2403,15 +2403,6 @@
   render_view_host_->is_waiting_for_close_ack_ = false;
 }
 
-bool RenderFrameHostImpl::CanCommitURL(const GURL& url) {
-  // TODO(creis): We should also check for WebUI pages here.  Also, when the
-  // out-of-process iframes implementation is ready, we should check for
-  // cross-site URLs that are not allowed to commit in this process.
-
-  // Give the client a chance to disallow URLs from committing.
-  return GetContentClient()->browser()->CanCommitURL(GetProcess(), url);
-}
-
 bool RenderFrameHostImpl::CanCommitOrigin(
     const url::Origin& origin,
     const GURL& url) {
@@ -2912,6 +2903,15 @@
   Send(new FrameMsg_ClearFocusedElement(GetRoutingID()));
 }
 
+bool RenderFrameHostImpl::CanCommitURL(const GURL& url) {
+  // TODO(creis): We should also check for WebUI pages here.  Also, when the
+  // out-of-process iframes implementation is ready, we should check for
+  // cross-site URLs that are not allowed to commit in this process.
+
+  // Give the client a chance to disallow URLs from committing.
+  return GetContentClient()->browser()->CanCommitURL(GetProcess(), url);
+}
+
 bool RenderFrameHostImpl::IsSameSiteInstance(
     RenderFrameHostImpl* other_render_frame_host) {
   // As a sanity check, make sure the frame belongs to the same BrowserContext.
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 60f8694..103a23ed 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -607,6 +607,11 @@
 
   void ClearFocusedElement();
 
+  // Returns whether the given URL is allowed to commit in the current process.
+  // This is a more conservative check than RenderProcessHost::FilterURL, since
+  // it will be used to kill processes that commit unauthorized URLs.
+  bool CanCommitURL(const GURL& url);
+
   // PlzNavigate: returns the PreviewsState of the last successful navigation
   // that made a network request. The PreviewsState is a bitmask of potentially
   // several Previews optimizations.
@@ -777,11 +782,6 @@
   // relevant.
   void ResetWaitingState();
 
-  // Returns whether the given URL is allowed to commit in the current process.
-  // This is a more conservative check than RenderProcessHost::FilterURL, since
-  // it will be used to kill processes that commit unauthorized URLs.
-  bool CanCommitURL(const GURL& url);
-
   // Returns whether the given origin is allowed to commit in the current
   // RenderFrameHost. The |url| is used to ensure it matches the origin in cases
   // where it is applicable. This is a more conservative check than
diff --git a/content/browser/media/session/media_session_service_impl_browsertest.cc b/content/browser/media/session/media_session_service_impl_browsertest.cc
new file mode 100644
index 0000000..959bbae
--- /dev/null
+++ b/content/browser/media/session/media_session_service_impl_browsertest.cc
@@ -0,0 +1,29 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/command_line.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+
+namespace content {
+
+class MediaSessionServiceImplBrowserTest : public ContentBrowserTest {
+ protected:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    ContentBrowserTest::SetUpCommandLine(command_line);
+    command_line->AppendSwitchASCII("--enable-blink-features", "MediaSession");
+  }
+};
+
+// Two windows from the same BrowserContext.
+IN_PROC_BROWSER_TEST_F(MediaSessionServiceImplBrowserTest,
+                       CrashMessageOnUnload) {
+  NavigateToURL(shell(), GetTestUrl("media/session", "embedder.html"));
+  // Navigate to a chrome:// URL to avoid render process re-use.
+  NavigateToURL(shell(), GURL("chrome://flags"));
+  // Should not crash.
+}
+
+}  // namespace content
diff --git a/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc b/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
index a2ca470..7e213f0 100644
--- a/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
+++ b/content/browser/webrtc/webrtc_capture_from_element_browsertest.cc
@@ -88,17 +88,10 @@
   MakeTypicalCall("testCanvasCapture(drawWebGL);", kCanvasCaptureTestHtmlFile);
 }
 
-#if defined(OS_MACOSX)
-// This test causes GL related issues in Mac: https://crbug.com/695452.
-#define MAYBE_VerifyCanvasCaptureOffscreenCanvasCommitFrames \
-  DISABLED_VerifyCanvasCaptureOffscreenCanvasCommitFrames
-#else
-#define MAYBE_VerifyCanvasCaptureOffscreenCanvasCommitFrames \
-  VerifyCanvasCaptureOffscreenCanvasCommitFrames
-#endif
-
-IN_PROC_BROWSER_TEST_F(WebRtcCaptureFromElementBrowserTest,
-                       MAYBE_VerifyCanvasCaptureOffscreenCanvasCommitFrames) {
+// This test causes GL related issues on Win and Mac: https://crbug.com/695452.
+IN_PROC_BROWSER_TEST_F(
+    WebRtcCaptureFromElementBrowserTest,
+    DISABLED_VerifyCanvasCaptureOffscreenCanvasCommitFrames) {
   MakeTypicalCall("testCanvasCapture(drawOffscreenCanvasCommit);",
                   kCanvasCaptureTestHtmlFile);
 }
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index 04759bb..2a52bbd 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -668,10 +668,8 @@
   }
 
   if (ipc_type == blink::WebURLRequest::LoadingIPCType::Mojo) {
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner =
-        loading_task_runner ? loading_task_runner : main_thread_task_runner_;
     std::unique_ptr<URLLoaderClientImpl> client(
-        new URLLoaderClientImpl(request_id, this, std::move(task_runner)));
+        new URLLoaderClientImpl(request_id, this, main_thread_task_runner_));
     mojom::URLLoaderAssociatedPtr url_loader;
     mojom::URLLoaderClientAssociatedPtrInfo client_ptr_info;
     client->Bind(&client_ptr_info);
diff --git a/content/child/url_loader_client_impl.cc b/content/child/url_loader_client_impl.cc
index c1d25c8..ab1e930 100644
--- a/content/child/url_loader_client_impl.cc
+++ b/content/child/url_loader_client_impl.cc
@@ -30,7 +30,7 @@
 
 void URLLoaderClientImpl::Bind(
     mojom::URLLoaderClientAssociatedPtrInfo* client_ptr_info) {
-  binding_.Bind(client_ptr_info, task_runner_.get());
+  binding_.Bind(client_ptr_info);
 }
 
 void URLLoaderClientImpl::SetDefersLoading() {
diff --git a/content/public/test/test_utils.cc b/content/public/test/test_utils.cc
index 1d2da32a..4afe2321 100644
--- a/content/public/test/test_utils.cc
+++ b/content/public/test/test_utils.cc
@@ -292,8 +292,8 @@
     return;
 
   running_ = true;
-  run_loop_.reset(new base::RunLoop);
-  run_loop_->Run();
+  message_loop_runner_ = new MessageLoopRunner;
+  message_loop_runner_->Run();
   EXPECT_TRUE(seen_);
 }
 
@@ -310,7 +310,7 @@
   if (!running_)
     return;
 
-  run_loop_->Quit();
+  message_loop_runner_->Quit();
   running_ = false;
 }
 
diff --git a/content/public/test/test_utils.h b/content/public/test/test_utils.h
index ed1f8e6..29f5965 100644
--- a/content/public/test/test_utils.h
+++ b/content/public/test/test_utils.h
@@ -235,7 +235,7 @@
 
   NotificationSource source_;
   NotificationDetails details_;
-  std::unique_ptr<base::RunLoop> run_loop_;
+  scoped_refptr<MessageLoopRunner> message_loop_runner_;
 
   DISALLOW_COPY_AND_ASSIGN(WindowedNotificationObserver);
 };
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn
index f62e2f3..abbbbfa 100644
--- a/content/renderer/BUILD.gn
+++ b/content/renderer/BUILD.gn
@@ -586,8 +586,8 @@
       "media/media_stream_center.h",
       "media/media_stream_constraints_util.cc",
       "media/media_stream_constraints_util.h",
-      "media/media_stream_constraints_util_video_source.cc",
-      "media/media_stream_constraints_util_video_source.h",
+      "media/media_stream_constraints_util_video_device.cc",
+      "media/media_stream_constraints_util_video_device.h",
       "media/media_stream_dispatcher.cc",
       "media/media_stream_dispatcher.h",
       "media/media_stream_dispatcher_eventhandler.h",
diff --git a/content/renderer/media/media_stream_constraints_util.h b/content/renderer/media/media_stream_constraints_util.h
index 7b24be2..a3f75a6e 100644
--- a/content/renderer/media/media_stream_constraints_util.h
+++ b/content/renderer/media/media_stream_constraints_util.h
@@ -69,6 +69,30 @@
     const blink::WebMediaConstraints& constraints,
     const blink::BooleanConstraint blink::WebMediaTrackConstraintSet::*picker);
 
+template <typename ConstraintType>
+bool ConstraintHasMax(const ConstraintType& constraint) {
+  return constraint.hasMax() || constraint.hasExact();
+}
+
+template <typename ConstraintType>
+bool ConstraintHasMin(const ConstraintType& constraint) {
+  return constraint.hasMin() || constraint.hasExact();
+}
+
+template <typename ConstraintType>
+auto ConstraintMax(const ConstraintType& constraint)
+    -> decltype(constraint.max()) {
+  DCHECK(ConstraintHasMax(constraint));
+  return constraint.hasExact() ? constraint.exact() : constraint.max();
+}
+
+template <typename ConstraintType>
+auto ConstraintMin(const ConstraintType& constraint)
+    -> decltype(constraint.min()) {
+  DCHECK(ConstraintHasMin(constraint));
+  return constraint.hasExact() ? constraint.exact() : constraint.min();
+}
+
 }  // namespace content
 
 #endif  // CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_H_
diff --git a/content/renderer/media/media_stream_constraints_util_video_source.cc b/content/renderer/media/media_stream_constraints_util_video_device.cc
similarity index 84%
rename from content/renderer/media/media_stream_constraints_util_video_source.cc
rename to content/renderer/media/media_stream_constraints_util_video_device.cc
index 59826d5..3e2f3e8 100644
--- a/content/renderer/media/media_stream_constraints_util_video_source.cc
+++ b/content/renderer/media/media_stream_constraints_util_video_device.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 "content/renderer/media/media_stream_constraints_util_video_source.h"
+#include "content/renderer/media/media_stream_constraints_util_video_device.h"
 
 #include <algorithm>
 #include <cmath>
@@ -10,6 +10,7 @@
 #include <utility>
 #include <vector>
 
+#include "content/renderer/media/media_stream_constraints_util.h"
 #include "content/renderer/media/media_stream_video_source.h"
 #include "third_party/WebKit/public/platform/WebMediaConstraints.h"
 #include "third_party/WebKit/public/platform/WebString.h"
@@ -49,28 +50,73 @@
   }
 }
 
-template <typename ConstraintType>
-bool ConstraintHasMax(const ConstraintType& constraint) {
-  return constraint.hasMax() || constraint.hasExact();
-}
+struct VideoDeviceCaptureSourceSettings {
+ public:
+  VideoDeviceCaptureSourceSettings()
+      : facing_mode_(::mojom::FacingMode::NONE),
+        power_line_frequency_(media::PowerLineFrequency::FREQUENCY_DEFAULT) {}
 
-template <typename ConstraintType>
-bool ConstraintHasMin(const ConstraintType& constraint) {
-  return constraint.hasMin() || constraint.hasExact();
-}
+  VideoDeviceCaptureSourceSettings(
+      const std::string& device_id,
+      const media::VideoCaptureFormat& format,
+      ::mojom::FacingMode facing_mode,
+      media::PowerLineFrequency power_line_frequency)
+      : device_id_(device_id),
+        format_(format),
+        facing_mode_(facing_mode),
+        power_line_frequency_(power_line_frequency) {}
 
-template <typename ConstraintType>
-auto ConstraintMax(const ConstraintType& constraint)
-    -> decltype(constraint.max()) {
-  DCHECK(ConstraintHasMax(constraint));
-  return constraint.hasExact() ? constraint.exact() : constraint.max();
-}
+  VideoDeviceCaptureSourceSettings(
+      const VideoDeviceCaptureSourceSettings& other) = default;
+  VideoDeviceCaptureSourceSettings& operator=(
+      const VideoDeviceCaptureSourceSettings& other) = default;
+  VideoDeviceCaptureSourceSettings(VideoDeviceCaptureSourceSettings&& other) =
+      default;
+  VideoDeviceCaptureSourceSettings& operator=(
+      VideoDeviceCaptureSourceSettings&& other) = default;
+  ~VideoDeviceCaptureSourceSettings() = default;
 
-template <typename ConstraintType>
-auto ConstraintMin(const ConstraintType& constraint)
-    -> decltype(constraint.min()) {
-  DCHECK(ConstraintHasMin(constraint));
-  return constraint.hasExact() ? constraint.exact() : constraint.min();
+  // These accessor-like methods transform types to what Blink constraint
+  // classes expect.
+  blink::WebString GetFacingMode() const { return ToWebString(facing_mode_); }
+  long GetPowerLineFrequency() const {
+    return static_cast<long>(power_line_frequency_);
+  }
+  long GetWidth() const { return format_.frame_size.width(); }
+  long GetHeight() const { return format_.frame_size.height(); }
+  double GetFrameRate() const { return format_.frame_rate; }
+  blink::WebString GetDeviceId() const {
+    return blink::WebString::fromASCII(device_id_.data());
+  }
+  blink::WebString GetVideoKind() const {
+    return GetVideoKindForFormat(format_);
+  }
+
+  // Accessors.
+  const media::VideoCaptureFormat& format() const { return format_; }
+  const std::string& device_id() const { return device_id_; }
+  ::mojom::FacingMode facing_mode() const { return facing_mode_; }
+  media::PowerLineFrequency power_line_frequency() const {
+    return power_line_frequency_;
+  }
+
+ private:
+  std::string device_id_;
+  media::VideoCaptureFormat format_;
+  ::mojom::FacingMode facing_mode_;
+  media::PowerLineFrequency power_line_frequency_;
+};
+
+VideoDeviceCaptureSourceSelectionResult ResultFromSettings(
+    const VideoDeviceCaptureSourceSettings& settings) {
+  VideoDeviceCaptureSourceSelectionResult result;
+  result.capture_params.power_line_frequency = settings.power_line_frequency();
+  result.capture_params.requested_format = settings.format();
+  result.device_id = settings.device_id();
+  result.facing_mode = settings.facing_mode();
+  result.failed_constraint_name = nullptr;
+
+  return result;
 }
 
 // Generic distance function between two numeric values. Based on the fitness
@@ -324,7 +370,7 @@
 // Otherwise the distance is a finite value. Candidates with lower distance
 // satisfy |constraint_set| in a "better" way.
 double CandidateSourceDistance(
-    const VideoCaptureSourceSettings& candidate,
+    const VideoDeviceCaptureSourceSettings& candidate,
     const blink::WebMediaTrackConstraintSet& constraint_set,
     const char** failed_constraint_name) {
   return DeviceSourceDistance(candidate.device_id(), candidate.facing_mode(),
@@ -470,7 +516,7 @@
 // setting in |candidate| and the corresponding constraint in |constraint_set|.
 // Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance.
 double CandidateFitnessDistance(
-    const VideoCaptureSourceSettings& candidate,
+    const VideoDeviceCaptureSourceSettings& candidate,
     const blink::WebMediaTrackConstraintSet& constraint_set) {
   DCHECK(std::isfinite(
       CandidateSourceDistance(candidate, constraint_set, nullptr)));
@@ -502,7 +548,7 @@
 // height and frame rate).
 // Based on https://w3c.github.io/mediacapture-main/#dfn-fitness-distance.
 double CandidateNativeFitnessDistance(
-    const VideoCaptureSourceSettings& candidate,
+    const VideoDeviceCaptureSourceSettings& candidate,
     const blink::WebMediaTrackConstraintSet& constraint_set) {
   DCHECK(std::isfinite(
       CandidateSourceDistance(candidate, constraint_set, nullptr)));
@@ -524,9 +570,10 @@
 // These entries are to be used as the final tie breaker for candidates that
 // are equally good according to the spec and the custom distance functions
 // between candidates and constraints.
-void AppendDistanceFromDefault(const VideoCaptureSourceSettings& candidate,
-                               const VideoCaptureCapabilities& capabilities,
-                               DistanceVector* distance_vector) {
+void AppendDistanceFromDefault(
+    const VideoDeviceCaptureSourceSettings& candidate,
+    const VideoDeviceCaptureCapabilities& capabilities,
+    DistanceVector* distance_vector) {
   // Favor IDs that appear first in the enumeration.
   for (size_t i = 0; i < capabilities.device_capabilities.size(); ++i) {
     if (candidate.device_id() ==
@@ -570,82 +617,36 @@
              : blink::WebString::fromASCII(kVideoKindColor);
 }
 
-VideoCaptureCapabilities::VideoCaptureCapabilities() = default;
-VideoCaptureCapabilities::VideoCaptureCapabilities(
-    VideoCaptureCapabilities&& other) = default;
-VideoCaptureCapabilities::~VideoCaptureCapabilities() = default;
-VideoCaptureCapabilities& VideoCaptureCapabilities::operator=(
-    VideoCaptureCapabilities&& other) = default;
-
-VideoCaptureSourceSettings::VideoCaptureSourceSettings(
-    const VideoCaptureSourceSettings& other) = default;
-VideoCaptureSourceSettings::VideoCaptureSourceSettings(
-    VideoCaptureSourceSettings&& other) = default;
-VideoCaptureSourceSettings::~VideoCaptureSourceSettings() = default;
-VideoCaptureSourceSettings& VideoCaptureSourceSettings::operator=(
-    const VideoCaptureSourceSettings& other) = default;
-VideoCaptureSourceSettings& VideoCaptureSourceSettings::operator=(
-    VideoCaptureSourceSettings&& other) = default;
-
-VideoCaptureSourceSettings::VideoCaptureSourceSettings()
-    : facing_mode_(::mojom::FacingMode::NONE),
-      power_line_frequency_(media::PowerLineFrequency::FREQUENCY_DEFAULT) {}
-
-VideoCaptureSourceSettings::VideoCaptureSourceSettings(
-    const std::string& device_id,
-    const media::VideoCaptureFormat& format,
-    ::mojom::FacingMode facing_mode,
-    media::PowerLineFrequency power_line_frequency)
-    : device_id_(device_id),
-      format_(format),
-      facing_mode_(facing_mode),
-      power_line_frequency_(power_line_frequency) {}
-
-blink::WebString VideoCaptureSourceSettings::GetFacingMode() const {
-  return ToWebString(facing_mode_);
-}
-
-long VideoCaptureSourceSettings::GetPowerLineFrequency() const {
-  return static_cast<long>(power_line_frequency_);
-}
-
-long VideoCaptureSourceSettings::GetWidth() const {
-  return format_.frame_size.width();
-}
-
-long VideoCaptureSourceSettings::GetHeight() const {
-  return format_.frame_size.height();
-}
-
-double VideoCaptureSourceSettings::GetFrameRate() const {
-  return format_.frame_rate;
-}
-
-blink::WebString VideoCaptureSourceSettings::GetDeviceId() const {
-  return blink::WebString::fromASCII(device_id_.data());
-}
-
-blink::WebString VideoCaptureSourceSettings::GetVideoKind() const {
-  return GetVideoKindForFormat(format_);
-}
+VideoDeviceCaptureCapabilities::VideoDeviceCaptureCapabilities() = default;
+VideoDeviceCaptureCapabilities::VideoDeviceCaptureCapabilities(
+    VideoDeviceCaptureCapabilities&& other) = default;
+VideoDeviceCaptureCapabilities::~VideoDeviceCaptureCapabilities() = default;
+VideoDeviceCaptureCapabilities& VideoDeviceCaptureCapabilities::operator=(
+    VideoDeviceCaptureCapabilities&& other) = default;
 
 const char kDefaultFailedConstraintName[] = "";
 
-VideoCaptureSourceSelectionResult::VideoCaptureSourceSelectionResult()
-    : failed_constraint_name(kDefaultFailedConstraintName) {}
-VideoCaptureSourceSelectionResult::VideoCaptureSourceSelectionResult(
-    const VideoCaptureSourceSelectionResult& other) = default;
-VideoCaptureSourceSelectionResult::VideoCaptureSourceSelectionResult(
-    VideoCaptureSourceSelectionResult&& other) = default;
-VideoCaptureSourceSelectionResult::~VideoCaptureSourceSelectionResult() =
-    default;
-VideoCaptureSourceSelectionResult& VideoCaptureSourceSelectionResult::operator=(
-    const VideoCaptureSourceSelectionResult& other) = default;
-VideoCaptureSourceSelectionResult& VideoCaptureSourceSelectionResult::operator=(
-    VideoCaptureSourceSelectionResult&& other) = default;
+VideoDeviceCaptureSourceSelectionResult::
+    VideoDeviceCaptureSourceSelectionResult()
+    : failed_constraint_name(kDefaultFailedConstraintName),
+      facing_mode(::mojom::FacingMode::NONE) {}
+VideoDeviceCaptureSourceSelectionResult::
+    VideoDeviceCaptureSourceSelectionResult(
+        const VideoDeviceCaptureSourceSelectionResult& other) = default;
+VideoDeviceCaptureSourceSelectionResult::
+    VideoDeviceCaptureSourceSelectionResult(
+        VideoDeviceCaptureSourceSelectionResult&& other) = default;
+VideoDeviceCaptureSourceSelectionResult::
+    ~VideoDeviceCaptureSourceSelectionResult() = default;
+VideoDeviceCaptureSourceSelectionResult&
+VideoDeviceCaptureSourceSelectionResult::operator=(
+    const VideoDeviceCaptureSourceSelectionResult& other) = default;
+VideoDeviceCaptureSourceSelectionResult&
+VideoDeviceCaptureSourceSelectionResult::operator=(
+    VideoDeviceCaptureSourceSelectionResult&& other) = default;
 
-VideoCaptureSourceSelectionResult SelectVideoCaptureSourceSettings(
-    const VideoCaptureCapabilities& capabilities,
+VideoDeviceCaptureSourceSelectionResult SelectVideoDeviceCaptureSourceSettings(
+    const VideoDeviceCaptureCapabilities& capabilities,
     const blink::WebMediaConstraints& constraints) {
   // This function works only if infinity is defined for the double type.
   DCHECK(std::numeric_limits<double>::has_infinity);
@@ -667,7 +668,7 @@
   DistanceVector best_distance(2 * constraints.advanced().size() + 3 +
                                kNumDefaultDistanceEntries);
   std::fill(best_distance.begin(), best_distance.end(), HUGE_VAL);
-  VideoCaptureSourceSelectionResult result;
+  VideoDeviceCaptureSourceSelectionResult result;
   const char* failed_constraint_name = result.failed_constraint_name;
 
   for (auto& device : capabilities.device_capabilities) {
@@ -701,9 +702,9 @@
         // Custom distances must be added to the candidate distance vector after
         // all the spec-mandated values.
         DistanceVector advanced_custom_distance_vector;
-        VideoCaptureSourceSettings candidate(device->device_id, format,
-                                             device->facing_mode,
-                                             power_line_frequency);
+        VideoDeviceCaptureSourceSettings candidate(device->device_id, format,
+                                                   device->facing_mode,
+                                                   power_line_frequency);
         DistanceVector candidate_distance_vector;
         // First criteria for valid candidates is satisfaction of advanced
         // constraint sets.
@@ -736,14 +737,13 @@
         DCHECK_EQ(best_distance.size(), candidate_distance_vector.size());
         if (candidate_distance_vector < best_distance) {
           best_distance = candidate_distance_vector;
-          result.settings = std::move(candidate);
-          result.failed_constraint_name = nullptr;
+          result = ResultFromSettings(candidate);
         }
       }
     }
   }
 
-  if (!result.has_value())
+  if (!result.HasValue())
     result.failed_constraint_name = failed_constraint_name;
 
   return result;
diff --git a/content/renderer/media/media_stream_constraints_util_video_source.h b/content/renderer/media/media_stream_constraints_util_video_device.h
similarity index 66%
rename from content/renderer/media/media_stream_constraints_util_video_source.h
rename to content/renderer/media/media_stream_constraints_util_video_device.h
index b3df2ff8..af55fdc 100644
--- a/content/renderer/media/media_stream_constraints_util_video_source.h
+++ b/content/renderer/media/media_stream_constraints_util_video_device.h
@@ -2,10 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_SOURCE_H_
-#define CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_SOURCE_H_
+#ifndef CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_DEVICE_H_
+#define CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_DEVICE_H_
 
-#include <iosfwd>
 #include <string>
 #include <vector>
 
@@ -25,69 +24,51 @@
 blink::WebString CONTENT_EXPORT
 GetVideoKindForFormat(const media::VideoCaptureFormat& format);
 
-struct CONTENT_EXPORT VideoCaptureCapabilities {
-  VideoCaptureCapabilities();
-  VideoCaptureCapabilities(VideoCaptureCapabilities&& other);
-  ~VideoCaptureCapabilities();
-  VideoCaptureCapabilities& operator=(VideoCaptureCapabilities&& other);
+struct CONTENT_EXPORT VideoDeviceCaptureCapabilities {
+  VideoDeviceCaptureCapabilities();
+  VideoDeviceCaptureCapabilities(VideoDeviceCaptureCapabilities&& other);
+  ~VideoDeviceCaptureCapabilities();
+  VideoDeviceCaptureCapabilities& operator=(
+      VideoDeviceCaptureCapabilities&& other);
 
   // Each field is independent of each other.
   std::vector<::mojom::VideoInputDeviceCapabilitiesPtr> device_capabilities;
   std::vector<media::PowerLineFrequency> power_line_capabilities;
 };
 
-class CONTENT_EXPORT VideoCaptureSourceSettings {
- public:
-  VideoCaptureSourceSettings();
-  VideoCaptureSourceSettings(const VideoCaptureSourceSettings& other);
-  VideoCaptureSourceSettings(VideoCaptureSourceSettings&& other);
-  VideoCaptureSourceSettings(const std::string& device_id,
-                             const media::VideoCaptureFormat& format,
-                             ::mojom::FacingMode facing_mode,
-                             media::PowerLineFrequency power_line_frequency);
-  ~VideoCaptureSourceSettings();
-  VideoCaptureSourceSettings& operator=(
-      const VideoCaptureSourceSettings& other);
-  VideoCaptureSourceSettings& operator=(VideoCaptureSourceSettings&& other);
+struct CONTENT_EXPORT VideoDeviceCaptureSourceSelectionResult {
+  VideoDeviceCaptureSourceSelectionResult();
+  VideoDeviceCaptureSourceSelectionResult(
+      const VideoDeviceCaptureSourceSelectionResult& other);
+  VideoDeviceCaptureSourceSelectionResult(
+      VideoDeviceCaptureSourceSelectionResult&& other);
+  ~VideoDeviceCaptureSourceSelectionResult();
+  VideoDeviceCaptureSourceSelectionResult& operator=(
+      const VideoDeviceCaptureSourceSelectionResult& other);
+  VideoDeviceCaptureSourceSelectionResult& operator=(
+      VideoDeviceCaptureSourceSelectionResult&& other);
 
-  // Accessors for easier interaction with blink constraint classes.
-  blink::WebString GetFacingMode() const;
-  long GetPowerLineFrequency() const;
-  long GetWidth() const;
-  long GetHeight() const;
-  double GetFrameRate() const;
-  blink::WebString GetDeviceId() const;
-  blink::WebString GetVideoKind() const;
+  bool HasValue() const { return failed_constraint_name == nullptr; }
 
-  const media::VideoCaptureFormat& format() const { return format_; }
-  const std::string& device_id() const { return device_id_; }
-  ::mojom::FacingMode facing_mode() const { return facing_mode_; }
-  media::PowerLineFrequency power_line_frequency() const {
-    return power_line_frequency_;
+  // Convenience accessors for fields embedded in |capture_params|.
+  const media::VideoCaptureFormat& Format() const {
+    return capture_params.requested_format;
+  }
+  int Width() const {
+    return capture_params.requested_format.frame_size.width();
+  }
+  int Height() const {
+    return capture_params.requested_format.frame_size.height();
+  }
+  float FrameRate() const { return capture_params.requested_format.frame_rate; }
+  media::PowerLineFrequency PowerLineFrequency() const {
+    return capture_params.power_line_frequency;
   }
 
- private:
-  std::string device_id_;
-  media::VideoCaptureFormat format_;
-  ::mojom::FacingMode facing_mode_;
-  media::PowerLineFrequency power_line_frequency_;
-};
-
-struct CONTENT_EXPORT VideoCaptureSourceSelectionResult {
-  VideoCaptureSourceSelectionResult();
-  VideoCaptureSourceSelectionResult(
-      const VideoCaptureSourceSelectionResult& other);
-  VideoCaptureSourceSelectionResult(VideoCaptureSourceSelectionResult&& other);
-  ~VideoCaptureSourceSelectionResult();
-  VideoCaptureSourceSelectionResult& operator=(
-      const VideoCaptureSourceSelectionResult& other);
-  VideoCaptureSourceSelectionResult& operator=(
-      VideoCaptureSourceSelectionResult&& other);
-
-  bool has_value() const { return failed_constraint_name == nullptr; }
-
-  VideoCaptureSourceSettings settings;
   const char* failed_constraint_name;
+  std::string device_id;
+  ::mojom::FacingMode facing_mode;
+  media::VideoCaptureParams capture_params;
 };
 
 // This function performs source and source-settings selection based on
@@ -152,10 +133,11 @@
 //    settings that include the device ID, power-line frequency, resolution, and
 //    frame rate, in that order. Note that there is no default facing mode or
 //    aspect ratio.
-VideoCaptureSourceSelectionResult CONTENT_EXPORT
-SelectVideoCaptureSourceSettings(const VideoCaptureCapabilities& capabilities,
-                                 const blink::WebMediaConstraints& constraints);
+VideoDeviceCaptureSourceSelectionResult CONTENT_EXPORT
+SelectVideoDeviceCaptureSourceSettings(
+    const VideoDeviceCaptureCapabilities& capabilities,
+    const blink::WebMediaConstraints& constraints);
 
 }  // namespace content
 
-#endif  // CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_SOURCE_H_
+#endif  // CONTENT_RENDERER_MEDIA_MEDIA_STREAM_CONSTRAINTS_UTIL_VIDEO_DEVICE_H_
diff --git a/content/renderer/media/media_stream_constraints_util_video_source_unittest.cc b/content/renderer/media/media_stream_constraints_util_video_device_unittest.cc
similarity index 67%
rename from content/renderer/media/media_stream_constraints_util_video_source_unittest.cc
rename to content/renderer/media/media_stream_constraints_util_video_device_unittest.cc
index cc92442f..5247f39 100644
--- a/content/renderer/media/media_stream_constraints_util_video_source_unittest.cc
+++ b/content/renderer/media/media_stream_constraints_util_video_device_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 "content/renderer/media/media_stream_constraints_util_video_source.h"
+#include "content/renderer/media/media_stream_constraints_util_video_device.h"
 
 #include <algorithm>
 #include <utility>
@@ -23,7 +23,7 @@
 const char kDeviceID4[] = "fake_device_4";
 }
 
-class MediaStreamConstraintsUtilVideoSourceTest : public testing::Test {
+class MediaStreamConstraintsUtilVideoDeviceTest : public testing::Test {
  public:
   void SetUp() override {
     // Default device. It is default because it is the first in the enumeration.
@@ -110,13 +110,13 @@
   }
 
  protected:
-  VideoCaptureSourceSelectionResult SelectSettings() {
+  VideoDeviceCaptureSourceSelectionResult SelectSettings() {
     blink::WebMediaConstraints constraints =
         constraint_factory_.CreateWebMediaConstraints();
-    return SelectVideoCaptureSourceSettings(capabilities_, constraints);
+    return SelectVideoDeviceCaptureSourceSettings(capabilities_, constraints);
   }
 
-  VideoCaptureCapabilities capabilities_;
+  VideoDeviceCaptureCapabilities capabilities_;
   const mojom::VideoInputDeviceCapabilities* default_device_;
   const mojom::VideoInputDeviceCapabilities* low_res_device_;
   const mojom::VideoInputDeviceCapabilities* high_res_device_;
@@ -130,109 +130,109 @@
 };
 
 // The Unconstrained test checks the default selection criteria.
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, Unconstrained) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, Unconstrained) {
   constraint_factory_.Reset();
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // Should select the default device with closest-to-default settings.
-  EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(default_device_->facing_mode, result.settings.facing_mode());
-  EXPECT_EQ(*default_closest_format_, result.settings.format());
+  EXPECT_EQ(default_device_->device_id, result.device_id);
+  EXPECT_EQ(default_device_->facing_mode, result.facing_mode);
+  EXPECT_EQ(*default_closest_format_, result.Format());
 }
 
 // The "Overconstrained" tests verify that failure of any single required
 // constraint results in failure to select a candidate.
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnDeviceID) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnDeviceID) {
   constraint_factory_.Reset();
   constraint_factory_.basic().deviceId.setExact(
       blink::WebString::fromASCII("NONEXISTING"));
   auto result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().deviceId.name(),
             result.failed_constraint_name);
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnFacingMode) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnFacingMode) {
   constraint_factory_.Reset();
   // No device in |capabilities_| has facing mode equal to LEFT.
   constraint_factory_.basic().facingMode.setExact(
       blink::WebString::fromASCII("left"));
   auto result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().facingMode.name(),
             result.failed_constraint_name);
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnVideoKind) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnVideoKind) {
   constraint_factory_.Reset();
   // No device in |capabilities_| has video kind infrared.
   constraint_factory_.basic().videoKind.setExact(
       blink::WebString::fromASCII("infrared"));
   auto result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().videoKind.name(),
             result.failed_constraint_name);
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnHeight) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnHeight) {
   constraint_factory_.Reset();
   constraint_factory_.basic().height.setExact(123467890);
   auto result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().height.name(),
             result.failed_constraint_name);
 
   constraint_factory_.Reset();
   constraint_factory_.basic().height.setMin(123467890);
   result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().height.name(),
             result.failed_constraint_name);
 
   constraint_factory_.Reset();
   constraint_factory_.basic().height.setMax(0);
   result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().height.name(),
             result.failed_constraint_name);
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnWidth) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnWidth) {
   constraint_factory_.Reset();
   constraint_factory_.basic().width.setExact(123467890);
   auto result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().width.name(),
             result.failed_constraint_name);
 
   constraint_factory_.Reset();
   constraint_factory_.basic().width.setMin(123467890);
   result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().width.name(),
             result.failed_constraint_name);
 
   constraint_factory_.Reset();
   constraint_factory_.basic().width.setMax(0);
   result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().width.name(),
             result.failed_constraint_name);
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest,
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
        OverconstrainedOnAspectRatio) {
   constraint_factory_.Reset();
   constraint_factory_.basic().aspectRatio.setExact(123467890.0);
   auto result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(),
             result.failed_constraint_name);
 
   constraint_factory_.Reset();
   constraint_factory_.basic().aspectRatio.setMin(123467890.0);
   result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(),
             result.failed_constraint_name);
 
@@ -241,132 +241,132 @@
   double kLowAspectRatio = 0.01;
   constraint_factory_.basic().aspectRatio.setMax(kLowAspectRatio);
   result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().aspectRatio.name(),
             result.failed_constraint_name);
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, OverconstrainedOnFrameRate) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, OverconstrainedOnFrameRate) {
   constraint_factory_.Reset();
   constraint_factory_.basic().frameRate.setExact(123467890.0);
   auto result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().frameRate.name(),
             result.failed_constraint_name);
 
   constraint_factory_.Reset();
   constraint_factory_.basic().frameRate.setMin(123467890.0);
   result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().frameRate.name(),
             result.failed_constraint_name);
 
   constraint_factory_.Reset();
   constraint_factory_.basic().frameRate.setMax(0.0);
   result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().frameRate.name(),
             result.failed_constraint_name);
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest,
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
        OverconstrainedOnPowerLineFrequency) {
   constraint_factory_.Reset();
   constraint_factory_.basic().googPowerLineFrequency.setExact(123467890);
   auto result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(),
             result.failed_constraint_name);
 
   constraint_factory_.Reset();
   constraint_factory_.basic().googPowerLineFrequency.setMin(123467890);
   result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(),
             result.failed_constraint_name);
 
   constraint_factory_.Reset();
   constraint_factory_.basic().googPowerLineFrequency.setMax(-1);
   result = SelectSettings();
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_EQ(constraint_factory_.basic().googPowerLineFrequency.name(),
             result.failed_constraint_name);
 }
 
 // The "Mandatory" and "Ideal" tests check that various selection criteria work
 // for each individual constraint in the basic constraint set.
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryDeviceID) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryDeviceID) {
   constraint_factory_.Reset();
   constraint_factory_.basic().deviceId.setExact(
       blink::WebString::fromASCII(default_device_->device_id));
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
-  EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*default_closest_format_, result.settings.format());
+  EXPECT_TRUE(result.HasValue());
+  EXPECT_EQ(default_device_->device_id, result.device_id);
+  EXPECT_EQ(*default_closest_format_, result.Format());
   EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT,
-            result.settings.power_line_frequency());
+            result.PowerLineFrequency());
 
   constraint_factory_.basic().deviceId.setExact(
       blink::WebString::fromASCII(low_res_device_->device_id));
   result = SelectSettings();
-  EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*low_res_closest_format_, result.settings.format());
+  EXPECT_EQ(low_res_device_->device_id, result.device_id);
+  EXPECT_EQ(*low_res_closest_format_, result.Format());
   EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT,
-            result.settings.power_line_frequency());
+            result.PowerLineFrequency());
 
   constraint_factory_.basic().deviceId.setExact(
       blink::WebString::fromASCII(high_res_device_->device_id));
   result = SelectSettings();
-  EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*high_res_closest_format_, result.settings.format());
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(*high_res_closest_format_, result.Format());
   EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT,
-            result.settings.power_line_frequency());
+            result.PowerLineFrequency());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryFacingMode) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryFacingMode) {
   constraint_factory_.Reset();
   constraint_factory_.basic().facingMode.setExact(
       blink::WebString::fromASCII("environment"));
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
-  EXPECT_EQ(::mojom::FacingMode::ENVIRONMENT, result.settings.facing_mode());
+  EXPECT_TRUE(result.HasValue());
+  EXPECT_EQ(::mojom::FacingMode::ENVIRONMENT, result.facing_mode);
   // Only the low-res device supports environment facing mode. Should select
   // default settings for everything else.
-  EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*low_res_closest_format_, result.settings.format());
+  EXPECT_EQ(low_res_device_->device_id, result.device_id);
+  EXPECT_EQ(*low_res_closest_format_, result.Format());
   EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT,
-            result.settings.power_line_frequency());
+            result.PowerLineFrequency());
 
   constraint_factory_.basic().facingMode.setExact(
       blink::WebString::fromASCII("user"));
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
-  EXPECT_EQ(::mojom::FacingMode::USER, result.settings.facing_mode());
+  EXPECT_TRUE(result.HasValue());
+  EXPECT_EQ(::mojom::FacingMode::USER, result.facing_mode);
   // Only the high-res device supports user facing mode. Should select default
   // settings for everything else.
-  EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*high_res_closest_format_, result.settings.format());
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(*high_res_closest_format_, result.Format());
   EXPECT_EQ(media::PowerLineFrequency::FREQUENCY_DEFAULT,
-            result.settings.power_line_frequency());
+            result.PowerLineFrequency());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryVideoKind) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryVideoKind) {
   constraint_factory_.Reset();
   constraint_factory_.basic().videoKind.setExact(
       blink::WebString::fromASCII("depth"));
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
-  EXPECT_EQ(kDeviceID4, result.settings.device_id());
-  EXPECT_EQ(media::PIXEL_FORMAT_Y16, result.settings.format().pixel_format);
+  EXPECT_TRUE(result.HasValue());
+  EXPECT_EQ(kDeviceID4, result.device_id);
+  EXPECT_EQ(media::PIXEL_FORMAT_Y16, result.Format().pixel_format);
 
   constraint_factory_.basic().videoKind.setExact(
       blink::WebString::fromASCII("color"));
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
-  EXPECT_EQ(default_device_->device_id, result.settings.device_id());
+  EXPECT_TRUE(result.HasValue());
+  EXPECT_EQ(default_device_->device_id, result.device_id);
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryPowerLineFrequency) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryPowerLineFrequency) {
   constraint_factory_.Reset();
   const media::PowerLineFrequency kPowerLineFrequencies[] = {
       media::PowerLineFrequency::FREQUENCY_50HZ,
@@ -375,73 +375,73 @@
     constraint_factory_.basic().googPowerLineFrequency.setExact(
         static_cast<long>(power_line_frequency));
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
-    EXPECT_EQ(power_line_frequency, result.settings.power_line_frequency());
+    EXPECT_TRUE(result.HasValue());
+    EXPECT_EQ(power_line_frequency, result.PowerLineFrequency());
     // The default device and settings closest to the default should be
     // selected.
-    EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(default_device_->facing_mode, result.settings.facing_mode());
-    EXPECT_EQ(*default_closest_format_, result.settings.format());
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_EQ(default_device_->facing_mode, result.facing_mode);
+    EXPECT_EQ(*default_closest_format_, result.Format());
   }
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactHeight) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryExactHeight) {
   constraint_factory_.Reset();
   const int kHeight = MediaStreamVideoSource::kDefaultHeight;
   constraint_factory_.basic().height.setExact(kHeight);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // All devices in |capabilities_| support the requested height. The algorithm
   // should prefer the first device that supports the requested height natively,
   // which is the low-res device.
-  EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(kHeight, result.settings.GetHeight());
+  EXPECT_EQ(low_res_device_->device_id, result.device_id);
+  EXPECT_EQ(kHeight, result.Height());
 
   const int kLargeHeight = 1500;
   constraint_factory_.basic().height.setExact(kLargeHeight);
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // Only the high-res device at the highest resolution supports the requested
   // height, even if not natively.
-  EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*high_res_highest_format_, result.settings.format());
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(*high_res_highest_format_, result.Format());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinHeight) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMinHeight) {
   constraint_factory_.Reset();
   const int kHeight = MediaStreamVideoSource::kDefaultHeight;
   constraint_factory_.basic().height.setMin(kHeight);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // All devices in |capabilities_| support the requested height range. The
   // algorithm should prefer the default device.
-  EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-  EXPECT_LE(kHeight, result.settings.GetHeight());
+  EXPECT_EQ(default_device_->device_id, result.device_id);
+  EXPECT_LE(kHeight, result.Height());
 
   const int kLargeHeight = 1500;
   constraint_factory_.basic().height.setMin(kLargeHeight);
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // Only the high-res device at the highest resolution supports the requested
   // height range.
-  EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*high_res_highest_format_, result.settings.format());
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(*high_res_highest_format_, result.Format());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxHeight) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMaxHeight) {
   constraint_factory_.Reset();
   const int kLowHeight = 20;
   constraint_factory_.basic().height.setMax(kLowHeight);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // All devices in |capabilities_| support the requested height range. The
   // algorithm should prefer the settings that natively exceed the requested
   // maximum by the lowest amount. In this case it is the low-res device.
-  EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(low_res_device_->formats[0], result.settings.format());
+  EXPECT_EQ(low_res_device_->device_id, result.device_id);
+  EXPECT_EQ(low_res_device_->formats[0], result.Format());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryHeightRange) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryHeightRange) {
   constraint_factory_.Reset();
   {
     const int kMinHeight = 480;
@@ -449,15 +449,15 @@
     constraint_factory_.basic().height.setMin(kMinHeight);
     constraint_factory_.basic().height.setMax(kMaxHeight);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
-    EXPECT_GE(result.settings.GetHeight(), kMinHeight);
-    EXPECT_LE(result.settings.GetHeight(), kMaxHeight);
+    EXPECT_TRUE(result.HasValue());
+    EXPECT_GE(result.Height(), kMinHeight);
+    EXPECT_LE(result.Height(), kMaxHeight);
     // All devices in |capabilities_| support the constraint range. The
     // algorithm should prefer the default device since it has at least one
     // native format (the closest-to-default format) included in the requested
     // range.
-    EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*default_closest_format_, result.settings.format());
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_EQ(*default_closest_format_, result.Format());
   }
 
   {
@@ -466,15 +466,15 @@
     constraint_factory_.basic().height.setMin(kMinHeight);
     constraint_factory_.basic().height.setMax(kMaxHeight);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
-    EXPECT_GE(result.settings.GetHeight(), kMinHeight);
-    EXPECT_LE(result.settings.GetHeight(), kMaxHeight);
+    EXPECT_TRUE(result.HasValue());
+    EXPECT_GE(result.Height(), kMinHeight);
+    EXPECT_LE(result.Height(), kMaxHeight);
     // In this case, the algorithm should prefer the low-res device since it is
     // the first device with a native format (800x600) included in the requested
     // range.
-    EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(800, result.settings.GetWidth());
-    EXPECT_EQ(600, result.settings.GetHeight());
+    EXPECT_EQ(low_res_device_->device_id, result.device_id);
+    EXPECT_EQ(800, result.Width());
+    EXPECT_EQ(600, result.Height());
   }
 
   {
@@ -483,132 +483,132 @@
     constraint_factory_.basic().height.setMin(kMinHeight);
     constraint_factory_.basic().height.setMax(kMaxHeight);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
-    EXPECT_GE(result.settings.GetHeight(), kMinHeight);
-    EXPECT_LE(result.settings.GetHeight(), kMaxHeight);
+    EXPECT_TRUE(result.HasValue());
+    EXPECT_GE(result.Height(), kMinHeight);
+    EXPECT_LE(result.Height(), kMaxHeight);
     // In this case, the algorithm should prefer the high-res device since it is
     // the only device with a native format (1280x720) included in the requested
     // range.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1280, result.settings.GetWidth());
-    EXPECT_EQ(720, result.settings.GetHeight());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1280, result.Width());
+    EXPECT_EQ(720, result.Height());
   }
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealHeight) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealHeight) {
   constraint_factory_.Reset();
   {
     const int kIdealHeight = 480;
     constraint_factory_.basic().height.setIdeal(kIdealHeight);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The algorithm should select the first device that supports the ideal
     // height natively.
-    EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(kIdealHeight, result.settings.GetHeight());
+    EXPECT_EQ(low_res_device_->device_id, result.device_id);
+    EXPECT_EQ(kIdealHeight, result.Height());
   }
 
   {
     const int kIdealHeight = 481;
     constraint_factory_.basic().height.setIdeal(kIdealHeight);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // In this case, the default device is selected because it can satisfy the
     // ideal at a lower cost than the other devices (500 vs 600 or 720).
     // Note that a native resolution of 480 is further from the ideal than
     // 500 cropped to 480.
-    EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*default_closest_format_, result.settings.format());
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_EQ(*default_closest_format_, result.Format());
   }
 
   {
     const int kIdealHeight = 1079;
     constraint_factory_.basic().height.setIdeal(kIdealHeight);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // In this case, the high-res device has two configurations that satisfy
     // the ideal value (1920x1080 and 2304x1536). Select the one with shortest
     // native distance to the ideal value (1920x1080).
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1920, result.settings.GetWidth());
-    EXPECT_EQ(1080, result.settings.GetHeight());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1920, result.Width());
+    EXPECT_EQ(1080, result.Height());
   }
 
   {
     const int kIdealHeight = 1200;
     constraint_factory_.basic().height.setIdeal(kIdealHeight);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The algorithm must the select the only device that can satisfy the ideal,
     // which is the high-res device at the highest resolution.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*high_res_highest_format_, result.settings.format());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(*high_res_highest_format_, result.Format());
   }
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactWidth) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryExactWidth) {
   constraint_factory_.Reset();
   const int kWidth = 640;
   constraint_factory_.basic().width.setExact(kWidth);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // All devices in |capabilities_| support the requested width. The algorithm
   // should prefer the first device that supports the requested width natively,
   // which is the low-res device.
-  EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(kWidth, result.settings.GetWidth());
+  EXPECT_EQ(low_res_device_->device_id, result.device_id);
+  EXPECT_EQ(kWidth, result.Width());
 
   const int kLargeWidth = 2000;
   constraint_factory_.basic().width.setExact(kLargeWidth);
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
-  EXPECT_LE(kLargeWidth, result.settings.GetWidth());
+  EXPECT_TRUE(result.HasValue());
+  EXPECT_LE(kLargeWidth, result.Width());
   // Only the high-res device at the highest resolution supports the requested
   // width, even if not natively.
-  EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*high_res_highest_format_, result.settings.format());
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(*high_res_highest_format_, result.Format());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinWidth) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMinWidth) {
   constraint_factory_.Reset();
   const int kWidth = 640;
   constraint_factory_.basic().width.setMin(kWidth);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // All devices in |capabilities_| support the requested width range. The
   // algorithm should prefer the default device at 1000x1000, which is the
   // first configuration that satisfies the minimum width.
-  EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-  EXPECT_LE(kWidth, result.settings.GetWidth());
-  EXPECT_EQ(1000, result.settings.GetWidth());
-  EXPECT_EQ(1000, result.settings.GetHeight());
+  EXPECT_EQ(default_device_->device_id, result.device_id);
+  EXPECT_LE(kWidth, result.Width());
+  EXPECT_EQ(1000, result.Width());
+  EXPECT_EQ(1000, result.Height());
 
   const int kLargeWidth = 2000;
   constraint_factory_.basic().width.setMin(kLargeWidth);
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // Only the high-res device at the highest resolution supports the requested
   // minimum width.
-  EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-  EXPECT_LE(kLargeWidth, result.settings.GetWidth());
-  EXPECT_EQ(*high_res_highest_format_, result.settings.format());
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_LE(kLargeWidth, result.Width());
+  EXPECT_EQ(*high_res_highest_format_, result.Format());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxWidth) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMaxWidth) {
   constraint_factory_.Reset();
   const int kLowWidth = 30;
   constraint_factory_.basic().width.setMax(kLowWidth);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // All devices in |capabilities_| support the requested width range. The
   // algorithm should prefer the settings that natively exceed the requested
   // maximum by the lowest amount. In this case it is the low-res device at its
   // lowest resolution.
-  EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(low_res_device_->formats[0], result.settings.format());
+  EXPECT_EQ(low_res_device_->device_id, result.device_id);
+  EXPECT_EQ(low_res_device_->formats[0], result.Format());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryWidthRange) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryWidthRange) {
   constraint_factory_.Reset();
   {
     const int kMinWidth = 640;
@@ -616,15 +616,15 @@
     constraint_factory_.basic().width.setMin(kMinWidth);
     constraint_factory_.basic().width.setMax(kMaxWidth);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
-    EXPECT_GE(result.settings.GetWidth(), kMinWidth);
-    EXPECT_LE(result.settings.GetWidth(), kMaxWidth);
+    EXPECT_TRUE(result.HasValue());
+    EXPECT_GE(result.Width(), kMinWidth);
+    EXPECT_LE(result.Width(), kMaxWidth);
     // All devices in |capabilities_| support the constraint range. The
     // algorithm should prefer the default device since it has at least one
     // native format (1000x1000) included in the requested range.
-    EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1000, result.settings.GetWidth());
-    EXPECT_EQ(1000, result.settings.GetHeight());
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_EQ(1000, result.Width());
+    EXPECT_EQ(1000, result.Height());
   }
 
   {
@@ -633,15 +633,15 @@
     constraint_factory_.basic().width.setMin(kMinWidth);
     constraint_factory_.basic().width.setMax(kMaxWidth);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
-    EXPECT_GE(result.settings.GetWidth(), kMinWidth);
-    EXPECT_LE(result.settings.GetWidth(), kMaxWidth);
+    EXPECT_TRUE(result.HasValue());
+    EXPECT_GE(result.Width(), kMinWidth);
+    EXPECT_LE(result.Width(), kMaxWidth);
     // In this case, the algorithm should prefer the low-res device since it is
     // the first device with a native format (800x600) included in the requested
     // range.
-    EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(800, result.settings.GetWidth());
-    EXPECT_EQ(600, result.settings.GetHeight());
+    EXPECT_EQ(low_res_device_->device_id, result.device_id);
+    EXPECT_EQ(800, result.Width());
+    EXPECT_EQ(600, result.Height());
   }
 
   {
@@ -650,135 +650,134 @@
     constraint_factory_.basic().width.setMin(kMinWidth);
     constraint_factory_.basic().width.setMax(kMaxWidth);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
-    EXPECT_GE(result.settings.GetWidth(), kMinWidth);
-    EXPECT_LE(result.settings.GetWidth(), kMaxWidth);
+    EXPECT_TRUE(result.HasValue());
+    EXPECT_GE(result.Width(), kMinWidth);
+    EXPECT_LE(result.Width(), kMaxWidth);
     // In this case, the algorithm should prefer the high-res device since it is
     // the only device with a native format (1920x1080) included in the
     // requested range.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1920, result.settings.GetWidth());
-    EXPECT_EQ(1080, result.settings.GetHeight());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1920, result.Width());
+    EXPECT_EQ(1080, result.Height());
   }
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealWidth) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealWidth) {
   constraint_factory_.Reset();
   {
     const int kIdealWidth = 320;
     constraint_factory_.basic().width.setIdeal(kIdealWidth);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The algorithm should select the first device that supports the ideal
     // width natively, which is the low-res device at 320x240.
-    EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(kIdealWidth, result.settings.GetWidth());
+    EXPECT_EQ(low_res_device_->device_id, result.device_id);
+    EXPECT_EQ(kIdealWidth, result.Width());
   }
 
   {
     const int kIdealWidth = 321;
     constraint_factory_.basic().width.setIdeal(kIdealWidth);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // In this case, the default device is selected because it can satisfy the
     // ideal at a lower cost than the other devices (500 vs 640).
     // Note that a native resolution of 320 is further from the ideal value of
     // 321 than 500 cropped to 321.
-    EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*default_closest_format_, result.settings.format());
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_EQ(*default_closest_format_, result.Format());
   }
 
   {
     const int kIdealWidth = 2000;
     constraint_factory_.basic().width.setIdeal(kIdealWidth);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The algorithm must the select the only device that can satisfy the ideal.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*high_res_highest_format_, result.settings.format());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(*high_res_highest_format_, result.Format());
   }
 
   {
     const int kIdealWidth = 3000;
     constraint_factory_.basic().width.setIdeal(kIdealWidth);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The algorithm must the select the device and setting with less distance
     // to the ideal.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*high_res_highest_format_, result.settings.format());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(*high_res_highest_format_, result.Format());
   }
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactFrameRate) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryExactFrameRate) {
   constraint_factory_.Reset();
   const double kFrameRate = MediaStreamVideoSource::kDefaultFrameRate;
   constraint_factory_.basic().frameRate.setExact(kFrameRate);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // All devices in |capabilities_| support the requested frame rate. The
   // algorithm should prefer the first device that supports the requested frame
   // rate natively, which is the low-res device at 640x480x30Hz.
-  EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(kFrameRate, result.settings.GetFrameRate());
-  EXPECT_EQ(640, result.settings.GetWidth());
-  EXPECT_EQ(480, result.settings.GetHeight());
+  EXPECT_EQ(low_res_device_->device_id, result.device_id);
+  EXPECT_EQ(kFrameRate, result.FrameRate());
+  EXPECT_EQ(640, result.Width());
+  EXPECT_EQ(480, result.Height());
 
   const double kLargeFrameRate = 50;
   constraint_factory_.basic().frameRate.setExact(kLargeFrameRate);
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // Only the high-res device supports the requested frame rate, even if not
   // natively. The least expensive configuration that supports the requested
   // frame rate is 1280x720x60Hz.
-  EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(60.0, result.settings.GetFrameRate());
-  EXPECT_EQ(1280, result.settings.GetWidth());
-  EXPECT_EQ(720, result.settings.GetHeight());
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(60.0, result.FrameRate());
+  EXPECT_EQ(1280, result.Width());
+  EXPECT_EQ(720, result.Height());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinFrameRate) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMinFrameRate) {
   constraint_factory_.Reset();
   const double kFrameRate = MediaStreamVideoSource::kDefaultFrameRate;
   constraint_factory_.basic().frameRate.setMin(kFrameRate);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // All devices in |capabilities_| support the requested frame-rate range. The
   // algorithm should prefer the default device.
-  EXPECT_EQ(default_device_->device_id, result.settings.device_id());
+  EXPECT_EQ(default_device_->device_id, result.device_id);
   // The format closest to the default satisfies the constraint.
-  EXPECT_EQ(*default_closest_format_, result.settings.format());
+  EXPECT_EQ(*default_closest_format_, result.Format());
 
   const double kLargeFrameRate = 50;
   constraint_factory_.basic().frameRate.setMin(kLargeFrameRate);
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // Only the high-res device supports the requested frame-rate range.
   // The least expensive configuration is 1280x720x60Hz.
-  EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-  EXPECT_LE(kLargeFrameRate, result.settings.GetFrameRate());
-  EXPECT_EQ(1280, result.settings.GetWidth());
-  EXPECT_EQ(720, result.settings.GetHeight());
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_LE(kLargeFrameRate, result.FrameRate());
+  EXPECT_EQ(1280, result.Width());
+  EXPECT_EQ(720, result.Height());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxFrameRate) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMaxFrameRate) {
   constraint_factory_.Reset();
   const double kLowFrameRate = 10;
   constraint_factory_.basic().frameRate.setMax(kLowFrameRate);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   // All devices in |capabilities_| support the requested frame-rate range. The
   // algorithm should prefer the settings that natively exceed the requested
   // maximum by the lowest amount. In this case it is the high-res device with
   // default resolution .
-  EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(kLowFrameRate, result.settings.GetFrameRate());
-  EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight,
-            result.settings.GetHeight());
-  EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.settings.GetWidth());
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(kLowFrameRate, result.FrameRate());
+  EXPECT_EQ(MediaStreamVideoSource::kDefaultHeight, result.Height());
+  EXPECT_EQ(MediaStreamVideoSource::kDefaultWidth, result.Width());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryFrameRateRange) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryFrameRateRange) {
   constraint_factory_.Reset();
   {
     const double kMinFrameRate = 10;
@@ -786,14 +785,14 @@
     constraint_factory_.basic().frameRate.setMin(kMinFrameRate);
     constraint_factory_.basic().frameRate.setMax(kMaxFrameRate);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
-    EXPECT_LE(kMinFrameRate, result.settings.GetFrameRate());
-    EXPECT_GE(kMaxFrameRate, result.settings.GetFrameRate());
+    EXPECT_TRUE(result.HasValue());
+    EXPECT_LE(kMinFrameRate, result.FrameRate());
+    EXPECT_GE(kMaxFrameRate, result.FrameRate());
     // All devices in |capabilities_| support the constraint range. The
     // algorithm should prefer the default device since its closest-to-default
     // format has a frame rate included in the requested range.
-    EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*default_closest_format_, result.settings.format());
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_EQ(*default_closest_format_, result.Format());
   }
 
   {
@@ -802,14 +801,14 @@
     constraint_factory_.basic().frameRate.setMin(kMinFrameRate);
     constraint_factory_.basic().frameRate.setMax(kMaxFrameRate);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
-    EXPECT_GE(result.settings.GetFrameRate(), kMinFrameRate);
-    EXPECT_LE(result.settings.GetFrameRate(), kMaxFrameRate);
+    EXPECT_TRUE(result.HasValue());
+    EXPECT_GE(result.FrameRate(), kMinFrameRate);
+    EXPECT_LE(result.FrameRate(), kMaxFrameRate);
     // In this case, the algorithm should prefer the low-res device since it is
     // the first device with a native frame rate included in the requested
     // range. The default resolution should be preferred as secondary criterion.
-    EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*low_res_closest_format_, result.settings.format());
+    EXPECT_EQ(low_res_device_->device_id, result.device_id);
+    EXPECT_EQ(*low_res_closest_format_, result.Format());
   }
 
   {
@@ -818,86 +817,86 @@
     constraint_factory_.basic().frameRate.setMin(kMinFrameRate);
     constraint_factory_.basic().frameRate.setMax(kMaxFrameRate);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
-    EXPECT_GE(result.settings.GetFrameRate(), kMinFrameRate);
-    EXPECT_LE(result.settings.GetFrameRate(), kMaxFrameRate);
+    EXPECT_TRUE(result.HasValue());
+    EXPECT_GE(result.FrameRate(), kMinFrameRate);
+    EXPECT_LE(result.FrameRate(), kMaxFrameRate);
     // In this case, the algorithm should prefer the high-res device since it is
     // the only device with a native format included in the requested range.
     // The 1280x720 resolution should be selected due to closeness to default
     // settings, which is the second tie-breaker criterion that applies.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1280, result.settings.GetWidth());
-    EXPECT_EQ(720, result.settings.GetHeight());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1280, result.Width());
+    EXPECT_EQ(720, result.Height());
   }
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealFrameRate) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealFrameRate) {
   constraint_factory_.Reset();
   {
     const double kIdealFrameRate = MediaStreamVideoSource::kDefaultFrameRate;
     constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The algorithm should select the first configuration that supports the
     // ideal frame rate natively, which is the low-res device. Default
     // resolution should be selected as secondary criterion.
-    EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*low_res_closest_format_, result.settings.format());
+    EXPECT_EQ(low_res_device_->device_id, result.device_id);
+    EXPECT_EQ(*low_res_closest_format_, result.Format());
   }
 
   {
     const double kIdealFrameRate = 31;
     constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // In this case, the default device is selected because it can satisfy the
     // ideal at a lower cost than the other devices (40 vs 60).
     // Note that a native frame rate of 30 is further from the ideal than
     // 31 adjusted to 30.
-    EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*default_closest_format_, result.settings.format());
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_EQ(*default_closest_format_, result.Format());
   }
 
   {
     const double kIdealFrameRate = 55;
     constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The high-res device format 1280x720x60.0 must be selected because its
     // frame rate can satisfy the ideal frame rate and has resolution closest
     // to the default.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1280, result.settings.GetWidth());
-    EXPECT_EQ(720, result.settings.GetHeight());
-    EXPECT_EQ(60, result.settings.GetFrameRate());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1280, result.Width());
+    EXPECT_EQ(720, result.Height());
+    EXPECT_EQ(60, result.FrameRate());
   }
 
   {
     const double kIdealFrameRate = 100;
     constraint_factory_.basic().frameRate.setIdeal(kIdealFrameRate);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The algorithm must select settings with frame rate closest to the ideal.
     // The high-res device format 1280x720x60.0 must be selected because its
     // frame rate it closest to the ideal value and it has resolution closest to
     // the default.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1280, result.settings.GetWidth());
-    EXPECT_EQ(720, result.settings.GetHeight());
-    EXPECT_EQ(60, result.settings.GetFrameRate());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1280, result.Width());
+    EXPECT_EQ(720, result.Height());
+    EXPECT_EQ(60, result.FrameRate());
   }
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryExactAspectRatio) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryExactAspectRatio) {
   constraint_factory_.Reset();
   const double kAspectRatio = 4.0 / 3.0;
   constraint_factory_.basic().aspectRatio.setExact(kAspectRatio);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   double min_width = 1.0;
-  double max_width = result.settings.GetWidth();
+  double max_width = result.Width();
   double min_height = 1.0;
-  double max_height = result.settings.GetHeight();
+  double max_height = result.Height();
   double min_aspect_ratio = min_width / max_height;
   double max_aspect_ratio = max_width / min_height;
   // The requested aspect ratio must be within the supported range.
@@ -906,22 +905,22 @@
   // All devices in |capabilities_| support the requested aspect ratio.
   // The algorithm should prefer the first device that supports the requested
   // aspect ratio.
-  EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*default_closest_format_, result.settings.format());
+  EXPECT_EQ(default_device_->device_id, result.device_id);
+  EXPECT_EQ(*default_closest_format_, result.Format());
 
-  const long kMinWidth = 500;
-  const long kMaxWidth = 1000;
-  const long kMaxHeight = 500;
+  const int kMinWidth = 500;
+  const int kMaxWidth = 1000;
+  const int kMaxHeight = 500;
   constraint_factory_.basic().height.setMax(kMaxHeight);
   constraint_factory_.basic().width.setMin(kMinWidth);
   constraint_factory_.basic().width.setMax(kMaxWidth);
   constraint_factory_.basic().aspectRatio.setExact(kAspectRatio);
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
-  min_width = std::max(1L, kMinWidth);
-  max_width = std::min(result.settings.GetWidth(), kMaxWidth);
+  EXPECT_TRUE(result.HasValue());
+  min_width = std::max(1, kMinWidth);
+  max_width = std::min(result.Width(), kMaxWidth);
   min_height = 1.0;
-  max_height = std::min(result.settings.GetHeight(), kMaxHeight);
+  max_height = std::min(result.Height(), kMaxHeight);
   min_aspect_ratio = min_width / max_height;
   max_aspect_ratio = max_width / min_height;
   // The requested aspect ratio must be within the supported range.
@@ -929,21 +928,21 @@
   EXPECT_LE(kAspectRatio, max_aspect_ratio);
   // The default device can support the requested aspect ratio with the default
   // settings (500x500) using cropping.
-  EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*default_closest_format_, result.settings.format());
+  EXPECT_EQ(default_device_->device_id, result.device_id);
+  EXPECT_EQ(*default_closest_format_, result.Format());
 
-  const long kMinHeight = 480;
+  const int kMinHeight = 480;
   constraint_factory_.basic().height.setMin(kMinHeight);
   constraint_factory_.basic().height.setMax(kMaxHeight);
   constraint_factory_.basic().width.setMin(kMinWidth);
   constraint_factory_.basic().width.setMax(kMaxWidth);
   constraint_factory_.basic().aspectRatio.setExact(kAspectRatio);
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
-  min_width = std::max(1L, kMinWidth);
-  max_width = std::min(result.settings.GetWidth(), kMaxWidth);
-  min_height = std::max(1L, kMinHeight);
-  max_height = std::min(result.settings.GetHeight(), kMaxHeight);
+  EXPECT_TRUE(result.HasValue());
+  min_width = std::max(1, kMinWidth);
+  max_width = std::min(result.Width(), kMaxWidth);
+  min_height = std::max(1, kMinHeight);
+  max_height = std::min(result.Height(), kMaxHeight);
   min_aspect_ratio = min_width / max_height;
   max_aspect_ratio = max_width / min_height;
   // The requested aspect ratio must be within the supported range.
@@ -955,17 +954,17 @@
   // resolution of 640x480. Higher resolutions for the default device are more
   // penalized by the constraints than the default native resolution of the
   // low-res device.
-  EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*low_res_closest_format_, result.settings.format());
+  EXPECT_EQ(low_res_device_->device_id, result.device_id);
+  EXPECT_EQ(*low_res_closest_format_, result.Format());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMinAspectRatio) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMinAspectRatio) {
   constraint_factory_.Reset();
   const double kAspectRatio = 4.0 / 3.0;
   constraint_factory_.basic().aspectRatio.setMin(kAspectRatio);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
-  double max_width = result.settings.GetWidth();
+  EXPECT_TRUE(result.HasValue());
+  double max_width = result.Width();
   double min_height = 1.0;
   double max_aspect_ratio = max_width / min_height;
   // Minimum constraint aspect ratio must be less than or equal to the maximum
@@ -974,22 +973,22 @@
   // All devices in |capabilities_| support the requested aspect-ratio range.
   // The algorithm should prefer the first device that supports the requested
   // aspect-ratio range, which in this case is the default device.
-  EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*default_closest_format_, result.settings.format());
+  EXPECT_EQ(default_device_->device_id, result.device_id);
+  EXPECT_EQ(*default_closest_format_, result.Format());
 
-  const long kMinWidth = 500;
-  const long kMaxWidth = 1000;
-  const long kMinHeight = 480;
-  const long kMaxHeight = 500;
+  const int kMinWidth = 500;
+  const int kMaxWidth = 1000;
+  const int kMinHeight = 480;
+  const int kMaxHeight = 500;
   constraint_factory_.basic().width.setMin(kMinWidth);
   constraint_factory_.basic().width.setMax(kMaxWidth);
   constraint_factory_.basic().height.setMin(kMinHeight);
   constraint_factory_.basic().height.setMax(kMaxHeight);
   constraint_factory_.basic().aspectRatio.setMin(kAspectRatio);
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
-  max_width = std::min(result.settings.GetWidth(), kMaxWidth);
-  min_height = std::max(1L, kMinHeight);
+  EXPECT_TRUE(result.HasValue());
+  max_width = std::min(result.Width(), kMaxWidth);
+  min_height = std::max(1, kMinHeight);
   max_aspect_ratio = max_width / min_height;
   // Minimum constraint aspect ratio must be less than or equal to the minimum
   // supported by the source.
@@ -1000,18 +999,18 @@
   // resolution of 640x480.
   // Higher resolutions for the default device are more penalized by the
   // constraints than the default native resolution of the low-res device.
-  EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*low_res_closest_format_, result.settings.format());
+  EXPECT_EQ(low_res_device_->device_id, result.device_id);
+  EXPECT_EQ(*low_res_closest_format_, result.Format());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryMaxAspectRatio) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryMaxAspectRatio) {
   constraint_factory_.Reset();
   const double kAspectRatio = 0.5;
   constraint_factory_.basic().aspectRatio.setMax(kAspectRatio);
   auto result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
+  EXPECT_TRUE(result.HasValue());
   double min_width = 1.0;
-  double max_height = result.settings.GetHeight();
+  double max_height = result.Height();
   double min_aspect_ratio = min_width / max_height;
   // Minimum constraint aspect ratio must be less than or equal to the maximum
   // supported by the source.
@@ -1019,20 +1018,20 @@
   // All devices in |capabilities_| support the requested aspect-ratio range.
   // The algorithm should prefer the first device that supports the requested
   // aspect-ratio range, which in this case is the default device.
-  EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(*default_closest_format_, result.settings.format());
+  EXPECT_EQ(default_device_->device_id, result.device_id);
+  EXPECT_EQ(*default_closest_format_, result.Format());
 
-  const long kExactWidth = 360;
-  const long kMinHeight = 360;
-  const long kMaxHeight = 720;
+  const int kExactWidth = 360;
+  const int kMinHeight = 360;
+  const int kMaxHeight = 720;
   constraint_factory_.basic().width.setExact(kExactWidth);
   constraint_factory_.basic().height.setMin(kMinHeight);
   constraint_factory_.basic().height.setMax(kMaxHeight);
   constraint_factory_.basic().aspectRatio.setMax(kAspectRatio);
   result = SelectSettings();
-  EXPECT_TRUE(result.has_value());
-  min_width = std::max(1L, kExactWidth);
-  max_height = std::min(result.settings.GetHeight(), kMaxHeight);
+  EXPECT_TRUE(result.HasValue());
+  min_width = std::max(1, kExactWidth);
+  max_height = std::min(result.Height(), kMaxHeight);
   min_aspect_ratio = min_width / max_height;
   // Minimum constraint aspect ratio must be less than or equal to the minimum
   // supported by the source.
@@ -1043,12 +1042,12 @@
   // The high-res device with a native resolution of 1280x720 can support
   // 360x720 with cropping with less penalty than the default device at
   // 1000x1000.
-  EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-  EXPECT_EQ(1280, result.settings.GetWidth());
-  EXPECT_EQ(720, result.settings.GetHeight());
+  EXPECT_EQ(high_res_device_->device_id, result.device_id);
+  EXPECT_EQ(1280, result.Width());
+  EXPECT_EQ(720, result.Height());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, MandatoryAspectRatioRange) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, MandatoryAspectRatioRange) {
   constraint_factory_.Reset();
   {
     const double kMinAspectRatio = 0.5;
@@ -1057,11 +1056,11 @@
     constraint_factory_.basic().aspectRatio.setMin(kMinAspectRatio);
     constraint_factory_.basic().aspectRatio.setMax(kMaxAspectRatio);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     double min_width = 1.0;
-    double max_width = result.settings.GetWidth();
+    double max_width = result.Width();
     double min_height = 1.0;
-    double max_height = result.settings.GetHeight();
+    double max_height = result.Height();
     double min_aspect_ratio = min_width / max_height;
     double max_aspect_ratio = max_width / min_height;
     // Constraint aspect-ratio range must have nonempty intersection with
@@ -1071,8 +1070,8 @@
     // All devices in |capabilities_| support the requested aspect-ratio range.
     // The algorithm should prefer the first device that supports the requested
     // aspect-ratio range, which in this case is the default device.
-    EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*default_closest_format_, result.settings.format());
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_EQ(*default_closest_format_, result.Format());
   }
 
   {
@@ -1085,11 +1084,11 @@
     constraint_factory_.basic().aspectRatio.setMin(kMinAspectRatio);
     constraint_factory_.basic().aspectRatio.setMax(kMaxAspectRatio);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     double min_width = 1.0;
-    double max_width = result.settings.GetWidth();
+    double max_width = result.Width();
     double min_height = 1.0;
-    double max_height = result.settings.GetHeight();
+    double max_height = result.Height();
     double min_aspect_ratio = min_width / max_height;
     double max_aspect_ratio = max_width / min_height;
     // Constraint aspect-ratio range must have nonempty intersection with
@@ -1098,23 +1097,23 @@
     EXPECT_GE(kMaxAspectRatio, min_aspect_ratio);
     // The only device that supports the resolution and aspect ratio constraint
     // is the high-res device. The 1920x1080 is the least expensive format.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1920, result.settings.GetWidth());
-    EXPECT_EQ(1080, result.settings.GetHeight());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1920, result.Width());
+    EXPECT_EQ(1080, result.Height());
   }
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, IdealAspectRatio) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, IdealAspectRatio) {
   constraint_factory_.Reset();
   {
     const double kIdealAspectRatio = 0.5;
     constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     double min_width = 1.0;
-    double max_width = result.settings.GetWidth();
+    double max_width = result.Width();
     double min_height = 1.0;
-    double max_height = result.settings.GetHeight();
+    double max_height = result.Height();
     double min_aspect_ratio = min_width / max_height;
     double max_aspect_ratio = max_width / min_height;
     // All devices in |capabilities_| support the ideal aspect-ratio.
@@ -1122,43 +1121,43 @@
     // settings.
     EXPECT_LE(kIdealAspectRatio, max_aspect_ratio);
     EXPECT_GE(kIdealAspectRatio, min_aspect_ratio);
-    EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*default_closest_format_, result.settings.format());
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_EQ(*default_closest_format_, result.Format());
   }
 
   {
     const double kIdealAspectRatio = 1500.0;
     constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The only device that supports the ideal aspect ratio is the high-res
     // device. The least expensive way to support it with the 1920x1080 format
     // cropped to 1500x1.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1920, result.settings.GetWidth());
-    EXPECT_EQ(1080, result.settings.GetHeight());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1920, result.Width());
+    EXPECT_EQ(1080, result.Height());
   }
 
   {
     const double kIdealAspectRatio = 2000.0;
     constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The only device that supports the ideal aspect ratio is the high-res
     // device with its highest resolution, cropped to 2000x1.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*high_res_highest_format_, result.settings.format());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(*high_res_highest_format_, result.Format());
   }
 
   {
     const double kIdealAspectRatio = 4000.0;
     constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The configuration closest to the ideal aspect ratio is is the high-res
     // device with its highest resolution, cropped to 2304x1.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*high_res_highest_format_, result.settings.format());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(*high_res_highest_format_, result.Format());
   }
 
   {
@@ -1166,13 +1165,13 @@
     constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio);
     constraint_factory_.basic().height.setExact(400);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The first device to support the ideal aspect ratio and the resolution
     // constraint is the low-res device. The 800x600 format cropped to 800x400
     // is the lest expensive way to achieve it.
-    EXPECT_EQ(low_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(800, result.settings.GetWidth());
-    EXPECT_EQ(600, result.settings.GetHeight());
+    EXPECT_EQ(low_res_device_->device_id, result.device_id);
+    EXPECT_EQ(800, result.Width());
+    EXPECT_EQ(600, result.Height());
   }
 
   {
@@ -1180,19 +1179,19 @@
     constraint_factory_.basic().aspectRatio.setIdeal(kIdealAspectRatio);
     constraint_factory_.basic().height.setExact(400);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The only device that supports the ideal aspect ratio and the resolution
     // constraint is the high-res device. The 1280x720 cropped to 1200x400 is
     // the lest expensive way to achieve it.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1280, result.settings.GetWidth());
-    EXPECT_EQ(720, result.settings.GetHeight());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1280, result.Width());
+    EXPECT_EQ(720, result.Height());
   }
 }
 
 // The "Advanced" tests check selection criteria involving advanced constraint
 // sets.
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, AdvancedExactResolution) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, AdvancedExactResolution) {
   {
     constraint_factory_.Reset();
     blink::WebMediaTrackConstraintSet& advanced1 =
@@ -1206,62 +1205,62 @@
     auto result = SelectSettings();
     // No device supports the advanced constraint sets.
     // Tie-breaker rule that applies is closeness to default settings.
-    EXPECT_EQ(default_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*default_closest_format_, result.settings.format());
+    EXPECT_EQ(default_device_->device_id, result.device_id);
+    EXPECT_EQ(*default_closest_format_, result.Format());
 
     blink::WebMediaTrackConstraintSet& advanced3 =
         constraint_factory_.AddAdvanced();
     advanced3.width.setExact(1920);
     advanced3.height.setExact(1080);
     result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The high-res device natively supports the third advanced constraint set
     // and should be selected.
     // First tie-breaker rule that applies is support for advanced constraints
     // that appear first. Second tie-breaker rule is custom distance to advanced
     // constraint sets that appear first.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1920, result.settings.GetWidth());
-    EXPECT_EQ(1080, result.settings.GetHeight());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1920, result.Width());
+    EXPECT_EQ(1080, result.Height());
 
     blink::WebMediaTrackConstraintSet& advanced4 =
         constraint_factory_.AddAdvanced();
     advanced4.width.setExact(640);
     advanced4.height.setExact(480);
     result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // First tie-breaker rule that applies is support for advanced constraints
     // that appear first, which leaves out configurations that only support the
     // fourth advanced constraint set in favor of configurations that support
     // the third set.
     // Second tie-breaker rule is custom distance to advanced constraint sets
     // that appear first.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1920, result.settings.GetWidth());
-    EXPECT_EQ(1080, result.settings.GetHeight());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1920, result.Width());
+    EXPECT_EQ(1080, result.Height());
 
     constraint_factory_.basic().width.setIdeal(800);
     constraint_factory_.basic().height.setIdeal(600);
     result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The ideal value is supported by the same configuration, so nothing
     // changes.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1920, result.settings.GetWidth());
-    EXPECT_EQ(1080, result.settings.GetHeight());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1920, result.Width());
+    EXPECT_EQ(1080, result.Height());
 
     constraint_factory_.basic().width.setIdeal(2000);
     constraint_factory_.basic().height.setIdeal(1500);
     result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The closest configuration to the ideal resolution is the high-res device
     // at the highest resolution.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(*high_res_highest_format_, result.settings.format());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(*high_res_highest_format_, result.Format());
   }
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest,
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest,
        AdvancedResolutionAndFrameRate) {
   {
     constraint_factory_.Reset();
@@ -1277,36 +1276,36 @@
     advanced3.width.setExact(2304);
     advanced3.height.setExact(1536);
     auto result = SelectSettings();
-    EXPECT_TRUE(result.has_value());
+    EXPECT_TRUE(result.HasValue());
     // The high-res device is the only one that satisfies the first advanced
     // set. 2304x1536x10.0 satisfies sets 1 and 3, while 1920x1080x60.0
     // satisfies sets 1, and 2. The latter must be selected, regardless of
     // any other criteria.
-    EXPECT_EQ(high_res_device_->device_id, result.settings.device_id());
-    EXPECT_EQ(1920, result.settings.GetWidth());
-    EXPECT_EQ(1080, result.settings.GetHeight());
-    EXPECT_EQ(60.0, result.settings.GetFrameRate());
+    EXPECT_EQ(high_res_device_->device_id, result.device_id);
+    EXPECT_EQ(1920, result.Width());
+    EXPECT_EQ(1080, result.Height());
+    EXPECT_EQ(60.0, result.FrameRate());
   }
 }
 
 // The "NoDevices" tests verify that the algorithm returns the expected result
 // when there are no candidates to choose from.
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, NoDevicesNoConstraints) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, NoDevicesNoConstraints) {
   constraint_factory_.Reset();
-  VideoCaptureCapabilities capabilities;
-  auto result = SelectVideoCaptureSourceSettings(
+  VideoDeviceCaptureCapabilities capabilities;
+  auto result = SelectVideoDeviceCaptureSourceSettings(
       capabilities, constraint_factory_.CreateWebMediaConstraints());
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_TRUE(std::string(result.failed_constraint_name).empty());
 }
 
-TEST_F(MediaStreamConstraintsUtilVideoSourceTest, NoDevicesWithConstraints) {
+TEST_F(MediaStreamConstraintsUtilVideoDeviceTest, NoDevicesWithConstraints) {
   constraint_factory_.Reset();
   constraint_factory_.basic().height.setExact(100);
-  VideoCaptureCapabilities capabilities;
-  auto result = SelectVideoCaptureSourceSettings(
+  VideoDeviceCaptureCapabilities capabilities;
+  auto result = SelectVideoDeviceCaptureSourceSettings(
       capabilities, constraint_factory_.CreateWebMediaConstraints());
-  EXPECT_FALSE(result.has_value());
+  EXPECT_FALSE(result.HasValue());
   EXPECT_TRUE(std::string(result.failed_constraint_name).empty());
 }
 
diff --git a/content/renderer/media/media_stream_video_source.cc b/content/renderer/media/media_stream_video_source.cc
index 0c2dd59..3c962ff0 100644
--- a/content/renderer/media/media_stream_video_source.cc
+++ b/content/renderer/media/media_stream_video_source.cc
@@ -13,7 +13,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "content/child/child_process.h"
-#include "content/renderer/media/media_stream_constraints_util_video_source.h"
+#include "content/renderer/media/media_stream_constraints_util_video_device.h"
 #include "content/renderer/media/media_stream_video_track.h"
 #include "content/renderer/media/video_track_adapter.h"
 
diff --git a/content/renderer/media/media_stream_video_track.cc b/content/renderer/media/media_stream_video_track.cc
index c6fc030..599018f61 100644
--- a/content/renderer/media/media_stream_video_track.cc
+++ b/content/renderer/media/media_stream_video_track.cc
@@ -11,7 +11,7 @@
 #include "base/macros.h"
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
-#include "content/renderer/media/media_stream_constraints_util_video_source.h"
+#include "content/renderer/media/media_stream_constraints_util_video_device.h"
 
 namespace content {
 
diff --git a/content/renderer/media/user_media_client_impl.cc b/content/renderer/media/user_media_client_impl.cc
index 691e768..d8cc904 100644
--- a/content/renderer/media/user_media_client_impl.cc
+++ b/content/renderer/media/user_media_client_impl.cc
@@ -26,7 +26,7 @@
 #include "content/renderer/media/local_media_stream_audio_source.h"
 #include "content/renderer/media/media_stream.h"
 #include "content/renderer/media/media_stream_constraints_util.h"
-#include "content/renderer/media/media_stream_constraints_util_video_source.h"
+#include "content/renderer/media/media_stream_constraints_util_video_device.h"
 #include "content/renderer/media/media_stream_dispatcher.h"
 #include "content/renderer/media/media_stream_video_capturer_source.h"
 #include "content/renderer/media/media_stream_video_track.h"
@@ -366,7 +366,7 @@
   DCHECK(controls->video.requested);
   DCHECK(IsDeviceSource(controls->video.stream_source));
 
-  VideoCaptureCapabilities capabilities;
+  VideoDeviceCaptureCapabilities capabilities;
   capabilities.device_capabilities = std::move(video_input_capabilities);
   capabilities.power_line_capabilities = {
       media::PowerLineFrequency::FREQUENCY_DEFAULT,
@@ -375,7 +375,8 @@
 
   base::PostTaskAndReplyWithResult(
       worker_task_runner_.get(), FROM_HERE,
-      base::Bind(&SelectVideoCaptureSourceSettings, std::move(capabilities),
+      base::Bind(&SelectVideoDeviceCaptureSourceSettings,
+                 std::move(capabilities),
                  user_media_request.videoConstraints()),
       base::Bind(&UserMediaClientImpl::FinalizeSelectVideoDeviceSourceSettings,
                  weak_factory_.GetWeakPtr(), request_id, user_media_request,
@@ -387,10 +388,10 @@
     const blink::WebUserMediaRequest& user_media_request,
     std::unique_ptr<StreamControls> controls,
     const RequestSettings& request_settings,
-    const VideoCaptureSourceSelectionResult& selection_result) {
+    const VideoDeviceCaptureSourceSelectionResult& selection_result) {
   DCHECK(CalledOnValidThread());
-  if (selection_result.has_value()) {
-    controls->video.device_id = selection_result.settings.device_id();
+  if (selection_result.HasValue()) {
+    controls->video.device_id = selection_result.device_id;
   } else {
     // TODO(guidou): Abort the request in all cases where |selection_result|
     // has no value, as the spec mandates.
diff --git a/content/renderer/media/user_media_client_impl.h b/content/renderer/media/user_media_client_impl.h
index db866f2..7c72248 100644
--- a/content/renderer/media/user_media_client_impl.h
+++ b/content/renderer/media/user_media_client_impl.h
@@ -39,7 +39,7 @@
 class MediaStreamAudioSource;
 class MediaStreamDispatcher;
 class MediaStreamVideoSource;
-struct VideoCaptureSourceSelectionResult;
+struct VideoDeviceCaptureSourceSelectionResult;
 
 // UserMediaClientImpl is a delegate for the Media Stream GetUserMedia API.
 // It ties together WebKit and MediaStreamManager
@@ -315,7 +315,7 @@
       const blink::WebUserMediaRequest& user_media_request,
       std::unique_ptr<StreamControls> controls,
       const RequestSettings& request_settings,
-      const VideoCaptureSourceSelectionResult& selection_result);
+      const VideoDeviceCaptureSourceSelectionResult& selection_result);
 
   void FinalizeRequestUserMedia(
       int request_id,
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 59ae8b6..0fdae4b 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -616,6 +616,7 @@
     "../browser/media/session/audio_focus_delegate_default_browsertest.cc",
     "../browser/media/session/media_session_impl_browsertest.cc",
     "../browser/media/session/media_session_impl_visibility_browsertest.cc",
+    "../browser/media/session/media_session_service_impl_browsertest.cc",
     "../browser/media/session/mock_media_session_player_observer.cc",
     "../browser/media/session/mock_media_session_player_observer.h",
     "../browser/memory/memory_coordinator_impl_browsertest.cc",
@@ -1575,7 +1576,7 @@
       "../renderer/media/media_stream_audio_processor_unittest.cc",
       "../renderer/media/media_stream_audio_unittest.cc",
       "../renderer/media/media_stream_constraints_util_unittest.cc",
-      "../renderer/media/media_stream_constraints_util_video_source_unittest.cc",
+      "../renderer/media/media_stream_constraints_util_video_device_unittest.cc",
       "../renderer/media/media_stream_dispatcher_unittest.cc",
       "../renderer/media/media_stream_video_capturer_source_unittest.cc",
       "../renderer/media/media_stream_video_renderer_sink_unittest.cc",
diff --git a/content/test/data/media/session/embed-unload.html b/content/test/data/media/session/embed-unload.html
new file mode 100644
index 0000000..676280f
--- /dev/null
+++ b/content/test/data/media/session/embed-unload.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script>
+navigator.mediaSession.playbackState = 'playing';
+window.addEventListener('unload', function() {
+  navigator.mediaSession.playbackState = 'none';
+});
+</script>
diff --git a/content/test/data/media/session/embedder.html b/content/test/data/media/session/embedder.html
new file mode 100644
index 0000000..b2577d9b
--- /dev/null
+++ b/content/test/data/media/session/embedder.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<iframe src=embed-unload.html></iframe>
diff --git a/device/generic_sensor/platform_sensor.cc b/device/generic_sensor/platform_sensor.cc
index ab3e1cd6..34afa2d6 100644
--- a/device/generic_sensor/platform_sensor.cc
+++ b/device/generic_sensor/platform_sensor.cc
@@ -33,6 +33,10 @@
   return GetDefaultConfiguration().frequency();
 }
 
+double PlatformSensor::GetMinimumSupportedFrequency() {
+  return 1.0 / (60 * 60);
+}
+
 bool PlatformSensor::StartListening(Client* client,
                                     const PlatformSensorConfiguration& config) {
   DCHECK(clients_.HasObserver(client));
diff --git a/device/generic_sensor/platform_sensor.h b/device/generic_sensor/platform_sensor.h
index 62320a5..2df4ade 100644
--- a/device/generic_sensor/platform_sensor.h
+++ b/device/generic_sensor/platform_sensor.h
@@ -48,6 +48,10 @@
   // The default implementation returns default frequency.
   virtual double GetMaximumSupportedFrequency();
 
+  // Can be overriden to return the sensor minimum sampling frequency.
+  // The default implementation returns '1.0 / (60 * 60)', i.e. once per hour.
+  virtual double GetMinimumSupportedFrequency();
+
   mojom::SensorType GetType() const;
 
   bool StartListening(Client* client,
diff --git a/device/generic_sensor/public/interfaces/sensor_provider.mojom b/device/generic_sensor/public/interfaces/sensor_provider.mojom
index 7b89d3aa..8e9a3c2 100644
--- a/device/generic_sensor/public/interfaces/sensor_provider.mojom
+++ b/device/generic_sensor/public/interfaces/sensor_provider.mojom
@@ -24,6 +24,9 @@
   // capabilities.
   double maximum_frequency;
 
+  // Minimum sampling frequency for the sensor.
+  double minimum_frequency;
+
   // Each sensor's read buffer contains 4 tightly packed 64-bit floating
   // point fields (please see sensor_reading.h) and a seqlock, so its size is
   // 5 * 8 = 40 bytes.
diff --git a/device/generic_sensor/sensor_provider_impl.cc b/device/generic_sensor/sensor_provider_impl.cc
index 7322901..8f36c47f 100644
--- a/device/generic_sensor/sensor_provider_impl.cc
+++ b/device/generic_sensor/sensor_provider_impl.cc
@@ -95,11 +95,13 @@
   init_params->default_configuration = sensor->GetDefaultConfiguration();
 
   double maximum_frequency = sensor->GetMaximumSupportedFrequency();
-  DCHECK(maximum_frequency > 0);
+  DCHECK_GT(maximum_frequency, 0.0);
   if (maximum_frequency > mojom::SensorConfiguration::kMaxAllowedFrequency)
     maximum_frequency = mojom::SensorConfiguration::kMaxAllowedFrequency;
 
   init_params->maximum_frequency = maximum_frequency;
+  init_params->minimum_frequency = sensor->GetMinimumSupportedFrequency();
+  DCHECK_GT(init_params->minimum_frequency, 0.0);
 
   NotifySensorCreated(std::move(init_params), sensor_impl->GetClient(),
                       callback);
diff --git a/extensions/test/extension_test_notification_observer.cc b/extensions/test/extension_test_notification_observer.cc
index 8c79ac54..0e4d75d0c 100644
--- a/extensions/test/extension_test_notification_observer.cc
+++ b/extensions/test/extension_test_notification_observer.cc
@@ -141,9 +141,6 @@
 void ExtensionTestNotificationObserver::Wait() {
   observer_->Wait();
 
-  // TODO(https://crbug.com/695073): Find out why tests fail without it.
-  content::RunAllPendingInMessageLoop();
-
   registrar_.RemoveAll();
   observer_.reset();
 }
@@ -190,15 +187,16 @@
     return;
   condition_ = condition;
 
-  base::RunLoop run_loop;
-  quit_closure_ = run_loop.QuitClosure();
+  scoped_refptr<content::MessageLoopRunner> runner(
+      new content::MessageLoopRunner);
+  quit_closure_ = runner->QuitClosure();
 
   std::unique_ptr<base::CallbackList<void()>::Subscription> subscription;
   if (notification_set) {
     subscription = notification_set->callback_list().Add(base::Bind(
         &ExtensionTestNotificationObserver::MaybeQuit, base::Unretained(this)));
   }
-  run_loop.Run();
+  runner->Run();
 
   condition_.Reset();
   quit_closure_.Reset();
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 22067c0b..f5b45ac 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -8,19 +8,6 @@
 import("//rlz/features/features.gni")
 import("//third_party/protobuf/proto_library.gni")
 
-declare_args() {
-  google_test_gaia_client_id = ""
-  google_test_gaia_client_secret = ""
-  google_staging_api_url = ""
-  google_staging_lso_url = ""
-  google_test_api_url = ""
-  google_test_lso_url = ""
-  google_test_oauth_client_id = ""
-  google_test_oauth_client_secret = ""
-  google_test_oauth_url = ""
-  google_test_sync_url = ""
-}
-
 source_set("browser") {
   configs += [ "//build/config/compiler:enable_arc" ]
   sources = [
@@ -79,7 +66,6 @@
     "xcallback_parameters.mm",
   ]
   deps = [
-    ":google_api_keys_header",
     ":settings_resources",
     "//base",
     "//components/autofill/core/browser",
@@ -194,20 +180,6 @@
   }
 }
 
-buildflag_header("google_api_keys_header") {
-  header = "google_api_keys.h"
-  flags = [
-    "GOOGLE_STAGING_API_URL=\"$google_staging_api_url\"",
-    "GOOGLE_STAGING_LSO_URL=\"$google_staging_lso_url\"",
-    "GOOGLE_TEST_API_URL=\"$google_test_api_url\"",
-    "GOOGLE_TEST_LSO_URL=\"$google_test_lso_url\"",
-    "GOOGLE_TEST_OAUTH_CLIENT_ID=\"$google_test_oauth_client_id\"",
-    "GOOGLE_TEST_OAUTH_CLIENT_SECRET=\"$google_test_oauth_client_secret\"",
-    "GOOGLE_TEST_OAUTH_URL=\"$google_test_oauth_url\"",
-    "GOOGLE_TEST_SYNC_URL=\"$google_test_sync_url\"",
-  ]
-}
-
 bundle_data("settings_resources") {
   sources = [
     "resources/Settings.bundle/Experimental.plist",
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 5a97a54..b89a3be 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -28,11 +28,9 @@
 #include "components/ntp_tiles/switches.h"
 #include "components/reading_list/core/reading_list_switches.h"
 #include "components/strings/grit/components_strings.h"
-#include "components/sync/driver/sync_driver_switches.h"
-#include "google_apis/gaia/gaia_switches.h"
 #include "ios/chrome/browser/chrome_switches.h"
-#include "ios/chrome/browser/google_api_keys.h"
 #include "ios/chrome/grit/ios_strings.h"
+#include "ios/public/provider/chrome/browser/chrome_browser_provider.h"
 #include "ios/web/public/user_agent.h"
 #include "ios/web/public/web_view_creation_util.h"
 
@@ -75,29 +73,6 @@
 void AppendSwitchesFromExperimentalSettings(base::CommandLine* command_line) {
   NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
 
-  // GAIA staging environment.
-  NSString* kGAIAEnvironment = @"GAIAEnvironment";
-  NSString* gaia_environment = [defaults stringForKey:kGAIAEnvironment];
-  if ([gaia_environment isEqualToString:@"Staging"]) {
-    command_line->AppendSwitchASCII(switches::kGoogleApisUrl,
-                                    BUILDFLAG(GOOGLE_STAGING_API_URL));
-    command_line->AppendSwitchASCII(switches::kLsoUrl,
-                                    BUILDFLAG(GOOGLE_STAGING_LSO_URL));
-  } else if ([gaia_environment isEqualToString:@"Test"]) {
-    command_line->AppendSwitchASCII(switches::kGaiaUrl,
-                                    BUILDFLAG(GOOGLE_TEST_OAUTH_URL));
-    command_line->AppendSwitchASCII(switches::kGoogleApisUrl,
-                                    BUILDFLAG(GOOGLE_TEST_API_URL));
-    command_line->AppendSwitchASCII(switches::kLsoUrl,
-                                    BUILDFLAG(GOOGLE_TEST_LSO_URL));
-    command_line->AppendSwitchASCII(switches::kSyncServiceURL,
-                                    BUILDFLAG(GOOGLE_TEST_SYNC_URL));
-    command_line->AppendSwitchASCII(switches::kOAuth2ClientID,
-                                    BUILDFLAG(GOOGLE_TEST_OAUTH_CLIENT_ID));
-    command_line->AppendSwitchASCII(switches::kOAuth2ClientSecret,
-                                    BUILDFLAG(GOOGLE_TEST_OAUTH_CLIENT_SECRET));
-  }
-
   // Populate command line flag for the tab strip auto scroll new tabs
   // experiment from the configuration plist.
   if ([defaults boolForKey:@"TabStripAutoScrollNewTabsDisabled"])
@@ -255,6 +230,9 @@
     base::CommandLine temp_command_line(flags);
     command_line->AppendArguments(temp_command_line, false);
   }
+
+  ios::GetChromeBrowserProvider()->AppendSwitchesFromExperimentalSettings(
+      defaults, command_line);
 }
 
 bool SkipConditionalFeatureEntry(const flags_ui::FeatureEntry& entry) {
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h
index a656e1f..59fe49be 100644
--- a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.h
@@ -15,6 +15,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/threading/thread_checker.h"
+#include "components/metrics/metrics_log_uploader.h"
 #include "components/metrics/metrics_service_client.h"
 #include "components/metrics/profiler/tracking_synchronizer_observer.h"
 #include "components/omnibox/browser/omnibox_event_global_tracker.h"
@@ -73,6 +74,7 @@
   std::unique_ptr<metrics::MetricsLogUploader> CreateUploader(
       const std::string& server_url,
       const std::string& mime_type,
+      metrics::MetricsLogUploader::MetricServiceType service_type,
       const base::Callback<void(int)>& on_upload_complete) override;
   base::TimeDelta GetStandardUploadInterval() override;
   base::string16 GetRegistryBackupKey() override;
diff --git a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
index 22078e4..010a20f 100644
--- a/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
+++ b/ios/chrome/browser/metrics/ios_chrome_metrics_service_client.mm
@@ -27,6 +27,7 @@
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/metrics/call_stack_profile_metrics_provider.h"
 #include "components/metrics/drive_metrics_provider.h"
+#include "components/metrics/metrics_log_uploader.h"
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_reporting_default_state.h"
 #include "components/metrics/metrics_service.h"
@@ -164,10 +165,11 @@
 IOSChromeMetricsServiceClient::CreateUploader(
     const std::string& server_url,
     const std::string& mime_type,
+    metrics::MetricsLogUploader::MetricServiceType service_type,
     const base::Callback<void(int)>& on_upload_complete) {
   return base::MakeUnique<metrics::NetMetricsLogUploader>(
-      GetApplicationContext()->GetSystemURLRequestContext(),
-      server_url, mime_type, on_upload_complete);
+      GetApplicationContext()->GetSystemURLRequestContext(), server_url,
+      mime_type, service_type, on_upload_complete);
 }
 
 base::TimeDelta IOSChromeMetricsServiceClient::GetStandardUploadInterval() {
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.mm
index 5993c41e..4928dc8 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_navigation_controller.mm
@@ -28,4 +28,10 @@
   return NO;
 }
 
+#pragma mark - UIResponder
+
+- (BOOL)canBecomeFirstResponder {
+  return YES;
+}
+
 @end
diff --git a/ios/chrome/browser/ui/browser_view_controller_unittest.mm b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
index ca22cbc..cbe5c55e 100644
--- a/ios/chrome/browser/ui/browser_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/browser_view_controller_unittest.mm
@@ -156,10 +156,6 @@
     [[[tabModel stub] andReturnValue:OCMOCK_VALUE(enabled)] webUsageEnabled];
     [[[tabModel stub] andReturn:currentTab] currentTab];
     [[[tabModel stub] andReturn:currentTab] tabAtIndex:0];
-    GURL URL("http://www.google.com");
-    [[[tabModel stub] andReturn:currentTab] addTabWithURL:URL
-                                                 referrer:web::Referrer()
-                                               windowName:[OCMArg any]];
     [[tabModel stub] addObserver:[OCMArg any]];
     [[tabModel stub] removeObserver:[OCMArg any]];
     [[tabModel stub] saveSessionImmediately:NO];
@@ -199,8 +195,8 @@
         newTabStripControllerWithTabModel:[OCMArg any]];
     [[[factory stub] andReturn:nil] newPreloadController];
     [[[factory stub] andReturnValue:OCMOCK_VALUE(toolbarModelIOS_)]
-        newToolbarModelIOSWithDelegate:(ToolbarModelDelegateIOS*)
-                                           [OCMArg anyPointer]];
+        newToolbarModelIOSWithDelegate:static_cast<ToolbarModelDelegateIOS*>(
+                                           [OCMArg anyPointer])];
     [[[factory stub] andReturn:nil]
         newWebToolbarControllerWithDelegate:[OCMArg any]
                                   urlLoader:[OCMArg any]
@@ -306,7 +302,7 @@
 }
 
 TEST_F(BrowserViewControllerTest, TestTabDeselected) {
-  OCMockObject* tabMock = (OCMockObject*)tab_.get();
+  OCMockObject* tabMock = static_cast<OCMockObject*>(tab_.get());
   [[tabMock expect] wasHidden];
   NSDictionary* userInfoWithThisTab =
       [NSDictionary dictionaryWithObject:tab_ forKey:kTabModelTabKey];
@@ -366,10 +362,10 @@
 // load on a handset, but not stop the load on a tablet.
 TEST_F(BrowserViewControllerTest,
        TestLocationBarBeganEdit_whenPageLoadIsInProgress) {
-  OCMockObject* tabMock = (OCMockObject*)tab_.get();
+  OCMockObject* tabMock = static_cast<OCMockObject*>(tab_.get());
 
   // Have the TestToolbarModel indicate that a page load is in progress.
-  ((TestToolbarModelIOS*)toolbarModelIOS_)->set_is_loading(true);
+  static_cast<TestToolbarModelIOS*>(toolbarModelIOS_)->set_is_loading(true);
 
   // The tab should only stop loading on handsets.
   if (!IsIPadIdiom())
@@ -383,10 +379,10 @@
 // to stop the load on a handset or a tablet.
 TEST_F(BrowserViewControllerTest,
        TestLocationBarBeganEdit_whenPageLoadIsComplete) {
-  OCMockObject* tabMock = (OCMockObject*)tab_.get();
+  OCMockObject* tabMock = static_cast<OCMockObject*>(tab_.get());
 
   // Have the TestToolbarModel indicate that the page load is complete.
-  ((TestToolbarModelIOS*)toolbarModelIOS_)->set_is_loading(false);
+  static_cast<TestToolbarModelIOS*>(toolbarModelIOS_)->set_is_loading(false);
 
   // Don't set any expectation for stopLoading to be called on the mock tab.
   [bvc_ locationBarBeganEdit:nil];
@@ -399,8 +395,8 @@
 TEST_F(BrowserViewControllerTest, TestSharePageCommandHandling) {
   GURL expectedUrl("http://www.testurl.net");
   NSString* expectedTitle = @"title";
-  [(BVCTestTabMock*)tab_.get() setUrl:expectedUrl];
-  OCMockObject* tabMock = (OCMockObject*)tab_.get();
+  [static_cast<BVCTestTabMock*>(tab_.get()) setUrl:expectedUrl];
+  OCMockObject* tabMock = static_cast<OCMockObject*>(tab_.get());
   ios::ChromeBrowserState* ptr = chrome_browser_state_.get();
   [[[tabMock stub] andReturnValue:OCMOCK_VALUE(ptr)] browserState];
   [[[tabMock stub] andReturn:expectedTitle] title];
@@ -410,14 +406,15 @@
       CGSizeMake(300, 400), [UIColor blueColor]);
   [[[tabMock stub] andReturn:tabSnapshot] generateSnapshotWithOverlay:NO
                                                      visibleFrameOnly:YES];
-  OCMockObject* shareControllerMock = (OCMockObject*)shareController_.get();
+  OCMockObject* shareControllerMock =
+      static_cast<OCMockObject*>(shareController_.get());
   // Passing non zero/nil |fromRect| and |inView| parameters to satisfy protocol
   // requirements.
   BOOL (^shareDataChecker)
   (id value) = ^BOOL(id value) {
     if (![value isMemberOfClass:ShareToData.class])
       return NO;
-    ShareToData* shareToData = (ShareToData*)value;
+    ShareToData* shareToData = static_cast<ShareToData*>(value);
     CGSize size = CGSizeMake(40, 40);
     BOOL thumbnailDataIsEqual = ui::test::uiimage_utils::UIImagesAreEqual(
         shareToData.thumbnailGenerator(size),
@@ -446,13 +443,14 @@
   GURL expectedUrl("http://www.testurl.net");
   NSString* expectedTitle = @"title";
   // Sets WebState to nil because [tab close] clears the WebState.
-  [(BVCTestTabMock*)tab_.get() setWebState:nil];
-  [(BVCTestTabMock*)tab_.get() setUrl:expectedUrl];
-  OCMockObject* tabMock = (OCMockObject*)tab_.get();
+  [static_cast<BVCTestTabMock*>(tab_.get()) setWebState:nil];
+  [static_cast<BVCTestTabMock*>(tab_.get()) setUrl:expectedUrl];
+  OCMockObject* tabMock = static_cast<OCMockObject*>(tab_.get());
   [[[tabMock stub] andReturn:expectedTitle] title];
   [[[tabMock stub] andReturn:expectedTitle] originalTitle];
   // Explicitly disallow the execution of the ShareController.
-  OCMockObject* shareControllerMock = (OCMockObject*)shareController_.get();
+  OCMockObject* shareControllerMock =
+      static_cast<OCMockObject*>(shareController_.get());
   [[shareControllerMock reject]
         shareWithData:[OCMArg any]
            controller:bvc_
@@ -489,7 +487,7 @@
       alertCoordinatorWithTitle:errorTitle
                         message:errorMessage
                  viewController:OCMOCK_ANY];
-  [((AlertCoordinator*)[mockCoordinator expect])start];
+  [static_cast<AlertCoordinator*>([mockCoordinator expect]) start];
 
   [bvc_ shareDidComplete:ShareTo::SHARE_ERROR successMessage:@"dummy"];
   EXPECT_OCMOCK_VERIFY(dependencyFactory_);
@@ -535,7 +533,8 @@
 }
 
 TEST_F(BrowserViewControllerTest, TestClearPresentedState) {
-  OCMockObject* shareControllerMock = (OCMockObject*)shareController_.get();
+  OCMockObject* shareControllerMock =
+      static_cast<OCMockObject*>(shareController_.get());
   [[shareControllerMock expect] cancelShareAnimated:NO];
   EXPECT_CALL(*this, OnCompletionCalled());
   [bvc_ clearPresentedStateWithCompletion:^{
diff --git a/ios/chrome/browser/ui/history/history_panel_view_controller.mm b/ios/chrome/browser/ui/history/history_panel_view_controller.mm
index 2989f1e..59ff508b 100644
--- a/ios/chrome/browser/ui/history/history_panel_view_controller.mm
+++ b/ios/chrome/browser/ui/history/history_panel_view_controller.mm
@@ -409,6 +409,10 @@
 
 #pragma mark - UIResponder
 
+- (BOOL)canBecomeFirstResponder {
+  return YES;
+}
+
 - (NSArray*)keyCommands {
   __weak HistoryPanelViewController* weakSelf = self;
   return @[ [UIKeyCommand cr_keyCommandWithInput:UIKeyInputEscape
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm
index 6e0eb577..499549b 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_view_controller.mm
@@ -164,6 +164,10 @@
 
 #pragma mark - UIResponder
 
+- (BOOL)canBecomeFirstResponder {
+  return YES;
+}
+
 - (NSArray*)keyCommands {
   __weak ReadingListViewController* weakSelf = self;
   return @[ [UIKeyCommand
diff --git a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
index e80c01d0..b1b25e5 100644
--- a/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
+++ b/ios/chrome/browser/ui/settings/settings_navigation_controller.mm
@@ -656,4 +656,10 @@
   return [NSValue valueWithPointer:controller];
 }
 
+#pragma mark - UIResponder
+
+- (BOOL)canBecomeFirstResponder {
+  return YES;
+}
+
 @end
diff --git a/ios/chrome/today_extension/today_metrics_logger.mm b/ios/chrome/today_extension/today_metrics_logger.mm
index 17b47bc..8022d43 100644
--- a/ios/chrome/today_extension/today_metrics_logger.mm
+++ b/ios/chrome/today_extension/today_metrics_logger.mm
@@ -71,6 +71,7 @@
   std::unique_ptr<metrics::MetricsLogUploader> CreateUploader(
       const std::string& server_url,
       const std::string& mime_type,
+      metrics::MetricsLogUploader::MetricServiceType service_type,
       const base::Callback<void(int)>& on_upload_complete) override;
   base::TimeDelta GetStandardUploadInterval() override;
 
@@ -151,6 +152,7 @@
 TodayMetricsServiceClient::CreateUploader(
     const std::string& server_url,
     const std::string& mime_type,
+    metrics::MetricsLogUploader::MetricServiceType service_type,
     const base::Callback<void(int)>& on_upload_complete) {
   NOTREACHED();
   return nullptr;
diff --git a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
index dd85b85..706910fe 100644
--- a/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
+++ b/ios/clean/chrome/browser/ui/tab_grid/tab_grid_view_controller.mm
@@ -11,6 +11,7 @@
 #include "base/mac/foundation_util.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_cell.h"
 #import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_collection_view_layout.h"
+#import "ios/chrome/browser/ui/tab_switcher/tab_switcher_panel_overlay_view.h"
 #import "ios/clean/chrome/browser/ui/actions/settings_actions.h"
 #import "ios/clean/chrome/browser/ui/actions/tab_grid_actions.h"
 #import "ios/clean/chrome/browser/ui/commands/settings_commands.h"
@@ -35,6 +36,7 @@
                                     UICollectionViewDelegate,
                                     SessionCellDelegate>
 @property(nonatomic, weak) UICollectionView* grid;
+@property(nonatomic, weak) UIView* noTabsOverlay;
 @property(nonatomic, strong) MDCFloatingButton* floatingNewTabButton;
 @end
 
@@ -45,6 +47,7 @@
 @synthesize tabGridCommandHandler = _tabGridCommandHandler;
 @synthesize tabCommandHandler = _tabCommandHandler;
 @synthesize grid = _grid;
+@synthesize noTabsOverlay = _noTabsOverlay;
 @synthesize floatingNewTabButton = _floatingNewTabButton;
 
 - (void)viewDidLoad {
@@ -103,7 +106,15 @@
 
 - (NSInteger)collectionView:(UICollectionView*)collectionView
      numberOfItemsInSection:(NSInteger)section {
-  return [self.dataSource numberOfTabsInTabGrid];
+  NSInteger items = [self.dataSource numberOfTabsInTabGrid];
+  // HACK: Do not make showing noTabsOverlay a side effect of the dataSource
+  // callback.
+  if (items) {
+    [self removeNoTabsOverlay];
+  } else {
+    [self showNoTabsOverlay];
+  }
+  return items;
 }
 
 - (UICollectionViewCell*)collectionView:(UICollectionView*)collectionView
@@ -176,4 +187,28 @@
   [self.grid performBatchUpdates:updateBlock completion:nil];
 }
 
+#pragma mark - Private
+
+// Shows an overlay covering the entire tab grid that informs the user that
+// there are no tabs.
+- (void)showNoTabsOverlay {
+  // PLACEHOLDER: The new tab grid will have a completely different zero tab
+  // overlay from the tab switcher. Also, the overlay will be above the recent
+  // tabs section.
+  TabSwitcherPanelOverlayView* overlayView =
+      [[TabSwitcherPanelOverlayView alloc] initWithFrame:self.grid.bounds
+                                            browserState:nil];
+  overlayView.overlayType =
+      TabSwitcherPanelOverlayType::OVERLAY_PANEL_USER_NO_OPEN_TABS;
+  overlayView.autoresizingMask =
+      UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+  [self.grid addSubview:overlayView];
+  self.noTabsOverlay = overlayView;
+}
+
+// Removes the noTabsOverlay covering the entire tab grid.
+- (void)removeNoTabsOverlay {
+  [self.noTabsOverlay removeFromSuperview];
+}
+
 @end
diff --git a/media/midi/dynamically_initialized_midi_manager_win.cc b/media/midi/dynamically_initialized_midi_manager_win.cc
index 26a4c835e..2a83b00 100644
--- a/media/midi/dynamically_initialized_midi_manager_win.cc
+++ b/media/midi/dynamically_initialized_midi_manager_win.cc
@@ -26,6 +26,10 @@
 
 namespace {
 
+// Assumes that nullptr represents an invalid MIDI handle.
+constexpr HMIDIIN kInvalidInHandle = nullptr;
+constexpr HMIDIOUT kInvalidOutHandle = nullptr;
+
 // Global variables to identify MidiManager instance.
 constexpr int kInvalidInstanceId = -1;
 int g_active_instance_id = kInvalidInstanceId;
@@ -47,6 +51,9 @@
 constexpr int kTaskRunner = 0;
 
 // Obtains base::Lock instance pointer to ensure tasks run safely on TaskRunner.
+// Since all tasks on TaskRunner run behind a lock of *GetTaskLock(), we can
+// access all members even on the I/O thread if a lock of *GetTaskLock() is
+// obtained.
 base::Lock* GetTaskLock() {
   static base::Lock* lock = new base::Lock;
   return lock;
@@ -69,6 +76,36 @@
 // TODO(toyoshim): Factor out TaskRunner related functionaliries above, and
 // deprecate MidiScheduler. It should be available via MidiManager::scheduler().
 
+// Helper functions to close MIDI device handles on TaskRunner asynchronously.
+void FinalizeInPort(HMIDIIN handle) {
+  midiInClose(handle);
+}
+
+void FinalizeOutPort(HMIDIOUT handle) {
+  midiOutClose(handle);
+}
+
+// Handles MIDI input port callbacks that runs on a system provided thread.
+void CALLBACK HandleMidiInCallback(HMIDIIN hmi,
+                                   UINT msg,
+                                   DWORD_PTR instance,
+                                   DWORD_PTR param1,
+                                   DWORD_PTR param2) {
+  // TODO(toyoshim): Following patches will implement actual functions.
+}
+
+// Handles MIDI output port callbacks that runs on a system provided thread.
+void CALLBACK HandleMidiOutCallback(HMIDIOUT hmo,
+                                    UINT msg,
+                                    DWORD_PTR instance,
+                                    DWORD_PTR param1,
+                                    DWORD_PTR param2) {
+  // TODO(toyoshim): Following patches will implement actual functions.
+}
+
+// All instances of Port subclasses are always accessed behind a lock of
+// *GetTaskLock(). Port and subclasses implementation do not need to
+// consider thread safety.
 class Port {
  public:
   Port(const std::string& type,
@@ -162,7 +199,8 @@
              caps.wPid,
              caps.vDriverVersion,
              base::WideToUTF8(
-                 base::string16(caps.szPname, wcslen(caps.szPname)))) {}
+                 base::string16(caps.szPname, wcslen(caps.szPname)))),
+        in_handle_(kInvalidInHandle) {}
 
   static std::vector<std::unique_ptr<InPort>> EnumerateActivePorts() {
     std::vector<std::unique_ptr<InPort>> ports;
@@ -180,6 +218,13 @@
     return ports;
   }
 
+  void Finalize(scoped_refptr<base::SingleThreadTaskRunner> runner) {
+    if (in_handle_ != kInvalidInHandle) {
+      runner->PostTask(FROM_HERE, base::Bind(&FinalizeInPort, in_handle_));
+      in_handle_ = kInvalidInHandle;
+    }
+  }
+
   void NotifyPortStateSet(DynamicallyInitializedMidiManagerWin* manager) {
     manager->PostReplyTask(
         base::Bind(&DynamicallyInitializedMidiManagerWin::SetInputPortState,
@@ -191,6 +236,34 @@
         base::Bind(&DynamicallyInitializedMidiManagerWin::AddInputPort,
                    base::Unretained(manager), info_));
   }
+
+  // Port overrides:
+  bool Disconnect() override {
+    if (in_handle_ != kInvalidInHandle) {
+      // Following API call may fail because device was already disconnected.
+      // But just in case.
+      midiInClose(in_handle_);
+      in_handle_ = kInvalidInHandle;
+    }
+    return Port::Disconnect();
+  }
+
+  void Open() override {
+    // TODO(toyoshim): Pass instance_id to implement HandleMidiInCallback.
+    MMRESULT result =
+        midiInOpen(&in_handle_, device_id_,
+                   reinterpret_cast<DWORD_PTR>(&HandleMidiInCallback), 0,
+                   CALLBACK_FUNCTION);
+    if (result == MMSYSERR_NOERROR) {
+      Port::Open();
+    } else {
+      in_handle_ = kInvalidInHandle;
+      Disconnect();
+    }
+  }
+
+ private:
+  HMIDIIN in_handle_;
 };
 
 // TODO(toyoshim): Following patches will implement actual functions.
@@ -204,7 +277,8 @@
              caps.vDriverVersion,
              base::WideToUTF8(
                  base::string16(caps.szPname, wcslen(caps.szPname)))),
-        software_(caps.wTechnology == MOD_SWSYNTH) {}
+        software_(caps.wTechnology == MOD_SWSYNTH),
+        out_handle_(kInvalidOutHandle) {}
 
   static std::vector<std::unique_ptr<OutPort>> EnumerateActivePorts() {
     std::vector<std::unique_ptr<OutPort>> ports;
@@ -222,19 +296,13 @@
     return ports;
   }
 
-  // Port overrides:
-  bool Connect() override {
-    // Until |software| option is supported, disable Microsoft GS Wavetable
-    // Synth that has a known security issue.
-    if (software_ && manufacturer_id_ == MM_MICROSOFT &&
-        (product_id_ == MM_MSFT_WDMAUDIO_MIDIOUT ||
-         product_id_ == MM_MSFT_GENERIC_MIDISYNTH)) {
-      return false;
+  void Finalize(scoped_refptr<base::SingleThreadTaskRunner> runner) {
+    if (out_handle_ != kInvalidOutHandle) {
+      runner->PostTask(FROM_HERE, base::Bind(&FinalizeOutPort, out_handle_));
+      out_handle_ = kInvalidOutHandle;
     }
-    return Port::Connect();
   }
 
-  // Port Overrides:
   void NotifyPortStateSet(DynamicallyInitializedMidiManagerWin* manager) {
     manager->PostReplyTask(
         base::Bind(&DynamicallyInitializedMidiManagerWin::SetOutputPortState,
@@ -247,7 +315,43 @@
                    base::Unretained(manager), info_));
   }
 
+  // Port overrides:
+  bool Connect() override {
+    // Until |software| option is supported, disable Microsoft GS Wavetable
+    // Synth that has a known security issue.
+    if (software_ && manufacturer_id_ == MM_MICROSOFT &&
+        (product_id_ == MM_MSFT_WDMAUDIO_MIDIOUT ||
+         product_id_ == MM_MSFT_GENERIC_MIDISYNTH)) {
+      return false;
+    }
+    return Port::Connect();
+  }
+
+  bool Disconnect() override {
+    if (out_handle_ != kInvalidOutHandle) {
+      // Following API call may fail because device was already disconnected.
+      // But just in case.
+      midiOutClose(out_handle_);
+      out_handle_ = kInvalidOutHandle;
+    }
+    return Port::Disconnect();
+  }
+
+  void Open() override {
+    MMRESULT result =
+        midiOutOpen(&out_handle_, device_id_,
+                    reinterpret_cast<DWORD_PTR>(&HandleMidiOutCallback), 0,
+                    CALLBACK_FUNCTION);
+    if (result == MMSYSERR_NOERROR) {
+      Port::Open();
+    } else {
+      out_handle_ = kInvalidOutHandle;
+      Disconnect();
+    }
+  }
+
   const bool software_;
+  HMIDIOUT out_handle_;
 };
 
 DynamicallyInitializedMidiManagerWin::DynamicallyInitializedMidiManagerWin(
@@ -304,7 +408,18 @@
   // Ensures that no task runs on TaskRunner so to destruct the instance safely.
   // Tasks that did not started yet will do nothing after invalidate the
   // instance ID above.
+  // Behind the lock below, we can safely access all members for finalization
+  // even on the I/O thread.
   base::AutoLock lock(*GetTaskLock());
+
+  // Posts tasks that finalize each device port without MidiManager instance
+  // on TaskRunner. If another MidiManager instance is created, its
+  // initialization runs on the same task runner after all tasks posted here
+  // finish.
+  for (const auto& port : input_ports_)
+    port->Finalize(service()->GetTaskRunner(kTaskRunner));
+  for (const auto& port : output_ports_)
+    port->Finalize(service()->GetTaskRunner(kTaskRunner));
 }
 
 void DynamicallyInitializedMidiManagerWin::DispatchSendMidiData(
diff --git a/net/base/sdch_manager.cc b/net/base/sdch_manager.cc
index d577db84..11e9e3b7 100644
--- a/net/base/sdch_manager.cc
+++ b/net/base/sdch_manager.cc
@@ -4,6 +4,7 @@
 
 #include "net/base/sdch_manager.h"
 
+#include <inttypes.h>
 #include <limits.h>
 
 #include <utility>
@@ -335,7 +336,8 @@
   size_t total_count = dictionaries_.size();
   if (total_count == 0)
     return;
-  std::string name = base::StringPrintf("net/sdch_manager_%p", this);
+  std::string name = base::StringPrintf("net/sdch_manager_0x%" PRIxPTR,
+                                        reinterpret_cast<uintptr_t>(this));
   base::trace_event::MemoryAllocatorDump* dump = pmd->GetAllocatorDump(name);
   if (dump == nullptr) {
     dump = pmd->CreateAllocatorDump(name);
@@ -350,6 +352,7 @@
                     base::trace_event::MemoryAllocatorDump::kUnitsObjects,
                     total_count);
   }
+
   // Create an empty row under parent's dump so size can be attributed correctly
   // if |this| is shared between URLRequestContexts.
   base::trace_event::MemoryAllocatorDump* empty_row_dump =
diff --git a/net/base/sdch_manager_unittest.cc b/net/base/sdch_manager_unittest.cc
index 31162841..72913a3 100644
--- a/net/base/sdch_manager_unittest.cc
+++ b/net/base/sdch_manager_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "net/base/sdch_manager.h"
 
+#include <inttypes.h>
 #include <limits.h>
 
 #include <memory>
@@ -640,7 +641,18 @@
   sdch_manager()->RemoveObserver(&observer);
 }
 
-TEST_F(SdchManagerTest, DumpMemoryStats) {
+class SdchManagerMemoryDumpTest
+    : public SdchManagerTest,
+      public testing::WithParamInterface<
+          base::trace_event::MemoryDumpLevelOfDetail> {};
+
+INSTANTIATE_TEST_CASE_P(
+    /* no prefix */,
+    SdchManagerMemoryDumpTest,
+    ::testing::Values(base::trace_event::MemoryDumpLevelOfDetail::DETAILED,
+                      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND));
+
+TEST_P(SdchManagerMemoryDumpTest, DumpMemoryStats) {
   MockSdchObserver observer;
   sdch_manager()->AddObserver(&observer);
 
@@ -655,20 +667,20 @@
   EXPECT_EQ(target_gurl, observer.last_dictionary_url());
   EXPECT_EQ(server_hash, observer.last_server_hash());
 
-  base::trace_event::MemoryDumpArgs dump_args = {
-      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+  base::trace_event::MemoryDumpArgs dump_args = {GetParam()};
   std::unique_ptr<base::trace_event::ProcessMemoryDump> pmd(
       new base::trace_event::ProcessMemoryDump(nullptr, dump_args));
 
   base::trace_event::MemoryAllocatorDump* parent =
-      pmd->CreateAllocatorDump("parent");
+      pmd->CreateAllocatorDump("net/url_request_context_0x123");
   sdch_manager()->DumpMemoryStats(pmd.get(), parent->absolute_name());
 
   const base::trace_event::MemoryAllocatorDump* sub_dump =
-      pmd->GetAllocatorDump("parent/sdch_manager");
+      pmd->GetAllocatorDump("net/url_request_context_0x123/sdch_manager");
   ASSERT_NE(nullptr, sub_dump);
   const base::trace_event::MemoryAllocatorDump* dump = pmd->GetAllocatorDump(
-      base::StringPrintf("net/sdch_manager_%p", sdch_manager()));
+      base::StringPrintf("net/sdch_manager_0x%" PRIxPTR,
+                         reinterpret_cast<uintptr_t>(sdch_manager())));
   std::unique_ptr<base::Value> raw_attrs =
       dump->attributes_for_testing()->ToBaseValue();
   base::DictionaryValue* attrs;
diff --git a/net/http/http_cache_unittest.cc b/net/http/http_cache_unittest.cc
index f7acbde..71509a42 100644
--- a/net/http/http_cache_unittest.cc
+++ b/net/http/http_cache_unittest.cc
@@ -23,6 +23,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/simple_test_clock.h"
 #include "base/trace_event/memory_allocator_dump.h"
+#include "base/trace_event/memory_dump_request_args.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event_argument.h"
 #include "net/base/cache_type.h"
@@ -8357,8 +8358,18 @@
             response_info.cache_entry_status);
 }
 
+class HttpCacheMemoryDumpTest
+    : public testing::TestWithParam<
+          base::trace_event::MemoryDumpLevelOfDetail> {};
+
+INSTANTIATE_TEST_CASE_P(
+    /* no prefix */,
+    HttpCacheMemoryDumpTest,
+    ::testing::Values(base::trace_event::MemoryDumpLevelOfDetail::DETAILED,
+                      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND));
+
 // Basic test to make sure HttpCache::DumpMemoryStats doesn't crash.
-TEST(HttpCache, DumpMemoryStats) {
+TEST_P(HttpCacheMemoryDumpTest, DumpMemoryStats) {
   MockHttpCache cache;
   cache.FailConditionalizations();
   RunTransactionTest(cache.http_cache(), kTypicalGET_Transaction);
@@ -8372,17 +8383,17 @@
   EXPECT_EQ(CacheEntryStatus::ENTRY_CANT_CONDITIONALIZE,
             response_info.cache_entry_status);
 
-  base::trace_event::MemoryDumpArgs dump_args = {
-      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+  base::trace_event::MemoryDumpArgs dump_args = {GetParam()};
   std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
       new base::trace_event::ProcessMemoryDump(nullptr, dump_args));
   base::trace_event::MemoryAllocatorDump* parent_dump =
-      process_memory_dump->CreateAllocatorDump("parent");
+      process_memory_dump->CreateAllocatorDump("net/url_request_context_0x123");
   cache.http_cache()->DumpMemoryStats(process_memory_dump.get(),
                                       parent_dump->absolute_name());
 
   const base::trace_event::MemoryAllocatorDump* dump =
-      process_memory_dump->GetAllocatorDump("parent/http_cache");
+      process_memory_dump->GetAllocatorDump(
+          "net/url_request_context_0x123/http_cache");
   ASSERT_NE(nullptr, dump);
   std::unique_ptr<base::Value> raw_attrs =
       dump->attributes_for_testing()->ToBaseValue();
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index fda084ea..b57653a 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -4,6 +4,8 @@
 
 #include "net/http/http_network_session.h"
 
+#include <inttypes.h>
+
 #include <utility>
 
 #include "base/atomic_sequence_num.h"
@@ -423,7 +425,8 @@
 void HttpNetworkSession::DumpMemoryStats(
     base::trace_event::ProcessMemoryDump* pmd,
     const std::string& parent_absolute_name) const {
-  std::string name = base::StringPrintf("net/http_network_session_%p", this);
+  std::string name = base::StringPrintf("net/http_network_session_0x%" PRIxPTR,
+                                        reinterpret_cast<uintptr_t>(this));
   base::trace_event::MemoryAllocatorDump* http_network_session_dump =
       pmd->GetAllocatorDump(name);
   if (http_network_session_dump == nullptr) {
@@ -439,6 +442,7 @@
     quic_stream_factory_.DumpMemoryStats(
         pmd, http_network_session_dump->absolute_name());
   }
+
   // Create an empty row under parent's dump so size can be attributed correctly
   // if |this| is shared between URLRequestContexts.
   base::trace_event::MemoryAllocatorDump* empty_row_dump =
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc
index 51362da..e7840946 100644
--- a/net/spdy/spdy_session_pool_unittest.cc
+++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -671,7 +671,18 @@
   spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
 }
 
-TEST_F(SpdySessionPoolTest, DumpMemoryStats) {
+class SpdySessionMemoryDumpTest
+    : public SpdySessionPoolTest,
+      public testing::WithParamInterface<
+          base::trace_event::MemoryDumpLevelOfDetail> {};
+
+INSTANTIATE_TEST_CASE_P(
+    /* no prefix */,
+    SpdySessionMemoryDumpTest,
+    ::testing::Values(base::trace_event::MemoryDumpLevelOfDetail::DETAILED,
+                      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND));
+
+TEST_P(SpdySessionMemoryDumpTest, DumpMemoryStats) {
   SpdySessionKey key(HostPortPair("https://www.example.org", 443),
                      ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
 
@@ -692,12 +703,12 @@
   base::RunLoop().RunUntilIdle();
 
   EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key));
-  base::trace_event::MemoryDumpArgs dump_args = {
-      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+  base::trace_event::MemoryDumpArgs dump_args = {GetParam()};
   std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
       new base::trace_event::ProcessMemoryDump(nullptr, dump_args));
   base::trace_event::MemoryAllocatorDump* parent_dump =
-      process_memory_dump->CreateAllocatorDump("parent");
+      process_memory_dump->CreateAllocatorDump(
+          "net/http_network_session_0x123");
   spdy_session_pool_->DumpMemoryStats(process_memory_dump.get(),
                                       parent_dump->absolute_name());
 
diff --git a/net/ssl/ssl_client_session_cache_unittest.cc b/net/ssl/ssl_client_session_cache_unittest.cc
index 5158782..07ae81b 100644
--- a/net/ssl/ssl_client_session_cache_unittest.cc
+++ b/net/ssl/ssl_client_session_cache_unittest.cc
@@ -354,8 +354,19 @@
   EXPECT_EQ(0u, cache.size());
 }
 
+class SSLClientSessionCacheMemoryDumpTest
+    : public SSLClientSessionCacheTest,
+      public testing::WithParamInterface<
+          base::trace_event::MemoryDumpLevelOfDetail> {};
+
+INSTANTIATE_TEST_CASE_P(
+    /* no prefix */,
+    SSLClientSessionCacheMemoryDumpTest,
+    ::testing::Values(base::trace_event::MemoryDumpLevelOfDetail::DETAILED,
+                      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND));
+
 // Basic test for dumping memory stats.
-TEST_F(SSLClientSessionCacheTest, TestDumpMemoryStats) {
+TEST_P(SSLClientSessionCacheMemoryDumpTest, TestDumpMemoryStats) {
   SSLClientSessionCache::Config config;
   SSLClientSessionCache cache(config);
 
@@ -372,8 +383,7 @@
   EXPECT_EQ(session3.get(), cache.Lookup("key3", nullptr).get());
   EXPECT_EQ(3u, cache.size());
 
-  base::trace_event::MemoryDumpArgs dump_args = {
-      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+  base::trace_event::MemoryDumpArgs dump_args = {GetParam()};
   std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
       new base::trace_event::ProcessMemoryDump(nullptr, dump_args));
   cache.DumpMemoryStats(process_memory_dump.get());
diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc
index 300c050e..a7b0233 100644
--- a/net/url_request/url_request_context.cc
+++ b/net/url_request/url_request_context.cc
@@ -4,6 +4,8 @@
 
 #include "net/url_request/url_request_context.h"
 
+#include <inttypes.h>
+
 #include "base/compiler_specific.h"
 #include "base/debug/alias.h"
 #include "base/memory/ptr_util.h"
@@ -12,6 +14,7 @@
 #include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/memory_allocator_dump.h"
 #include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_request_args.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "net/base/sdch_manager.h"
 #include "net/cookies/cookie_store.h"
@@ -138,11 +141,21 @@
     base::trace_event::ProcessMemoryDump* pmd) {
   if (name_.empty())
     name_ = "unknown";
-  base::trace_event::MemoryAllocatorDump* dump = pmd->CreateAllocatorDump(
-      base::StringPrintf("net/url_request_context/%s_%p", name_.c_str(), this));
+
+  SSLClientSocketImpl::DumpSSLClientSessionMemoryStats(pmd);
+
+  std::string dump_name = base::StringPrintf(
+      "net/url_request_context_0x%" PRIxPTR, reinterpret_cast<uintptr_t>(this));
+  base::trace_event::MemoryAllocatorDump* dump =
+      pmd->CreateAllocatorDump(dump_name);
   dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
                   base::trace_event::MemoryAllocatorDump::kUnitsObjects,
                   url_requests_->size());
+  if (args.level_of_detail !=
+      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) {
+    dump->AddString("origin",
+                    base::trace_event::MemoryAllocatorDump::kTypeString, name_);
+  }
   HttpTransactionFactory* transaction_factory = http_transaction_factory();
   if (transaction_factory) {
     HttpNetworkSession* network_session = transaction_factory->GetSession();
@@ -152,9 +165,8 @@
     if (http_cache)
       http_cache->DumpMemoryStats(pmd, dump->absolute_name());
   }
-  SSLClientSocketImpl::DumpSSLClientSessionMemoryStats(pmd);
   if (sdch_manager_)
-    sdch_manager_->DumpMemoryStats(pmd, dump->absolute_name());
+    sdch_manager_->DumpMemoryStats(pmd, dump_name);
   return true;
 }
 
diff --git a/net/url_request/url_request_context_unittest.cc b/net/url_request/url_request_context_unittest.cc
index bae1685..147e350 100644
--- a/net/url_request/url_request_context_unittest.cc
+++ b/net/url_request/url_request_context_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "base/memory/ptr_util.h"
+#include "base/trace_event/memory_dump_request_args.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "net/proxy/proxy_config_service_fixed.h"
 #include "net/url_request/url_request_context_builder.h"
@@ -14,10 +15,19 @@
 
 namespace net {
 
+class URLRequestContextMemoryDumpTest
+    : public testing::TestWithParam<
+          base::trace_event::MemoryDumpLevelOfDetail> {};
+
+INSTANTIATE_TEST_CASE_P(
+    /* no prefix */,
+    URLRequestContextMemoryDumpTest,
+    ::testing::Values(base::trace_event::MemoryDumpLevelOfDetail::DETAILED,
+                      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND));
+
 // Checks if the dump provider runs without crashing and dumps root objects.
-TEST(URLRequestContextTest, MemoryDumpProvider) {
-  base::trace_event::MemoryDumpArgs dump_args = {
-      base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
+TEST_P(URLRequestContextMemoryDumpTest, MemoryDumpProvider) {
+  base::trace_event::MemoryDumpArgs dump_args = {GetParam()};
   std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
       new base::trace_event::ProcessMemoryDump(nullptr, dump_args));
   URLRequestContextBuilder builder;
diff --git a/skia/ext/raster_handle_allocator_win.cc b/skia/ext/raster_handle_allocator_win.cc
index f5c4bdd..22d9bf4 100644
--- a/skia/ext/raster_handle_allocator_win.cc
+++ b/skia/ext/raster_handle_allocator_win.cc
@@ -108,6 +108,10 @@
   }
 };
 
+void unmap_view_proc(void* pixels, void*) {
+  UnmapViewOfFile(pixels);
+}
+
 }  // namespace
 
 namespace skia {
@@ -137,8 +141,13 @@
     DCHECK(shared_section != NULL);
     void* pixels =
         MapViewOfFile(shared_section, FILE_MAP_WRITE, 0, 0, row_bytes * height);
-    if (pixels)
-      return SkCanvas::MakeRasterDirect(info, pixels, row_bytes);
+    if (pixels) {
+      SkBitmap bitmap;
+      if (bitmap.installPixels(info, pixels, row_bytes, nullptr,
+                               unmap_view_proc, nullptr)) {
+        return base::MakeUnique<SkCanvas>(bitmap);
+      }
+    }
   }
 
   if (failure_type == CRASH_ON_FAILURE)
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json
index 9de4709..951707fb 100644
--- a/testing/variations/fieldtrial_testing_config.json
+++ b/testing/variations/fieldtrial_testing_config.json
@@ -1262,6 +1262,21 @@
             ]
         }
     ],
+    "NTPPreferAmpUrls": [
+        {
+            "platforms": [
+                "android"
+            ],
+            "experiments": [
+                {
+                    "name": "Enabled",
+                    "enable_features": [
+                        "NTPPreferAmpUrls"
+                    ]
+                }
+            ]
+        }
+    ],
     "NTPRecentForeignTabs": [
         {
             "platforms": [
diff --git a/third_party/WebKit/LayoutTests/editing/selection/extend-crash.html b/third_party/WebKit/LayoutTests/editing/selection/extend-crash.html
new file mode 100644
index 0000000..b92dcc9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/editing/selection/extend-crash.html
@@ -0,0 +1,15 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<div contenteditable="true">foo</div>
+<script>
+test(() => {
+  // Note that this test can be removed when crbug.com/690272 is fixed.
+  let selection = getSelection();
+  let editor = document.querySelector('div');
+  editor.addEventListener('focus', () => { selection.removeAllRanges(); });
+  selection.collapse(editor, 0);
+  assert_throws('InvalidStateError', () => { selection.extend(editor, 1);});
+}, 'Focus event handler should not make inconsistent state of Selection, and extend() should not crash.');
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/redirect-with-delay.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/redirect-with-delay.html
new file mode 100644
index 0000000..bd3cc035
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/redirect-with-delay.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<script src = "/resources/testharness.js"></script>
+<script src = "/resources/testharnessreport.js"></script>
+<script>
+let test = async_test('CSP should be enforced to the iframe');
+let counter = 0;
+const global = window;
+
+function check() {
+  ++counter;
+  if (counter !== 2)
+    return;
+  const iframe = document.querySelector('iframe');
+  assert_true(global.script_loaded, 'in the main frame');
+  assert_equals(iframe.contentWindow.script_loaded, undefined, 'in the iframe');
+  test.done();
+}
+</script>
+
+<script src="http://localhost:8000/security/contentSecurityPolicy/resources/redirect.pl?type=script&wait=true" async onload="test.step(check)"></script>
+<iframe src="resources/redirect-with-delay-iframe.html" onload="test.step(check)"></iframe>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/redirect-with-delay-iframe.html b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/redirect-with-delay-iframe.html
new file mode 100644
index 0000000..8882d48d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/redirect-with-delay-iframe.html
@@ -0,0 +1,4 @@
+<!doctype html>
+<meta http-equiv = "Content-Security-Policy" content = "script-src http://localhost:8000/ 'unsafe-inline'">
+<script src="http://localhost:8000/security/contentSecurityPolicy/resources/redirect.pl?type=script&wait=true"></script>
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/redirect.pl b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/redirect.pl
index 81304916..a2e593e 100755
--- a/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/redirect.pl
+++ b/third_party/WebKit/LayoutTests/http/tests/security/contentSecurityPolicy/resources/redirect.pl
@@ -5,6 +5,11 @@
 my $cgi = new CGI;
 
 my $resourceType = $cgi->param("type");
+my $wait = $cgi->param("wait");
+
+if ($wait) {
+    sleep(2);
+}
 
 if ($resourceType eq "script") {
     print "Location: http://127.0.0.1:8000/security/contentSecurityPolicy/resources/script-redirect-not-allowed.js";
diff --git a/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js b/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js
index 8971afa..1e27c4d0 100644
--- a/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js
+++ b/third_party/WebKit/LayoutTests/sensor/resources/generic-sensor-tests.js
@@ -5,11 +5,6 @@
 // is called so that the value read in JavaScript are the values expected (the ones
 // sent by |updateReading|).
 function runGenericSensorTests(sensorType, updateReading, verifyReading) {
-  test(() => assert_throws(
-    new RangeError(),
-    () => new sensorType({frequency: -60})),
-    'Test that negative frequency causes exception from constructor.');
-
   sensor_test(sensor => {
     sensor.mockSensorProvider.setGetSensorShouldFail(true);
     let sensorObject = new sensorType;
@@ -97,6 +92,30 @@
   }, 'Test that frequency is capped to the maximum supported from frequency.');
 
   sensor_test(sensor => {
+    let minSupportedFrequency = 2;
+    sensor.mockSensorProvider.setMinimumSupportedFrequency(minSupportedFrequency);
+    let sensorObject = new sensorType({frequency: -1});
+    sensorObject.start();
+    let testPromise = sensor.mockSensorProvider.getCreatedSensor()
+        .then(mockSensor => { return mockSensor.addConfigurationCalled(); })
+        .then(mockSensor => {
+          return new Promise((resolve, reject) => {
+            let wrapper = new CallbackWrapper(() => {
+              let configuration = mockSensor.active_sensor_configurations_[0];
+              assert_equals(configuration.frequency, minSupportedFrequency);
+              sensorObject.stop();
+              assert_equals(sensorObject.state, 'idle');
+              resolve(mockSensor);
+           }, reject);
+           sensorObject.onactivate = wrapper.callback;
+           sensorObject.onerror = reject;
+          });
+        })
+        .then(mockSensor => { return mockSensor.removeConfigurationCalled(); });
+    return testPromise;
+  }, 'Test that frequency is limited to the minimum supported from frequency.');
+
+  sensor_test(sensor => {
     let sensorObject = new sensorType({frequency: 60});
     assert_equals(sensorObject.state, 'unconnected');
     sensorObject.start();
diff --git a/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js b/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js
index e514fe0..7d3c97e4 100644
--- a/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js
+++ b/third_party/WebKit/LayoutTests/sensor/resources/sensor-helpers.js
@@ -249,6 +249,7 @@
         this.resolve_func_ = null;
         this.is_continuous_ = false;
         this.max_frequency_ = 60;
+        this.min_frequency_ = 1;
         this.binding_ = new bindings.Binding(sensor_provider.SensorProvider,
                                              this);
       }
@@ -288,6 +289,7 @@
                   buffer_offset: offset,
                   mode: reporting_mode,
                   default_configuration: default_config,
+                  minimum_frequency: this.min_frequency_,
                   maximum_frequency: this.max_frequency_});
 
         if (this.resolve_func_ !== null) {
@@ -319,6 +321,7 @@
         this.get_sensor_should_fail_ = false;
         this.resolve_func_ = null;
         this.max_frequency_ = 60;
+        this.min_frequency_ = 1;
         this.is_continuous_ = false;
         this.binding_.close();
       }
@@ -349,6 +352,11 @@
       setMaximumSupportedFrequency(frequency) {
           this.max_frequency_ = frequency;
       }
+
+      // Sets the minimum frequency for a concrete sensor.
+      setMinimumSupportedFrequency(frequency) {
+          this.min_frequency_ = frequency;
+      }
     }
 
     let mockSensorProvider = new MockSensorProvider;
diff --git a/third_party/WebKit/Source/core/dom/Range.cpp b/third_party/WebKit/Source/core/dom/Range.cpp
index c439b5d0..4e1d44a 100644
--- a/third_party/WebKit/Source/core/dom/Range.cpp
+++ b/third_party/WebKit/Source/core/dom/Range.cpp
@@ -57,6 +57,51 @@
 
 namespace blink {
 
+class RangeUpdateScope {
+  STACK_ALLOCATED();
+  RangeUpdateScope(Range* range) {
+    DCHECK(range);
+    if (++s_scopeCount == 1) {
+      m_range = range;
+      m_oldDocument = range->ownerDocument();
+#if DCHECK_IS_ON()
+      s_range = range;
+    } else {
+      DCHECK_EQ(s_range, range);
+#endif
+    }
+  }
+
+  ~RangeUpdateScope() {
+    DCHECK_GE(s_scopeCount, 1);
+    if (--s_scopeCount > 0)
+      return;
+    m_range->removeFromSelectionIfInDifferentRoot(*m_oldDocument);
+    m_range->updateSelectionIfAddedToSelection();
+#if DCHECK_IS_ON()
+    s_range = nullptr;
+#endif
+  }
+
+ private:
+  static int s_scopeCount;
+#if DCHECK_IS_ON()
+  // This raw pointer is safe because
+  //  - s_range has a valid pointer only if RangeUpdateScope instance is live.
+  //  - RangeUpdateScope is used only in Range member functions.
+  static Range* s_range;
+#endif
+  Member<Range> m_range;
+  Member<Document> m_oldDocument;
+
+  DISALLOW_COPY_AND_ASSIGN(RangeUpdateScope);
+};
+
+int RangeUpdateScope::s_scopeCount = 0;
+#if DCHECK_IS_ON()
+Range* RangeUpdateScope::s_range;
+#endif
+
 inline Range::Range(Document& ownerDocument)
     : m_ownerDocument(&ownerDocument),
       m_start(m_ownerDocument),
@@ -172,7 +217,7 @@
     return;
   }
 
-  Document& oldDocument = ownerDocument();
+  RangeUpdateScope scope(this);
   bool didMoveDocument = false;
   if (refNode->document() != m_ownerDocument) {
     setDocument(refNode->document());
@@ -185,12 +230,8 @@
 
   m_start.set(refNode, offset, childNode);
 
-  if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) {
-    removeFromSelectionIfInDifferentRoot(oldDocument);
+  if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end))
     collapse(true);
-    return;
-  }
-  updateSelectionIfAddedToSelection();
 }
 
 void Range::setEnd(Node* refNode,
@@ -203,8 +244,8 @@
     return;
   }
 
+  RangeUpdateScope scope(this);
   bool didMoveDocument = false;
-  Document& oldDocument = ownerDocument();
   if (refNode->document() != m_ownerDocument) {
     setDocument(refNode->document());
     didMoveDocument = true;
@@ -216,12 +257,8 @@
 
   m_end.set(refNode, offset, childNode);
 
-  if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end)) {
-    removeFromSelectionIfInDifferentRoot(oldDocument);
+  if (didMoveDocument || checkForDifferentRootContainer(m_start, m_end))
     collapse(false);
-    return;
-  }
-  updateSelectionIfAddedToSelection();
 }
 
 void Range::setStart(const Position& start, ExceptionState& exceptionState) {
@@ -237,11 +274,11 @@
 }
 
 void Range::collapse(bool toStart) {
+  RangeUpdateScope scope(this);
   if (toStart)
     m_end = m_start;
   else
     m_start = m_end;
-  updateSelectionIfAddedToSelection();
 }
 
 bool Range::isNodeFullyContained(Node& node) const {
@@ -1208,6 +1245,7 @@
       return;
   }
 
+  RangeUpdateScope scope(this);
   setStartBefore(refNode);
   setEndAfter(refNode);
 }
@@ -1242,14 +1280,12 @@
     }
   }
 
-  Document& oldDocument = ownerDocument();
+  RangeUpdateScope scope(this);
   if (m_ownerDocument != refNode->document())
     setDocument(refNode->document());
 
   m_start.setToStartOfNode(*refNode);
   m_end.setToEndOfNode(*refNode);
-  removeFromSelectionIfInDifferentRoot(oldDocument);
-  updateSelectionIfAddedToSelection();
 }
 
 bool Range::selectNodeContents(Node* refNode, Position& start, Position& end) {
@@ -1746,8 +1782,13 @@
   DCHECK(startContainer()->document() == ownerDocument());
   DCHECK(endContainer()->isConnected());
   DCHECK(endContainer()->document() == ownerDocument());
-  selection.setSelectedRange(EphemeralRange(this), VP_DEFAULT_AFFINITY);
+  bool didSet = selection.setSelectionDeprecated(SelectionInDOMTree::Builder()
+                                                     .collapse(startPosition())
+                                                     .extend(endPosition())
+                                                     .build());
   selection.cacheRangeOfDocument(this);
+  if (didSet)
+    selection.didSetSelectionDeprecated();
 }
 
 void Range::removeFromSelectionIfInDifferentRoot(Document& oldDocument) {
diff --git a/third_party/WebKit/Source/core/dom/Range.h b/third_party/WebKit/Source/core/dom/Range.h
index f76b3f020..f6db2360 100644
--- a/third_party/WebKit/Source/core/dom/Range.h
+++ b/third_party/WebKit/Source/core/dom/Range.h
@@ -213,6 +213,8 @@
   Member<Document> m_ownerDocument;  // Cannot be null.
   RangeBoundaryPoint m_start;
   RangeBoundaryPoint m_end;
+
+  friend class RangeUpdateScope;
 };
 
 CORE_EXPORT bool areRangesEqual(const Range*, const Range*);
diff --git a/third_party/WebKit/Source/core/editing/DOMSelection.cpp b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
index 4540f0f..d835822 100644
--- a/third_party/WebKit/Source/core/editing/DOMSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/DOMSelection.cpp
@@ -75,6 +75,17 @@
   return frame() && frame()->selection().isAvailable();
 }
 
+void DOMSelection::updateFrameSelection(const SelectionInDOMTree& selection,
+                                        Range* newCachedRange) const {
+  DCHECK(frame());
+  FrameSelection& frameSelection = frame()->selection();
+  // TODO(tkent): Specify FrameSelection::DoNotSetFocus. crbug.com/690272
+  bool didSet = frameSelection.setSelectionDeprecated(selection);
+  cacheRangeIfSelectionOfDocument(newCachedRange);
+  if (didSet)
+    frameSelection.didSetSelectionDeprecated();
+}
+
 const VisibleSelection& DOMSelection::visibleSelection() const {
   DCHECK(frame());
   return frame()->selection().computeVisibleSelectionInDOMTreeDeprecated();
@@ -254,12 +265,12 @@
     return;
 
   // 6. Set the context object's range to newRange.
-  frame()->selection().setSelection(
+  updateFrameSelection(
       SelectionInDOMTree::Builder()
           .collapse(Position(node, offset))
           .setIsDirectional(frame()->selection().isDirectional())
-          .build());
-  cacheRangeIfSelectionOfDocument(newRange);
+          .build(),
+      newRange);
 }
 
 // https://www.w3.org/TR/selection-api/#dom-selection-collapsetoend
@@ -283,8 +294,7 @@
   // and then set the context object's range to the newly-created range.
   SelectionInDOMTree::Builder builder;
   builder.collapse(newRange->endPosition());
-  frame()->selection().setSelection(builder.build());
-  cacheRangeIfSelectionOfDocument(newRange);
+  updateFrameSelection(builder.build(), newRange);
 }
 
 // https://www.w3.org/TR/selection-api/#dom-selection-collapsetostart
@@ -308,8 +318,7 @@
   // and then set the context object's range to the newly-created range.
   SelectionInDOMTree::Builder builder;
   builder.collapse(newRange->startPosition());
-  frame()->selection().setSelection(builder.build());
-  cacheRangeIfSelectionOfDocument(newRange);
+  updateFrameSelection(builder.build(), newRange);
 }
 
 void DOMSelection::empty() {
@@ -360,12 +369,6 @@
 
   Position basePosition(baseNode, baseOffset);
   Position extentPosition(extentNode, extentOffset);
-  frame()->selection().setSelection(
-      SelectionInDOMTree::Builder()
-          .setBaseAndExtentDeprecated(basePosition, extentPosition)
-          .setIsDirectional(true)
-          .build());
-
   Range* newRange = Range::create(baseNode->document());
   if (extentPosition.isNull()) {
     newRange->setStart(baseNode, baseOffset);
@@ -377,7 +380,12 @@
     newRange->setStart(extentNode, extentOffset);
     newRange->setEnd(baseNode, baseOffset);
   }
-  cacheRangeIfSelectionOfDocument(newRange);
+  updateFrameSelection(
+      SelectionInDOMTree::Builder()
+          .setBaseAndExtentDeprecated(basePosition, extentPosition)
+          .setIsDirectional(true)
+          .build(),
+      newRange);
 }
 
 void DOMSelection::modify(const String& alterString,
@@ -509,8 +517,7 @@
     builder.collapse(newFocus);
   else
     builder.collapse(oldAnchor).extend(newFocus);
-  frame()->selection().setSelection(builder.setIsDirectional(true).build());
-  cacheRangeIfSelectionOfDocument(newRange);
+  updateFrameSelection(builder.setIsDirectional(true).build(), newRange);
 }
 
 Range* DOMSelection::getRangeAt(unsigned index,
@@ -609,8 +616,11 @@
   }
 
   if (rangeCount() == 0) {
-    selection.setSelectedRange(EphemeralRange(newRange), VP_DEFAULT_AFFINITY);
-    cacheRangeIfSelectionOfDocument(newRange);
+    updateFrameSelection(SelectionInDOMTree::Builder()
+                             .collapse(newRange->startPosition())
+                             .extend(newRange->endPosition())
+                             .build(),
+                         newRange);
     return;
   }
 
diff --git a/third_party/WebKit/Source/core/editing/DOMSelection.h b/third_party/WebKit/Source/core/editing/DOMSelection.h
index c8c53d76..094a1e0 100644
--- a/third_party/WebKit/Source/core/editing/DOMSelection.h
+++ b/third_party/WebKit/Source/core/editing/DOMSelection.h
@@ -108,6 +108,7 @@
 
   bool isAvailable() const;
 
+  void updateFrameSelection(const SelectionInDOMTree&, Range*) const;
   // Convenience methods for accessors, does not check m_frame present.
   const VisibleSelection& visibleSelection() const;
   bool isBaseFirstInSelection() const;
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
index 84465a9..8fe6ece 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.cpp
@@ -1739,39 +1739,45 @@
   return targetNode->layoutObject()->positionForPoint(selectionEndPoint);
 }
 
-void updatePositionForNodeRemoval(Position& position, Node& node) {
+Position computePositionForNodeRemoval(const Position& position, Node& node) {
   if (position.isNull())
-    return;
+    return position;
   switch (position.anchorType()) {
     case PositionAnchorType::BeforeChildren:
-      if (node.isShadowIncludingInclusiveAncestorOf(
-              position.computeContainerNode()))
-        position = Position::inParentBeforeNode(node);
-      break;
+      if (!node.isShadowIncludingInclusiveAncestorOf(
+              position.computeContainerNode())) {
+        return position;
+      }
+      return Position::inParentBeforeNode(node);
     case PositionAnchorType::AfterChildren:
-      if (node.isShadowIncludingInclusiveAncestorOf(
-              position.computeContainerNode()))
-        position = Position::inParentAfterNode(node);
-      break;
+      if (!node.isShadowIncludingInclusiveAncestorOf(
+              position.computeContainerNode())) {
+        return position;
+      }
+      return Position::inParentAfterNode(node);
     case PositionAnchorType::OffsetInAnchor:
       if (position.computeContainerNode() == node.parentNode() &&
           static_cast<unsigned>(position.offsetInContainerNode()) >
-              node.nodeIndex())
-        position = Position(position.computeContainerNode(),
-                            position.offsetInContainerNode() - 1);
-      else if (node.isShadowIncludingInclusiveAncestorOf(
-                   position.computeContainerNode()))
-        position = Position::inParentBeforeNode(node);
-      break;
+              node.nodeIndex()) {
+        return Position(position.computeContainerNode(),
+                        position.offsetInContainerNode() - 1);
+      }
+      if (!node.isShadowIncludingInclusiveAncestorOf(
+              position.computeContainerNode())) {
+        return position;
+      }
+      return Position::inParentBeforeNode(node);
     case PositionAnchorType::AfterAnchor:
-      if (node.isShadowIncludingInclusiveAncestorOf(position.anchorNode()))
-        position = Position::inParentAfterNode(node);
-      break;
+      if (!node.isShadowIncludingInclusiveAncestorOf(position.anchorNode()))
+        return position;
+      return Position::inParentAfterNode(node);
     case PositionAnchorType::BeforeAnchor:
-      if (node.isShadowIncludingInclusiveAncestorOf(position.anchorNode()))
-        position = Position::inParentBeforeNode(node);
-      break;
+      if (!node.isShadowIncludingInclusiveAncestorOf(position.anchorNode()))
+        return position;
+      return Position::inParentBeforeNode(node);
   }
+  NOTREACHED() << "We should handle all PositionAnchorType";
+  return position;
 }
 
 bool isMailHTMLBlockquoteElement(const Node* node) {
diff --git a/third_party/WebKit/Source/core/editing/EditingUtilities.h b/third_party/WebKit/Source/core/editing/EditingUtilities.h
index a35dcfb..b8bf1cdf 100644
--- a/third_party/WebKit/Source/core/editing/EditingUtilities.h
+++ b/third_party/WebKit/Source/core/editing/EditingUtilities.h
@@ -81,6 +81,8 @@
 Element* rootEditableElementOf(const Position&);
 Element* rootEditableElementOf(const PositionInFlatTree&);
 Element* rootEditableElementOf(const VisiblePosition&);
+ContainerNode* rootEditableElementOrTreeScopeRootNodeOf(
+    const VisibleSelection&);
 // highestEditableRoot returns the highest editable node. If the
 // rootEditableElement of the speicified Position is <body>, this returns the
 // <body>. Otherwise, this searches ancestors for the highest editable node in
@@ -303,7 +305,7 @@
     const Position&,
     const LayoutPoint& localPoint,
     Node* targetNode);
-void updatePositionForNodeRemoval(Position&, Node&);
+Position computePositionForNodeRemoval(const Position&, Node&);
 
 // -------------------------------------------------------------------------
 // VisiblePosition
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.cpp b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
index 700cbd2d..791876c 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.cpp
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.cpp
@@ -139,15 +139,15 @@
   return selectionRoot ? selectionRoot : document().documentElement();
 }
 
-ContainerNode* FrameSelection::rootEditableElementOrTreeScopeRootNode() const {
-  Element* selectionRoot =
-      computeVisibleSelectionInDOMTreeDeprecated().rootEditableElement();
+// TODO(yosin): We should move |rootEditableElementOrTreeScopeRootNodeOf()| to
+// "EditingUtilities.cpp"
+ContainerNode* rootEditableElementOrTreeScopeRootNodeOf(
+    const VisibleSelection& visibleSelection) {
+  Element* selectionRoot = visibleSelection.rootEditableElement();
   if (selectionRoot)
     return selectionRoot;
 
-  Node* node = computeVisibleSelectionInDOMTreeDeprecated()
-                   .base()
-                   .computeContainerNode();
+  Node* const node = visibleSelection.base().computeContainerNode();
   return node ? &node->treeScope().rootNode() : 0;
 }
 
@@ -186,6 +186,14 @@
                                   SetSelectionOptions options,
                                   CursorAlignOnScroll align,
                                   TextGranularity granularity) {
+  if (setSelectionDeprecated(passedSelection, options, granularity))
+    didSetSelectionDeprecated(options, align);
+}
+
+bool FrameSelection::setSelectionDeprecated(
+    const SelectionInDOMTree& passedSelection,
+    SetSelectionOptions options,
+    TextGranularity granularity) {
   DCHECK(isAvailable());
   passedSelection.assertValidFor(document());
 
@@ -211,7 +219,7 @@
   const SelectionInDOMTree oldSelectionInDOMTree =
       m_selectionEditor->selectionInDOMTree();
   if (oldSelectionInDOMTree == newSelection)
-    return;
+    return false;
   m_selectionEditor->setSelection(newSelection);
   scheduleVisualUpdateForPaintInvalidationIfNeeded();
 
@@ -223,7 +231,12 @@
   m_frame->editor().respondToChangedSelection(
       oldSelectionInDOMTree.computeStartPosition(), options);
   DCHECK_EQ(currentDocument, document());
+  return true;
+}
 
+void FrameSelection::didSetSelectionDeprecated(SetSelectionOptions options,
+                                               CursorAlignOnScroll align) {
+  const Document& currentDocument = document();
   if (!selectionInDOMTree().isNone() && !(options & DoNotSetFocus)) {
     setFocusedNodeIfNeeded();
     // |setFocusedNodeIfNeeded()| dispatches sync events "FocusOut" and
diff --git a/third_party/WebKit/Source/core/editing/FrameSelection.h b/third_party/WebKit/Source/core/editing/FrameSelection.h
index da88306..d78e98a 100644
--- a/third_party/WebKit/Source/core/editing/FrameSelection.h
+++ b/third_party/WebKit/Source/core/editing/FrameSelection.h
@@ -101,7 +101,6 @@
   Document& document() const;
   LocalFrame* frame() const { return m_frame; }
   Element* rootEditableElementOrDocumentElement() const;
-  ContainerNode* rootEditableElementOrTreeScopeRootNode() const;
 
   // An implementation of |WebFrame::moveCaretSelection()|
   void moveCaretSelection(const IntPoint&);
@@ -148,6 +147,19 @@
   void selectAll();
   void clear();
 
+  // TODO(tkent): These two functions were added to fix crbug.com/695211 without
+  // changing focus behavior. Once we fix crbug.com/690272, we can remove these
+  // functions.
+  // setSelectionDeprecated() returns true if didSetSelectionDeprecated() should
+  // be called.
+  bool setSelectionDeprecated(const SelectionInDOMTree&,
+                              SetSelectionOptions = CloseTyping |
+                                                    ClearTypingStyle,
+                              TextGranularity = CharacterGranularity);
+  void didSetSelectionDeprecated(
+      SetSelectionOptions = CloseTyping | ClearTypingStyle,
+      CursorAlignOnScroll = CursorAlignOnScroll::IfNeeded);
+
   // Call this after doing user-triggered selections to make it easy to delete
   // the frame you entirely selected.
   void selectFrameElementInParentIfFullySelected();
diff --git a/third_party/WebKit/Source/core/editing/InputMethodController.cpp b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
index 8fd939a..be4e5a0 100644
--- a/third_party/WebKit/Source/core/editing/InputMethodController.cpp
+++ b/third_party/WebKit/Source/core/editing/InputMethodController.cpp
@@ -698,8 +698,8 @@
       frame().selection().computeVisibleSelectionInDOMTreeDeprecated());
   if (range.isNull())
     return PlainTextRange();
-  ContainerNode* editable =
-      frame().selection().rootEditableElementOrTreeScopeRootNode();
+  ContainerNode* const editable = rootEditableElementOrTreeScopeRootNodeOf(
+      frame().selection().computeVisibleSelectionInDOMTreeDeprecated());
   DCHECK(editable);
   return PlainTextRange::create(*editable, range);
 }
diff --git a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
index 04dd0915..7d38c7e 100644
--- a/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
+++ b/third_party/WebKit/Source/core/editing/SelectionEditor.cpp
@@ -191,15 +191,6 @@
   markCacheDirty();
 }
 
-static Position computePositionForNodeRemoval(const Position& position,
-                                              Node& nodeToBeRemoved) {
-  Position result = position;
-  // TODO(yosin): We should rename |updatePositionForNodeRemoval()|
-  // to |computePositionForNodeRemoval()| to avoid using output parameter.
-  updatePositionForNodeRemoval(result, nodeToBeRemoved);
-  return result;
-}
-
 void SelectionEditor::nodeWillBeRemoved(Node& nodeToBeRemoved) {
   if (m_selection.isNone())
     return;
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
index e8cd1338..fe67f4e2 100644
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp
@@ -432,7 +432,7 @@
     Node& node) {
   int offset =
       position.isOffsetInAnchor() ? position.offsetInContainerNode() : 0;
-  updatePositionForNodeRemoval(position, node);
+  position = computePositionForNodeRemoval(position, node);
   if (offset == 0)
     return;
   position = Position(position.computeContainerNode(), offset);
diff --git a/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp b/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp
index 074bb7a..cb59bcd5 100644
--- a/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/DeleteSelectionCommand.cpp
@@ -517,9 +517,11 @@
   }
 
   // FIXME: Update the endpoints of the range being deleted.
-  updatePositionForNodeRemoval(m_endingPosition, *node);
-  updatePositionForNodeRemoval(m_leadingWhitespace, *node);
-  updatePositionForNodeRemoval(m_trailingWhitespace, *node);
+  m_endingPosition = computePositionForNodeRemoval(m_endingPosition, *node);
+  m_leadingWhitespace =
+      computePositionForNodeRemoval(m_leadingWhitespace, *node);
+  m_trailingWhitespace =
+      computePositionForNodeRemoval(m_trailingWhitespace, *node);
 
   CompositeEditCommand::removeNode(node, editingState,
                                    shouldAssumeContentIsAlwaysEditable);
@@ -671,7 +673,7 @@
         Node* nextNode = NodeTraversal::nextSkippingChildren(*node);
         // if we just removed a node from the end container, update end position
         // so the check above will work
-        updatePositionForNodeRemoval(m_downstreamEnd, *node);
+        m_downstreamEnd = computePositionForNodeRemoval(m_downstreamEnd, *node);
         removeNode(node, editingState);
         if (editingState->isAborted())
           return;
diff --git a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
index 773302a6..a0a4b7a 100644
--- a/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/ReplaceSelectionCommand.cpp
@@ -1818,12 +1818,13 @@
         previous->data().length() <= kMergeSizeLimit) {
       insertTextIntoNode(text, 0, previous->data());
 
-      if (positionIsOffsetInAnchor)
+      if (positionIsOffsetInAnchor) {
         position =
             Position(position.computeContainerNode(),
                      previous->length() + position.offsetInContainerNode());
-      else
-        updatePositionForNodeRemoval(position, *previous);
+      } else {
+        position = computePositionForNodeRemoval(position, *previous);
+      }
 
       if (positionOnlyToBeUpdatedIsOffsetInAnchor) {
         if (positionOnlyToBeUpdated.computeContainerNode() == text)
@@ -1834,7 +1835,8 @@
           positionOnlyToBeUpdated =
               Position(text, positionOnlyToBeUpdated.offsetInContainerNode());
       } else {
-        updatePositionForNodeRemoval(positionOnlyToBeUpdated, *previous);
+        positionOnlyToBeUpdated =
+            computePositionForNodeRemoval(positionOnlyToBeUpdated, *previous);
       }
 
       removeNode(previous, editingState);
@@ -1850,15 +1852,17 @@
     insertTextIntoNode(text, originalLength, next->data());
 
     if (!positionIsOffsetInAnchor)
-      updatePositionForNodeRemoval(position, *next);
+      position = computePositionForNodeRemoval(position, *next);
 
     if (positionOnlyToBeUpdatedIsOffsetInAnchor &&
-        positionOnlyToBeUpdated.computeContainerNode() == next)
+        positionOnlyToBeUpdated.computeContainerNode() == next) {
       positionOnlyToBeUpdated =
           Position(text, originalLength +
                              positionOnlyToBeUpdated.offsetInContainerNode());
-    else
-      updatePositionForNodeRemoval(positionOnlyToBeUpdated, *next);
+    } else {
+      positionOnlyToBeUpdated =
+          computePositionForNodeRemoval(positionOnlyToBeUpdated, *next);
+    }
 
     removeNode(next, editingState);
     if (editingState->isAborted())
diff --git a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
index 7313874..e47b8b2 100644
--- a/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
+++ b/third_party/WebKit/Source/core/editing/commands/TypingCommand.cpp
@@ -85,8 +85,8 @@
       frame->selection().computeVisibleSelectionInDOMTreeDeprecated());
   if (range.isNull())
     return PlainTextRange();
-  ContainerNode* editable =
-      frame->selection().rootEditableElementOrTreeScopeRootNode();
+  ContainerNode* const editable = rootEditableElementOrTreeScopeRootNodeOf(
+      frame->selection().computeVisibleSelectionInDOMTreeDeprecated());
   DCHECK(editable);
   return PlainTextRange::create(*editable, range);
 }
diff --git a/third_party/WebKit/Source/core/frame/csp/CSPSourceTest.cpp b/third_party/WebKit/Source/core/frame/csp/CSPSourceTest.cpp
index 36590e96..161c1e3 100644
--- a/third_party/WebKit/Source/core/frame/csp/CSPSourceTest.cpp
+++ b/third_party/WebKit/Source/core/frame/csp/CSPSourceTest.cpp
@@ -187,11 +187,13 @@
         *SecurityOrigin::createFromString("non-standard-scheme://a.com/"));
     CSPSource source(csp.get(), "", "a.com", 0, "/", CSPSource::NoWildcard,
                      CSPSource::NoWildcard);
-    // TODO(mkwst, arthursonzogni): This result might be wrong.
-    // See http://crbug.com/692449
     EXPECT_FALSE(source.matches(KURL(base, "http://a.com")));
-    // TODO(mkwst, arthursonzogni): This result might be wrong.
-    // See http://crbug.com/692449
+
+    // The reason matching fails is because the host is parsed as "" when
+    // using a non standard scheme even though it should be parsed as "a.com"
+    // After adding it to the list of standard schemes it now gets parsed
+    // correctly. This does not matter in practice though because there is
+    // no way to render/load anything like "non-standard-scheme://a.com"
     EXPECT_FALSE(source.matches(KURL(base, "non-standard-scheme://a.com")));
   }
 }
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
index ae4caa2..a7f28c6 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasAsyncBlobCreator.h
@@ -2,6 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#ifndef CanvasAsyncBlobCreator_h
+#define CanvasAsyncBlobCreator_h
+
 #include "bindings/core/v8/ScriptPromiseResolver.h"
 #include "core/CoreExport.h"
 #include "core/dom/DOMTypedArray.h"
@@ -143,3 +146,5 @@
 };
 
 }  // namespace blink
+
+#endif  // CanvasAsyncBlobCreator_h
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
index 3ad812c..f50247e 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.cpp
@@ -36,7 +36,6 @@
 LayoutSVGResourceContainer::LayoutSVGResourceContainer(SVGElement* node)
     : LayoutSVGHiddenContainer(node),
       m_isInLayout(false),
-      m_id(node->getIdAttribute()),
       m_invalidationMask(0),
       m_registered(false),
       m_isInvalidating(false) {}
@@ -74,8 +73,10 @@
   detachAllClients();
 
   LayoutSVGHiddenContainer::willBeDestroyed();
-  if (m_registered)
-    svgTreeScopeResourcesFromElement(element()).removeResource(m_id);
+  if (!m_registered)
+    return;
+  svgTreeScopeResourcesFromElement(element()).removeResource(
+      element()->getIdAttribute());
 }
 
 void LayoutSVGResourceContainer::styleDidChange(StyleDifference diff,
@@ -85,10 +86,12 @@
   if (m_registered)
     return;
   m_registered = true;
-  svgTreeScopeResourcesFromElement(element()).updateResource(m_id, this);
+  svgTreeScopeResourcesFromElement(element()).updateResource(
+      element()->getIdAttribute(), this);
 }
 
 void LayoutSVGResourceContainer::detachAllClients() {
+  const AtomicString& id = element()->getIdAttribute();
   for (auto* client : m_clients) {
     // Unlink the resource from the client's SVGResources. (The actual
     // removal will be signaled after processing all the clients.)
@@ -101,22 +104,22 @@
     // Add a pending resolution based on the id of the old resource.
     Element* clientElement = toElement(client->node());
     svgTreeScopeResourcesFromElement(clientElement)
-        .addPendingResource(m_id, *clientElement);
+        .addPendingResource(id, *clientElement);
   }
 
   removeAllClientsFromCache();
 }
 
-void LayoutSVGResourceContainer::idChanged() {
+void LayoutSVGResourceContainer::idChanged(const AtomicString& oldId,
+                                           const AtomicString& newId) {
   // Invalidate all our current clients.
   removeAllClientsFromCache();
 
   // Remove old id, that is guaranteed to be present in cache.
   SVGTreeScopeResources& treeScopeResources =
       svgTreeScopeResourcesFromElement(element());
-  treeScopeResources.removeResource(m_id);
-  m_id = element()->getIdAttribute();
-  treeScopeResources.updateResource(m_id, this);
+  treeScopeResources.removeResource(oldId);
+  treeScopeResources.updateResource(newId, this);
 }
 
 void LayoutSVGResourceContainer::markAllClientsForInvalidation(
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h
index 1884621..f22b7f9 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourceContainer.h
@@ -62,7 +62,7 @@
            resourceType == RadialGradientResourceType;
   }
 
-  void idChanged();
+  void idChanged(const AtomicString& oldId, const AtomicString& newId);
 
   void invalidateCacheAndMarkForLayout(SubtreeLayoutScope* = nullptr);
 
@@ -99,7 +99,6 @@
   void removeClient(LayoutObject*);
   void detachAllClients();
 
-  AtomicString m_id;
   // Track global (markAllClientsForInvalidation) invals to avoid redundant
   // crawls.
   unsigned m_invalidationMask : 8;
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp
index 67a9d57..58a7d3fd 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -904,8 +904,10 @@
     LayoutObject* object = layoutObject();
     // Notify resources about id changes, this is important as we cache
     // resources by id in SVGDocumentExtensions
-    if (object && object->isSVGResourceContainer())
-      toLayoutSVGResourceContainer(object)->idChanged();
+    if (object && object->isSVGResourceContainer()) {
+      toLayoutSVGResourceContainer(object)->idChanged(params.oldValue,
+                                                      params.newValue);
+    }
     if (isConnected())
       buildPendingResourcesIfNeeded();
     invalidateInstances();
diff --git a/third_party/WebKit/Source/modules/sensor/Sensor.cpp b/third_party/WebKit/Source/modules/sensor/Sensor.cpp
index e930490d..c864dda 100644
--- a/third_party/WebKit/Source/modules/sensor/Sensor.cpp
+++ b/third_party/WebKit/Source/modules/sensor/Sensor.cpp
@@ -45,11 +45,6 @@
   // Check the given frequency value.
   if (m_sensorOptions.hasFrequency()) {
     double frequency = m_sensorOptions.frequency();
-    if (frequency <= 0.0) {
-      exceptionState.throwRangeError("Frequency must be positive.");
-      return;
-    }
-
     if (frequency > SensorConfiguration::kMaxAllowedFrequency) {
       m_sensorOptions.setFrequency(SensorConfiguration::kMaxAllowedFrequency);
       ConsoleMessage* consoleMessage = ConsoleMessage::create(
@@ -151,7 +146,8 @@
   auto result = SensorConfiguration::New();
 
   double defaultFrequency = m_sensorProxy->defaultConfig()->frequency;
-  double maximumFrequency = m_sensorProxy->maximumFrequency();
+  double minimumFrequency = m_sensorProxy->frequencyLimits().first;
+  double maximumFrequency = m_sensorProxy->frequencyLimits().second;
 
   double frequency = m_sensorOptions.hasFrequency()
                          ? m_sensorOptions.frequency()
@@ -159,6 +155,8 @@
 
   if (frequency > maximumFrequency)
     frequency = maximumFrequency;
+  if (frequency < minimumFrequency)
+    frequency = minimumFrequency;
 
   result->frequency = frequency;
   return result;
@@ -248,7 +246,8 @@
     m_configuration = createSensorConfig();
     DCHECK(m_configuration);
     DCHECK(m_configuration->frequency > 0 &&
-           m_configuration->frequency <= m_sensorProxy->maximumFrequency());
+           m_configuration->frequency <=
+               SensorConfiguration::kMaxAllowedFrequency);
   }
 
   auto startCallback =
diff --git a/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp b/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp
index 6caf643..baa7be2 100644
--- a/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp
+++ b/third_party/WebKit/Source/modules/sensor/SensorProxy.cpp
@@ -24,8 +24,7 @@
       m_provider(provider),
       m_clientBinding(this),
       m_state(SensorProxy::Uninitialized),
-      m_suspended(false),
-      m_maximumFrequency(0.0) {}
+      m_suspended(false) {}
 
 SensorProxy::~SensorProxy() {}
 
@@ -211,9 +210,14 @@
     handleSensorError();
     return;
   }
+  m_frequencyLimits.first = params->minimum_frequency;
+  m_frequencyLimits.second = params->maximum_frequency;
 
-  m_maximumFrequency = params->maximum_frequency;
-  DCHECK(m_maximumFrequency <= SensorConfiguration::kMaxAllowedFrequency);
+  DCHECK_GT(m_frequencyLimits.first, 0.0);
+  DCHECK_GE(m_frequencyLimits.second, m_frequencyLimits.first);
+  constexpr double kMaxAllowedFrequency =
+      SensorConfiguration::kMaxAllowedFrequency;
+  DCHECK_GE(kMaxAllowedFrequency, m_frequencyLimits.second);
 
   auto errorCallback =
       WTF::bind(&SensorProxy::handleSensorError, wrapWeakPersistent(this));
diff --git a/third_party/WebKit/Source/modules/sensor/SensorProxy.h b/third_party/WebKit/Source/modules/sensor/SensorProxy.h
index 91434ebf..65baab79 100644
--- a/third_party/WebKit/Source/modules/sensor/SensorProxy.h
+++ b/third_party/WebKit/Source/modules/sensor/SensorProxy.h
@@ -81,7 +81,9 @@
 
   const device::mojom::blink::SensorConfiguration* defaultConfig() const;
 
-  double maximumFrequency() const { return m_maximumFrequency; }
+  const std::pair<double, double>& frequencyLimits() const {
+    return m_frequencyLimits;
+  }
 
   Document* document() const;
   const WTF::Vector<double>& frequenciesUsed() const {
@@ -138,7 +140,7 @@
   mojo::ScopedSharedBufferMapping m_sharedBuffer;
   bool m_suspended;
   device::SensorReading m_reading;
-  double m_maximumFrequency;
+  std::pair<double, double> m_frequencyLimits;
 
   Member<SensorReadingUpdater> m_readingUpdater;
   WTF::Vector<double> m_frequenciesUsed;
diff --git a/third_party/WebKit/Source/platform/heap/PageMemory.cpp b/third_party/WebKit/Source/platform/heap/PageMemory.cpp
index 967c764c..faa6548 100644
--- a/third_party/WebKit/Source/platform/heap/PageMemory.cpp
+++ b/third_party/WebKit/Source/platform/heap/PageMemory.cpp
@@ -72,7 +72,6 @@
 }
 
 PageMemoryRegion* RegionTree::lookup(Address address) {
-  MutexLocker locker(m_mutex);
   RegionTreeNode* current = m_root;
   while (current) {
     Address base = current->m_region->base();
@@ -93,7 +92,6 @@
 void RegionTree::add(PageMemoryRegion* region) {
   ASSERT(region);
   RegionTreeNode* newTree = new RegionTreeNode(region);
-  MutexLocker locker(m_mutex);
   newTree->addTo(&m_root);
 }
 
@@ -108,11 +106,6 @@
 }
 
 void RegionTree::remove(PageMemoryRegion* region) {
-  // Deletion of large objects (and thus their regions) can happen
-  // concurrently on sweeper threads.  Removal can also happen during thread
-  // shutdown, but that case is safe.  Regardless, we make all removals
-  // mutually exclusive.
-  MutexLocker locker(m_mutex);
   ASSERT(region);
   ASSERT(m_root);
   Address base = region->base();
diff --git a/third_party/WebKit/Source/platform/heap/PageMemory.h b/third_party/WebKit/Source/platform/heap/PageMemory.h
index 6e1e87a..a217ea8c 100644
--- a/third_party/WebKit/Source/platform/heap/PageMemory.h
+++ b/third_party/WebKit/Source/platform/heap/PageMemory.h
@@ -11,11 +11,6 @@
 #include "wtf/Compiler.h"
 #include "wtf/allocator/Partitions.h"
 
-#if OS(POSIX)
-#include <sys/mman.h>
-#include <unistd.h>
-#endif
-
 namespace blink {
 
 class RegionTree;
@@ -122,7 +117,6 @@
   PageMemoryRegion* lookup(Address);
 
  private:
-  Mutex m_mutex;
   RegionTreeNode* m_root;
 };
 
@@ -174,6 +168,15 @@
 
   WARN_UNUSED_RESULT bool commit() {
     m_reserved->markPageUsed(writableStart());
+    // Check that in-use page isn't also marked as being a non-heap page
+    // by the current heap's negative cache. That cache is invalidated
+    // when allocating new pages, but crbug.com/649485 suggests that
+    // we do get out of sync somehow.
+    //
+    // TODO(sof): consider removing check once bug has been diagnosed
+    // and addressed.
+    CHECK(!ThreadState::current()->isAddressInHeapDoesNotContainCache(
+        writableStart()));
     return m_writable.commit();
   }
 
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 9b8d8098..09617fb 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -1086,6 +1086,15 @@
 }
 #endif
 
+bool ThreadState::isAddressInHeapDoesNotContainCache(Address address) {
+  // If the cache has been marked as invalidated, it's cleared prior
+  // to performing the next GC. Hence, consider the cache as being
+  // effectively empty.
+  if (m_shouldFlushHeapDoesNotContainCache)
+    return false;
+  return heap().m_heapDoesNotContainCache->lookup(address);
+}
+
 size_t ThreadState::objectPayloadSizeForTesting() {
   size_t objectPayloadSize = 0;
   for (int i = 0; i < BlinkGC::NumberOfArenas; ++i)
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.h b/third_party/WebKit/Source/platform/heap/ThreadState.h
index 522977f..70919b6 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.h
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.h
@@ -379,6 +379,8 @@
     m_shouldFlushHeapDoesNotContainCache = true;
   }
 
+  bool isAddressInHeapDoesNotContainCache(Address);
+
   void registerTraceDOMWrappers(
       v8::Isolate* isolate,
       void (*traceDOMWrappers)(v8::Isolate*, Visitor*),
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
index fb2bdcf..d62e6a12 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcher.cpp
@@ -800,6 +800,14 @@
   if (!existingResource)
     return Load;
 
+  // If the existing resource is loading and the associated fetcher is not equal
+  // to |this|, we must not use the resource. Otherwise, CSP violation may
+  // happen in redirect handling.
+  if (existingResource->loader() &&
+      existingResource->loader()->fetcher() != this) {
+    return Reload;
+  }
+
   // Checks if the resource has an explicit policy about integrity metadata.
   //
   // This is necessary because ScriptResource and CSSStyleSheetResource objects
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcherTest.cpp b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcherTest.cpp
index 6be9d2a9..9e23fdb 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcherTest.cpp
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceFetcherTest.cpp
@@ -647,13 +647,14 @@
   Resource* resource = MockResource::fetch(fetchRequestOriginal, fetcher);
   ASSERT_TRUE(resource);
   EXPECT_TRUE(resource->isLinkPreload());
+  EXPECT_FALSE(fetcher->isFetching());
   fetcher->preloadStarted(resource);
 
   // Resource created by parser on the second fetcher
   FetchRequest fetchRequest2 = FetchRequest(url, FetchInitiatorInfo());
   Resource* newResource2 = MockResource::fetch(fetchRequest2, fetcher2);
   Persistent<MockResourceClient> client2 = new MockResourceClient(newResource2);
-  EXPECT_EQ(resource, newResource2);
+  EXPECT_NE(resource, newResource2);
   EXPECT_FALSE(fetcher2->isFetching());
   Platform::current()->getURLLoaderMockFactory()->serveAsynchronousRequests();
 }
diff --git a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.h b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.h
index 57895587..94a3c53 100644
--- a/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.h
+++ b/third_party/WebKit/Source/platform/loader/fetch/ResourceLoader.h
@@ -74,6 +74,8 @@
     return m_isCacheAwareLoadingActivated;
   }
 
+  ResourceFetcher* fetcher() { return m_fetcher; }
+
   // WebURLLoaderClient
   //
   // A succesful load will consist of:
diff --git a/third_party/widevine/cdm/BUILD.gn b/third_party/widevine/cdm/BUILD.gn
index 413b1fa2..34ae399f 100644
--- a/third_party/widevine/cdm/BUILD.gn
+++ b/third_party/widevine/cdm/BUILD.gn
@@ -42,10 +42,7 @@
     widevine_cdm_manifest_file = [ "win/$widevine_arch/manifest.json" ]
   } else if (is_mac) {
     widevine_cdm_version_h_file = "mac/$widevine_arch/widevine_cdm_version.h"
-    widevine_cdm_binary_files = [
-      "mac/$widevine_arch/libwidevinecdm.dylib",
-      "mac/$widevine_arch/libwidevinecdm.dylib.sig",
-    ]
+    widevine_cdm_binary_files = [ "mac/$widevine_arch/libwidevinecdm.dylib" ]
     widevine_cdm_manifest_file = [ "mac/$widevine_arch/manifest.json" ]
   } else {
     # Other platforms, use the default one.
diff --git a/third_party/widevine/cdm/widevine.gni b/third_party/widevine/cdm/widevine.gni
index a0b3164..b10a92b 100644
--- a/third_party/widevine/cdm/widevine.gni
+++ b/third_party/widevine/cdm/widevine.gni
@@ -6,35 +6,3 @@
   # Allow widevinecdmadapter to be built in Chromium.
   enable_widevine = false
 }
-
-template("widevine_sign_file") {
-  # For official builds, generate a signature file for |file| which will
-  # be used by Widevine. If |signature_file| is not specified, the signature
-  # file will be in the same directory as |file|.
-  action(target_name) {
-    forward_variables_from(invoker,
-                           [
-                             "file",
-                             "signature_file",
-                             "deps",
-                           ])
-    assert(defined(file), "File to be signed must be specified.")
-    if (!defined(signature_file)) {
-      signature_file = "$file.sig"
-    }
-
-    script = "//third_party/widevine/scripts/signature_generator.py"
-    sources = [
-      "$file",
-    ]
-    outputs = [
-      "$signature_file",
-    ]
-    args = [
-      "--input_file",
-      rebase_path("$file", root_build_dir),
-      "--output_file",
-      rebase_path("$signature_file", root_build_dir),
-    ]
-  }
-}
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index b3867068..8aef59a 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -62410,16 +62410,17 @@
 </histogram>
 
 <histogram name="SessionRestore.AllTabsLoaded" units="ms">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <owner>chrisha@chromium.org</owner>
+  <owner>georgesak@chromium.org</owner>
   <summary>
     The time from SessionRestore start until all tabs have finished loading.
   </summary>
 </histogram>
 
 <histogram name="SessionRestore.command_size" units="bytes">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>
     The size of the commands written to disk. See SessionBackend for details.
   </summary>
@@ -62436,8 +62437,8 @@
 </histogram>
 
 <histogram name="SessionRestore.ForegroundTabFirstLoaded" units="ms">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <owner>chrisha@chromium.org</owner>
+  <owner>georgesak@chromium.org</owner>
   <summary>
     The time from SessionRestore start until a visible tab has finished loading.
   </summary>
@@ -62470,8 +62471,7 @@
 
 <histogram name="SessionRestore.ForegroundTabFirstPaint3" units="ms">
   <owner>chrisha@chromium.org</owner>
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <owner>georgesak@chromium.org</owner>
   <summary>
     The time from SessionRestore start until a visible tab's first paint.
   </summary>
@@ -62488,14 +62488,16 @@
 </histogram>
 
 <histogram name="SessionRestore.last_session_file_size" units="KB">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>The size, in k, of the last session file on disk.</summary>
 </histogram>
 
 <histogram name="SessionRestore.NavEntryCommittedLongPeriod">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>
     Like NavEntryCommittedPeriod, but specifically to provide a clearer
     breakdown of samples in the 10 minutes - 8 hours range.
@@ -62503,8 +62505,9 @@
 </histogram>
 
 <histogram name="SessionRestore.NavEntryCommittedPeriod" units="ms">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>
     Milliseconds between subsequent Save() operations due to a nav entry being
     committed (new tab created + nav initiated).
@@ -62512,8 +62515,9 @@
 </histogram>
 
 <histogram name="SessionRestore.NavigationListPrunedLongPeriod">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>
     Like NavListPrunedPeriod, but specifically to provide a clearer breakdown of
     samples in the 10 minutes - 8 hours range.
@@ -62521,8 +62525,9 @@
 </histogram>
 
 <histogram name="SessionRestore.NavigationListPrunedPeriod" units="ms">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>
     Milliseconds between subsequent Save() operations due to the navigation list
     being pruned (typically a change in back/forward stacks).
@@ -62530,16 +62535,18 @@
 </histogram>
 
 <histogram name="SessionRestore.ParallelTabLoads">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>
     The number of tabs that were loaded simultaneously when restoring a session.
   </summary>
 </histogram>
 
 <histogram name="SessionRestore.read_session_file_time" units="ms">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>
     Amount of time to read and assemble the commands from the last session.
   </summary>
@@ -62565,8 +62572,9 @@
 </histogram>
 
 <histogram name="SessionRestore.SaveLongPeriod">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>
     Like SavePeriod, but specifically to provide a clearer breakdown of samples
     in the 10 minutes - 8 hours range.
@@ -62574,8 +62582,9 @@
 </histogram>
 
 <histogram name="SessionRestore.SavePeriod" units="ms">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>
     Amount of time between subsequent SessionService Save() operations (aka
     updates to session data).
@@ -62604,8 +62613,9 @@
 </histogram>
 
 <histogram name="SessionRestore.TabClosedLongPeriod">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>
     TabClosedPeriod, but specifically to provide a clearer breakdown of samples
     in the 10 minutes - 8 hours range.
@@ -62613,8 +62623,9 @@
 </histogram>
 
 <histogram name="SessionRestore.TabClosedPeriod" units="ms">
-  <owner>jeremy@chromium.org</owner>
-  <owner>sky@chromium.org</owner>
+  <obsolete>
+    Deprecated 2017-02 as not actionable.
+  </obsolete>
   <summary>
     Milliseconds between subsequent Save() operations due to a tab being closed.
   </summary>
@@ -66856,7 +66867,6 @@
 </histogram>
 
 <histogram name="Startup.ShowAppListColdStart" units="ms">
-  <owner>jeremy@chromium.org</owner>
   <owner>tapted@chromium.org</owner>
   <summary>
     Time for a newly created browser process to reach the code that starts
@@ -66866,7 +66876,6 @@
 </histogram>
 
 <histogram name="Startup.ShowAppListWarmStart" units="ms">
-  <owner>jeremy@chromium.org</owner>
   <owner>tapted@chromium.org</owner>
   <summary>
     Time for a running browser process to reach the code that starts showing the
@@ -69396,7 +69405,6 @@
 </histogram>
 
 <histogram name="Sync.Startup.TimeDeferred2" units="ms">
-  <owner>jeremy@chromium.org</owner>
   <owner>zea@google.com</owner>
   <summary>
     Time spent after ProfileSyncService *creation* but before SyncEngine
@@ -85194,6 +85202,7 @@
   <int value="35" label="NTPSnippets suggestions"/>
   <int value="36" label="NTPSnippets thumbnails"/>
   <int value="37" label="Doodle"/>
+  <int value="38" label="UKM"/>
 </enum>
 
 <enum name="DecodedImageOrientation" type="int">
diff --git a/ui/gl/gl_context_glx.cc b/ui/gl/gl_context_glx.cc
index 8f823ef..145162d 100644
--- a/ui/gl/gl_context_glx.cc
+++ b/ui/gl/gl_context_glx.cc
@@ -71,69 +71,68 @@
 GLXContext CreateHighestVersionContext(Display* display,
                                        GLXFBConfig config,
                                        GLXContext share) {
-  // It is commonly assumed that glXCreateContextAttrib will create a context
-  // of the highest version possible but it is not specified in the spec and
-  // is not true on the Mesa drivers. On Mesa, Instead we try to create a
-  // context per GL version until we succeed, starting from newer version.
-  // On both Mesa and other drivers we try to create a desktop context and fall
-  // back to ES context.
-  // The code could be simpler if the Mesa code path was used for all drivers,
-  // however the cost of failing a context creation can be high (3 milliseconds
-  // for the NVIDIA driver). The good thing is that failed context creation only
-  // takes 0.1 milliseconds on Mesa.
+  // The only way to get a core profile context of the highest version using
+  // glXCreateContextAttrib is to try creationg contexts in decreasing version
+  // numbers. It might look that asking for a core context of version (0, 0)
+  // works on some driver but it create a _compatibility_ context of the highest
+  // version instead. The cost of failing a context creation is small (< 0.1 ms)
+  // on Mesa but is unfortunately a bit expensive on the Nvidia driver (~3ms).
 
-  struct ContextCreationInfo {
-    int profileFlag;
-    GLVersion version;
-  };
-
-  // clang-format off
-  // For regular drivers we try to create a compatibility, core, then ES
-  // context. Without requiring any specific version.
-  const ContextCreationInfo contexts_to_try[] = {
-      { 0, GLVersion(0, 0) },
-      { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLVersion(0, 0) },
-      { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, GLVersion(0, 0) },
-  };
-
-  // On Mesa we try to create a core context, except for versions below 3.2
-  // where it is not applicable. (and fallback to ES as well)
-  const ContextCreationInfo mesa_contexts_to_try[] = {
-      { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 5) } },
-      { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 4) } },
-      { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 3) } },
-      { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 2) } },
-      { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 1) } },
-      { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(4, 0) } },
-      { GLX_CONTEXT_CORE_PROFILE_BIT_ARB, { GLVersion(3, 3) } },
-      // Do not try to create OpenGL context versions between 3.0 and
-      // 3.2 because of compatibility problems. crbug.com/659030
-      { 0, { GLVersion(2, 0) } },
-      { 0, { GLVersion(1, 5) } },
-      { 0, { GLVersion(1, 4) } },
-      { 0, { GLVersion(1, 3) } },
-      { 0, { GLVersion(1, 2) } },
-      { 0, { GLVersion(1, 1) } },
-      { 0, { GLVersion(1, 0) } },
-      { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(3, 2) } },
-      { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(3, 1) } },
-      { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(3, 0) } },
-      { GLX_CONTEXT_ES2_PROFILE_BIT_EXT, { GLVersion(2, 0) } },
-  };
-  // clang-format on
+  // Also try to get any Desktop GL context, but if that fails fallback to
+  // asking for OpenGL ES contexts.
 
   std::string client_vendor = glXGetClientString(display, GLX_VENDOR);
   bool is_mesa = client_vendor.find("Mesa") != std::string::npos;
 
-  const ContextCreationInfo* to_try = contexts_to_try;
-  size_t to_try_length = arraysize(contexts_to_try);
-  if (is_mesa) {
-    to_try = mesa_contexts_to_try;
-    to_try_length = arraysize(mesa_contexts_to_try);
+  struct ContextCreationInfo {
+    ContextCreationInfo(int profileFlag, GLVersion version)
+        : profileFlag(profileFlag), version(version) {}
+    int profileFlag;
+    GLVersion version;
+  };
+
+  std::vector<ContextCreationInfo> contexts_to_try;
+  contexts_to_try.emplace_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+                               GLVersion(4, 5));
+  contexts_to_try.emplace_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+                               GLVersion(4, 4));
+  contexts_to_try.emplace_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+                               GLVersion(4, 3));
+  contexts_to_try.emplace_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+                               GLVersion(4, 2));
+  contexts_to_try.emplace_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+                               GLVersion(4, 1));
+  contexts_to_try.emplace_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+                               GLVersion(4, 0));
+  contexts_to_try.emplace_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+                               GLVersion(3, 3));
+
+  // On Mesa, do not try to create OpenGL context versions between 3.0 and
+  // 3.2 because of compatibility problems. See crbug.com/659030
+  if (!is_mesa) {
+    contexts_to_try.emplace_back(0, GLVersion(3, 2));
+    contexts_to_try.emplace_back(0, GLVersion(3, 1));
+    contexts_to_try.emplace_back(0, GLVersion(3, 0));
   }
 
-  for (size_t i = 0; i < to_try_length; ++i) {
-    const ContextCreationInfo& info = to_try[i];
+  contexts_to_try.emplace_back(0, GLVersion(2, 1));
+  contexts_to_try.emplace_back(0, GLVersion(2, 0));
+  contexts_to_try.emplace_back(0, GLVersion(1, 5));
+  contexts_to_try.emplace_back(0, GLVersion(1, 4));
+  contexts_to_try.emplace_back(0, GLVersion(1, 3));
+  contexts_to_try.emplace_back(0, GLVersion(1, 2));
+  contexts_to_try.emplace_back(0, GLVersion(1, 1));
+  contexts_to_try.emplace_back(0, GLVersion(1, 0));
+  contexts_to_try.emplace_back(GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
+                               GLVersion(3, 2));
+  contexts_to_try.emplace_back(GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
+                               GLVersion(3, 1));
+  contexts_to_try.emplace_back(GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
+                               GLVersion(3, 0));
+  contexts_to_try.emplace_back(GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
+                               GLVersion(2, 0));
+
+  for (const auto& info : contexts_to_try) {
     if (!GLSurfaceGLX::IsCreateContextES2ProfileSupported() &&
         info.profileFlag == GLX_CONTEXT_ES2_PROFILE_BIT_EXT) {
       continue;